Merge branch 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 31 Mar 2018 17:26:48 +0000 (07:26 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 31 Mar 2018 17:26:48 +0000 (07:26 -1000)
Pull x86 PTI fixes from Ingo Molnar:
 "Two fixes: a relatively simple objtool fix that makes Clang built
  kernels work with ORC debug info, plus an alternatives macro fix"

* 'x86-pti-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/alternatives: Fixup alternative_call_2
  objtool: Add Clang support

1592 files changed:
.gitignore
.mailmap
Documentation/ABI/testing/sysfs-ata
Documentation/ABI/testing/sysfs-block-device [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class-scsi_host
Documentation/ABI/testing/sysfs-devices-platform-dock [new file with mode: 0644]
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/ABI/testing/sysfs-platform-dptf [new file with mode: 0644]
Documentation/PCI/pci.txt
Documentation/accelerators/ocxl.rst
Documentation/atomic_bitops.txt
Documentation/devicetree/bindings/auxdisplay/arm-charlcd.txt [moved from Documentation/devicetree/bindings/misc/arm-charlcd.txt with 100% similarity]
Documentation/devicetree/bindings/display/exynos/exynos_hdmi.txt
Documentation/devicetree/bindings/dma/mv-xor-v2.txt
Documentation/devicetree/bindings/eeprom/at24.txt
Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.txt
Documentation/devicetree/bindings/interrupt-controller/renesas,irqc.txt
Documentation/devicetree/bindings/net/dsa/marvell.txt
Documentation/devicetree/bindings/net/renesas,ravb.txt
Documentation/devicetree/bindings/power/wakeup-source.txt
Documentation/devicetree/bindings/thermal/imx-thermal.txt
Documentation/devicetree/bindings/usb/dwc2.txt
Documentation/devicetree/bindings/usb/renesas_usb3.txt
Documentation/devicetree/bindings/usb/renesas_usbhs.txt
Documentation/devicetree/bindings/usb/usb-xhci.txt
Documentation/features/sched/membarrier-sync-core/arch-support.txt [new file with mode: 0644]
Documentation/gpu/tve200.rst
Documentation/i2c/busses/i2c-i801
Documentation/ia64/serial.txt
Documentation/isdn/INTERFACE.CAPI
Documentation/isdn/README
Documentation/isdn/README.FAQ
Documentation/isdn/README.gigaset
Documentation/locking/mutex-design.txt
Documentation/media/dmx.h.rst.exceptions
Documentation/media/uapi/dvb/dmx-qbuf.rst
Documentation/networking/segmentation-offloads.txt
Documentation/sphinx/kerneldoc.py
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/cpuid.txt
Documentation/virtual/kvm/msr.txt
Documentation/x86/intel_rdt_ui.txt
Documentation/x86/topology.txt
MAINTAINERS
Makefile
arch/alpha/include/asm/cmpxchg.h
arch/alpha/include/asm/xchg.h
arch/arc/Kconfig
arch/arc/boot/dts/axs101.dts
arch/arc/boot/dts/axs10x_mb.dtsi
arch/arc/boot/dts/haps_hs_idu.dts
arch/arc/boot/dts/nsim_700.dts
arch/arc/boot/dts/nsim_hs.dts
arch/arc/boot/dts/nsim_hs_idu.dts
arch/arc/boot/dts/nsimosci.dts
arch/arc/boot/dts/nsimosci_hs.dts
arch/arc/boot/dts/nsimosci_hs_idu.dts
arch/arc/include/asm/bug.h
arch/arc/include/asm/entry-arcv2.h
arch/arc/kernel/mcip.c
arch/arc/kernel/setup.c
arch/arc/kernel/smp.c
arch/arc/kernel/unwind.c
arch/arc/mm/cache.c
arch/arm/Kconfig.debug
arch/arm/boot/deflate_xip_data.sh
arch/arm/boot/dts/aspeed-g4.dtsi
arch/arm/boot/dts/aspeed-g5.dtsi
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/bcm21664.dtsi
arch/arm/boot/dts/bcm2835.dtsi
arch/arm/boot/dts/bcm2836.dtsi
arch/arm/boot/dts/bcm2837.dtsi
arch/arm/boot/dts/bcm283x.dtsi
arch/arm/boot/dts/bcm958625hr.dts
arch/arm/boot/dts/gemini-dlink-dns-313.dts
arch/arm/boot/dts/imx6dl-icore-rqs.dts
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/logicpd-som-lv.dtsi
arch/arm/boot/dts/logicpd-torpedo-som.dtsi
arch/arm/boot/dts/omap5-uevm.dts
arch/arm/boot/dts/rk3036.dtsi
arch/arm/boot/dts/rk322x.dtsi
arch/arm/boot/dts/rk3288-phycore-som.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
arch/arm/boot/dts/zx296702.dtsi
arch/arm/configs/omap2plus_defconfig
arch/arm/include/asm/vdso.h
arch/arm/kernel/time.c
arch/arm/kernel/vdso.c
arch/arm/kvm/hyp/Makefile
arch/arm/kvm/hyp/banked-sr.c
arch/arm/mach-clps711x/board-dt.c
arch/arm/mach-davinci/board-dm355-evm.c
arch/arm/mach-davinci/board-dm355-leopard.c
arch/arm/mach-davinci/board-dm365-evm.c
arch/arm/mach-davinci/board-omapl138-hawk.c
arch/arm/mach-mvebu/Kconfig
arch/arm/mach-omap1/clock.c
arch/arm/mach-omap2/omap-wakeupgen.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/pm.c
arch/arm/mach-omap2/timer.c
arch/arm/mach-orion5x/Kconfig
arch/arm/mach-orion5x/dns323-setup.c
arch/arm/mach-orion5x/tsx09-common.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/include/plat/sram.h
arch/arm/plat-omap/sram.c
arch/arm/plat-orion/common.c
arch/arm/vfp/vfpmodule.c
arch/arm64/boot/dts/amlogic/meson-axg.dtsi
arch/arm64/boot/dts/amlogic/meson-gx.dtsi
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi
arch/arm64/boot/dts/cavium/thunder2-99xx.dtsi
arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
arch/arm64/boot/dts/mediatek/mt8173.dtsi
arch/arm64/boot/dts/qcom/apq8096-db820c.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/rockchip/rk3328-rock64.dts
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3368.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
arch/arm64/boot/dts/rockchip/rk3399-sapphire.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/hugetlb.h
arch/arm64/include/asm/kvm_mmu.h
arch/arm64/include/asm/mmu_context.h
arch/arm64/include/asm/pgalloc.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/stacktrace.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/efi.c
arch/arm64/kernel/hibernate.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/process.c
arch/arm64/kernel/ptrace.c
arch/arm64/kernel/stacktrace.c
arch/arm64/kernel/sys_compat.c
arch/arm64/kernel/time.c
arch/arm64/kernel/traps.c
arch/arm64/kvm/guest.c
arch/arm64/kvm/hyp/switch.c
arch/arm64/mm/dump.c
arch/arm64/mm/fault.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/kasan_init.c
arch/arm64/mm/mmu.c
arch/arm64/mm/pageattr.c
arch/arm64/mm/proc.S
arch/arm64/net/bpf_jit_comp.c
arch/cris/include/arch-v10/arch/bug.h
arch/h8300/include/asm/byteorder.h
arch/ia64/include/asm/atomic.h
arch/ia64/include/asm/bug.h
arch/ia64/kernel/Makefile
arch/ia64/kernel/err_inject.c
arch/ia64/scripts/unwcheck.py
arch/m68k/include/asm/bug.h
arch/microblaze/Kconfig
arch/microblaze/Kconfig.platform
arch/microblaze/include/asm/setup.h
arch/microblaze/lib/fastcopy.S
arch/microblaze/mm/init.c
arch/mips/ath25/board.c
arch/mips/boot/Makefile
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/include/asm/compat.h
arch/mips/kernel/setup.c
arch/mips/kernel/smp-bmips.c
arch/mips/lantiq/Kconfig
arch/mips/lantiq/xway/sysctrl.c
arch/mips/loongson64/Kconfig
arch/mips/ralink/mt7621.c
arch/mips/ralink/reset.c
arch/parisc/include/asm/cacheflush.h
arch/parisc/include/asm/processor.h
arch/parisc/kernel/cache.c
arch/parisc/kernel/head.S
arch/parisc/kernel/pacache.S
arch/parisc/kernel/smp.c
arch/parisc/kernel/time.c
arch/parisc/mm/init.c
arch/powerpc/boot/Makefile
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/book3s/64/tlbflush-radix.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/firmware.h
arch/powerpc/include/asm/mmu_context.h
arch/powerpc/include/asm/topology.h
arch/powerpc/kernel/dt_cpu_ftrs.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kvm/book3s_64_mmu_radix.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_xive.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/mm/drmem.c
arch/powerpc/mm/hash_native_64.c
arch/powerpc/mm/mmu_context_book3s64.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/tlb-radix.c
arch/powerpc/net/bpf_jit_comp.c
arch/powerpc/net/bpf_jit_comp64.c
arch/powerpc/platforms/powernv/opal-imc.c
arch/powerpc/platforms/powernv/pci-ioda.c
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/xive/spapr.c
arch/riscv/Kconfig
arch/riscv/include/asm/barrier.h
arch/riscv/kernel/entry.S
arch/riscv/kernel/head.S
arch/riscv/kernel/setup.c
arch/s390/include/asm/mmu_context.h
arch/s390/kernel/entry.S
arch/s390/kernel/nospec-branch.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/kvm/priv.c
arch/s390/kvm/vsie.c
arch/sh/boot/dts/Makefile
arch/sparc/Kconfig
arch/sparc/include/asm/bug.h
arch/sparc/mm/tlb.c
arch/x86/.gitignore
arch/x86/Kconfig
arch/x86/Kconfig.cpu
arch/x86/boot/compressed/eboot.c
arch/x86/entry/entry_64.S
arch/x86/events/core.c
arch/x86/events/intel/core.c
arch/x86/events/intel/ds.c
arch/x86/events/intel/uncore_snbep.c
arch/x86/events/perf_event.h
arch/x86/include/asm/bitops.h
arch/x86/include/asm/cpufeature.h
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/page_64.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/refcount.h
arch/x86/include/asm/smp.h
arch/x86/include/asm/vmx.h
arch/x86/include/uapi/asm/hyperv.h
arch/x86/include/uapi/asm/kvm_para.h
arch/x86/include/uapi/asm/mce.h
arch/x86/kernel/apic/vector.c
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/cpu/intel_rdt_rdtgroup.c
arch/x86/kernel/cpu/mcheck/mce-internal.h
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/kvm.c
arch/x86/kernel/machine_kexec_64.c
arch/x86/kernel/module.c
arch/x86/kernel/signal_compat.c
arch/x86/kernel/smpboot.c
arch/x86/kvm/cpuid.c
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lib/error-inject.c
arch/x86/mm/fault.c
arch/x86/mm/init_64.c
arch/x86/mm/pgtable.c
arch/x86/net/bpf_jit_comp.c
arch/x86/oprofile/nmi_int.c
arch/x86/platform/intel-mid/intel-mid.c
arch/x86/tools/relocs.c
arch/x86/xen/enlighten_pv.c
arch/x86/xen/smp.c
arch/xtensa/kernel/pci-dma.c
arch/xtensa/mm/init.c
block/blk-cgroup.c
block/blk-core.c
block/blk-mq.c
block/genhd.c
block/ioctl.c
block/kyber-iosched.c
block/mq-deadline.c
block/partition-generic.c
block/sed-opal.c
certs/blacklist_nohashes.c
crypto/asymmetric_keys/pkcs7_trust.c
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/public_key.c
crypto/asymmetric_keys/restrict.c
drivers/acpi/acpi_watchdog.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/ec.c
drivers/acpi/nfit/core.c
drivers/acpi/numa.c
drivers/acpi/property.c
drivers/acpi/spcr.c
drivers/android/binder.c
drivers/ata/ahci.c
drivers/ata/libahci.c
drivers/ata/libahci_platform.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/sata_rcar.c
drivers/atm/iphase.c
drivers/auxdisplay/img-ascii-lcd.c
drivers/auxdisplay/panel.c
drivers/base/core.c
drivers/base/power/wakeirq.c
drivers/base/property.c
drivers/block/amiflop.c
drivers/block/ataflop.c
drivers/block/brd.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/nbd.c
drivers/block/pktcdvd.c
drivers/block/swim.c
drivers/block/xen-blkfront.c
drivers/block/z2ram.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_bcm.c
drivers/bus/ti-sysc.c
drivers/char/tpm/st33zp24/st33zp24.c
drivers/char/tpm/tpm-interface.c
drivers/char/tpm/tpm2-cmd.c
drivers/char/tpm/tpm_i2c_infineon.c
drivers/char/tpm/tpm_i2c_nuvoton.c
drivers/char/tpm/tpm_tis_core.c
drivers/clk/bcm/clk-bcm2835.c
drivers/clk/clk-aspeed.c
drivers/clk/clk.c
drivers/clk/hisilicon/clk-hi3660-stub.c
drivers/clk/imx/clk-imx51-imx53.c
drivers/clk/qcom/apcs-msm8916.c
drivers/clk/sunxi-ng/ccu-sun6i-a31.c
drivers/clk/ti/clk-33xx.c
drivers/clk/ti/clk-43xx.c
drivers/clk/ti/clkctrl.c
drivers/clocksource/Kconfig
drivers/clocksource/arc_timer.c
drivers/clocksource/fsl_ftm_timer.c
drivers/clocksource/mips-gic-timer.c
drivers/clocksource/timer-sun5i.c
drivers/cpufreq/Kconfig.arm
drivers/cpufreq/s3c24xx-cpufreq.c
drivers/cpufreq/scpi-cpufreq.c
drivers/crypto/ccp/psp-dev.c
drivers/crypto/s5p-sss.c
drivers/dax/super.c
drivers/dma/mv_xor_v2.c
drivers/dma/sh/rcar-dmac.c
drivers/dma/stm32-dmamux.c
drivers/edac/sb_edac.c
drivers/extcon/extcon-axp288.c
drivers/extcon/extcon-intel-int3496.c
drivers/firmware/dcdbas.c
drivers/firmware/efi/libstub/tpm.c
drivers/gpio/gpio-rcar.c
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c
drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gtt_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c
drivers/gpu/drm/amd/amdgpu/atombios_encoders.c
drivers/gpu/drm/amd/amdgpu/atombios_encoders.h
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_v7_0.c
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c
drivers/gpu/drm/amd/amdgpu/sdma_v4_0.c
drivers/gpu/drm/amd/amdgpu/si.c
drivers/gpu/drm/amd/amdgpu/si_dpm.c
drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/core/dc_stream.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_stream.h
drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
drivers/gpu/drm/amd/display/dc/dce/dce_opp.c
drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h
drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c
drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
drivers/gpu/drm/amd/display/include/signal_types.h
drivers/gpu/drm/amd/powerplay/amd_powerplay.c
drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c
drivers/gpu/drm/ast/ast_tables.h
drivers/gpu/drm/cirrus/cirrus_mode.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_framebuffer.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_probe_helper.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_rotator.h [deleted file]
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/regs-fimc.h
drivers/gpu/drm/exynos/regs-hdmi.h
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/gvt/kvmgt.c
drivers/gpu/drm/i915/gvt/mmio_context.c
drivers/gpu/drm/i915/gvt/scheduler.c
drivers/gpu/drm/i915/gvt/scheduler.h
drivers/gpu/drm/i915/gvt/trace.h
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_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_request.c
drivers/gpu/drm/i915/i915_oa_cflgt3.c
drivers/gpu/drm/i915/i915_oa_cnl.c
drivers/gpu/drm/i915/i915_perf.c
drivers/gpu/drm/i915/i915_pmu.c
drivers/gpu/drm/i915/i915_pmu.h
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_breadcrumbs.c
drivers/gpu/drm/i915/intel_cdclk.c
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_engine_cs.c
drivers/gpu/drm/i915/intel_hangcheck.c
drivers/gpu/drm/i915/intel_lrc.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/imx/ipuv3-crtc.c
drivers/gpu/drm/imx/ipuv3-plane.c
drivers/gpu/drm/meson/meson_crtc.c
drivers/gpu/drm/meson/meson_drv.h
drivers/gpu/drm/meson/meson_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
drivers/gpu/drm/nouveau/nouveau_backlight.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c
drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/scheduler/gpu_scheduler.c
drivers/gpu/drm/sun4i/sun4i_crtc.c
drivers/gpu/drm/sun4i/sun4i_dotclock.c
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
drivers/gpu/drm/sun4i/sun4i_rgb.c
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/plane.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/virtio/virtgpu_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
drivers/gpu/ipu-v3/ipu-common.c
drivers/gpu/ipu-v3/ipu-cpmem.c
drivers/gpu/ipu-v3/ipu-csi.c
drivers/gpu/ipu-v3/ipu-pre.c
drivers/gpu/ipu-v3/ipu-prg.c
drivers/hid/hid-ids.h
drivers/hid/hid-quirks.c
drivers/hv/ring_buffer.c
drivers/hwmon/k10temp.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-bcm2835.c
drivers/i2c/busses/i2c-designware-master.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-octeon-core.c
drivers/i2c/busses/i2c-octeon-core.h
drivers/i2c/busses/i2c-sirf.c
drivers/i2c/busses/i2c-stm32f7.c
drivers/ide/ide-probe.c
drivers/iio/accel/st_accel_core.c
drivers/iio/adc/aspeed_adc.c
drivers/iio/adc/meson_saradc.c
drivers/iio/adc/stm32-adc.c
drivers/iio/adc/stm32-dfsdm-adc.c
drivers/iio/adc/stm32-dfsdm-core.c
drivers/iio/chemical/ccs811.c
drivers/iio/imu/adis_trigger.c
drivers/iio/industrialio-buffer.c
drivers/iio/pressure/st_pressure_core.c
drivers/iio/proximity/Kconfig
drivers/infiniband/core/addr.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/cq.c
drivers/infiniband/core/device.c
drivers/infiniband/core/rdma_core.c
drivers/infiniband/core/restrack.c
drivers/infiniband/core/sa_query.c
drivers/infiniband/core/ucma.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_ioctl.c
drivers/infiniband/core/uverbs_ioctl_merge.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/core/uverbs_std_types.c
drivers/infiniband/core/verbs.c
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/ib_verbs.h
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_fp.h
drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
drivers/infiniband/hw/bnxt_re/qplib_sp.c
drivers/infiniband/hw/bnxt_re/roce_hsi.h
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/mlx4/cq.c
drivers/infiniband/hw/mlx4/main.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/mlx5/srq.c
drivers/infiniband/hw/qedr/main.c
drivers/infiniband/hw/qedr/qedr_iw_cm.c
drivers/infiniband/hw/qedr/verbs.c
drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
drivers/infiniband/hw/vmw_pvrdma/pvrdma_srq.c
drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c
drivers/infiniband/sw/rdmavt/mr.c
drivers/infiniband/ulp/ipoib/ipoib_fs.c
drivers/input/keyboard/matrix_keypad.c
drivers/input/mouse/synaptics.c
drivers/input/touchscreen/mms114.c
drivers/iommu/intel-svm.c
drivers/irqchip/irq-bcm7038-l1.c
drivers/irqchip/irq-bcm7120-l2.c
drivers/irqchip/irq-brcmstb-l2.c
drivers/irqchip/irq-gic-v2m.c
drivers/irqchip/irq-gic-v3-its-pci-msi.c
drivers/irqchip/irq-gic-v3-its-platform-msi.c
drivers/irqchip/irq-gic-v3-its.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-imx-gpcv2.c
drivers/irqchip/irq-mips-gic.c
drivers/macintosh/macio_asic.c
drivers/md/bcache/request.c
drivers/md/bcache/super.c
drivers/md/dm-bufio.c
drivers/md/dm-mpath.c
drivers/md/dm-raid.c
drivers/md/dm-table.c
drivers/md/dm.c
drivers/md/md-multipath.c
drivers/md/md.c
drivers/md/md.h
drivers/md/raid1.c
drivers/md/raid1.h
drivers/md/raid10.c
drivers/md/raid10.h
drivers/md/raid5-log.h
drivers/md/raid5-ppl.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/Kconfig
drivers/media/common/videobuf2/Kconfig
drivers/media/common/videobuf2/Makefile
drivers/media/common/videobuf2/vb2-trace.c [moved from drivers/media/v4l2-core/vb2-trace.c with 100% similarity]
drivers/media/dvb-core/Makefile
drivers/media/dvb-core/dmxdev.c
drivers/media/dvb-core/dvb_demux.c
drivers/media/dvb-core/dvb_net.c
drivers/media/dvb-core/dvb_vb2.c
drivers/media/dvb-frontends/m88ds3103.c
drivers/media/i2c/tvp5150.c
drivers/media/pci/ttpci/av7110.c
drivers/media/pci/ttpci/av7110_av.c
drivers/media/platform/tegra-cec/tegra_cec.c
drivers/media/usb/au0828/Kconfig
drivers/media/usb/ttusb-dec/ttusb_dec.c
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/Makefile
drivers/memory/brcmstb_dpfe.c
drivers/message/fusion/mptctl.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/pci-me.c
drivers/misc/ocxl/file.c
drivers/mmc/core/block.c
drivers/mmc/core/card.h
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/quirks.h
drivers/mmc/host/bcm2835.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc-rockchip.c
drivers/mmc/host/dw_mmc-zx.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/meson-gx-mmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-pci-core.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/atmel/pmecc.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/vf610_nfc.c
drivers/net/bonding/bond_main.c
drivers/net/can/cc770/cc770.c
drivers/net/can/cc770/cc770.h
drivers/net/can/ifi_canfd/ifi_canfd.c
drivers/net/can/m_can/m_can.c
drivers/net/can/peak_canfd/peak_canfd.c
drivers/net/can/peak_canfd/peak_pciefd_main.c
drivers/net/dsa/Makefile
drivers/net/dsa/b53/b53_common.c
drivers/net/dsa/mt7530.c
drivers/net/ethernet/8390/Kconfig
drivers/net/ethernet/amd/xgbe/xgbe-pci.c
drivers/net/ethernet/aquantia/atlantic/aq_cfg.h
drivers/net/ethernet/aquantia/atlantic/aq_nic.c
drivers/net/ethernet/aquantia/atlantic/aq_nic.h
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
drivers/net/ethernet/aquantia/atlantic/aq_ring.c
drivers/net/ethernet/aquantia/atlantic/aq_ring.h
drivers/net/ethernet/aquantia/atlantic/aq_vec.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.c
drivers/net/ethernet/aquantia/atlantic/hw_atl/hw_atl_utils.h
drivers/net/ethernet/aquantia/atlantic/ver.h
drivers/net/ethernet/arc/emac_rockchip.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bcmsysport.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_tc.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cavium/common/cavium_ptp.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/chelsio/cxgb4/cudbg_lib.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_cudbg.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
drivers/net/ethernet/cortina/gemini.c
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/freescale/fman/fman_dtsec.c
drivers/net/ethernet/freescale/gianfar.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c
drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c
drivers/net/ethernet/hisilicon/hns/hns_ethtool.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/e1000e/defines.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/mac.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/mvneta.c
drivers/net/ethernet/marvell/mvpp2.c
drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/mellanox/mlx4/en_main.c
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/diag/fs_tracepoint.c
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_selftest.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/eswitch.c
drivers/net/ethernet/mellanox/mlx5/core/fs_core.c
drivers/net/ethernet/mellanox/mlx5/core/health.c
drivers/net/ethernet/mellanox/mlx5/core/lib/clock.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_keys.h
drivers/net/ethernet/mellanox/mlxsw/spectrum.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.h
drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_buffers.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_fid.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c
drivers/net/ethernet/natsemi/Kconfig
drivers/net/ethernet/natsemi/Makefile
drivers/net/ethernet/netronome/nfp/bpf/jit.c
drivers/net/ethernet/qlogic/qed/qed_cxt.c
drivers/net/ethernet/qlogic/qed/qed_iwarp.c
drivers/net/ethernet/qlogic/qed/qed_rdma.c
drivers/net/ethernet/qlogic/qede/qede_fp.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/qlogic/qede/qede_ptp.c
drivers/net/ethernet/qualcomm/emac/emac-mac.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/renesas/ravb_main.c
drivers/net/ethernet/renesas/sh_eth.c
drivers/net/ethernet/renesas/sh_eth.h
drivers/net/ethernet/smsc/Kconfig
drivers/net/ethernet/smsc/smsc911x.c
drivers/net/ethernet/socionext/sni_ave.c
drivers/net/ethernet/sun/sunvnet.c
drivers/net/ethernet/ti/cpsw.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/macsec.c
drivers/net/macvlan.c
drivers/net/phy/bcm-phy-lib.c
drivers/net/phy/marvell.c
drivers/net/phy/micrel.c
drivers/net/phy/phy.c
drivers/net/phy/phy_device.c
drivers/net/phy/realtek.c
drivers/net/ppp/ppp_generic.c
drivers/net/team/team.c
drivers/net/thunderbolt.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/lan78xx.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/r8152.c
drivers/net/usb/smsc75xx.c
drivers/net/usb/usbnet.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vrf.c
drivers/net/wan/hdlc_ppp.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/cfg/9000.c
drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h
drivers/net/wireless/intel/iwlwifi/fw/dbg.c
drivers/net/wireless/intel/iwlwifi/fw/dbg.h
drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
drivers/net/wireless/intel/iwlwifi/fw/file.h
drivers/net/wireless/intel/iwlwifi/fw/init.c
drivers/net/wireless/intel/iwlwifi/fw/runtime.h
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.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/phy-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c
drivers/net/xen-netfront.c
drivers/nvdimm/blk.c
drivers/nvdimm/btt.c
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
drivers/nvdimm/region_devs.c
drivers/nvme/host/core.c
drivers/nvme/host/fabrics.c
drivers/nvme/host/fabrics.h
drivers/nvme/host/fc.c
drivers/nvme/host/multipath.c
drivers/nvme/host/nvme.h
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/target/core.c
drivers/nvme/target/io-cmd.c
drivers/nvme/target/loop.c
drivers/of/property.c
drivers/opp/cpu.c
drivers/pci/dwc/pcie-designware-host.c
drivers/pci/quirks.c
drivers/pci/setup-res.c
drivers/perf/arm_pmu.c
drivers/perf/arm_pmu_acpi.c
drivers/perf/arm_pmu_platform.c
drivers/phy/qualcomm/phy-qcom-ufs.c
drivers/pinctrl/meson/pinctrl-meson-axg.c
drivers/pinctrl/samsung/pinctrl-exynos-arm.c
drivers/pinctrl/samsung/pinctrl-exynos-arm64.c
drivers/pinctrl/samsung/pinctrl-s3c24xx.c
drivers/pinctrl/samsung/pinctrl-s3c64xx.c
drivers/pinctrl/samsung/pinctrl-samsung.c
drivers/pinctrl/samsung/pinctrl-samsung.h
drivers/pinctrl/sh-pfc/pfc-r8a7795.c
drivers/platform/chrome/chromeos_laptop.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-smbios-base.c [moved from drivers/platform/x86/dell-smbios.c with 95% similarity]
drivers/platform/x86/dell-smbios-smm.c
drivers/platform/x86/dell-smbios-wmi.c
drivers/platform/x86/dell-smbios.h
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel-hid.c
drivers/platform/x86/intel-vbtn.c
drivers/platform/x86/wmi.c
drivers/regulator/core.c
drivers/regulator/stm32-vrefbuf.c
drivers/s390/block/dasd.c
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/io_sch.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3.h
drivers/s390/net/qeth_l3_main.c
drivers/s390/virtio/virtio_ccw.c
drivers/scsi/Makefile
drivers/scsi/aacraid/linit.c
drivers/scsi/aic7xxx/aiclib.c [deleted file]
drivers/scsi/bnx2fc/bnx2fc_io.c
drivers/scsi/csiostor/csio_lnode.c
drivers/scsi/device_handler/scsi_dh_alua.c
drivers/scsi/hosts.c
drivers/scsi/hpsa.c
drivers/scsi/hpsa.h
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/iscsi_tcp.c
drivers/scsi/libsas/sas_scsi_host.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mpt3sas/mpt3sas_base.c
drivers/scsi/mpt3sas/mpt3sas_base.h
drivers/scsi/mpt3sas/mpt3sas_scsih.c
drivers/scsi/qedi/qedi_fw.c
drivers/scsi/qedi/qedi_main.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gs.c
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla4xxx/ql4_def.h
drivers/scsi/qla4xxx/ql4_os.c
drivers/scsi/scsi_error.c
drivers/scsi/scsi_lib.c
drivers/scsi/sd.c
drivers/scsi/sd_zbc.c
drivers/scsi/storvsc_drv.c
drivers/scsi/sym53c8xx_2/sym_hipd.c
drivers/scsi/ufs/ufshcd.c
drivers/scsi/virtio_scsi.c
drivers/soc/fsl/qbman/qman.c
drivers/soc/imx/gpc.c
drivers/staging/android/ashmem.c
drivers/staging/android/ion/ion_cma_heap.c
drivers/staging/comedi/drivers.c
drivers/staging/fsl-mc/bus/Kconfig
drivers/staging/fsl-mc/bus/irq-gic-v3-its-fsl-mc-msi.c
drivers/staging/iio/adc/ad7192.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/ncpfs/ncplib_kernel.c
drivers/tty/n_tty.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/atmel_serial.c
drivers/tty/serial/earlycon.c
drivers/tty/serial/imx.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/sh-sci.c
drivers/tty/tty_io.c
drivers/tty/vt/vt.c
drivers/usb/Kconfig
drivers/usb/class/cdc-acm.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/params.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/dwc3-of-simple.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/function/f_uac2.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/bdc/bdc_pci.c
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/fsl_udc_core.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-q.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-dbgtty.c
drivers/usb/host/xhci-debugfs.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-rcar.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/ldusb.c
drivers/usb/mon/mon_text.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_host.c
drivers/usb/phy/phy-mxs-usb.c
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/serial/option.c
drivers/usb/storage/uas.c
drivers/usb/storage/unusual_devs.h
drivers/usb/typec/fusb302/fusb302.c
drivers/usb/typec/tcpm.c
drivers/usb/usbip/stub_dev.c
drivers/usb/usbip/vhci_hcd.c
drivers/usb/usbip/vudc_sysfs.c
drivers/vfio/pci/vfio_pci.c
drivers/vfio/vfio_iommu_type1.c
drivers/vhost/net.c
drivers/vhost/vhost.c
drivers/video/fbdev/sbuslib.c
drivers/virtio/virtio_ring.c
drivers/watchdog/Kconfig
drivers/watchdog/f71808e_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/sbsa_gwdt.c
drivers/watchdog/wdat_wdt.c
drivers/xen/events/events_base.c
drivers/xen/pvcalls-back.c
drivers/xen/pvcalls-front.c
drivers/xen/tmem.c
drivers/xen/xenbus/xenbus.h
drivers/xen/xenbus/xenbus_comms.c
drivers/xen/xenbus/xenbus_probe.c
drivers/xen/xenbus/xenbus_xs.c
fs/aio.c
fs/block_dev.c
fs/btrfs/backref.c
fs/btrfs/ctree.h
fs/btrfs/delayed-ref.c
fs/btrfs/extent-tree.c
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/qgroup.c
fs/btrfs/raid56.c
fs/btrfs/relocation.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/super.c
fs/ceph/super.h
fs/dcache.c
fs/direct-io.c
fs/efivarfs/file.c
fs/gfs2/bmap.c
fs/hugetlbfs/inode.c
fs/namei.c
fs/nfs/callback_proc.c
fs/nfs/direct.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4client.c
fs/nfs/pnfs.c
fs/nfs/super.c
fs/nfs/write.c
fs/nfsd/nfs4state.c
fs/overlayfs/Kconfig
fs/overlayfs/export.c
fs/overlayfs/inode.c
fs/overlayfs/namei.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/proc/kcore.c
fs/signalfd.c
fs/sysfs/symlink.c
fs/xfs/scrub/agheader.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_refcount_item.c
fs/xfs/xfs_rmap_item.c
fs/xfs/xfs_super.c
include/asm-generic/bitops/lock.h
include/asm-generic/bug.h
include/asm-generic/pgtable.h
include/drm/drm_atomic.h
include/drm/drm_crtc_helper.h
include/drm/drm_drv.h
include/kvm/arm_vgic.h
include/linux/acpi.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/cgroup-defs.h
include/linux/compat.h
include/linux/compiler-gcc.h
include/linux/compiler.h
include/linux/cpuidle.h
include/linux/cpumask.h
include/linux/dma-mapping.h
include/linux/fs.h
include/linux/fsl_ifc.h
include/linux/fwnode.h
include/linux/genhd.h
include/linux/if_tun.h
include/linux/if_vlan.h
include/linux/irqchip/arm-gic-v3.h
include/linux/irqchip/arm-gic.h
include/linux/jump_label.h
include/linux/kconfig.h
include/linux/kcore.h
include/linux/kvm_host.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/mlx5/driver.h
include/linux/mm_inline.h
include/linux/mutex.h
include/linux/net.h
include/linux/net_dim.h
include/linux/netfilter/x_tables.h
include/linux/of_pci.h
include/linux/percpu-refcount.h
include/linux/perf/arm_pmu.h
include/linux/phy.h
include/linux/property.h
include/linux/ptr_ring.h
include/linux/rhashtable.h
include/linux/sched/mm.h
include/linux/sched/user.h
include/linux/semaphore.h
include/linux/skbuff.h
include/linux/swap.h
include/linux/tty.h
include/linux/u64_stats_sync.h
include/linux/usb/quirks.h
include/linux/workqueue.h
include/media/demux.h
include/media/dmxdev.h
include/media/dvb_demux.h
include/media/dvb_vb2.h
include/net/devlink.h
include/net/ip.h
include/net/ip6_route.h
include/net/ip_fib.h
include/net/llc_conn.h
include/net/mac80211.h
include/net/netfilter/nf_tables.h
include/net/regulatory.h
include/net/route.h
include/net/sch_generic.h
include/net/sock.h
include/net/udplite.h
include/rdma/ib_addr.h
include/rdma/ib_verbs.h
include/rdma/restrack.h
include/rdma/uverbs_ioctl.h
include/scsi/scsi_cmnd.h
include/scsi/scsi_host.h
include/soc/arc/mcip.h
include/sound/ac97/regs.h
include/trace/events/mmc.h
include/uapi/asm-generic/siginfo.h
include/uapi/drm/virtgpu_drm.h
include/uapi/linux/blktrace_api.h
include/uapi/linux/dvb/dmx.h
include/uapi/linux/if_ether.h
include/uapi/linux/kvm.h
include/uapi/linux/libc-compat.h
include/uapi/linux/lirc.h
include/uapi/linux/psp-sev.h
include/uapi/linux/ptrace.h
include/uapi/linux/usb/audio.h
include/uapi/misc/ocxl.h
include/uapi/rdma/rdma_user_ioctl.h
init/main.c
ipc/mqueue.c
ipc/shm.c
kernel/bpf/arraymap.c
kernel/bpf/core.c
kernel/bpf/cpumap.c
kernel/bpf/lpm_trie.c
kernel/bpf/sockmap.c
kernel/bpf/syscall.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/compat.c
kernel/events/core.c
kernel/fail_function.c
kernel/fork.c
kernel/irq/irqdomain.c
kernel/irq/matrix.c
kernel/jump_label.c
kernel/kprobes.c
kernel/locking/mutex.c
kernel/locking/qspinlock.c
kernel/locking/rtmutex.c
kernel/memremap.c
kernel/module.c
kernel/panic.c
kernel/printk/printk.c
kernel/relay.c
kernel/sched/core.c
kernel/sched/cpufreq_schedutil.c
kernel/sched/deadline.c
kernel/sched/debug.c
kernel/sched/rt.c
kernel/seccomp.c
kernel/time/posix-timers.c
kernel/time/timer.c
kernel/trace/bpf_trace.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_probe.c
kernel/trace/trace_probe.h
kernel/user.c
kernel/workqueue.c
lib/Kconfig.debug
lib/btree.c
lib/bug.c
lib/dma-debug.c
lib/dma-direct.c
lib/idr.c
lib/ioremap.c
lib/percpu-refcount.c
lib/radix-tree.c
lib/rhashtable.c
lib/test_bpf.c
lib/test_kmod.c
lib/test_rhashtable.c
lib/vsprintf.c
mm/gup.c
mm/huge_memory.c
mm/hugetlb.c
mm/khugepaged.c
mm/kmemleak.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/mempolicy.c
mm/mlock.c
mm/page_alloc.c
mm/page_owner.c
mm/percpu-km.c
mm/percpu-vm.c
mm/percpu.c
mm/shmem.c
mm/slab.c
mm/swap.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
mm/zpool.c
mm/zswap.c
net/8021q/vlan_core.c
net/9p/trans_virtio.c
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_v.c
net/batman-adv/bridge_loop_avoidance.c
net/batman-adv/distributed-arp-table.c
net/batman-adv/fragmentation.c
net/batman-adv/gateway_client.c
net/batman-adv/hard-interface.c
net/batman-adv/icmp_socket.c
net/batman-adv/log.c
net/batman-adv/multicast.c
net/batman-adv/originator.c
net/batman-adv/originator.h
net/batman-adv/routing.c
net/batman-adv/soft-interface.c
net/batman-adv/types.h
net/bluetooth/smp.c
net/bridge/br_netfilter_hooks.c
net/bridge/br_sysfs_if.c
net/bridge/br_vlan.c
net/bridge/netfilter/ebt_among.c
net/bridge/netfilter/ebt_limit.c
net/bridge/netfilter/ebtables.c
net/ceph/ceph_common.c
net/core/dev.c
net/core/dev_ioctl.c
net/core/devlink.c
net/core/ethtool.c
net/core/filter.c
net/core/gen_estimator.c
net/core/skbuff.c
net/core/sock.c
net/core/sock_diag.c
net/dccp/proto.c
net/decnet/af_decnet.c
net/dsa/legacy.c
net/ieee802154/6lowpan/core.c
net/ipv4/fib_semantics.c
net/ipv4/inet_diag.c
net/ipv4/inet_fragment.c
net/ipv4/ip_forward.c
net/ipv4/ip_gre.c
net/ipv4/ip_output.c
net/ipv4/ip_sockglue.c
net/ipv4/ip_tunnel.c
net/ipv4/ip_vti.c
net/ipv4/netfilter/Makefile
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/netfilter/ipt_CLUSTERIP.c
net/ipv4/netfilter/ipt_ECN.c
net/ipv4/netfilter/ipt_REJECT.c
net/ipv4/netfilter/ipt_rpfilter.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_flow_table_ipv4.c
net/ipv4/netfilter/nf_socket_ipv4.c
net/ipv4/route.c
net/ipv4/syncookies.c
net/ipv4/tcp.c
net/ipv4/tcp_illinois.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv4/tcp_timer.c
net/ipv4/udp.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_policy.c
net/ipv6/datagram.c
net/ipv6/ip6_checksum.c
net/ipv6/ip6_gre.c
net/ipv6/ip6_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_vti.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ndisc.c
net/ipv6/netfilter.c
net/ipv6/netfilter/ip6_tables.c
net/ipv6/netfilter/ip6t_REJECT.c
net/ipv6/netfilter/ip6t_rpfilter.c
net/ipv6/netfilter/ip6t_srh.c
net/ipv6/netfilter/nf_flow_table_ipv6.c
net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
net/ipv6/netfilter/nf_socket_ipv6.c
net/ipv6/netfilter/nft_fib_ipv6.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/ipv6/sit.c
net/ipv6/syncookies.c
net/ipv6/xfrm6_mode_tunnel.c
net/ipv6/xfrm6_output.c
net/ipv6/xfrm6_policy.c
net/iucv/af_iucv.c
net/kcm/kcmsock.c
net/l2tp/l2tp_core.c
net/l2tp/l2tp_core.h
net/l2tp/l2tp_ip.c
net/l2tp/l2tp_ip6.c
net/l2tp/l2tp_ppp.c
net/llc/llc_c_ac.c
net/llc/llc_conn.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/ieee80211_i.h
net/mac80211/mesh.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/tx.c
net/mpls/af_mpls.c
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/nf_nat_proto_common.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_hash.c
net/netfilter/x_tables.c
net/netfilter/xt_AUDIT.c
net/netfilter/xt_CHECKSUM.c
net/netfilter/xt_CONNSECMARK.c
net/netfilter/xt_CT.c
net/netfilter/xt_DSCP.c
net/netfilter/xt_HL.c
net/netfilter/xt_HMARK.c
net/netfilter/xt_IDLETIMER.c
net/netfilter/xt_LED.c
net/netfilter/xt_NFQUEUE.c
net/netfilter/xt_SECMARK.c
net/netfilter/xt_TCPMSS.c
net/netfilter/xt_TPROXY.c
net/netfilter/xt_addrtype.c
net/netfilter/xt_bpf.c
net/netfilter/xt_cgroup.c
net/netfilter/xt_cluster.c
net/netfilter/xt_connbytes.c
net/netfilter/xt_connlabel.c
net/netfilter/xt_connmark.c
net/netfilter/xt_conntrack.c
net/netfilter/xt_dscp.c
net/netfilter/xt_ecn.c
net/netfilter/xt_hashlimit.c
net/netfilter/xt_helper.c
net/netfilter/xt_ipcomp.c
net/netfilter/xt_ipvs.c
net/netfilter/xt_l2tp.c
net/netfilter/xt_limit.c
net/netfilter/xt_nat.c
net/netfilter/xt_nfacct.c
net/netfilter/xt_physdev.c
net/netfilter/xt_policy.c
net/netfilter/xt_recent.c
net/netfilter/xt_set.c
net/netfilter/xt_socket.c
net/netfilter/xt_state.c
net/netfilter/xt_time.c
net/netlink/af_netlink.c
net/netlink/genetlink.c
net/nfc/llcp_commands.c
net/nfc/netlink.c
net/openvswitch/meter.c
net/qrtr/smd.c
net/rds/connection.c
net/rds/tcp_listen.c
net/rxrpc/output.c
net/rxrpc/recvmsg.c
net/sched/act_api.c
net/sched/act_bpf.c
net/sched/act_csum.c
net/sched/act_ipt.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/act_sample.c
net/sched/act_simple.c
net/sched/act_skbmod.c
net/sched/act_tunnel_key.c
net/sched/act_vlan.c
net/sched/cls_api.c
net/sched/cls_u32.c
net/sched/sch_generic.c
net/sched/sch_netem.c
net/sched/sch_tbf.c
net/sctp/debug.c
net/sctp/input.c
net/sctp/inqueue.c
net/sctp/offload.c
net/sctp/stream.c
net/sctp/stream_interleave.c
net/smc/af_smc.c
net/smc/smc_cdc.c
net/smc/smc_clc.c
net/smc/smc_close.c
net/smc/smc_core.c
net/smc/smc_llc.c
net/socket.c
net/strparser/strparser.c
net/tipc/bearer.c
net/tipc/bearer.h
net/tipc/group.c
net/tipc/net.c
net/tipc/net.h
net/tipc/netlink_compat.c
net/tipc/socket.c
net/tls/tls_main.c
net/unix/af_unix.c
net/wireless/Kconfig
net/wireless/mesh.c
net/wireless/sme.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_ipcomp.c
net/xfrm/xfrm_output.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_replay.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
samples/seccomp/Makefile
scripts/Makefile.lib
scripts/adjust_autoksyms.sh
scripts/basic/fixdep.c
scripts/bloat-o-meter
scripts/coccinelle/api/memdup.cocci
scripts/kallsyms.c
scripts/kconfig/confdata.c
scripts/kconfig/kxgettext.c
scripts/kconfig/lkc.h
scripts/kconfig/lxdialog/check-lxdialog.sh
scripts/kconfig/menu.c
scripts/kconfig/symbol.c
scripts/kconfig/util.c
scripts/kconfig/zconf.l
scripts/kconfig/zconf.y
scripts/link-vmlinux.sh
scripts/package/builddeb
scripts/package/mkspec
security/integrity/digsig.c
security/keys/big_key.c
sound/ac97/Kconfig
sound/core/control.c
sound/core/oss/pcm_oss.c
sound/core/pcm_native.c
sound/core/seq/seq_clientmgr.c
sound/core/seq/seq_fifo.c
sound/core/seq/seq_memory.c
sound/core/seq/seq_memory.h
sound/core/seq/seq_prioq.c
sound/core/seq/seq_prioq.h
sound/core/seq/seq_queue.c
sound/drivers/aloop.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/soc/amd/acp-pcm-dma.c
sound/soc/amd/acp.h
sound/soc/codecs/hdmi-codec.c
sound/soc/codecs/rt5651.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/wm_adsp.c
sound/soc/sunxi/sun4i-i2s.c
sound/usb/mixer.c
sound/usb/pcm.c
sound/usb/quirks-table.h
sound/usb/quirks.c
sound/x86/intel_hdmi_audio.c
tools/arch/powerpc/include/uapi/asm/kvm.h
tools/arch/s390/include/uapi/asm/unistd.h [deleted file]
tools/arch/x86/include/asm/cpufeatures.h
tools/bpf/bpftool/common.c
tools/bpf/bpftool/main.c
tools/bpf/bpftool/map.c
tools/bpf/bpftool/prog.c
tools/cgroup/Makefile
tools/gpio/Makefile
tools/hv/Makefile
tools/iio/Makefile
tools/include/uapi/drm/i915_drm.h
tools/include/uapi/linux/if_link.h
tools/include/uapi/linux/kvm.h
tools/kvm/kvm_stat/kvm_stat
tools/kvm/kvm_stat/kvm_stat.txt
tools/laptop/freefall/Makefile
tools/leds/Makefile
tools/lib/bpf/libbpf.c
tools/perf/Documentation/perf-data.txt
tools/perf/Documentation/perf-kallsyms.txt
tools/perf/Makefile.perf
tools/perf/arch/s390/Makefile
tools/perf/arch/s390/entry/syscalls/mksyscalltbl
tools/perf/arch/s390/entry/syscalls/syscall.tbl [new file with mode: 0644]
tools/perf/builtin-c2c.c
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-stat.c
tools/perf/builtin-top.c
tools/perf/check-headers.sh
tools/perf/perf.h
tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/cortex-a53/other.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json [new file with mode: 0644]
tools/perf/pmu-events/arch/arm64/mapfile.csv
tools/perf/tests/backward-ring-buffer.c
tools/perf/tests/shell/trace+probe_libc_inet_pton.sh
tools/perf/ui/browsers/annotate.c
tools/perf/ui/browsers/hists.c
tools/perf/ui/browsers/hists.h
tools/perf/util/auxtrace.c
tools/perf/util/evlist.c
tools/perf/util/evlist.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/hist.h
tools/perf/util/mmap.c
tools/perf/util/mmap.h
tools/perf/util/record.c
tools/perf/util/trigger.h
tools/perf/util/util.c
tools/power/acpi/Makefile.config
tools/scripts/Makefile.include
tools/spi/Makefile
tools/testing/radix-tree/idr-test.c
tools/testing/radix-tree/linux.c
tools/testing/radix-tree/linux/compiler_types.h [new file with mode: 0644]
tools/testing/radix-tree/linux/gfp.h
tools/testing/radix-tree/linux/slab.h
tools/testing/selftests/android/Makefile
tools/testing/selftests/bpf/.gitignore
tools/testing/selftests/bpf/test_maps.c
tools/testing/selftests/bpf/test_tcpbpf_kern.c
tools/testing/selftests/bpf/test_verifier.c
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc [new file with mode: 0644]
tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc [new file with mode: 0644]
tools/testing/selftests/futex/Makefile
tools/testing/selftests/memfd/Makefile
tools/testing/selftests/memfd/config [new file with mode: 0644]
tools/testing/selftests/memory-hotplug/Makefile
tools/testing/selftests/powerpc/mm/subpage_prot.c
tools/testing/selftests/powerpc/tm/Makefile
tools/testing/selftests/powerpc/tm/tm-trap.c
tools/testing/selftests/pstore/config
tools/testing/selftests/seccomp/seccomp_bpf.c
tools/testing/selftests/sync/Makefile
tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json
tools/testing/selftests/vDSO/Makefile
tools/testing/selftests/vm/.gitignore
tools/testing/selftests/vm/run_vmtests
tools/usb/Makefile
tools/vm/Makefile
tools/wmi/Makefile
virt/kvm/arm/arch_timer.c
virt/kvm/arm/arm.c
virt/kvm/arm/hyp/vgic-v3-sr.c
virt/kvm/arm/mmu.c
virt/kvm/arm/vgic/vgic-mmio.c
virt/kvm/arm/vgic/vgic-v2.c
virt/kvm/arm/vgic/vgic-v3.c
virt/kvm/arm/vgic/vgic.c
virt/kvm/arm/vgic/vgic.h
virt/kvm/kvm_main.c

index 705e099..1be78fd 100644 (file)
@@ -127,3 +127,7 @@ all.config
 
 # Kdevelop4
 *.kdev4
+
+#Automatically generated by ASN.1 compiler
+net/ipv4/netfilter/nf_nat_snmp_basic-asn1.c
+net/ipv4/netfilter/nf_nat_snmp_basic-asn1.h
index e18cab7..a2ce89a 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -62,6 +62,7 @@ Frank Zago <fzago@systemfabricworks.com>
 Greg Kroah-Hartman <greg@echidna.(none)>
 Greg Kroah-Hartman <gregkh@suse.de>
 Greg Kroah-Hartman <greg@kroah.com>
+Gregory CLEMENT <gregory.clement@bootlin.com> <gregory.clement@free-electrons.com>
 Henk Vergonet <Henk.Vergonet@gmail.com>
 Henrik Kretzschmar <henne@nachtwindheim.de>
 Henrik Rydberg <rydberg@bitmath.org>
index aa42964..9ab0ef1 100644 (file)
 What:          /sys/class/ata_...
-Date:          August 2008
-Contact:       Gwendal Grignou<gwendal@google.com>
 Description:
-
-Provide a place in sysfs for storing the ATA topology of the system.  This allows
-retrieving various information about ATA objects.
+               Provide a place in sysfs for storing the ATA topology of the
+               system. This allows retrieving various information about ATA
+               objects.
 
 Files under /sys/class/ata_port
 -------------------------------
 
-       For each port, a directory ataX is created where X is the ata_port_id of
-       the port. The device parent is the ata host device.
+For each port, a directory ataX is created where X is the ata_port_id of the
+port. The device parent is the ata host device.
 
-idle_irq (read)
 
-       Number of IRQ received by the port while idle [some ata HBA only].
+What:          /sys/class/ata_port/ataX/nr_pmp_links
+What:          /sys/class/ata_port/ataX/idle_irq
+Date:          May, 2010
+KernelVersion: v2.6.37
+Contact:       Gwendal Grignou <gwendal@chromium.org>
+Description:
+               nr_pmp_links:   (RO) If a SATA Port Multiplier (PM) is
+                               connected, the number of links behind it.
 
-nr_pmp_links (read)
+               idle_irq:       (RO) Number of IRQ received by the port while
+                               idle [some ata HBA only].
 
-       If a SATA Port Multiplier (PM) is connected, number of link behind it.
+
+What:          /sys/class/ata_port/ataX/port_no
+Date:          May, 2013
+KernelVersion: v3.11
+Contact:       Gwendal Grignou <gwendal@chromium.org>
+Description:
+               (RO) Host local port number. While registering host controller,
+               port numbers are tracked based upon number of ports available on
+               the controller. This attribute is needed by udev for composing
+               persistent links in /dev/disk/by-path.
 
 Files under /sys/class/ata_link
 -------------------------------
 
-       Behind each port, there is a ata_link. If there is a SATA PM in the
-       topology, 15 ata_link objects are created.
-
-       If a link is behind a port, the directory name is linkX, where X is
-       ata_port_id of the port.
-       If a link is behind a PM, its name is linkX.Y where X is ata_port_id
-       of the parent port and Y the PM port.
+Behind each port, there is a ata_link. If there is a SATA PM in the topology, 15
+ata_link objects are created.
 
-hw_sata_spd_limit
+If a link is behind a port, the directory name is linkX, where X is ata_port_id
+of the port. If a link is behind a PM, its name is linkX.Y where X is
+ata_port_id of the parent port and Y the PM port.
 
-       Maximum speed supported by the connected SATA device.
 
-sata_spd_limit
+What:          /sys/class/ata_link/linkX[.Y]/hw_sata_spd_limit
+What:          /sys/class/ata_link/linkX[.Y]/sata_spd_limit
+What:          /sys/class/ata_link/linkX[.Y]/sata_spd
+Date:          May, 2010
+KernelVersion: v2.6.37
+Contact:       Gwendal Grignou <gwendal@chromium.org>
+Description:
+               hw_sata_spd_limit:      (RO) Maximum speed supported by the
+                                       connected SATA device.
 
-       Maximum speed imposed by libata.
+               sata_spd_limit:         (RO) Maximum speed imposed by libata.
 
-sata_spd
+               sata_spd:               (RO) Current speed of the link
+                                       eg. 1.5, 3 Gbps etc.
 
-       Current speed of the link [1.5, 3Gps,...].
 
 Files under /sys/class/ata_device
 ---------------------------------
 
-       Behind each link, up to two ata device are created.
-       The name of the directory is devX[.Y].Z where:
-       - X is ata_port_id of the port where the device is connected,
-       - Y the port of the PM if any, and
-       - Z the device id: for PATA, there is usually 2 devices [0,1],
-       only 1 for SATA.
-
-class
-       Device class. Can be "ata" for disk, "atapi" for packet device,
-       "pmp" for PM, or "none" if no device was found behind the link.
-
-dma_mode
+Behind each link, up to two ata devices are created.
+The name of the directory is devX[.Y].Z where:
+- X is ata_port_id of the port where the device is connected,
+- Y the port of the PM if any, and
+- Z the device id: for PATA, there is usually 2 devices [0,1], only 1 for SATA.
+
+
+What:          /sys/class/ata_device/devX[.Y].Z/spdn_cnt
+What:          /sys/class/ata_device/devX[.Y].Z/gscr
+What:          /sys/class/ata_device/devX[.Y].Z/ering
+What:          /sys/class/ata_device/devX[.Y].Z/id
+What:          /sys/class/ata_device/devX[.Y].Z/pio_mode
+What:          /sys/class/ata_device/devX[.Y].Z/xfer_mode
+What:          /sys/class/ata_device/devX[.Y].Z/dma_mode
+What:          /sys/class/ata_device/devX[.Y].Z/class
+Date:          May, 2010
+KernelVersion: v2.6.37
+Contact:       Gwendal Grignou <gwendal@chromium.org>
+Description:
+               spdn_cnt:       (RO) Number of times libata decided to lower the
+                               speed of link due to errors.
 
-       Transfer modes supported by the device when in DMA mode.
-       Mostly used by PATA device.
+               gscr:           (RO) Cached result of the dump of PM GSCR
+                               register. Valid registers are:
 
-pio_mode
+                               0:      SATA_PMP_GSCR_PROD_ID,
+                               1:      SATA_PMP_GSCR_REV,
+                               2:      SATA_PMP_GSCR_PORT_INFO,
+                               32:     SATA_PMP_GSCR_ERROR,
+                               33:     SATA_PMP_GSCR_ERROR_EN,
+                               64:     SATA_PMP_GSCR_FEAT,
+                               96:     SATA_PMP_GSCR_FEAT_EN,
+                               130:    SATA_PMP_GSCR_SII_GPIO
 
-       Transfer modes supported by the device when in PIO mode.
-       Mostly used by PATA device.
+                               Only valid if the device is a PM.
 
-xfer_mode
+               ering:          (RO) Formatted output of the error ring of the
+                               device.
 
-       Current transfer mode.
+               id:             (RO) Cached result of IDENTIFY command, as
+                               described in ATA8 7.16 and 7.17. Only valid if
+                               the device is not a PM.
 
-id
+               pio_mode:       (RO) Transfer modes supported by the device when
+                               in PIO mode. Mostly used by PATA device.
 
-       Cached result of IDENTIFY command, as described in ATA8 7.16 and 7.17.
-       Only valid if the device is not a PM.
+               xfer_mode:      (RO) Current transfer mode
 
-gscr
+               dma_mode:       (RO) Transfer modes supported by the device when
+                               in DMA mode. Mostly used by PATA device.
 
-       Cached result of the dump of PM GSCR register.
-       Valid registers are:
-       0:      SATA_PMP_GSCR_PROD_ID,
-       1:      SATA_PMP_GSCR_REV,
-       2:      SATA_PMP_GSCR_PORT_INFO,
-       32:     SATA_PMP_GSCR_ERROR,
-       33:     SATA_PMP_GSCR_ERROR_EN,
-       64:     SATA_PMP_GSCR_FEAT,
-       96:     SATA_PMP_GSCR_FEAT_EN,
-       130:    SATA_PMP_GSCR_SII_GPIO
-       Only valid if the device is a PM.
+               class:          (RO) Device class. Can be "ata" for disk,
+                               "atapi" for packet device, "pmp" for PM, or
+                               "none" if no device was found behind the link.
 
-trim
 
-       Shows the DSM TRIM mode currently used by the device. Valid
-       values are:
-       unsupported:            Drive does not support DSM TRIM
-       unqueued:               Drive supports unqueued DSM TRIM only
-       queued:                 Drive supports queued DSM TRIM
-       forced_unqueued:        Drive's queued DSM support is known to be
-                               buggy and only unqueued TRIM commands
-                               are sent
+What:          /sys/class/ata_device/devX[.Y].Z/trim
+Date:          May, 2015
+KernelVersion: v4.10
+Contact:       Gwendal Grignou <gwendal@chromium.org>
+Description:
+               (RO) Shows the DSM TRIM mode currently used by the device. Valid
+               values are:
 
-spdn_cnt
+               unsupported:            Drive does not support DSM TRIM
 
-       Number of time libata decided to lower the speed of link due to errors.
+               unqueued:               Drive supports unqueued DSM TRIM only
 
-ering
+               queued:                 Drive supports queued DSM TRIM
 
-       Formatted output of the error ring of the device.
+               forced_unqueued:        Drive's queued DSM support is known to
+                                       be buggy and only unqueued TRIM commands
+                                       are sent
diff --git a/Documentation/ABI/testing/sysfs-block-device b/Documentation/ABI/testing/sysfs-block-device
new file mode 100644 (file)
index 0000000..82ef6ea
--- /dev/null
@@ -0,0 +1,58 @@
+What:          /sys/block/*/device/sw_activity
+Date:          Jun, 2008
+KernelVersion: v2.6.27
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RW) Used by drivers which support software controlled activity
+               LEDs.
+
+               It has the following valid values:
+
+               0       OFF - the LED is not activated on activity
+               1       BLINK_ON - the LED blinks on every 10ms when activity is
+                       detected.
+               2       BLINK_OFF - the LED is on when idle, and blinks off
+                       every 10ms when activity is detected.
+
+               Note that the user must turn sw_activity OFF it they wish to
+               control the activity LED via the em_message file.
+
+
+What:          /sys/block/*/device/unload_heads
+Date:          Sep, 2008
+KernelVersion: v2.6.28
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RW) Hard disk shock protection
+
+               Writing an integer value to this file will take the heads of the
+               respective drive off the platter and block all I/O operations
+               for the specified number of milliseconds.
+
+               - If the device does not support the unload heads feature,
+                 access is denied with -EOPNOTSUPP.
+               - The maximal value accepted for a timeout is 30000
+                 milliseconds.
+               - A previously set timeout can be cancelled and disk can resume
+                 normal operation immediately by specifying a timeout of 0.
+               - Some hard drives only comply with an earlier version of the
+                 ATA standard, but support the unload feature nonetheless.
+                 There is no safe way Linux can detect these devices, so this
+                 is not enabled by default. If it is known that your device
+                 does support the unload feature, then you can tell the kernel
+                 to enable it by writing -1. It can be disabled again by
+                 writing -2.
+               - Values below -2 are rejected with -EINVAL
+
+               For more information, see
+               Documentation/laptops/disk-shock-protection.txt
+
+
+What:          /sys/block/*/device/ncq_prio_enable
+Date:          Oct, 2016
+KernelVersion: v4.10
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RW) Write to the file to turn on or off the SATA ncq (native
+               command queueing) support. By default this feature is turned
+               off.
index 0eb255e..bafc59f 100644 (file)
@@ -27,3 +27,92 @@ Description: This file contains the current status of the "SSD Smart Path"
                the direct i/o path to physical devices.  This setting is
                controller wide, affecting all configured logical drives on the
                controller.  This file is readable and writable.
+
+What:          /sys/class/scsi_host/hostX/link_power_management_policy
+Date:          Oct, 2007
+KernelVersion: v2.6.24
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RW) This parameter allows the user to read and set the link
+               (interface) power management.
+
+               There are four possible options:
+
+               min_power: Tell the controller to try to make the link use the
+               least possible power when possible. This may sacrifice some
+               performance due to increased latency when coming out of lower
+               power states.
+
+               max_performance: Generally, this means no power management.
+               Tell the controller to have performance be a priority over power
+               management.
+
+               medium_power: Tell the controller to enter a lower power state
+               when possible, but do not enter the lowest power state, thus
+               improving latency over min_power setting.
+
+               med_power_with_dipm: Identical to the existing medium_power
+               setting except that it enables dipm (device initiated power
+               management) on top, which makes it match the Windows IRST (Intel
+               Rapid Storage Technology) driver settings. This setting is also
+               close to min_power, except that:
+               a) It does not use host-initiated slumber mode, but it does
+               allow device-initiated slumber
+               b) It does not enable low power device sleep mode (DevSlp).
+
+What:          /sys/class/scsi_host/hostX/em_message
+What:          /sys/class/scsi_host/hostX/em_message_type
+Date:          Jun, 2008
+KernelVersion: v2.6.27
+Contact:       linux-ide@vger.kernel.org
+Description:
+               em_message: (RW) Enclosure management support. For the LED
+               protocol, writes and reads correspond to the LED message format
+               as defined in the AHCI spec.
+
+               The user must turn sw_activity (under /sys/block/*/device/) OFF
+               it they wish to control the activity LED via the em_message
+               file.
+
+               em_message_type: (RO) Displays the current enclosure management
+               protocol that is being used by the driver (for eg. LED, SAF-TE,
+               SES-2, SGPIO etc).
+
+What:          /sys/class/scsi_host/hostX/ahci_port_cmd
+What:          /sys/class/scsi_host/hostX/ahci_host_caps
+What:          /sys/class/scsi_host/hostX/ahci_host_cap2
+Date:          Mar, 2010
+KernelVersion: v2.6.35
+Contact:       linux-ide@vger.kernel.org
+Description:
+               [to be documented]
+
+What:          /sys/class/scsi_host/hostX/ahci_host_version
+Date:          Mar, 2010
+KernelVersion: v2.6.35
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RO) Display the version of the AHCI spec implemented by the
+               host.
+
+What:          /sys/class/scsi_host/hostX/em_buffer
+Date:          Apr, 2010
+KernelVersion: v2.6.35
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RW) Allows access to AHCI EM (enclosure management) buffer
+               directly if the host supports EM.
+
+               For eg. the AHCI driver supports SGPIO EM messages but the
+               SATA/AHCI specs do not define the SGPIO message format of the EM
+               buffer. Different hardware(HW) vendors may have different
+               definitions. With the em_buffer attribute, this issue can be
+               solved by allowing HW vendors to provide userland drivers and
+               tools for their SGPIO initiators.
+
+What:          /sys/class/scsi_host/hostX/em_message_supported
+Date:          Oct, 2009
+KernelVersion: v2.6.39
+Contact:       linux-ide@vger.kernel.org
+Description:
+               (RO) Displays supported enclosure management message types.
diff --git a/Documentation/ABI/testing/sysfs-devices-platform-dock b/Documentation/ABI/testing/sysfs-devices-platform-dock
new file mode 100644 (file)
index 0000000..1d8c18f
--- /dev/null
@@ -0,0 +1,39 @@
+What:          /sys/devices/platform/dock.N/docked
+Date:          Dec, 2006
+KernelVersion: 2.6.19
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Value 1 or 0 indicates whether the software believes the
+               laptop is docked in a docking station.
+
+What:          /sys/devices/platform/dock.N/undock
+Date:          Dec, 2006
+KernelVersion: 2.6.19
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (WO) Writing to this file causes the software to initiate an
+               undock request to the firmware.
+
+What:          /sys/devices/platform/dock.N/uid
+Date:          Feb, 2007
+KernelVersion: v2.6.21
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Displays the docking station the laptop is docked to.
+
+What:          /sys/devices/platform/dock.N/flags
+Date:          May, 2007
+KernelVersion: v2.6.21
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Show dock station flags, useful for checking if undock
+               request has been made by the user (from the immediate_undock
+               option).
+
+What:          /sys/devices/platform/dock.N/type
+Date:          Aug, 2008
+KernelVersion: v2.6.27
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Display the dock station type- dock_station, ata_bay or
+               battery_bay.
index bfd29bc..4ed63b6 100644 (file)
@@ -108,6 +108,8 @@ Description:        CPU topology files that describe a logical CPU's relationship
 
 What:          /sys/devices/system/cpu/cpuidle/current_driver
                /sys/devices/system/cpu/cpuidle/current_governer_ro
+               /sys/devices/system/cpu/cpuidle/available_governors
+               /sys/devices/system/cpu/cpuidle/current_governor
 Date:          September 2007
 Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:   Discover cpuidle policy and mechanism
@@ -119,13 +121,84 @@ Description:      Discover cpuidle policy and mechanism
                Idle policy (governor) is differentiated from idle mechanism
                (driver)
 
-               current_driver: displays current idle mechanism
+               current_driver: (RO) displays current idle mechanism
 
-               current_governor_ro: displays current idle policy
+               current_governor_ro: (RO) displays current idle policy
+
+               With the cpuidle_sysfs_switch boot option enabled (meant for
+               developer testing), the following three attributes are visible
+               instead:
+
+               current_driver: same as described above
+
+               available_governors: (RO) displays a space separated list of
+               available governors
+
+               current_governor: (RW) displays current idle policy. Users can
+               switch the governor at runtime by writing to this file.
 
                See files in Documentation/cpuidle/ for more information.
 
 
+What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/name
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/latency
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/power
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/time
+               /sys/devices/system/cpu/cpuX/cpuidle/stateN/usage
+Date:          September 2007
+KernelVersion: v2.6.24
+Contact:       Linux power management list <linux-pm@vger.kernel.org>
+Description:
+               The directory /sys/devices/system/cpu/cpuX/cpuidle contains per
+               logical CPU specific cpuidle information for each online cpu X.
+               The processor idle states which are available for use have the
+               following attributes:
+
+               name: (RO) Name of the idle state (string).
+
+               latency: (RO) The latency to exit out of this idle state (in
+               microseconds).
+
+               power: (RO) The power consumed while in this idle state (in
+               milliwatts).
+
+               time: (RO) The total time spent in this idle state (in microseconds).
+
+               usage: (RO) Number of times this state was entered (a count).
+
+
+What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/desc
+Date:          February 2008
+KernelVersion: v2.6.25
+Contact:       Linux power management list <linux-pm@vger.kernel.org>
+Description:
+               (RO) A small description about the idle state (string).
+
+
+What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/disable
+Date:          March 2012
+KernelVersion: v3.10
+Contact:       Linux power management list <linux-pm@vger.kernel.org>
+Description:
+               (RW) Option to disable this idle state (bool). The behavior and
+               the effect of the disable variable depends on the implementation
+               of a particular governor. In the ladder governor, for example,
+               it is not coherent, i.e. if one is disabling a light state, then
+               all deeper states are disabled as well, but the disable variable
+               does not reflect it. Likewise, if one enables a deep state but a
+               lighter state still is disabled, then this has no effect.
+
+
+What:          /sys/devices/system/cpu/cpuX/cpuidle/stateN/residency
+Date:          March 2014
+KernelVersion: v3.15
+Contact:       Linux power management list <linux-pm@vger.kernel.org>
+Description:
+               (RO) Display the target residency i.e. the minimum amount of
+               time (in microseconds) this cpu should spend in this idle state
+               to make the transition worth the effort.
+
+
 What:          /sys/devices/system/cpu/cpu#/cpufreq/*
 Date:          pre-git history
 Contact:       linux-pm@vger.kernel.org
diff --git a/Documentation/ABI/testing/sysfs-platform-dptf b/Documentation/ABI/testing/sysfs-platform-dptf
new file mode 100644 (file)
index 0000000..325dc06
--- /dev/null
@@ -0,0 +1,40 @@
+What:          /sys/bus/platform/devices/INT3407:00/dptf_power/charger_type
+Date:          Jul, 2016
+KernelVersion: v4.10
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) The charger type - Traditional, Hybrid or NVDC.
+
+What:          /sys/bus/platform/devices/INT3407:00/dptf_power/adapter_rating_mw
+Date:          Jul, 2016
+KernelVersion: v4.10
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Adapter rating in milliwatts (the maximum Adapter power).
+               Must be 0 if no AC Adaptor is plugged in.
+
+What:          /sys/bus/platform/devices/INT3407:00/dptf_power/max_platform_power_mw
+Date:          Jul, 2016
+KernelVersion: v4.10
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Maximum platform power that can be supported by the battery
+               in milliwatts.
+
+What:          /sys/bus/platform/devices/INT3407:00/dptf_power/platform_power_source
+Date:          Jul, 2016
+KernelVersion: v4.10
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) Display the platform power source
+               0x00 = DC
+               0x01 = AC
+               0x02 = USB
+               0x03 = Wireless Charger
+
+What:          /sys/bus/platform/devices/INT3407:00/dptf_power/battery_steady_power
+Date:          Jul, 2016
+KernelVersion: v4.10
+Contact:       linux-acpi@vger.kernel.org
+Description:
+               (RO) The maximum sustained power for battery in milliwatts.
index 611a75e..badb26a 100644 (file)
@@ -570,7 +570,9 @@ your driver if they're helpful, or just use plain hex constants.
 The device IDs are arbitrary hex numbers (vendor controlled) and normally used
 only in a single location, the pci_device_id table.
 
-Please DO submit new vendor/device IDs to http://pciids.sourceforge.net/.
+Please DO submit new vendor/device IDs to http://pci-ids.ucw.cz/.
+There are mirrors of the pci.ids file at http://pciids.sourceforge.net/
+and https://github.com/pciutils/pciids.
 
 
 
index 4f7af84..ddcc58d 100644 (file)
@@ -152,6 +152,11 @@ OCXL_IOCTL_IRQ_SET_FD:
   Associate an event fd to an AFU interrupt so that the user process
   can be notified when the AFU sends an interrupt.
 
+OCXL_IOCTL_GET_METADATA:
+
+  Obtains configuration information from the card, such at the size of
+  MMIO areas, the AFU version, and the PASID for the current context.
+
 
 mmap
 ----
index 5550bfd..be70b32 100644 (file)
@@ -58,7 +58,12 @@ Like with atomic_t, the rule of thumb is:
 
  - RMW operations that have a return value are fully ordered.
 
-Except for test_and_set_bit_lock() which has ACQUIRE semantics and
+ - RMW operations that are conditional are unordered on FAILURE,
+   otherwise the above rules apply. In the case of test_and_{}_bit() operations,
+   if the bit in memory is unchanged by the operation then it is deemed to have
+   failed.
+
+Except for a successful test_and_set_bit_lock() which has ACQUIRE semantics and
 clear_bit_unlock() which has RELEASE semantics.
 
 Since a platform only has a single means of achieving atomic operations
index 6394ea9..58b12e2 100644 (file)
@@ -16,6 +16,7 @@ Required properties:
 - ddc: phandle to the hdmi ddc node
 - phy: phandle to the hdmi phy node
 - samsung,syscon-phandle: phandle for system controller node for PMU.
+- #sound-dai-cells: should be 0.
 
 Required properties for Exynos 4210, 4212, 5420 and 5433:
 - clocks: list of clock IDs from SoC clock driver.
index 217a90e..9c38bbe 100644 (file)
@@ -11,7 +11,11 @@ Required properties:
   interrupts.
 
 Optional properties:
-- clocks: Optional reference to the clock used by the XOR engine.
+- clocks: Optional reference to the clocks used by the XOR engine.
+- clock-names: mandatory if there is a second clock, in this case the
+   name must be "core" for the first clock and "reg" for the second
+   one
+
 
 Example:
 
index 1812c84..abfae1b 100644 (file)
@@ -38,9 +38,9 @@ Required properties:
 
                 "catalyst",
                 "microchip",
+                "nxp",
                 "ramtron",
                 "renesas",
-                "nxp",
                 "st",
 
                 Some vendors use different model names for chips which are just
index e9ebb8a..ba24ca7 100644 (file)
@@ -3,11 +3,11 @@ Device-Tree bindings for sigma delta modulator
 Required properties:
 - compatible: should be "ads1201", "sd-modulator". "sd-modulator" can be use
        as a generic SD modulator if modulator not specified in compatible list.
-- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers".
+- #io-channel-cells = <0>: See the IIO bindings section "IIO consumers".
 
 Example node:
 
        ads1202: adc@0 {
                compatible = "sd-modulator";
-               #io-channel-cells = <1>;
+               #io-channel-cells = <0>;
        };
index 33c9a10..20f121d 100644 (file)
@@ -14,6 +14,7 @@ Required properties:
     - "renesas,irqc-r8a7794" (R-Car E2)
     - "renesas,intc-ex-r8a7795" (R-Car H3)
     - "renesas,intc-ex-r8a7796" (R-Car M3-W)
+    - "renesas,intc-ex-r8a77965" (R-Car M3-N)
     - "renesas,intc-ex-r8a77970" (R-Car V3M)
     - "renesas,intc-ex-r8a77995" (R-Car D3)
 - #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
index 1d4d0f4..8c033d4 100644 (file)
@@ -50,14 +50,15 @@ Example:
                        compatible = "marvell,mv88e6085";
                        reg = <0>;
                        reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
-               };
-               mdio {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       switch1phy0: switch1phy0@0 {
-                               reg = <0>;
-                               interrupt-parent = <&switch0>;
-                               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+                       mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               switch1phy0: switch1phy0@0 {
+                                       reg = <0>;
+                                       interrupt-parent = <&switch0>;
+                                       interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+                               };
                        };
                };
        };
@@ -74,23 +75,24 @@ Example:
                        compatible = "marvell,mv88e6390";
                        reg = <0>;
                        reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
-               };
-               mdio {
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       switch1phy0: switch1phy0@0 {
-                               reg = <0>;
-                               interrupt-parent = <&switch0>;
-                               interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+
+                       mdio {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               switch1phy0: switch1phy0@0 {
+                                       reg = <0>;
+                                       interrupt-parent = <&switch0>;
+                                       interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
+                               };
                        };
-               };
 
-               mdio1 {
-                       compatible = "marvell,mv88e6xxx-mdio-external";
-                       #address-cells = <1>;
-                       #size-cells = <0>;
-                       switch1phy9: switch1phy0@9 {
-                               reg = <9>;
+                       mdio1 {
+                               compatible = "marvell,mv88e6xxx-mdio-external";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                               switch1phy9: switch1phy0@9 {
+                                       reg = <9>;
+                               };
                        };
                };
        };
index c902261..b4dc455 100644 (file)
@@ -18,6 +18,7 @@ Required properties:
       - "renesas,etheravb-r8a7795" for the R8A7795 SoC.
       - "renesas,etheravb-r8a7796" for the R8A7796 SoC.
       - "renesas,etheravb-r8a77970" for the R8A77970 SoC.
+      - "renesas,etheravb-r8a77980" for the R8A77980 SoC.
       - "renesas,etheravb-r8a77995" for the R8A77995 SoC.
       - "renesas,etheravb-rcar-gen3" as a fallback for the above
                R-Car Gen3 devices.
@@ -26,7 +27,11 @@ Required properties:
        SoC-specific version corresponding to the platform first followed by
        the generic version.
 
-- reg: offset and length of (1) the register block and (2) the stream buffer.
+- reg: Offset and length of (1) the register block and (2) the stream buffer.
+       The region for the register block is mandatory.
+       The region for the stream buffer is optional, as it is only present on
+       R-Car Gen2 and RZ/G1 SoCs, and on R-Car H3 (R8A7795), M3-W (R8A7796),
+       and M3-N (R8A77965).
 - interrupts: A list of interrupt-specifiers, one for each entry in
              interrupt-names.
              If interrupt-names is not present, an interrupt specifier
index 3c81f78..5d254ab 100644 (file)
@@ -60,7 +60,7 @@ Examples
                #size-cells = <0>;
 
                button@1 {
-                       debounce_interval = <50>;
+                       debounce-interval = <50>;
                        wakeup-source;
                        linux,code = <116>;
                        label = "POWER";
index 28be51a..379eb76 100644 (file)
@@ -22,7 +22,32 @@ Optional properties:
 - clocks : thermal sensor's clock source.
 
 Example:
+ocotp: ocotp@21bc000 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "fsl,imx6sx-ocotp", "syscon";
+       reg = <0x021bc000 0x4000>;
+       clocks = <&clks IMX6SX_CLK_OCOTP>;
 
+       tempmon_calib: calib@38 {
+               reg = <0x38 4>;
+       };
+
+       tempmon_temp_grade: temp-grade@20 {
+               reg = <0x20 4>;
+       };
+};
+
+tempmon: tempmon {
+       compatible = "fsl,imx6sx-tempmon", "fsl,imx6q-tempmon";
+       interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+       fsl,tempmon = <&anatop>;
+       nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
+       nvmem-cell-names = "calib", "temp_grade";
+       clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
+};
+
+Legacy method (Deprecated):
 tempmon {
        compatible = "fsl,imx6q-tempmon";
        fsl,tempmon = <&anatop>;
index e64d903..46da5f1 100644 (file)
@@ -19,7 +19,7 @@ Required properties:
   configured in FS mode;
   - "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
   configured in HS mode;
-  - "st,stm32f7xx-hsotg": The DWC2 USB HS controller instance in STM32F7xx SoCs
+  - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in STM32F7 SoCs
     configured in HS mode;
 - reg : Should contain 1 register range (address and length)
 - interrupts : Should contain 1 interrupt
index 87a45e2..2c071bb 100644 (file)
@@ -4,6 +4,7 @@ Required properties:
   - compatible: Must contain one of the following:
        - "renesas,r8a7795-usb3-peri"
        - "renesas,r8a7796-usb3-peri"
+       - "renesas,r8a77965-usb3-peri"
        - "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible
          device
 
index d060172..43960fa 100644 (file)
@@ -12,6 +12,7 @@ Required properties:
        - "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
        - "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
        - "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
+       - "renesas,usbhs-r8a77965" for r8a77965 (R-Car M3-N) compatible device
        - "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
        - "renesas,usbhs-r7s72100" for r7s72100 (RZ/A1) compatible device
        - "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
index e2ea59b..1651483 100644 (file)
@@ -13,6 +13,7 @@ Required properties:
     - "renesas,xhci-r8a7793" for r8a7793 SoC
     - "renesas,xhci-r8a7795" for r8a7795 SoC
     - "renesas,xhci-r8a7796" for r8a7796 SoC
+    - "renesas,xhci-r8a77965" for r8a77965 SoC
     - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
       device
     - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
diff --git a/Documentation/features/sched/membarrier-sync-core/arch-support.txt b/Documentation/features/sched/membarrier-sync-core/arch-support.txt
new file mode 100644 (file)
index 0000000..2c815a7
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# Feature name:          membarrier-sync-core
+#         Kconfig:       ARCH_HAS_MEMBARRIER_SYNC_CORE
+#         description:   arch supports core serializing membarrier
+#
+# Architecture requirements
+#
+# * arm64
+#
+# Rely on eret context synchronization when returning from IPI handler, and
+# when returning to user-space.
+#
+# * x86
+#
+# x86-32 uses IRET as return from interrupt, which takes care of the IPI.
+# However, it uses both IRET and SYSEXIT to go back to user-space. The IRET
+# instruction is core serializing, but not SYSEXIT.
+#
+# x86-64 uses IRET as return from interrupt, which takes care of the IPI.
+# However, it can return to user-space through either SYSRETL (compat code),
+# SYSRETQ, or IRET.
+#
+# Given that neither SYSRET{L,Q}, nor SYSEXIT, are core serializing, we rely
+# instead on write_cr3() performed by switch_mm() to provide core serialization
+# after changing the current mm, and deal with the special case of kthread ->
+# uthread (temporarily keeping current mm into active_mm) by issuing a
+# sync_core_before_usermode() in that specific case.
+#
+    -----------------------
+    |         arch |status|
+    -----------------------
+    |       alpha: | TODO |
+    |         arc: | TODO |
+    |         arm: | TODO |
+    |       arm64: |  ok  |
+    |    blackfin: | TODO |
+    |         c6x: | TODO |
+    |        cris: | TODO |
+    |         frv: | TODO |
+    |       h8300: | TODO |
+    |     hexagon: | TODO |
+    |        ia64: | TODO |
+    |        m32r: | TODO |
+    |        m68k: | TODO |
+    |       metag: | TODO |
+    |  microblaze: | TODO |
+    |        mips: | TODO |
+    |     mn10300: | TODO |
+    |       nios2: | TODO |
+    |    openrisc: | TODO |
+    |      parisc: | TODO |
+    |     powerpc: | TODO |
+    |        s390: | TODO |
+    |       score: | TODO |
+    |          sh: | TODO |
+    |       sparc: | TODO |
+    |        tile: | TODO |
+    |          um: | TODO |
+    |   unicore32: | TODO |
+    |         x86: |  ok  |
+    |      xtensa: | TODO |
+    -----------------------
index 69b17b3..152ea93 100644 (file)
@@ -3,4 +3,4 @@
 ==================================
 
 .. kernel-doc:: drivers/gpu/drm/tve200/tve200_drv.c
-   :doc: Faraday TV Encoder 200
+   :doc: Faraday TV Encoder TVE200 DRM Driver
index d477024..65514c2 100644 (file)
@@ -28,8 +28,10 @@ Supported adapters:
   * Intel Wildcat Point (PCH)
   * Intel Wildcat Point-LP (PCH)
   * Intel BayTrail (SOC)
+  * Intel Braswell (SOC)
   * Intel Sunrise Point-H (PCH)
   * Intel Sunrise Point-LP (PCH)
+  * Intel Kaby Lake-H (PCH)
   * Intel DNV (SOC)
   * Intel Broxton (SOC)
   * Intel Lewisburg (PCH)
index 6869c73..a63d2c5 100644 (file)
@@ -111,7 +111,7 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
 
        - If you don't have an HCDP, the kernel doesn't know where
          your console lives until the driver discovers serial
-         devices.  Use "console=uart, io,0x3f8" (or appropriate
+         devices.  Use "console=uart,io,0x3f8" (or appropriate
          address for your machine).
 
     Kernel and init script output works fine, but no "login:" prompt:
index 1688b5a..021aa9c 100644 (file)
@@ -18,7 +18,7 @@ corresponding hardware driver. Kernel CAPI then forwards CAPI messages in both
 directions between the application and the hardware driver.
 
 Format and semantics of CAPI messages are specified in the CAPI 2.0 standard.
-This standard is freely available from http://www.capi.org.
+This standard is freely available from https://www.capi.org.
 
 
 2. Driver and Device Registration
index 32d4e80..74bd2bd 100644 (file)
@@ -33,10 +33,10 @@ README for the ISDN-subsystem
      de.alt.comm.isdn4linux
 
   There is also a well maintained FAQ in English available at
-     http://www.mhessler.de/i4lfaq/
+     https://www.mhessler.de/i4lfaq/
   It can be viewed online, or downloaded in sgml/text/html format.
   The FAQ can also be viewed online at
-     http://www.isdn4linux.de/faq/
+     https://www.isdn4linux.de/faq/i4lfaq.html
   or downloaded from
      ftp://ftp.isdn4linux.de/pub/isdn4linux/FAQ/
 
index 356f794..e5dd1ad 100644 (file)
@@ -8,9 +8,9 @@ You find it in:
 
 In case you just want to see the FAQ online, or download the newest version,
 you can have a look at my website:
-http://www.mhessler.de/i4lfaq/ (view + download)
+https://www.mhessler.de/i4lfaq/ (view + download)
 or:
-http://www.isdn4linux.de/faq/ (view)
+https://www.isdn4linux.de/faq/4lfaq.html (view)
 
 As the extension tells, the FAQ is in SGML format, and you can convert it
 into text/html/... format by using the sgml2txt/sgml2html/... tools.
index 7534c60..9b1ce27 100644 (file)
@@ -29,8 +29,9 @@ GigaSet 307x Device Driver
         T-Com Sinus 721 data
         Chicago 390 USB (KPN)
 
-     See also http://www.erbze.info/sinus_gigaset.htm and
-              http://gigaset307x.sourceforge.net/
+     See also http://www.erbze.info/sinus_gigaset.htm
+       (archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm ) and
+       http://gigaset307x.sourceforge.net/
 
      We had also reports from users of Gigaset M105 who could use the drivers
      with SX 100 and CX 100 ISDN bases (only in unimodem mode, see section 2.5.)
@@ -52,7 +53,7 @@ GigaSet 307x Device Driver
      to use CAPI 2.0 or ISDN4Linux for ISDN connections (voice or data).
 
      There are some user space tools available at
-     http://sourceforge.net/projects/gigaset307x/
+     https://sourceforge.net/projects/gigaset307x/
      which provide access to additional device specific functions like SMS,
      phonebook or call journal.
 
@@ -202,7 +203,7 @@ GigaSet 307x Device Driver
      You can use some configuration tool of your distribution to configure this
      "modem" or configure pppd/wvdial manually. There are some example ppp
      configuration files and chat scripts in the gigaset-VERSION/ppp directory
-     in the driver packages from http://sourceforge.net/projects/gigaset307x/.
+     in the driver packages from https://sourceforge.net/projects/gigaset307x/.
      Please note that the USB drivers are not able to change the state of the
      control lines. This means you must use "Stupid Mode" if you are using
      wvdial or you should use the nocrtscts option of pppd.
@@ -361,7 +362,7 @@ GigaSet 307x Device Driver
      ---------------------------
      If you can't solve problems with the driver on your own, feel free to
      use one of the forums, bug trackers, or mailing lists on
-         http://sourceforge.net/projects/gigaset307x
+         https://sourceforge.net/projects/gigaset307x
      or write an electronic mail to the maintainers.
 
      Try to provide as much information as possible, such as
@@ -391,11 +392,12 @@ GigaSet 307x Device Driver
 4.   Links, other software
      ---------------------
      - Sourceforge project developing this driver and associated tools
-         http://sourceforge.net/projects/gigaset307x
+         https://sourceforge.net/projects/gigaset307x
      - Yahoo! Group on the Siemens Gigaset family of devices
-         http://de.groups.yahoo.com/group/Siemens-Gigaset
+         https://de.groups.yahoo.com/group/Siemens-Gigaset
      - Siemens Gigaset/T-Sinus compatibility table
          http://www.erbze.info/sinus_gigaset.htm
+           (archived at https://web.archive.org/web/20100717020421/http://www.erbze.info:80/sinus_gigaset.htm )
 
 
 5.   Credits
index 60c482d..818aca1 100644 (file)
@@ -21,37 +21,23 @@ Implementation
 --------------
 
 Mutexes are represented by 'struct mutex', defined in include/linux/mutex.h
-and implemented in kernel/locking/mutex.c. These locks use a three
-state atomic counter (->count) to represent the different possible
-transitions that can occur during the lifetime of a lock:
-
-         1: unlocked
-         0: locked, no waiters
-   negative: locked, with potential waiters
-
-In its most basic form it also includes a wait-queue and a spinlock
-that serializes access to it. CONFIG_SMP systems can also include
-a pointer to the lock task owner (->owner) as well as a spinner MCS
-lock (->osq), both described below in (ii).
+and implemented in kernel/locking/mutex.c. These locks use an atomic variable
+(->owner) to keep track of the lock state during its lifetime.  Field owner
+actually contains 'struct task_struct *' to the current lock owner and it is
+therefore NULL if not currently owned. Since task_struct pointers are aligned
+at at least L1_CACHE_BYTES, low bits (3) are used to store extra state (e.g.,
+if waiter list is non-empty).  In its most basic form it also includes a
+wait-queue and a spinlock that serializes access to it. Furthermore,
+CONFIG_MUTEX_SPIN_ON_OWNER=y systems use a spinner MCS lock (->osq), described
+below in (ii).
 
 When acquiring a mutex, there are three possible paths that can be
 taken, depending on the state of the lock:
 
-(i) fastpath: tries to atomically acquire the lock by decrementing the
-    counter. If it was already taken by another task it goes to the next
-    possible path. This logic is architecture specific. On x86-64, the
-    locking fastpath is 2 instructions:
-
-    0000000000000e10 <mutex_lock>:
-    e21:   f0 ff 0b                lock decl (%rbx)
-    e24:   79 08                   jns    e2e <mutex_lock+0x1e>
-
-   the unlocking fastpath is equally tight:
-
-    0000000000000bc0 <mutex_unlock>:
-    bc8:   f0 ff 07                lock incl (%rdi)
-    bcb:   7f 0a                   jg     bd7 <mutex_unlock+0x17>
-
+(i) fastpath: tries to atomically acquire the lock by cmpxchg()ing the owner with
+    the current task. This only works in the uncontended case (cmpxchg() checks
+    against 0UL, so all 3 state bits above have to be 0). If the lock is
+    contended it goes to the next possible path.
 
 (ii) midpath: aka optimistic spinning, tries to spin for acquisition
      while the lock owner is running and there are no other tasks ready
@@ -143,11 +129,10 @@ Test if the mutex is taken:
 Disadvantages
 -------------
 
-Unlike its original design and purpose, 'struct mutex' is larger than
-most locks in the kernel. E.g: on x86-64 it is 40 bytes, almost twice
-as large as 'struct semaphore' (24 bytes) and tied, along with rwsems,
-for the largest lock in the kernel. Larger structure sizes mean more
-CPU cache and memory footprint.
+Unlike its original design and purpose, 'struct mutex' is among the largest
+locks in the kernel. E.g: on x86-64 it is 32 bytes, where 'struct semaphore'
+is 24 bytes and rw_semaphore is 40 bytes. Larger structure sizes mean more CPU
+cache and memory footprint.
 
 When to use mutexes
 -------------------
index 63f55a9..a8c4239 100644 (file)
@@ -50,9 +50,15 @@ replace typedef dmx_filter_t :c:type:`dmx_filter`
 replace typedef dmx_pes_type_t :c:type:`dmx_pes_type`
 replace typedef dmx_input_t :c:type:`dmx_input`
 
-ignore symbol DMX_OUT_DECODER
-ignore symbol DMX_OUT_TAP
-ignore symbol DMX_OUT_TS_TAP
-ignore symbol DMX_OUT_TSDEMUX_TAP
+replace symbol DMX_BUFFER_FLAG_HAD_CRC32_DISCARD :c:type:`dmx_buffer_flags`
+replace        symbol DMX_BUFFER_FLAG_TEI :c:type:`dmx_buffer_flags`
+replace        symbol DMX_BUFFER_PKT_COUNTER_MISMATCH :c:type:`dmx_buffer_flags`
+replace        symbol DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED :c:type:`dmx_buffer_flags`
+replace        symbol DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR :c:type:`dmx_buffer_flags`
+
+replace symbol DMX_OUT_DECODER :c:type:`dmx_output`
+replace symbol DMX_OUT_TAP :c:type:`dmx_output`
+replace symbol DMX_OUT_TS_TAP :c:type:`dmx_output`
+replace symbol DMX_OUT_TSDEMUX_TAP :c:type:`dmx_output`
 
 replace ioctl DMX_DQBUF dmx_qbuf
index b48c493..be5a4c6 100644 (file)
@@ -51,9 +51,10 @@ out to disk. Buffers remain locked until dequeued, until the
 the device is closed.
 
 Applications call the ``DMX_DQBUF`` ioctl to dequeue a filled
-(capturing) buffer from the driver's outgoing queue. They just set the ``reserved`` field array to zero. When ``DMX_DQBUF`` is called with a
-pointer to this structure, the driver fills the remaining fields or
-returns an error code.
+(capturing) buffer from the driver's outgoing queue.
+They just set the ``index`` field withe the buffer ID to be queued.
+When ``DMX_DQBUF`` is called with a pointer to struct :c:type:`dmx_buffer`,
+the driver fills the remaining fields or returns an error code.
 
 By default ``DMX_DQBUF`` blocks when no buffer is in the outgoing
 queue. When the ``O_NONBLOCK`` flag was given to the
index 2f09455..aca542e 100644 (file)
@@ -13,14 +13,15 @@ The following technologies are described:
  * Generic Segmentation Offload - GSO
  * Generic Receive Offload - GRO
  * Partial Generic Segmentation Offload - GSO_PARTIAL
+ * SCTP accelleration with GSO - GSO_BY_FRAGS
 
 TCP Segmentation Offload
 ========================
 
 TCP segmentation allows a device to segment a single frame into multiple
 frames with a data payload size specified in skb_shinfo()->gso_size.
-When TCP segmentation requested the bit for either SKB_GSO_TCP or
-SKB_GSO_TCP6 should be set in skb_shinfo()->gso_type and
+When TCP segmentation requested the bit for either SKB_GSO_TCPV4 or
+SKB_GSO_TCPV6 should be set in skb_shinfo()->gso_type and
 skb_shinfo()->gso_size should be set to a non-zero value.
 
 TCP segmentation is dependent on support for the use of partial checksum
@@ -49,6 +50,10 @@ datagram into multiple IPv4 fragments.  Many of the requirements for UDP
 fragmentation offload are the same as TSO.  However the IPv4 ID for
 fragments should not increment as a single IPv4 datagram is fragmented.
 
+UFO is deprecated: modern kernels will no longer generate UFO skbs, but can
+still receive them from tuntap and similar devices. Offload of UDP-based
+tunnel protocols is still supported.
+
 IPIP, SIT, GRE, UDP Tunnel, and Remote Checksum Offloads
 ========================================================
 
@@ -83,10 +88,10 @@ SKB_GSO_UDP_TUNNEL_CSUM.  These two additional tunnel types reflect the
 fact that the outer header also requests to have a non-zero checksum
 included in the outer header.
 
-Finally there is SKB_GSO_REMCSUM which indicates that a given tunnel header
-has requested a remote checksum offload.  In this case the inner headers
-will be left with a partial checksum and only the outer header checksum
-will be computed.
+Finally there is SKB_GSO_TUNNEL_REMCSUM which indicates that a given tunnel
+header has requested a remote checksum offload.  In this case the inner
+headers will be left with a partial checksum and only the outer header
+checksum will be computed.
 
 Generic Segmentation Offload
 ============================
@@ -128,3 +133,38 @@ values for if the header was simply duplicated.  The one exception to this
 is the outer IPv4 ID field.  It is up to the device drivers to guarantee
 that the IPv4 ID field is incremented in the case that a given header does
 not have the DF bit set.
+
+SCTP accelleration with GSO
+===========================
+
+SCTP - despite the lack of hardware support - can still take advantage of
+GSO to pass one large packet through the network stack, rather than
+multiple small packets.
+
+This requires a different approach to other offloads, as SCTP packets
+cannot be just segmented to (P)MTU. Rather, the chunks must be contained in
+IP segments, padding respected. So unlike regular GSO, SCTP can't just
+generate a big skb, set gso_size to the fragmentation point and deliver it
+to IP layer.
+
+Instead, the SCTP protocol layer builds an skb with the segments correctly
+padded and stored as chained skbs, and skb_segment() splits based on those.
+To signal this, gso_size is set to the special value GSO_BY_FRAGS.
+
+Therefore, any code in the core networking stack must be aware of the
+possibility that gso_size will be GSO_BY_FRAGS and handle that case
+appropriately.
+
+There are some helpers to make this easier:
+
+ - skb_is_gso(skb) && skb_is_gso_sctp(skb) is the best way to see if
+   an skb is an SCTP GSO skb.
+
+ - For size checks, the skb_gso_validate_*_len family of helpers correctly
+   considers GSO_BY_FRAGS.
+
+ - For manipulating packets, skb_increase_gso_size and skb_decrease_gso_size
+   will check for GSO_BY_FRAGS and WARN if asked to manipulate these skbs.
+
+This also affects drivers with the NETIF_F_FRAGLIST & NETIF_F_GSO_SCTP bits
+set. Note also that NETIF_F_GSO_SCTP is included in NETIF_F_GSO_SOFTWARE.
index 39aa9e8..fbedcc3 100644 (file)
@@ -36,8 +36,7 @@ import glob
 
 from docutils import nodes, statemachine
 from docutils.statemachine import ViewList
-from docutils.parsers.rst import directives
-from sphinx.util.compat import Directive
+from docutils.parsers.rst import directives, Directive
 from sphinx.ext.autodoc import AutodocReporter
 
 __version__  = '1.0'
index 792fa87..d6b3ff5 100644 (file)
@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
 flag KVM_VM_MIPS_VZ.
 
 
-4.3 KVM_GET_MSR_INDEX_LIST
+4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
 
-Capability: basic
+Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
 Architectures: x86
-Type: system
+Type: system ioctl
 Parameters: struct kvm_msr_list (in/out)
 Returns: 0 on success; -1 on error
 Errors:
+  EFAULT:    the msr index list cannot be read from or written to
   E2BIG:     the msr index list is to be to fit in the array specified by
              the user.
 
@@ -139,16 +140,23 @@ struct kvm_msr_list {
        __u32 indices[0];
 };
 
-This ioctl returns the guest msrs that are supported.  The list varies
-by kvm version and host processor, but does not change otherwise.  The
-user fills in the size of the indices array in nmsrs, and in return
-kvm adjusts nmsrs to reflect the actual number of msrs and fills in
-the indices array with their numbers.
+The user fills in the size of the indices array in nmsrs, and in return
+kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
+indices array with their numbers.
+
+KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported.  The list
+varies by kvm version and host processor, but does not change otherwise.
 
 Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
 not returned in the MSR list, as different vcpus can have a different number
 of banks, as set via the KVM_X86_SETUP_MCE ioctl.
 
+KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
+to the KVM_GET_MSRS system ioctl.  This lets userspace probe host capabilities
+and processor features that are exposed via MSRs (e.g., VMX capabilities).
+This list also varies by kvm version and host processor, but does not change
+otherwise.
+
 
 4.4 KVM_CHECK_EXTENSION
 
@@ -475,14 +483,22 @@ Support for this has been removed.  Use KVM_SET_GUEST_DEBUG instead.
 
 4.18 KVM_GET_MSRS
 
-Capability: basic
+Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
 Architectures: x86
-Type: vcpu ioctl
+Type: system ioctl, vcpu ioctl
 Parameters: struct kvm_msrs (in/out)
-Returns: 0 on success, -1 on error
+Returns: number of msrs successfully returned;
+        -1 on error
+
+When used as a system ioctl:
+Reads the values of MSR-based features that are available for the VM.  This
+is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
+The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
+in a system ioctl.
 
+When used as a vcpu ioctl:
 Reads model-specific registers from the vcpu.  Supported msr indices can
-be obtained using KVM_GET_MSR_INDEX_LIST.
+be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
 
 struct kvm_msrs {
        __u32 nmsrs; /* number of msrs in entries */
index dcab6dc..87a7506 100644 (file)
@@ -58,6 +58,10 @@ KVM_FEATURE_PV_TLB_FLUSH           ||     9 || guest checks this feature bit
                                    ||       || before enabling paravirtualized
                                    ||       || tlb flush.
 ------------------------------------------------------------------------------
+KVM_FEATURE_ASYNC_PF_VMEXIT        ||    10 || paravirtualized async PF VM exit
+                                   ||       || can be enabled by setting bit 2
+                                   ||       || when writing to msr 0x4b564d02
+------------------------------------------------------------------------------
 KVM_FEATURE_CLOCKSOURCE_STABLE_BIT ||    24 || host will warn if no guest-side
                                    ||       || per-cpu warps are expected in
                                    ||       || kvmclock.
index 1ebecc1..f3f0d57 100644 (file)
@@ -170,7 +170,8 @@ MSR_KVM_ASYNC_PF_EN: 0x4b564d02
        when asynchronous page faults are enabled on the vcpu 0 when
        disabled. Bit 1 is 1 if asynchronous page faults can be injected
        when vcpu is in cpl == 0. Bit 2 is 1 if asynchronous page faults
-       are delivered to L1 as #PF vmexits.
+       are delivered to L1 as #PF vmexits.  Bit 2 can be set only if
+       KVM_FEATURE_ASYNC_PF_VMEXIT is present in CPUID.
 
        First 4 byte of 64 byte memory location will be written to by
        the hypervisor at the time of asynchronous page fault (APF)
index 756fd76..71c3098 100644 (file)
@@ -671,7 +671,7 @@ occupancy of the real time threads on these cores.
 # mkdir p1
 
 Move the cpus 4-7 over to p1
-# echo f0 > p0/cpus
+# echo f0 > p1/cpus
 
 View the llc occupancy snapshot
 
index f3e9d7e..2953e3e 100644 (file)
@@ -108,7 +108,7 @@ The topology of a system is described in the units of:
 
     The number of online threads is also printed in /proc/cpuinfo "siblings."
 
-  - topology_sibling_mask():
+  - topology_sibling_cpumask():
 
     The cpumask contains all online threads in the core to which a thread
     belongs.
index 9a7f76e..6e950b8 100644 (file)
@@ -1060,41 +1060,42 @@ ARM PORT
 M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.armlinux.org.uk/
-S:     Maintained
+S:     Odd Fixes
 T:     git git://git.armlinux.org.uk/~rmk/linux-arm.git
 F:     arch/arm/
+X:     arch/arm/boot/dts/
 
 ARM PRIMECELL AACI PL041 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     sound/arm/aaci.*
 
 ARM PRIMECELL BUS SUPPORT
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/amba/
 F:     include/linux/amba/bus.h
 
 ARM PRIMECELL CLCD PL110 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/video/fbdev/amba-clcd.*
 
 ARM PRIMECELL KMI PL050 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/input/serio/ambakmi.*
 F:     include/linux/amba/kmi.h
 
 ARM PRIMECELL MMCI PL180/1 DRIVER
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/mmc/host/mmci.*
 F:     include/linux/amba/mmci.h
 
 ARM PRIMECELL UART PL010 AND PL011 DRIVERS
 M:     Russell King <linux@armlinux.org.uk>
-S:     Maintained
+S:     Odd Fixes
 F:     drivers/tty/serial/amba-pl01*.c
 F:     include/linux/amba/serial.h
 
@@ -1152,7 +1153,7 @@ S:        Maintained
 F:     drivers/clk/sunxi/
 
 ARM/Allwinner sunXi SoC support
-M:     Maxime Ripard <maxime.ripard@free-electrons.com>
+M:     Maxime Ripard <maxime.ripard@bootlin.com>
 M:     Chen-Yu Tsai <wens@csie.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -1238,7 +1239,7 @@ F:        drivers/clk/at91
 
 ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
 M:     Nicolas Ferre <nicolas.ferre@microchip.com>
-M:     Alexandre Belloni <alexandre.belloni@free-electrons.com>
+M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.linux4sam.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/nferre/linux-at91.git
@@ -1590,7 +1591,7 @@ ARM/Marvell Dove/MV78xx0/Orion SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
-M:     Gregory Clement <gregory.clement@free-electrons.com>
+M:     Gregory Clement <gregory.clement@bootlin.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/soc/dove/
@@ -1604,7 +1605,7 @@ F:        arch/arm/boot/dts/orion5x*
 ARM/Marvell Kirkwood and Armada 370, 375, 38x, 39x, XP, 3700, 7K/8K SOC support
 M:     Jason Cooper <jason@lakedaemon.net>
 M:     Andrew Lunn <andrew@lunn.ch>
-M:     Gregory Clement <gregory.clement@free-electrons.com>
+M:     Gregory Clement <gregory.clement@bootlin.com>
 M:     Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
@@ -1999,8 +2000,10 @@ M:       Maxime Coquelin <mcoquelin.stm32@gmail.com>
 M:     Alexandre Torgue <alexandre.torgue@st.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mcoquelin/stm32.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
 N:     stm32
+F:     arch/arm/boot/dts/stm32*
+F:     arch/arm/mach-stm32/
 F:     drivers/clocksource/armv7m_systick.c
 
 ARM/TANGO ARCHITECTURE
@@ -4624,7 +4627,7 @@ F:        include/uapi/drm/drm*
 F:     include/linux/vga*
 
 DRM DRIVERS FOR ALLWINNER A10
-M:     Maxime Ripard  <maxime.ripard@free-electrons.com>
+M:     Maxime Ripard  <maxime.ripard@bootlin.com>
 L:     dri-devel@lists.freedesktop.org
 S:     Supported
 F:     drivers/gpu/drm/sun4i/
@@ -7600,8 +7603,10 @@ F:       mm/kasan/
 F:     scripts/Makefile.kasan
 
 KCONFIG
+M:     Masahiro Yamada <yamada.masahiro@socionext.com>
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild.git kconfig
 L:     linux-kbuild@vger.kernel.org
-S:     Orphan
+S:     Maintained
 F:     Documentation/kbuild/kconfig-language.txt
 F:     scripts/kconfig/
 
@@ -7909,7 +7914,6 @@ S:        Maintained
 F:     scripts/leaking_addresses.pl
 
 LED SUBSYSTEM
-M:     Richard Purdie <rpurdie@rpsys.net>
 M:     Jacek Anaszewski <jacek.anaszewski@gmail.com>
 M:     Pavel Machek <pavel@ucw.cz>
 L:     linux-leds@vger.kernel.org
@@ -8431,7 +8435,7 @@ S:        Orphan
 F:     drivers/net/wireless/marvell/libertas/
 
 MARVELL MACCHIATOBIN SUPPORT
-M:     Russell King <rmk@armlinux.org.uk>
+M:     Russell King <linux@armlinux.org.uk>
 L:     linux-arm-kernel@lists.infradead.org
 S:     Maintained
 F:     arch/arm64/boot/dts/marvell/armada-8040-mcbin.dts
@@ -8444,7 +8448,7 @@ F:        drivers/net/ethernet/marvell/mv643xx_eth.*
 F:     include/linux/mv643xx.h
 
 MARVELL MV88X3310 PHY DRIVER
-M:     Russell King <rmk@armlinux.org.uk>
+M:     Russell King <linux@armlinux.org.uk>
 L:     netdev@vger.kernel.org
 S:     Maintained
 F:     drivers/net/phy/marvell10g.c
@@ -9922,6 +9926,13 @@ F:       Documentation/ABI/stable/sysfs-bus-nvmem
 F:     include/linux/nvmem-consumer.h
 F:     include/linux/nvmem-provider.h
 
+NXP SGTL5000 DRIVER
+M:     Fabio Estevam <fabio.estevam@nxp.com>
+L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
+S:     Maintained
+F:     Documentation/devicetree/bindings/sound/sgtl5000.txt
+F:     sound/soc/codecs/sgtl5000*
+
 NXP TDA998X DRM DRIVER
 M:     Russell King <linux@armlinux.org.uk>
 S:     Supported
@@ -10324,7 +10335,7 @@ F:      drivers/oprofile/
 F:     include/linux/oprofile.h
 
 ORACLE CLUSTER FILESYSTEM 2 (OCFS2)
-M:     Mark Fasheh <mfasheh@versity.com>
+M:     Mark Fasheh <mark@fasheh.com>
 M:     Joel Becker <jlbec@evilplan.org>
 L:     ocfs2-devel@oss.oracle.com (moderated for non-subscribers)
 W:     http://ocfs2.wiki.kernel.org
@@ -10834,6 +10845,7 @@ F:      drivers/platform/x86/peaq-wmi.c
 PER-CPU MEMORY ALLOCATOR
 M:     Tejun Heo <tj@kernel.org>
 M:     Christoph Lameter <cl@linux.com>
+M:     Dennis Zhou <dennisszhou@gmail.com>
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tj/percpu.git
 S:     Maintained
 F:     include/linux/percpu*.h
@@ -10927,6 +10939,17 @@ L:     linux-gpio@vger.kernel.org
 S:     Supported
 F:     drivers/pinctrl/pinctrl-at91-pio4.*
 
+PIN CONTROLLER - FREESCALE
+M:     Dong Aisheng <aisheng.dong@nxp.com>
+M:     Fabio Estevam <festevam@gmail.com>
+M:     Shawn Guo <shawnguo@kernel.org>
+M:     Stefan Agner <stefan@agner.ch>
+R:     Pengutronix Kernel Team <kernel@pengutronix.de>
+L:     linux-gpio@vger.kernel.org
+S:     Maintained
+F:     drivers/pinctrl/freescale/
+F:     Documentation/devicetree/bindings/pinctrl/fsl,*
+
 PIN CONTROLLER - INTEL
 M:     Mika Westerberg <mika.westerberg@linux.intel.com>
 M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
@@ -12093,6 +12116,7 @@ M:      Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/samsung/
+F:     Documentation/devicetree/bindings/sound/samsung*
 
 SAMSUNG EXYNOS PSEUDO RANDOM NUMBER GENERATOR (RNG) DRIVER
 M:     Krzysztof Kozlowski <krzk@kernel.org>
@@ -12852,6 +12876,19 @@ S:     Maintained
 F:     drivers/net/ethernet/socionext/netsec.c
 F:     Documentation/devicetree/bindings/net/socionext-netsec.txt
 
+SOLIDRUN CLEARFOG SUPPORT
+M:     Russell King <linux@armlinux.org.uk>
+S:     Maintained
+F:     arch/arm/boot/dts/armada-388-clearfog*
+F:     arch/arm/boot/dts/armada-38x-solidrun-*
+
+SOLIDRUN CUBOX-I/HUMMINGBOARD SUPPORT
+M:     Russell King <linux@armlinux.org.uk>
+S:     Maintained
+F:     arch/arm/boot/dts/imx6*-cubox-i*
+F:     arch/arm/boot/dts/imx6*-hummingboard*
+F:     arch/arm/boot/dts/imx6*-sr-*
+
 SONIC NETWORK DRIVER
 M:     Thomas Bogendoerfer <tsbogend@alpha.franken.de>
 L:     netdev@vger.kernel.org
@@ -13621,7 +13658,8 @@ S:      Supported
 F:     drivers/i2c/busses/i2c-tegra.c
 
 TEGRA IOMMU DRIVERS
-M:     Hiroshi Doyu <hdoyu@nvidia.com>
+M:     Thierry Reding <thierry.reding@gmail.com>
+L:     linux-tegra@vger.kernel.org
 S:     Supported
 F:     drivers/iommu/tegra*
 
index 3dfce4d..9f77440 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 4
 PATCHLEVEL = 16
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc7
 NAME = Fearless Coyote
 
 # *DOCUMENTATION*
@@ -388,7 +388,7 @@ PYTHON              = python
 CHECK          = sparse
 
 CHECKFLAGS     := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \
-                 -Wbitwise -Wno-return-void $(CF)
+                 -Wbitwise -Wno-return-void -Wno-unknown-attribute $(CF)
 NOSTDINC_FLAGS  =
 CFLAGS_MODULE   =
 AFLAGS_MODULE   =
@@ -487,6 +487,8 @@ CLANG_GCC_TC        := --gcc-toolchain=$(GCC_TOOLCHAIN)
 endif
 KBUILD_CFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
 KBUILD_AFLAGS += $(CLANG_TARGET) $(CLANG_GCC_TC)
+KBUILD_CFLAGS += $(call cc-option, -no-integrated-as)
+KBUILD_AFLAGS += $(call cc-option, -no-integrated-as)
 endif
 
 RETPOLINE_CFLAGS_GCC := -mindirect-branch=thunk-extern -mindirect-branch-register
@@ -584,10 +586,9 @@ ifeq ($(KBUILD_EXTMOD),)
 # To avoid any implicit rule to kick in, define an empty command
 $(KCONFIG_CONFIG) include/config/auto.conf.cmd: ;
 
-# If .config is newer than include/config/auto.conf, someone tinkered
-# with it and forgot to run make oldconfig.
-# if auto.conf.cmd is missing then we are probably in a cleaned tree so
-# we execute the config step to be sure to catch updated Kconfig files
+# The actual configuration files used during the build are stored in
+# include/generated/ and include/config/. Update them if .config is newer than
+# include/config/auto.conf (which mirrors .config).
 include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd
        $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig
 else
@@ -744,8 +745,6 @@ KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare)
 # See modpost pattern 2
 KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,)
 KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior)
-KBUILD_CFLAGS += $(call cc-option, -no-integrated-as)
-KBUILD_AFLAGS += $(call cc-option, -no-integrated-as)
 else
 
 # These warnings generated too much noise in a regular build.
@@ -827,6 +826,15 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign)
 # disable invalid "can't wrap" optimizations for signed / pointers
 KBUILD_CFLAGS  += $(call cc-option,-fno-strict-overflow)
 
+# clang sets -fmerge-all-constants by default as optimization, but this
+# is non-conforming behavior for C and in fact breaks the kernel, so we
+# need to disable it here generally.
+KBUILD_CFLAGS  += $(call cc-option,-fno-merge-all-constants)
+
+# for gcc -fno-merge-all-constants disables everything, but it is fine
+# to have actual conforming behavior enabled.
+KBUILD_CFLAGS  += $(call cc-option,-fmerge-constants)
+
 # Make sure -fstack-check isn't enabled (like gentoo apparently did)
 KBUILD_CFLAGS  += $(call cc-option,-fno-stack-check,)
 
@@ -862,8 +870,7 @@ KBUILD_AFLAGS   += $(ARCH_AFLAGS)   $(KAFLAGS)
 KBUILD_CFLAGS   += $(ARCH_CFLAGS)   $(KCFLAGS)
 
 # Use --build-id when available.
-LDFLAGS_BUILD_ID := $(patsubst -Wl$(comma)%,%,\
-                             $(call cc-ldoption, -Wl$(comma)--build-id,))
+LDFLAGS_BUILD_ID := $(call ld-option, --build-id)
 KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
 LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)
 
index 46ebf14..8a2b331 100644 (file)
@@ -6,7 +6,6 @@
  * Atomic exchange routines.
  */
 
-#define __ASM__MB
 #define ____xchg(type, args...)                __xchg ## type ## _local(args)
 #define ____cmpxchg(type, args...)     __cmpxchg ## type ## _local(args)
 #include <asm/xchg.h>
        cmpxchg_local((ptr), (o), (n));                                 \
 })
 
-#ifdef CONFIG_SMP
-#undef __ASM__MB
-#define __ASM__MB      "\tmb\n"
-#endif
 #undef ____xchg
 #undef ____cmpxchg
 #define ____xchg(type, args...)                __xchg ##type(args)
@@ -64,7 +59,6 @@
        cmpxchg((ptr), (o), (n));                                       \
 })
 
-#undef __ASM__MB
 #undef ____cmpxchg
 
 #endif /* _ALPHA_CMPXCHG_H */
index 68dfb3c..e2b59fa 100644 (file)
  * Atomic exchange.
  * Since it can be used to implement critical sections
  * it must clobber "memory" (also for interrupts in UP).
+ *
+ * The leading and the trailing memory barriers guarantee that these
+ * operations are fully ordered.
+ *
  */
 
 static inline unsigned long
@@ -19,6 +23,7 @@ ____xchg(_u8, volatile char *m, unsigned long val)
 {
        unsigned long ret, tmp, addr64;
 
+       smp_mb();
        __asm__ __volatile__(
        "       andnot  %4,7,%3\n"
        "       insbl   %1,%4,%1\n"
@@ -28,12 +33,12 @@ ____xchg(_u8, volatile char *m, unsigned long val)
        "       or      %1,%2,%2\n"
        "       stq_c   %2,0(%3)\n"
        "       beq     %2,2f\n"
-               __ASM__MB
        ".subsection 2\n"
        "2:     br      1b\n"
        ".previous"
        : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
        : "r" ((long)m), "1" (val) : "memory");
+       smp_mb();
 
        return ret;
 }
@@ -43,6 +48,7 @@ ____xchg(_u16, volatile short *m, unsigned long val)
 {
        unsigned long ret, tmp, addr64;
 
+       smp_mb();
        __asm__ __volatile__(
        "       andnot  %4,7,%3\n"
        "       inswl   %1,%4,%1\n"
@@ -52,12 +58,12 @@ ____xchg(_u16, volatile short *m, unsigned long val)
        "       or      %1,%2,%2\n"
        "       stq_c   %2,0(%3)\n"
        "       beq     %2,2f\n"
-               __ASM__MB
        ".subsection 2\n"
        "2:     br      1b\n"
        ".previous"
        : "=&r" (ret), "=&r" (val), "=&r" (tmp), "=&r" (addr64)
        : "r" ((long)m), "1" (val) : "memory");
+       smp_mb();
 
        return ret;
 }
@@ -67,17 +73,18 @@ ____xchg(_u32, volatile int *m, unsigned long val)
 {
        unsigned long dummy;
 
+       smp_mb();
        __asm__ __volatile__(
        "1:     ldl_l %0,%4\n"
        "       bis $31,%3,%1\n"
        "       stl_c %1,%2\n"
        "       beq %1,2f\n"
-               __ASM__MB
        ".subsection 2\n"
        "2:     br 1b\n"
        ".previous"
        : "=&r" (val), "=&r" (dummy), "=m" (*m)
        : "rI" (val), "m" (*m) : "memory");
+       smp_mb();
 
        return val;
 }
@@ -87,17 +94,18 @@ ____xchg(_u64, volatile long *m, unsigned long val)
 {
        unsigned long dummy;
 
+       smp_mb();
        __asm__ __volatile__(
        "1:     ldq_l %0,%4\n"
        "       bis $31,%3,%1\n"
        "       stq_c %1,%2\n"
        "       beq %1,2f\n"
-               __ASM__MB
        ".subsection 2\n"
        "2:     br 1b\n"
        ".previous"
        : "=&r" (val), "=&r" (dummy), "=m" (*m)
        : "rI" (val), "m" (*m) : "memory");
+       smp_mb();
 
        return val;
 }
@@ -128,10 +136,12 @@ ____xchg(, volatile void *ptr, unsigned long x, int size)
  * store NEW in MEM.  Return the initial value in MEM.  Success is
  * indicated by comparing RETURN with OLD.
  *
- * The memory barrier should be placed in SMP only when we actually
- * make the change. If we don't change anything (so if the returned
- * prev is equal to old) then we aren't acquiring anything new and
- * we don't need any memory barrier as far I can tell.
+ * The leading and the trailing memory barriers guarantee that these
+ * operations are fully ordered.
+ *
+ * The trailing memory barrier is placed in SMP unconditionally, in
+ * order to guarantee that dependency ordering is preserved when a
+ * dependency is headed by an unsuccessful operation.
  */
 
 static inline unsigned long
@@ -139,6 +149,7 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new)
 {
        unsigned long prev, tmp, cmp, addr64;
 
+       smp_mb();
        __asm__ __volatile__(
        "       andnot  %5,7,%4\n"
        "       insbl   %1,%5,%1\n"
@@ -150,13 +161,13 @@ ____cmpxchg(_u8, volatile char *m, unsigned char old, unsigned char new)
        "       or      %1,%2,%2\n"
        "       stq_c   %2,0(%4)\n"
        "       beq     %2,3f\n"
-               __ASM__MB
        "2:\n"
        ".subsection 2\n"
        "3:     br      1b\n"
        ".previous"
        : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
        : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+       smp_mb();
 
        return prev;
 }
@@ -166,6 +177,7 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new)
 {
        unsigned long prev, tmp, cmp, addr64;
 
+       smp_mb();
        __asm__ __volatile__(
        "       andnot  %5,7,%4\n"
        "       inswl   %1,%5,%1\n"
@@ -177,13 +189,13 @@ ____cmpxchg(_u16, volatile short *m, unsigned short old, unsigned short new)
        "       or      %1,%2,%2\n"
        "       stq_c   %2,0(%4)\n"
        "       beq     %2,3f\n"
-               __ASM__MB
        "2:\n"
        ".subsection 2\n"
        "3:     br      1b\n"
        ".previous"
        : "=&r" (prev), "=&r" (new), "=&r" (tmp), "=&r" (cmp), "=&r" (addr64)
        : "r" ((long)m), "Ir" (old), "1" (new) : "memory");
+       smp_mb();
 
        return prev;
 }
@@ -193,6 +205,7 @@ ____cmpxchg(_u32, volatile int *m, int old, int new)
 {
        unsigned long prev, cmp;
 
+       smp_mb();
        __asm__ __volatile__(
        "1:     ldl_l %0,%5\n"
        "       cmpeq %0,%3,%1\n"
@@ -200,13 +213,13 @@ ____cmpxchg(_u32, volatile int *m, int old, int new)
        "       mov %4,%1\n"
        "       stl_c %1,%2\n"
        "       beq %1,3f\n"
-               __ASM__MB
        "2:\n"
        ".subsection 2\n"
        "3:     br 1b\n"
        ".previous"
        : "=&r"(prev), "=&r"(cmp), "=m"(*m)
        : "r"((long) old), "r"(new), "m"(*m) : "memory");
+       smp_mb();
 
        return prev;
 }
@@ -216,6 +229,7 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new)
 {
        unsigned long prev, cmp;
 
+       smp_mb();
        __asm__ __volatile__(
        "1:     ldq_l %0,%5\n"
        "       cmpeq %0,%3,%1\n"
@@ -223,13 +237,13 @@ ____cmpxchg(_u64, volatile long *m, unsigned long old, unsigned long new)
        "       mov %4,%1\n"
        "       stq_c %1,%2\n"
        "       beq %1,3f\n"
-               __ASM__MB
        "2:\n"
        ".subsection 2\n"
        "3:     br 1b\n"
        ".previous"
        : "=&r"(prev), "=&r"(cmp), "=m"(*m)
        : "r"((long) old), "r"(new), "m"(*m) : "memory");
+       smp_mb();
 
        return prev;
 }
index f3a80cf..d76bf4a 100644 (file)
@@ -484,7 +484,6 @@ config ARC_CURR_IN_REG
 
 config ARC_EMUL_UNALIGNED
        bool "Emulate unaligned memory access (userspace only)"
-       default N
        select SYSCTL_ARCH_UNALIGN_NO_WARN
        select SYSCTL_ARCH_UNALIGN_ALLOW
        depends on ISA_ARCOMPACT
index 70aec7d..626b694 100644 (file)
@@ -17,6 +17,6 @@
        compatible = "snps,axs101", "snps,arc-sdp";
 
        chosen {
-               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60";
+               bootargs = "earlycon=uart8250,mmio32,0xe0022000,115200n8 console=tty0 console=ttyS3,115200n8 consoleblank=0 video=1280x720@60 print-fatal-signals=1";
        };
 };
index 74d070c..47b74fb 100644 (file)
                        };
 
                        eeprom@0x54{
-                               compatible = "24c01";
+                               compatible = "atmel,24c01";
                                reg = <0x54>;
                                pagesize = <0x8>;
                        };
 
                        eeprom@0x57{
-                               compatible = "24c04";
+                               compatible = "atmel,24c04";
                                reg = <0x57>;
                                pagesize = <0x8>;
                        };
index 215cddd..0c60330 100644 (file)
@@ -22,7 +22,7 @@
        };
 
        chosen {
-               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug";
+               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=ttyS0,115200n8 debug print-fatal-signals=1";
        };
 
        aliases {
index 5ee96b0..ff2f2c7 100644 (file)
@@ -17,7 +17,7 @@
        interrupt-parent = <&core_intc>;
 
        chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
        };
 
        aliases {
index 8d787b2..8e2489b 100644 (file)
@@ -24,7 +24,7 @@
        };
 
        chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
        };
 
        aliases {
index 4f98ebf..ed12f49 100644 (file)
@@ -15,7 +15,7 @@
        interrupt-parent = <&core_intc>;
 
        chosen {
-               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8";
+               bootargs = "earlycon=arc_uart,mmio32,0xc0fc1000,115200n8 console=ttyARC0,115200n8 print-fatal-signals=1";
        };
 
        aliases {
index 3c391ba..7842e5e 100644 (file)
@@ -20,7 +20,7 @@
                /* this is for console on PGU */
                /* bootargs = "console=tty0 consoleblank=0"; */
                /* this is for console on serial */
-               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
+               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1";
        };
 
        aliases {
index 14a727c..b8838cf 100644 (file)
@@ -20,7 +20,7 @@
                /* this is for console on PGU */
                /* bootargs = "console=tty0 consoleblank=0"; */
                /* this is for console on serial */
-               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24";
+               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblank=0 debug video=640x480-24 print-fatal-signals=1";
        };
 
        aliases {
index 5052917..72a2c72 100644 (file)
@@ -18,7 +18,7 @@
 
        chosen {
                /* this is for console on serial */
-               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24";
+               bootargs = "earlycon=uart8250,mmio32,0xf0000000,115200n8 console=tty0 console=ttyS0,115200n8 consoleblan=0 debug video=640x480-24 print-fatal-signals=1";
        };
 
        aliases {
index ea022d4..21ec824 100644 (file)
@@ -23,7 +23,8 @@ void die(const char *str, struct pt_regs *regs, unsigned long address);
 
 #define BUG()  do {                                                            \
        pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
-       dump_stack();                                                           \
+       barrier_before_unreachable();                                           \
+       __builtin_trap();                                                       \
 } while (0)
 
 #define HAVE_ARCH_BUG
index 257a68f..309f4e6 100644 (file)
 .macro FAKE_RET_FROM_EXCPN
        lr      r9, [status32]
        bic     r9, r9, (STATUS_U_MASK|STATUS_DE_MASK|STATUS_AE_MASK)
-       or      r9, r9, (STATUS_L_MASK|STATUS_IE_MASK)
+       or      r9, r9, STATUS_IE_MASK
        kflag   r9
 .endm
 
index f61a52b..5fe84e4 100644 (file)
@@ -22,10 +22,79 @@ static DEFINE_RAW_SPINLOCK(mcip_lock);
 
 static char smp_cpuinfo_buf[128];
 
+/*
+ * Set mask to halt GFRC if any online core in SMP cluster is halted.
+ * Only works for ARC HS v3.0+, on earlier versions has no effect.
+ */
+static void mcip_update_gfrc_halt_mask(int cpu)
+{
+       struct bcr_generic gfrc;
+       unsigned long flags;
+       u32 gfrc_halt_mask;
+
+       READ_BCR(ARC_REG_GFRC_BUILD, gfrc);
+
+       /*
+        * CMD_GFRC_SET_CORE and CMD_GFRC_READ_CORE commands were added in
+        * GFRC 0x3 version.
+        */
+       if (gfrc.ver < 0x3)
+               return;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+
+       __mcip_cmd(CMD_GFRC_READ_CORE, 0);
+       gfrc_halt_mask = read_aux_reg(ARC_REG_MCIP_READBACK);
+       gfrc_halt_mask |= BIT(cpu);
+       __mcip_cmd_data(CMD_GFRC_SET_CORE, 0, gfrc_halt_mask);
+
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+}
+
+static void mcip_update_debug_halt_mask(int cpu)
+{
+       u32 mcip_mask = 0;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&mcip_lock, flags);
+
+       /*
+        * mcip_mask is same for CMD_DEBUG_SET_SELECT and CMD_DEBUG_SET_MASK
+        * commands. So read it once instead of reading both CMD_DEBUG_READ_MASK
+        * and CMD_DEBUG_READ_SELECT.
+        */
+       __mcip_cmd(CMD_DEBUG_READ_SELECT, 0);
+       mcip_mask = read_aux_reg(ARC_REG_MCIP_READBACK);
+
+       mcip_mask |= BIT(cpu);
+
+       __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, mcip_mask);
+       /*
+        * Parameter specified halt cause:
+        * STATUS32[H]/actionpoint/breakpoint/self-halt
+        * We choose all of them (0xF).
+        */
+       __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xF, mcip_mask);
+
+       raw_spin_unlock_irqrestore(&mcip_lock, flags);
+}
+
 static void mcip_setup_per_cpu(int cpu)
 {
+       struct mcip_bcr mp;
+
+       READ_BCR(ARC_REG_MCIP_BCR, mp);
+
        smp_ipi_irq_setup(cpu, IPI_IRQ);
        smp_ipi_irq_setup(cpu, SOFTIRQ_IRQ);
+
+       /* Update GFRC halt mask as new CPU came online */
+       if (mp.gfrc)
+               mcip_update_gfrc_halt_mask(cpu);
+
+       /* Update MCIP debug mask as new CPU came online */
+       if (mp.dbg)
+               mcip_update_debug_halt_mask(cpu);
 }
 
 static void mcip_ipi_send(int cpu)
@@ -101,11 +170,6 @@ static void mcip_probe_n_setup(void)
                IS_AVAIL1(mp.gfrc, "GFRC"));
 
        cpuinfo_arc700[0].extn.gfrc = mp.gfrc;
-
-       if (mp.dbg) {
-               __mcip_cmd_data(CMD_DEBUG_SET_SELECT, 0, 0xf);
-               __mcip_cmd_data(CMD_DEBUG_SET_MASK, 0xf, 0xf);
-       }
 }
 
 struct plat_smp_ops plat_smp_ops = {
index 9d27331..b2cae79 100644 (file)
@@ -51,7 +51,7 @@ static const struct id_to_str arc_cpu_rel[] = {
        { 0x51, "R2.0" },
        { 0x52, "R2.1" },
        { 0x53, "R3.0" },
-       { 0x54, "R4.0" },
+       { 0x54, "R3.10a" },
 #endif
        { 0x00, NULL   }
 };
@@ -373,7 +373,7 @@ static void arc_chk_core_config(void)
 {
        struct cpuinfo_arc *cpu = &cpuinfo_arc700[smp_processor_id()];
        int saved = 0, present = 0;
-       char *opt_nm = NULL;;
+       char *opt_nm = NULL;
 
        if (!cpu->extn.timer0)
                panic("Timer0 is not present!\n");
index efe8b42..21d86c3 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/reboot.h>
 #include <linux/irqdomain.h>
 #include <linux/export.h>
+#include <linux/of_fdt.h>
 
 #include <asm/processor.h>
 #include <asm/setup.h>
@@ -47,6 +48,42 @@ void __init smp_prepare_boot_cpu(void)
 {
 }
 
+static int __init arc_get_cpu_map(const char *name, struct cpumask *cpumask)
+{
+       unsigned long dt_root = of_get_flat_dt_root();
+       const char *buf;
+
+       buf = of_get_flat_dt_prop(dt_root, name, NULL);
+       if (!buf)
+               return -EINVAL;
+
+       if (cpulist_parse(buf, cpumask))
+               return -EINVAL;
+
+       return 0;
+}
+
+/*
+ * Read from DeviceTree and setup cpu possible mask. If there is no
+ * "possible-cpus" property in DeviceTree pretend all [0..NR_CPUS-1] exist.
+ */
+static void __init arc_init_cpu_possible(void)
+{
+       struct cpumask cpumask;
+
+       if (arc_get_cpu_map("possible-cpus", &cpumask)) {
+               pr_warn("Failed to get possible-cpus from dtb, pretending all %u cpus exist\n",
+                       NR_CPUS);
+
+               cpumask_setall(&cpumask);
+       }
+
+       if (!cpumask_test_cpu(0, &cpumask))
+               panic("Master cpu (cpu[0]) is missed in cpu possible mask!");
+
+       init_cpu_possible(&cpumask);
+}
+
 /*
  * Called from setup_arch() before calling setup_processor()
  *
@@ -58,10 +95,7 @@ void __init smp_prepare_boot_cpu(void)
  */
 void __init smp_init_cpus(void)
 {
-       unsigned int i;
-
-       for (i = 0; i < NR_CPUS; i++)
-               set_cpu_possible(i, true);
+       arc_init_cpu_possible();
 
        if (plat_smp_ops.init_early_smp)
                plat_smp_ops.init_early_smp();
@@ -70,16 +104,12 @@ void __init smp_init_cpus(void)
 /* called from init ( ) =>  process 1 */
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
-       int i;
-
        /*
         * if platform didn't set the present map already, do it now
         * boot cpu is set to present already by init/main.c
         */
-       if (num_present_cpus() <= 1) {
-               for (i = 0; i < max_cpus; i++)
-                       set_cpu_present(i, true);
-       }
+       if (num_present_cpus() <= 1)
+               init_cpu_present(cpu_possible_mask);
 }
 
 void __init smp_cpus_done(unsigned int max_cpus)
index 333daab..183391d 100644 (file)
@@ -366,7 +366,7 @@ static void init_unwind_hdr(struct unwind_table *table,
        return;
 
 ret_err:
-       panic("Attention !!! Dwarf FDE parsing errors\n");;
+       panic("Attention !!! Dwarf FDE parsing errors\n");
 }
 
 #ifdef CONFIG_MODULES
index eee924d..2072f34 100644 (file)
@@ -780,7 +780,10 @@ noinline static void slc_entire_op(const int op)
 
        write_aux_reg(r, ctrl);
 
-       write_aux_reg(ARC_REG_SLC_INVALIDATE, 1);
+       if (op & OP_INV)        /* Inv or flush-n-inv use same cmd reg */
+               write_aux_reg(ARC_REG_SLC_INVALIDATE, 0x1);
+       else
+               write_aux_reg(ARC_REG_SLC_FLUSH, 0x1);
 
        /* Make sure "busy" bit reports correct stataus, see STAR 9001165532 */
        read_aux_reg(r);
index 78a6470..199ebc1 100644 (file)
@@ -22,6 +22,7 @@ config ARM_PTDUMP_DEBUGFS
 
 config DEBUG_WX
        bool "Warn on W+X mappings at boot"
+       depends on MMU
        select ARM_PTDUMP_CORE
        ---help---
                Generate a warning if any W+X mappings are found at boot.
index 1189598..5e7d758 100755 (executable)
@@ -30,7 +30,7 @@ esac
 
 sym_val() {
        # extract hex value for symbol in $1
-       local val=$($NM "$VMLINUX" | sed -n "/ $1$/{s/ .*$//p;q}")
+       local val=$($NM "$VMLINUX" 2>/dev/null | sed -n "/ $1\$/{s/ .*$//p;q}")
        [ "$val" ] || { echo "can't find $1 in $VMLINUX" 1>&2; exit 1; }
        # convert from hex to decimal
        echo $((0x$val))
@@ -48,12 +48,12 @@ data_end=$(($_edata_loc - $base_offset))
 file_end=$(stat -c "%s" "$XIPIMAGE")
 if [ "$file_end" != "$data_end" ]; then
        printf "end of xipImage doesn't match with _edata_loc (%#x vs %#x)\n" \
-              $(($file_end + $base_offset)) $_edata_loc 2>&1
+              $(($file_end + $base_offset)) $_edata_loc 1>&2
        exit 1;
 fi
 
 # be ready to clean up
-trap 'rm -f "$XIPIMAGE.tmp"' 0 1 2 3
+trap 'rm -f "$XIPIMAGE.tmp"; exit 1' 1 2 3
 
 # substitute the data section by a compressed version
 $DD if="$XIPIMAGE" count=$data_start iflag=count_bytes of="$XIPIMAGE.tmp"
index b0d8431..ae2b8c9 100644 (file)
                };
        };
 
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0x40000000 0>;
+       };
+
        ahb {
                compatible = "simple-bus";
                #address-cells = <1>;
index 40de3b6..2477ebc 100644 (file)
                };
        };
 
+       memory@80000000 {
+               device_type = "memory";
+               reg = <0x80000000 0>;
+       };
+
        ahb {
                compatible = "simple-bus";
                #address-cells = <1>;
index 18045c3..db7cded 100644 (file)
@@ -55,7 +55,7 @@
                      <0x3ff00100 0x100>;
        };
 
-       smc@0x3404c000 {
+       smc@3404c000 {
                compatible = "brcm,bcm11351-smc", "brcm,kona-smc";
                reg = <0x3404c000 0x400>; /* 1 KiB in SRAM */
        };
index 6dde95f..266f261 100644 (file)
@@ -55,7 +55,7 @@
                      <0x3ff00100 0x100>;
        };
 
-       smc@0x3404e000 {
+       smc@3404e000 {
                compatible = "brcm,bcm21664-smc", "brcm,kona-smc";
                reg = <0x3404e000 0x400>; /* 1 KiB in SRAM */
        };
index 0e3d2a5..a5c3824 100644 (file)
        soc {
                ranges = <0x7e000000 0x20000000 0x02000000>;
                dma-ranges = <0x40000000 0x00000000 0x20000000>;
+       };
 
-               arm-pmu {
-                       compatible = "arm,arm1176-pmu";
-               };
+       arm-pmu {
+               compatible = "arm,arm1176-pmu";
        };
 };
 
index 1dfd764..c933e84 100644 (file)
@@ -9,19 +9,19 @@
                         <0x40000000 0x40000000 0x00001000>;
                dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
 
-               local_intc: local_intc {
+               local_intc: local_intc@40000000 {
                        compatible = "brcm,bcm2836-l1-intc";
                        reg = <0x40000000 0x100>;
                        interrupt-controller;
                        #interrupt-cells = <2>;
                        interrupt-parent = <&local_intc>;
                };
+       };
 
-               arm-pmu {
-                       compatible = "arm,cortex-a7-pmu";
-                       interrupt-parent = <&local_intc>;
-                       interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
-               };
+       arm-pmu {
+               compatible = "arm,cortex-a7-pmu";
+               interrupt-parent = <&local_intc>;
+               interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
        };
 
        timer {
index efa7d33..7704bb0 100644 (file)
@@ -8,7 +8,7 @@
                         <0x40000000 0x40000000 0x00001000>;
                dma-ranges = <0xc0000000 0x00000000 0x3f000000>;
 
-               local_intc: local_intc {
+               local_intc: local_intc@40000000 {
                        compatible = "brcm,bcm2836-l1-intc";
                        reg = <0x40000000 0x100>;
                        interrupt-controller;
index 18db25a..9d293de 100644 (file)
                        status = "disabled";
                };
 
-               aux: aux@0x7e215000 {
+               aux: aux@7e215000 {
                        compatible = "brcm,bcm2835-aux";
                        #clock-cells = <1>;
                        reg = <0x7e215000 0x8>;
index 6a44b80..f0e2008 100644 (file)
@@ -49,7 +49,7 @@
 
        memory {
                device_type = "memory";
-               reg = <0x60000000 0x80000000>;
+               reg = <0x60000000 0x20000000>;
        };
 
        gpio-restart {
index 08568ce..da8bb9d 100644 (file)
 
                sata: sata@46000000 {
                        /* The ROM uses this muxmode */
-                       cortina,gemini-ata-muxmode = <3>;
+                       cortina,gemini-ata-muxmode = <0>;
                        cortina,gemini-enable-sata-bridge;
                        status = "okay";
                };
index cf42c2f..1281bc3 100644 (file)
@@ -42,7 +42,7 @@
 
 /dts-v1/;
 
-#include "imx6q.dtsi"
+#include "imx6dl.dtsi"
 #include "imx6qdl-icore-rqs.dtsi"
 
 / {
index a7a5dc7..e7d2db8 100644 (file)
@@ -82,7 +82,7 @@
                enable-active-high;
        };
 
-       reg_usb_otg2_vbus: regulator-usb-otg1-vbus {
+       reg_usb_otg2_vbus: regulator-usb-otg2-vbus {
                compatible = "regulator-fixed";
                regulator-name = "usb_otg2_vbus";
                regulator-min-microvolt = <5000000>;
index c1aa7a4..a30ee9f 100644 (file)
@@ -71,6 +71,8 @@
 };
 
 &i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins>;
        clock-frequency = <2600000>;
 
        twl: twl@48 {
                >;
        };
 
-
+       i2c1_pins: pinmux_i2c1_pins {
+               pinctrl-single,pins = <
+                       OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0)        /* i2c1_scl.i2c1_scl */
+                       OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0)        /* i2c1_sda.i2c1_sda */
+               >;
+       };
 };
 
 &omap3_pmx_wkup {
index b50b796..4791544 100644 (file)
@@ -66,6 +66,8 @@
 };
 
 &i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&i2c1_pins>;
        clock-frequency = <2600000>;
 
        twl: twl@48 {
                        OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT | MUX_MODE0)        /* hsusb0_data7.hsusb0_data7 */
                >;
        };
+       i2c1_pins: pinmux_i2c1_pins {
+               pinctrl-single,pins = <
+                       OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0)        /* i2c1_scl.i2c1_scl */
+                       OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0)        /* i2c1_sda.i2c1_sda */
+               >;
+       };
 };
 
 &uart2 {
index ec2c8ba..592e17f 100644 (file)
@@ -47,7 +47,7 @@
                        gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;    /* gpio3_83 */
                        wakeup-source;
                        autorepeat;
-                       debounce_interval = <50>;
+                       debounce-interval = <50>;
                };
        };
 
index 3b704cf..a974581 100644 (file)
                max-frequency = <37500000>;
                clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
                         <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                resets = <&cru SRST_SDIO>;
                max-frequency = <37500000>;
                clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
                         <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                default-sample-phase = <158>;
                disable-wp;
                dmas = <&pdma 12>;
index 780ec3a..341deaf 100644 (file)
                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
                         <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                pinctrl-names = "default";
                pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_bus4>;
                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
                         <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                pinctrl-names = "default";
                pinctrl-0 = <&sdio_clk &sdio_cmd &sdio_bus4>;
                max-frequency = <37500000>;
                clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
                         <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                bus-width = <8>;
                default-sample-phase = <158>;
                fifo-depth = <0x100>;
index 99cfae8..5eae477 100644 (file)
        };
 };
 
-&cpu0 {
-       cpu0-supply = <&vdd_cpu>;
-       operating-points = <
-               /* KHz    uV */
-               1800000 1400000
-               1608000 1350000
-               1512000 1300000
-               1416000 1200000
-               1200000 1100000
-               1008000 1050000
-                816000 1000000
-                696000  950000
-                600000  900000
-                408000  900000
-                312000  900000
-                216000  900000
-                126000  900000
-       >;
-};
-
 &emmc {
        status = "okay";
        bus-width = <8>;
index 6102e4e..354aff4 100644 (file)
        i2s: i2s@ff890000 {
                compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
                reg = <0x0 0xff890000 0x0 0x10000>;
+               #sound-dai-cells = <0>;
                interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "rockchip,rk3288-dw-hdmi";
                reg = <0x0 0xff980000 0x0 0x20000>;
                reg-io-width = <4>;
+               #sound-dai-cells = <0>;
                rockchip,grf = <&grf>;
                interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru  PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
index 51e6f1d..b2758dd 100644 (file)
@@ -42,7 +42,6 @@
 
 /dts-v1/;
 #include "sun6i-a31s.dtsi"
-#include "sunxi-common-regulators.dtsi"
 #include <dt-bindings/gpio/gpio.h>
 
 / {
@@ -99,6 +98,7 @@
        pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_bpi_m2>;
        phy = <&phy1>;
        phy-mode = "rgmii";
+       phy-supply = <&reg_dldo1>;
        snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; /* PA21 */
        snps,reset-active-low;
        snps,reset-delays-us = <0 10000 30000>;
 &mmc0 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bpi_m2>;
-       vmmc-supply = <&reg_vcc3v0>;
+       vmmc-supply = <&reg_dcdc1>;
        bus-width = <4>;
        cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
        cd-inverted;
 &mmc2 {
        pinctrl-names = "default";
        pinctrl-0 = <&mmc2_pins_a>;
-       vmmc-supply = <&reg_vcc3v0>;
+       vmmc-supply = <&reg_aldo1>;
        mmc-pwrseq = <&mmc2_pwrseq>;
        bus-width = <4>;
        non-removable;
                reg = <0x68>;
                interrupt-parent = <&nmi_intc>;
                interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+               eldoin-supply = <&reg_dcdc1>;
+               x-powers,drive-vbus-en;
        };
 };
 
 
 #include "axp22x.dtsi"
 
+&reg_aldo1 {
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-wifi";
+};
+
+&reg_aldo2 {
+       regulator-always-on;
+       regulator-min-microvolt = <2500000>;
+       regulator-max-microvolt = <2500000>;
+       regulator-name = "vcc-gmac";
+};
+
+&reg_aldo3 {
+       regulator-always-on;
+       regulator-min-microvolt = <3000000>;
+       regulator-max-microvolt = <3000000>;
+       regulator-name = "avcc";
+};
+
 &reg_dc5ldo {
+       regulator-always-on;
        regulator-min-microvolt = <700000>;
        regulator-max-microvolt = <1320000>;
        regulator-name = "vdd-cpus";
        regulator-name = "vcc-dram";
 };
 
+&reg_dldo1 {
+       regulator-min-microvolt = <3000000>;
+       regulator-max-microvolt = <3000000>;
+       regulator-name = "vcc-mac";
+};
+
+&reg_dldo2 {
+       regulator-min-microvolt = <2800000>;
+       regulator-max-microvolt = <2800000>;
+       regulator-name = "avdd-csi";
+};
+
+&reg_dldo3 {
+       regulator-always-on;
+       regulator-min-microvolt = <3300000>;
+       regulator-max-microvolt = <3300000>;
+       regulator-name = "vcc-pb";
+};
+
+&reg_eldo1 {
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-name = "vdd-csi";
+       status = "okay";
+};
+
+&reg_ldo_io1 {
+       regulator-always-on;
+       regulator-min-microvolt = <1800000>;
+       regulator-max-microvolt = <1800000>;
+       regulator-name = "vcc-pm-cpus";
+       status = "okay";
+};
+
 &uart0 {
        pinctrl-names = "default";
        pinctrl-0 = <&uart0_pins_a>;
index 8a74efd..240e7a2 100644 (file)
@@ -56,7 +56,7 @@
                        clocks = <&topclk ZX296702_A9_PERIPHCLK>;
                };
 
-               l2cc: l2-cache-controller@0x00c00000 {
+               l2cc: l2-cache-controller@c00000 {
                        compatible = "arm,pl310-cache";
                        reg = <0x00c00000 0x1000>;
                        cache-unified;
                        arm,double-linefill-incr = <0>;
                };
 
-               pcu: pcu@0xa0008000 {
+               pcu: pcu@a0008000 {
                        compatible = "zte,zx296702-pcu";
                        reg = <0xa0008000 0x1000>;
                };
 
-               topclk: topclk@0x09800000 {
+               topclk: topclk@9800000 {
                        compatible = "zte,zx296702-topcrm-clk";
                        reg = <0x09800000 0x1000>;
                        #clock-cells = <1>;
                };
 
-               lsp1clk: lsp1clk@0x09400000 {
+               lsp1clk: lsp1clk@9400000 {
                        compatible = "zte,zx296702-lsp1crpm-clk";
                        reg = <0x09400000 0x1000>;
                        #clock-cells = <1>;
                };
 
-               lsp0clk: lsp0clk@0x0b000000 {
+               lsp0clk: lsp0clk@b000000 {
                        compatible = "zte,zx296702-lsp0crpm-clk";
                        reg = <0x0b000000 0x1000>;
                        #clock-cells = <1>;
                };
 
-               uart0: serial@0x09405000 {
+               uart0: serial@9405000 {
                        compatible = "zte,zx296702-uart";
                        reg = <0x09405000 0x1000>;
                        interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
@@ -98,7 +98,7 @@
                        status = "disabled";
                };
 
-               uart1: serial@0x09406000 {
+               uart1: serial@9406000 {
                        compatible = "zte,zx296702-uart";
                        reg = <0x09406000 0x1000>;
                        interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                };
 
-               mmc0: mmc@0x09408000 {
+               mmc0: mmc@9408000 {
                        compatible = "snps,dw-mshc";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
-               mmc1: mmc@0x0b003000 {
+               mmc1: mmc@b003000 {
                        compatible = "snps,dw-mshc";
                        #address-cells = <1>;
                        #size-cells = <0>;
                        status = "disabled";
                };
 
-               sysctrl: sysctrl@0xa0007000 {
+               sysctrl: sysctrl@a0007000 {
                        compatible = "zte,sysctrl", "syscon";
                        reg = <0xa0007000 0x1000>;
                };
index 2f145c4..92674f2 100644 (file)
@@ -319,7 +319,7 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y
 CONFIG_RC_CORE=m
 CONFIG_MEDIA_CONTROLLER=y
 CONFIG_VIDEO_V4L2_SUBDEV_API=y
-CONFIG_LIRC=m
+CONFIG_LIRC=y
 CONFIG_RC_DEVICES=y
 CONFIG_IR_RX51=m
 CONFIG_V4L_PLATFORM_DRIVERS=y
index 9c99e81..5b85889 100644 (file)
@@ -12,8 +12,6 @@ struct mm_struct;
 
 void arm_install_vdso(struct mm_struct *mm, unsigned long addr);
 
-extern char vdso_start, vdso_end;
-
 extern unsigned int vdso_total_pages;
 
 #else /* CONFIG_VDSO */
index 629f8e9..cf2701c 100644 (file)
@@ -83,7 +83,7 @@ static void dummy_clock_access(struct timespec64 *ts)
 }
 
 static clock_access_fn __read_persistent_clock = dummy_clock_access;
-static clock_access_fn __read_boot_clock = dummy_clock_access;;
+static clock_access_fn __read_boot_clock = dummy_clock_access;
 
 void read_persistent_clock64(struct timespec64 *ts)
 {
index a4d6dc0..f4dd7f9 100644 (file)
@@ -39,6 +39,8 @@
 
 static struct page **vdso_text_pagelist;
 
+extern char vdso_start[], vdso_end[];
+
 /* Total number of pages needed for the data and text portions of the VDSO. */
 unsigned int vdso_total_pages __ro_after_init;
 
@@ -197,13 +199,13 @@ static int __init vdso_init(void)
        unsigned int text_pages;
        int i;
 
-       if (memcmp(&vdso_start, "\177ELF", 4)) {
+       if (memcmp(vdso_start, "\177ELF", 4)) {
                pr_err("VDSO is not a valid ELF object!\n");
                return -ENOEXEC;
        }
 
-       text_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
-       pr_debug("vdso: %i text pages at base %p\n", text_pages, &vdso_start);
+       text_pages = (vdso_end - vdso_start) >> PAGE_SHIFT;
+       pr_debug("vdso: %i text pages at base %p\n", text_pages, vdso_start);
 
        /* Allocate the VDSO text pagelist */
        vdso_text_pagelist = kcalloc(text_pages, sizeof(struct page *),
@@ -218,7 +220,7 @@ static int __init vdso_init(void)
        for (i = 0; i < text_pages; i++) {
                struct page *page;
 
-               page = virt_to_page(&vdso_start + i * PAGE_SIZE);
+               page = virt_to_page(vdso_start + i * PAGE_SIZE);
                vdso_text_pagelist[i] = page;
        }
 
@@ -229,7 +231,7 @@ static int __init vdso_init(void)
 
        cntvct_ok = cntvct_functional();
 
-       patch_vdso(&vdso_start);
+       patch_vdso(vdso_start);
 
        return 0;
 }
index 5638ce0..63d6b40 100644 (file)
@@ -7,6 +7,8 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
 
 KVM=../../../../virt/kvm
 
+CFLAGS_ARMV7VE            :=$(call cc-option, -march=armv7ve)
+
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o
@@ -15,7 +17,10 @@ obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
 obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o
 obj-$(CONFIG_KVM_ARM_HOST) += vfp.o
 obj-$(CONFIG_KVM_ARM_HOST) += banked-sr.o
+CFLAGS_banked-sr.o        += $(CFLAGS_ARMV7VE)
+
 obj-$(CONFIG_KVM_ARM_HOST) += entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
 obj-$(CONFIG_KVM_ARM_HOST) += switch.o
+CFLAGS_switch.o                   += $(CFLAGS_ARMV7VE)
 obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o
index 111bda8..be4b8b0 100644 (file)
 
 #include <asm/kvm_hyp.h>
 
+/*
+ * gcc before 4.9 doesn't understand -march=armv7ve, so we have to
+ * trick the assembler.
+ */
 __asm__(".arch_extension     virt");
 
 void __hyp_text __banked_save_state(struct kvm_cpu_context *ctxt)
index ee1f83b..4c89a8e 100644 (file)
@@ -69,7 +69,7 @@ static void clps711x_restart(enum reboot_mode mode, const char *cmd)
        soft_restart(0);
 }
 
-static const char *clps711x_compat[] __initconst = {
+static const char *const clps711x_compat[] __initconst = {
        "cirrus,ep7209",
        NULL
 };
index e457f29..d6b1190 100644 (file)
@@ -368,7 +368,7 @@ static struct spi_eeprom at25640a = {
        .flags          = EE_ADDR2,
 };
 
-static struct spi_board_info dm355_evm_spi_info[] __initconst = {
+static const struct spi_board_info dm355_evm_spi_info[] __initconst = {
        {
                .modalias       = "at25",
                .platform_data  = &at25640a,
index be99724..fad9a56 100644 (file)
@@ -217,7 +217,7 @@ static struct spi_eeprom at25640a = {
        .flags          = EE_ADDR2,
 };
 
-static struct spi_board_info dm355_leopard_spi_info[] __initconst = {
+static const struct spi_board_info dm355_leopard_spi_info[] __initconst = {
        {
                .modalias       = "at25",
                .platform_data  = &at25640a,
index e75741f..e378098 100644 (file)
@@ -726,7 +726,7 @@ static struct spi_eeprom at25640 = {
        .flags          = EE_ADDR2,
 };
 
-static struct spi_board_info dm365_evm_spi_info[] __initconst = {
+static const struct spi_board_info dm365_evm_spi_info[] __initconst = {
        {
                .modalias       = "at25",
                .platform_data  = &at25640,
index a3e7807..62eb7d6 100644 (file)
@@ -127,8 +127,8 @@ static struct gpiod_lookup_table mmc_gpios_table = {
        .dev_id = "da830-mmc.0",
        .table = {
                /* CD: gpio3_12: gpio60: chip 1 contains gpio range 32-63*/
-               GPIO_LOOKUP("davinci_gpio.1", 28, "cd", GPIO_ACTIVE_LOW),
-               GPIO_LOOKUP("davinci_gpio.1", 29, "wp", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("davinci_gpio.0", 28, "cd", GPIO_ACTIVE_LOW),
+               GPIO_LOOKUP("davinci_gpio.0", 29, "wp", GPIO_ACTIVE_LOW),
        },
 };
 
index 6b32dc5..2c20599 100644 (file)
@@ -41,7 +41,7 @@ config MACH_ARMADA_375
        depends on ARCH_MULTI_V7
        select ARMADA_370_XP_IRQ
        select ARM_ERRATA_720789
-       select ARM_ERRATA_753970
+       select PL310_ERRATA_753970
        select ARM_GIC
        select ARMADA_375_CLK
        select HAVE_ARM_SCU
@@ -57,7 +57,7 @@ config MACH_ARMADA_38X
        bool "Marvell Armada 380/385 boards"
        depends on ARCH_MULTI_V7
        select ARM_ERRATA_720789
-       select ARM_ERRATA_753970
+       select PL310_ERRATA_753970
        select ARM_GIC
        select ARM_GLOBAL_TIMER
        select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
index 43e3e18..fa51241 100644 (file)
@@ -1011,17 +1011,17 @@ static int clk_debugfs_register_one(struct clk *c)
                return -ENOMEM;
        c->dent = d;
 
-       d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+       d = debugfs_create_u8("usecount", S_IRUGO, c->dent, &c->usecount);
        if (!d) {
                err = -ENOMEM;
                goto err_out;
        }
-       d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+       d = debugfs_create_ulong("rate", S_IRUGO, c->dent, &c->rate);
        if (!d) {
                err = -ENOMEM;
                goto err_out;
        }
-       d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+       d = debugfs_create_x8("flags", S_IRUGO, c->dent, &c->flags);
        if (!d) {
                err = -ENOMEM;
                goto err_out;
index 4bb6751..fc5fb77 100644 (file)
@@ -299,8 +299,6 @@ static void irq_save_context(void)
        if (soc_is_dra7xx())
                return;
 
-       if (!sar_base)
-               sar_base = omap4_get_sar_ram_base();
        if (wakeupgen_ops && wakeupgen_ops->save_context)
                wakeupgen_ops->save_context();
 }
@@ -598,6 +596,8 @@ static int __init wakeupgen_init(struct device_node *node,
        irq_hotplug_init();
        irq_pm_init();
 
+       sar_base = omap4_get_sar_ram_base();
+
        return 0;
 }
 IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
index 124f9af..34156ec 100644 (file)
@@ -977,6 +977,9 @@ static int _enable_clocks(struct omap_hwmod *oh)
 
        pr_debug("omap_hwmod: %s: enabling clocks\n", oh->name);
 
+       if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+               _enable_optional_clocks(oh);
+
        if (oh->_clk)
                clk_enable(oh->_clk);
 
@@ -985,9 +988,6 @@ static int _enable_clocks(struct omap_hwmod *oh)
                        clk_enable(os->_clk);
        }
 
-       if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
-               _enable_optional_clocks(oh);
-
        /* The opt clocks are controlled by the device driver. */
 
        return 0;
index 366158a..6f68576 100644 (file)
@@ -186,7 +186,7 @@ static void omap_pm_end(void)
        cpu_idle_poll_ctrl(false);
 }
 
-static void omap_pm_finish(void)
+static void omap_pm_wake(void)
 {
        if (soc_is_omap34xx())
                omap_prcm_irq_complete();
@@ -196,7 +196,7 @@ static const struct platform_suspend_ops omap_pm_ops = {
        .begin          = omap_pm_begin,
        .end            = omap_pm_end,
        .enter          = omap_pm_enter,
-       .finish         = omap_pm_finish,
+       .wake           = omap_pm_wake,
        .valid          = suspend_valid_only_mem,
 };
 
index ece09c9..d61fbd7 100644 (file)
@@ -156,12 +156,6 @@ static struct clock_event_device clockevent_gpt = {
        .tick_resume            = omap2_gp_timer_shutdown,
 };
 
-static struct property device_disabled = {
-       .name = "status",
-       .length = sizeof("disabled"),
-       .value = "disabled",
-};
-
 static const struct of_device_id omap_timer_match[] __initconst = {
        { .compatible = "ti,omap2420-timer", },
        { .compatible = "ti,omap3430-timer", },
@@ -203,8 +197,17 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id *
                                  of_get_property(np, "ti,timer-secure", NULL)))
                        continue;
 
-               if (!of_device_is_compatible(np, "ti,omap-counter32k"))
-                       of_add_property(np, &device_disabled);
+               if (!of_device_is_compatible(np, "ti,omap-counter32k")) {
+                       struct property *prop;
+
+                       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+                       if (!prop)
+                               return NULL;
+                       prop->name = "status";
+                       prop->value = "disabled";
+                       prop->length = strlen(prop->value);
+                       of_add_property(np, prop);
+               }
                return np;
        }
 
index 2a7bb6c..a810f4d 100644 (file)
@@ -58,7 +58,6 @@ config MACH_KUROBOX_PRO
 
 config MACH_DNS323
        bool "D-Link DNS-323"
-       select GENERIC_NET_UTILS
        select I2C_BOARDINFO if I2C
        help
          Say 'Y' here if you want your kernel to support the
@@ -66,7 +65,6 @@ config MACH_DNS323
 
 config MACH_TS209
        bool "QNAP TS-109/TS-209"
-       select GENERIC_NET_UTILS
        help
          Say 'Y' here if you want your kernel to support the
          QNAP TS-109/TS-209 platform.
@@ -101,7 +99,6 @@ config MACH_LINKSTATION_LS_HGL
 
 config MACH_TS409
        bool "QNAP TS-409"
-       select GENERIC_NET_UTILS
        help
          Say 'Y' here if you want your kernel to support the
          QNAP TS-409 platform.
index cd483bf..d13344b 100644 (file)
@@ -173,10 +173,42 @@ static struct mv643xx_eth_platform_data dns323_eth_data = {
        .phy_addr = MV643XX_ETH_PHY_ADDR(8),
 };
 
+/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
+ * functions be kept somewhere?
+ */
+static int __init dns323_parse_hex_nibble(char n)
+{
+       if (n >= '0' && n <= '9')
+               return n - '0';
+
+       if (n >= 'A' && n <= 'F')
+               return n - 'A' + 10;
+
+       if (n >= 'a' && n <= 'f')
+               return n - 'a' + 10;
+
+       return -1;
+}
+
+static int __init dns323_parse_hex_byte(const char *b)
+{
+       int hi;
+       int lo;
+
+       hi = dns323_parse_hex_nibble(b[0]);
+       lo = dns323_parse_hex_nibble(b[1]);
+
+       if (hi < 0 || lo < 0)
+               return -1;
+
+       return (hi << 4) | lo;
+}
+
 static int __init dns323_read_mac_addr(void)
 {
        u_int8_t addr[6];
-       void __iomem *mac_page;
+       int i;
+       char *mac_page;
 
        /* MAC address is stored as a regular ol' string in /dev/mtdblock4
         * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
@@ -185,8 +217,23 @@ static int __init dns323_read_mac_addr(void)
        if (!mac_page)
                return -ENOMEM;
 
-       if (!mac_pton((__force const char *) mac_page, addr))
-               goto error_fail;
+       /* Sanity check the string we're looking at */
+       for (i = 0; i < 5; i++) {
+               if (*(mac_page + (i * 3) + 2) != ':') {
+                       goto error_fail;
+               }
+       }
+
+       for (i = 0; i < 6; i++) {
+               int byte;
+
+               byte = dns323_parse_hex_byte(mac_page + (i * 3));
+               if (byte < 0) {
+                       goto error_fail;
+               }
+
+               addr[i] = byte;
+       }
 
        iounmap(mac_page);
        printk("DNS-323: Found ethernet MAC address: %pM\n", addr);
index 8977498..905d4f2 100644 (file)
@@ -53,12 +53,53 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(8),
 };
 
+static int __init qnap_tsx09_parse_hex_nibble(char n)
+{
+       if (n >= '0' && n <= '9')
+               return n - '0';
+
+       if (n >= 'A' && n <= 'F')
+               return n - 'A' + 10;
+
+       if (n >= 'a' && n <= 'f')
+               return n - 'a' + 10;
+
+       return -1;
+}
+
+static int __init qnap_tsx09_parse_hex_byte(const char *b)
+{
+       int hi;
+       int lo;
+
+       hi = qnap_tsx09_parse_hex_nibble(b[0]);
+       lo = qnap_tsx09_parse_hex_nibble(b[1]);
+
+       if (hi < 0 || lo < 0)
+               return -1;
+
+       return (hi << 4) | lo;
+}
+
 static int __init qnap_tsx09_check_mac_addr(const char *addr_str)
 {
        u_int8_t addr[6];
+       int i;
 
-       if (!mac_pton(addr_str, addr))
-               return -1;
+       for (i = 0; i < 6; i++) {
+               int byte;
+
+               /*
+                * Enforce "xx:xx:xx:xx:xx:xx\n" format.
+                */
+               if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n'))
+                       return -1;
+
+               byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3));
+               if (byte < 0)
+                       return -1;
+               addr[i] = byte;
+       }
 
        printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr);
 
@@ -77,12 +118,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size)
        unsigned long addr;
 
        for (addr = mem_base; addr < (mem_base + size); addr += 1024) {
-               void __iomem *nor_page;
+               char *nor_page;
                int ret = 0;
 
                nor_page = ioremap(addr, 1024);
                if (nor_page != NULL) {
-                       ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page);
+                       ret = qnap_tsx09_check_mac_addr(nor_page);
                        iounmap(nor_page);
                }
 
index 57058ac..36cd23c 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
-#include <linux/perf/arm_pmu.h>
 #include <linux/regulator/machine.h>
 
 #include <asm/outercache.h>
@@ -112,37 +111,6 @@ static void ux500_restart(enum reboot_mode mode, const char *cmd)
        prcmu_system_reset(0);
 }
 
-/*
- * The PMU IRQ lines of two cores are wired together into a single interrupt.
- * Bounce the interrupt to the other core if it's not ours.
- */
-static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler)
-{
-       irqreturn_t ret = handler(irq, dev);
-       int other = !smp_processor_id();
-
-       if (ret == IRQ_NONE && cpu_online(other))
-               irq_set_affinity(irq, cpumask_of(other));
-
-       /*
-        * We should be able to get away with the amount of IRQ_NONEs we give,
-        * while still having the spurious IRQ detection code kick in if the
-        * interrupt really starts hitting spuriously.
-        */
-       return ret;
-}
-
-static struct arm_pmu_platdata db8500_pmu_platdata = {
-       .handle_irq             = db8500_pmu_handler,
-       .irq_flags              = IRQF_NOBALANCING | IRQF_NO_THREAD,
-};
-
-static struct of_dev_auxdata u8500_auxdata_lookup[] __initdata = {
-       /* Requires call-back bindings. */
-       OF_DEV_AUXDATA("arm,cortex-a9-pmu", 0, "arm-pmu", &db8500_pmu_platdata),
-       {},
-};
-
 static struct of_dev_auxdata u8540_auxdata_lookup[] __initdata = {
        OF_DEV_AUXDATA("stericsson,db8500-prcmu", 0x80157000, "db8500-prcmu", NULL),
        {},
@@ -167,7 +135,7 @@ static void __init u8500_init_machine(void)
                                     u8540_auxdata_lookup, NULL);
        else
                of_platform_populate(NULL, u8500_local_bus_nodes,
-                                    u8500_auxdata_lookup, NULL);
+                                    NULL, NULL);
 }
 
 static const char * stericsson_dt_platform_compat[] = {
index d443e48..8805a59 100644 (file)
@@ -888,11 +888,8 @@ static int omap_dm_timer_probe(struct platform_device *pdev)
        timer->irq = irq->start;
        timer->pdev = pdev;
 
-       /* Skip pm_runtime_enable for OMAP1 */
-       if (!(timer->capability & OMAP_TIMER_NEEDS_RESET)) {
-               pm_runtime_enable(dev);
-               pm_runtime_irq_safe(dev);
-       }
+       pm_runtime_enable(dev);
+       pm_runtime_irq_safe(dev);
 
        if (!timer->reserved) {
                ret = pm_runtime_get_sync(dev);
index fb061cf..30a0773 100644 (file)
@@ -5,13 +5,4 @@ void omap_map_sram(unsigned long start, unsigned long size,
                        unsigned long skip, int cached);
 void omap_sram_reset(void);
 
-extern void *omap_sram_push_address(unsigned long size);
-
-/* Macro to push a function to the internal SRAM, using the fncpy API */
-#define omap_sram_push(funcp, size) ({                         \
-       typeof(&(funcp)) _res = NULL;                           \
-       void *_sram_address = omap_sram_push_address(size);     \
-       if (_sram_address)                                      \
-               _res = fncpy(_sram_address, &(funcp), size);    \
-       _res;                                                   \
-})
+extern void *omap_sram_push(void *funcp, unsigned long size);
index a5bc92d..921840a 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/fncpy.h>
 #include <asm/tlb.h>
 #include <asm/cacheflush.h>
+#include <asm/set_memory.h>
 
 #include <asm/mach/map.h>
 
@@ -42,7 +43,7 @@ static void __iomem *omap_sram_ceil;
  * Note that fncpy requires the returned address to be aligned
  * to an 8-byte boundary.
  */
-void *omap_sram_push_address(unsigned long size)
+static void *omap_sram_push_address(unsigned long size)
 {
        unsigned long available, new_ceil = (unsigned long)omap_sram_ceil;
 
@@ -60,6 +61,30 @@ void *omap_sram_push_address(unsigned long size)
        return (void *)omap_sram_ceil;
 }
 
+void *omap_sram_push(void *funcp, unsigned long size)
+{
+       void *sram;
+       unsigned long base;
+       int pages;
+       void *dst = NULL;
+
+       sram = omap_sram_push_address(size);
+       if (!sram)
+               return NULL;
+
+       base = (unsigned long)sram & PAGE_MASK;
+       pages = PAGE_ALIGN(size) / PAGE_SIZE;
+
+       set_memory_rw(base, pages);
+
+       dst = fncpy(sram, funcp, size);
+
+       set_memory_ro(base, pages);
+       set_memory_x(base, pages);
+
+       return dst;
+}
+
 /*
  * The SRAM context is lost during off-idle and stack
  * needs to be reset.
@@ -75,6 +100,9 @@ void omap_sram_reset(void)
 void __init omap_map_sram(unsigned long start, unsigned long size,
                                 unsigned long skip, int cached)
 {
+       unsigned long base;
+       int pages;
+
        if (size == 0)
                return;
 
@@ -95,4 +123,10 @@ void __init omap_map_sram(unsigned long start, unsigned long size,
         */
        memset_io(omap_sram_base + omap_sram_skip, 0,
                  omap_sram_size - omap_sram_skip);
+
+       base = (unsigned long)omap_sram_base;
+       pages = PAGE_ALIGN(omap_sram_size) / PAGE_SIZE;
+
+       set_memory_ro(base, pages);
+       set_memory_x(base, pages);
 }
index aff6994..a2399fd 100644 (file)
@@ -472,28 +472,27 @@ void __init orion_ge11_init(struct mv643xx_eth_platform_data *eth_data,
 /*****************************************************************************
  * Ethernet switch
  ****************************************************************************/
-static __initconst const char *orion_ge00_mvmdio_bus_name = "orion-mii";
-static __initdata struct mdio_board_info
-                 orion_ge00_switch_board_info;
+static __initdata struct mdio_board_info orion_ge00_switch_board_info = {
+       .bus_id   = "orion-mii",
+       .modalias = "mv88e6085",
+};
 
 void __init orion_ge00_switch_init(struct dsa_chip_data *d)
 {
-       struct mdio_board_info *bd;
        unsigned int i;
 
        if (!IS_BUILTIN(CONFIG_PHYLIB))
                return;
 
-       for (i = 0; i < ARRAY_SIZE(d->port_names); i++)
-               if (!strcmp(d->port_names[i], "cpu"))
+       for (i = 0; i < ARRAY_SIZE(d->port_names); i++) {
+               if (!strcmp(d->port_names[i], "cpu")) {
+                       d->netdev[i] = &orion_ge00.dev;
                        break;
+               }
+       }
 
-       bd = &orion_ge00_switch_board_info;
-       bd->bus_id = orion_ge00_mvmdio_bus_name;
-       bd->mdio_addr = d->sw_addr;
-       d->netdev[i] = &orion_ge00.dev;
-       strcpy(bd->modalias, "mv88e6085");
-       bd->platform_data = d;
+       orion_ge00_switch_board_info.mdio_addr = d->sw_addr;
+       orion_ge00_switch_board_info.platform_data = d;
 
        mdiobus_register_board_info(&orion_ge00_switch_board_info, 1);
 }
index 03c6a3c..4c375e1 100644 (file)
@@ -648,7 +648,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
  */
 static int vfp_dying_cpu(unsigned int cpu)
 {
-       vfp_force_reload(cpu, current_thread_info());
+       vfp_current_hw_state[cpu] = NULL;
        return 0;
 }
 
index a806326..70c776e 100644 (file)
 
                        uart_A: serial@24000 {
                                compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart";
-                               reg = <0x0 0x24000 0x0 0x14>;
+                               reg = <0x0 0x24000 0x0 0x18>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_B: serial@23000 {
                                compatible = "amlogic,meson-gx-uart", "amlogic,meson-uart";
-                               reg = <0x0 0x23000 0x0 0x14>;
+                               reg = <0x0 0x23000 0x0 0x18>;
                                interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
index 6cb3c2a..4ee2e79 100644 (file)
 
                        uart_A: serial@84c0 {
                                compatible = "amlogic,meson-gx-uart";
-                               reg = <0x0 0x84c0 0x0 0x14>;
+                               reg = <0x0 0x84c0 0x0 0x18>;
                                interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_B: serial@84dc {
                                compatible = "amlogic,meson-gx-uart";
-                               reg = <0x0 0x84dc 0x0 0x14>;
+                               reg = <0x0 0x84dc 0x0 0x18>;
                                interrupts = <GIC_SPI 75 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_C: serial@8700 {
                                compatible = "amlogic,meson-gx-uart";
-                               reg = <0x0 0x8700 0x0 0x14>;
+                               reg = <0x0 0x8700 0x0 0x18>;
                                interrupts = <GIC_SPI 93 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_AO: serial@4c0 {
                                compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart";
-                               reg = <0x0 0x004c0 0x0 0x14>;
+                               reg = <0x0 0x004c0 0x0 0x18>;
                                interrupts = <GIC_SPI 193 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
 
                        uart_AO_B: serial@4e0 {
                                compatible = "amlogic,meson-gx-uart", "amlogic,meson-ao-uart";
-                               reg = <0x0 0x004e0 0x0 0x14>;
+                               reg = <0x0 0x004e0 0x0 0x18>;
                                interrupts = <GIC_SPI 197 IRQ_TYPE_EDGE_RISING>;
                                status = "disabled";
                        };
index 4f355f1..c851411 100644 (file)
 
                        internal_phy: ethernet-phy@8 {
                                compatible = "ethernet-phy-id0181.4400", "ethernet-phy-ieee802.3-c22";
+                               interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
                                reg = <8>;
                                max-speed = <100>;
                        };
index 4220fbd..ff5c4c4 100644 (file)
@@ -98,7 +98,7 @@
                clock-output-names = "clk125mhz";
        };
 
-       pci {
+       pcie@30000000 {
                compatible = "pci-host-ecam-generic";
                device_type = "pci";
                #interrupt-cells = <1>;
                ranges =
                  <0x02000000    0 0x40000000    0 0x40000000    0 0x20000000
                   0x43000000 0x40 0x00000000 0x40 0x00000000 0x20 0x00000000>;
+               bus-range = <0 0xff>;
                interrupt-map-mask = <0 0 0 7>;
                interrupt-map =
                      /* addr  pin  ic   icaddr  icintr */
index e94fa1a..047641f 100644 (file)
@@ -51,7 +51,7 @@
                #size-cells = <2>;
                ranges;
 
-               ramoops@0x21f00000 {
+               ramoops@21f00000 {
                        compatible = "ramoops";
                        reg = <0x0 0x21f00000 0x0 0x00100000>;
                        record-size     = <0x00020000>;
index 9fbe470..94597e3 100644 (file)
                        reg = <0 0x10005000 0 0x1000>;
                };
 
-               pio: pinctrl@0x10005000 {
+               pio: pinctrl@10005000 {
                        compatible = "mediatek,mt8173-pinctrl";
                        reg = <0 0x1000b000 0 0x1000>;
                        mediatek,pctl-regmap = <&syscfg_pctl_a>;
index 492a011..1c8f1b8 100644 (file)
                };
 
                agnoc@0 {
-                       qcom,pcie@00600000 {
+                       qcom,pcie@600000 {
                                perst-gpio = <&msmgpio 35 GPIO_ACTIVE_LOW>;
                        };
 
-                       qcom,pcie@00608000 {
+                       qcom,pcie@608000 {
                                status = "okay";
                                perst-gpio = <&msmgpio 130 GPIO_ACTIVE_LOW>;
                        };
 
-                       qcom,pcie@00610000 {
+                       qcom,pcie@610000 {
                                status = "okay";
                                perst-gpio = <&msmgpio 114 GPIO_ACTIVE_LOW>;
                        };
index 4b2afcc..0a6f795 100644 (file)
                        #size-cells = <1>;
                        ranges;
 
-                       pcie0: qcom,pcie@00600000 {
+                       pcie0: qcom,pcie@600000 {
                                compatible = "qcom,pcie-msm8996", "snps,dw-pcie";
                                status = "disabled";
                                power-domains = <&gcc PCIE0_GDSC>;
 
                        };
 
-                       pcie1: qcom,pcie@00608000 {
+                       pcie1: qcom,pcie@608000 {
                                compatible = "qcom,pcie-msm8996", "snps,dw-pcie";
                                power-domains = <&gcc PCIE1_GDSC>;
                                bus-range = <0x00 0xff>;
                                                "bus_slave";
                        };
 
-                       pcie2: qcom,pcie@00610000 {
+                       pcie2: qcom,pcie@610000 {
                                compatible = "qcom,pcie-msm8996", "snps,dw-pcie";
                                power-domains = <&gcc PCIE2_GDSC>;
                                bus-range = <0x00 0xff>;
index 3890468..2825772 100644 (file)
        assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
        assigned-clock-parents = <&gmac_clkin>, <&gmac_clkin>;
        clock_in_out = "input";
-       /* shows instability at 1GBit right now */
-       max-speed = <100>;
        phy-supply = <&vcc_io>;
        phy-mode = "rgmii";
        pinctrl-names = "default";
        pinctrl-0 = <&rgmiim1_pins>;
+       snps,force_thresh_dma_mode;
        snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
        snps,reset-active-low;
        snps,reset-delays-us = <0 10000 50000>;
-       tx_delay = <0x26>;
-       rx_delay = <0x11>;
+       tx_delay = <0x24>;
+       rx_delay = <0x18>;
        status = "okay";
 };
 
index a037ee5..cae3415 100644 (file)
                interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
                         <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                status = "disabled";
        };
                interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>,
                         <&cru SCLK_SDIO_DRV>, <&cru SCLK_SDIO_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                status = "disabled";
        };
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
                clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
                         <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                status = "disabled";
        };
index aa4d070..03458ac 100644 (file)
                max-frequency = <150000000>;
                clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>,
                         <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>;
-               clock-names = "biu", "ciu", "ciu_drv", "ciu_sample";
+               clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
                fifo-depth = <0x100>;
                interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
                resets = <&cru SRST_SDIO0>;
index 03f1950..204bdb9 100644 (file)
        wlan_pd_n: wlan-pd-n {
                compatible = "regulator-fixed";
                regulator-name = "wlan_pd_n";
+               pinctrl-names = "default";
+               pinctrl-0 = <&wlan_module_reset_l>;
 
-               /* Note the wlan_module_reset_l pinctrl */
                enable-active-high;
                gpio = <&gpio1 11 GPIO_ACTIVE_HIGH>;
 
@@ -983,12 +984,6 @@ ap_i2c_audio: &i2c8 {
        pinctrl-0 = <
                &ap_pwroff      /* AP will auto-assert this when in S3 */
                &clk_32k        /* This pin is always 32k on gru boards */
-
-               /*
-                * We want this driven low ASAP; firmware should help us, but
-                * we can help ourselves too.
-                */
-               &wlan_module_reset_l
        >;
 
        pcfg_output_low: pcfg-output-low {
@@ -1168,12 +1163,7 @@ ap_i2c_audio: &i2c8 {
                };
 
                wlan_module_reset_l: wlan-module-reset-l {
-                       /*
-                        * We want this driven low ASAP (As {Soon,Strongly} As
-                        * Possible), to avoid leakage through the powered-down
-                        * WiFi.
-                        */
-                       rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_output_low>;
+                       rockchip,pins = <1 11 RK_FUNC_GPIO &pcfg_pull_none>;
                };
 
                bt_host_wake_l: bt-host-wake-l {
index 0f873c8..ce592a4 100644 (file)
        assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
        assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
        assigned-clock-rates = <100000000>;
-       ep-gpios = <&gpio3 RK_PB5 GPIO_ACTIVE_HIGH>;
+       ep-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
        num-lanes = <4>;
        pinctrl-names = "default";
        pinctrl-0 = <&pcie_clkreqn_cpm>;
index 7aa2144..0b81ca1 100644 (file)
                        reg = <0x0 0xfe800000 0x0 0x100000>;
                        interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
                        dr_mode = "otg";
-                       phys = <&u2phy0_otg>, <&tcphy0_usb3>;
-                       phy-names = "usb2-phy", "usb3-phy";
+                       phys = <&u2phy0_otg>;
+                       phy-names = "usb2-phy";
                        phy_type = "utmi_wide";
                        snps,dis_enblslpm_quirk;
                        snps,dis-u2-freeclk-exists-quirk;
                        reg = <0x0 0xfe900000 0x0 0x100000>;
                        interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
                        dr_mode = "otg";
-                       phys = <&u2phy1_otg>, <&tcphy1_usb3>;
-                       phy-names = "usb2-phy", "usb3-phy";
+                       phys = <&u2phy1_otg>;
+                       phy-names = "usb2-phy";
                        phy_type = "utmi_wide";
                        snps,dis_enblslpm_quirk;
                        snps,dis-u2-freeclk-exists-quirk;
                compatible = "rockchip,rk3399-edp";
                reg = <0x0 0xff970000 0x0 0x8000>;
                interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH 0>;
-               clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>;
-               clock-names = "dp", "pclk";
+               clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>, <&cru PCLK_VIO_GRF>;
+               clock-names = "dp", "pclk", "grf";
                pinctrl-names = "default";
                pinctrl-0 = <&edp_hpd>;
                power-domains = <&power RK3399_PD_EDP>;
index be7bd19..350c76a 100644 (file)
@@ -20,7 +20,7 @@
 
 #define MPIDR_UP_BITMASK       (0x1 << 30)
 #define MPIDR_MT_BITMASK       (0x1 << 24)
-#define MPIDR_HWID_BITMASK     0xff00ffffff
+#define MPIDR_HWID_BITMASK     UL(0xff00ffffff)
 
 #define MPIDR_LEVEL_BITS_SHIFT 3
 #define MPIDR_LEVEL_BITS       (1 << MPIDR_LEVEL_BITS_SHIFT)
index 1dca41b..e73f685 100644 (file)
@@ -22,7 +22,7 @@
 
 static inline pte_t huge_ptep_get(pte_t *ptep)
 {
-       return *ptep;
+       return READ_ONCE(*ptep);
 }
 
 
index 9679067..7faed6e 100644 (file)
@@ -185,42 +185,42 @@ static inline pmd_t kvm_s2pmd_mkexec(pmd_t pmd)
        return pmd;
 }
 
-static inline void kvm_set_s2pte_readonly(pte_t *pte)
+static inline void kvm_set_s2pte_readonly(pte_t *ptep)
 {
        pteval_t old_pteval, pteval;
 
-       pteval = READ_ONCE(pte_val(*pte));
+       pteval = READ_ONCE(pte_val(*ptep));
        do {
                old_pteval = pteval;
                pteval &= ~PTE_S2_RDWR;
                pteval |= PTE_S2_RDONLY;
-               pteval = cmpxchg_relaxed(&pte_val(*pte), old_pteval, pteval);
+               pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval, pteval);
        } while (pteval != old_pteval);
 }
 
-static inline bool kvm_s2pte_readonly(pte_t *pte)
+static inline bool kvm_s2pte_readonly(pte_t *ptep)
 {
-       return (pte_val(*pte) & PTE_S2_RDWR) == PTE_S2_RDONLY;
+       return (READ_ONCE(pte_val(*ptep)) & PTE_S2_RDWR) == PTE_S2_RDONLY;
 }
 
-static inline bool kvm_s2pte_exec(pte_t *pte)
+static inline bool kvm_s2pte_exec(pte_t *ptep)
 {
-       return !(pte_val(*pte) & PTE_S2_XN);
+       return !(READ_ONCE(pte_val(*ptep)) & PTE_S2_XN);
 }
 
-static inline void kvm_set_s2pmd_readonly(pmd_t *pmd)
+static inline void kvm_set_s2pmd_readonly(pmd_t *pmdp)
 {
-       kvm_set_s2pte_readonly((pte_t *)pmd);
+       kvm_set_s2pte_readonly((pte_t *)pmdp);
 }
 
-static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
+static inline bool kvm_s2pmd_readonly(pmd_t *pmdp)
 {
-       return kvm_s2pte_readonly((pte_t *)pmd);
+       return kvm_s2pte_readonly((pte_t *)pmdp);
 }
 
-static inline bool kvm_s2pmd_exec(pmd_t *pmd)
+static inline bool kvm_s2pmd_exec(pmd_t *pmdp)
 {
-       return !(pmd_val(*pmd) & PMD_S2_XN);
+       return !(READ_ONCE(pmd_val(*pmdp)) & PMD_S2_XN);
 }
 
 static inline bool kvm_page_empty(void *ptr)
index 8d33319..39ec0b8 100644 (file)
@@ -141,13 +141,13 @@ static inline void cpu_install_idmap(void)
  * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD,
  * avoiding the possibility of conflicting TLB entries being allocated.
  */
-static inline void cpu_replace_ttbr1(pgd_t *pgd)
+static inline void cpu_replace_ttbr1(pgd_t *pgdp)
 {
        typedef void (ttbr_replace_func)(phys_addr_t);
        extern ttbr_replace_func idmap_cpu_replace_ttbr1;
        ttbr_replace_func *replace_phys;
 
-       phys_addr_t pgd_phys = virt_to_phys(pgd);
+       phys_addr_t pgd_phys = virt_to_phys(pgdp);
 
        replace_phys = (void *)__pa_symbol(idmap_cpu_replace_ttbr1);
 
index e9d9f1b..2e05bcd 100644 (file)
@@ -36,23 +36,23 @@ static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
        return (pmd_t *)__get_free_page(PGALLOC_GFP);
 }
 
-static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp)
 {
-       BUG_ON((unsigned long)pmd & (PAGE_SIZE-1));
-       free_page((unsigned long)pmd);
+       BUG_ON((unsigned long)pmdp & (PAGE_SIZE-1));
+       free_page((unsigned long)pmdp);
 }
 
-static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot)
+static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
 {
-       set_pud(pud, __pud(__phys_to_pud_val(pmd) | prot));
+       set_pud(pudp, __pud(__phys_to_pud_val(pmdp) | prot));
 }
 
-static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
 {
-       __pud_populate(pud, __pa(pmd), PMD_TYPE_TABLE);
+       __pud_populate(pudp, __pa(pmdp), PMD_TYPE_TABLE);
 }
 #else
-static inline void __pud_populate(pud_t *pud, phys_addr_t pmd, pudval_t prot)
+static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
 {
        BUILD_BUG();
 }
@@ -65,30 +65,30 @@ static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
        return (pud_t *)__get_free_page(PGALLOC_GFP);
 }
 
-static inline void pud_free(struct mm_struct *mm, pud_t *pud)
+static inline void pud_free(struct mm_struct *mm, pud_t *pudp)
 {
-       BUG_ON((unsigned long)pud & (PAGE_SIZE-1));
-       free_page((unsigned long)pud);
+       BUG_ON((unsigned long)pudp & (PAGE_SIZE-1));
+       free_page((unsigned long)pudp);
 }
 
-static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot)
+static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot)
 {
-       set_pgd(pgdp, __pgd(__phys_to_pgd_val(pud) | prot));
+       set_pgd(pgdp, __pgd(__phys_to_pgd_val(pudp) | prot));
 }
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, pud_t *pudp)
 {
-       __pgd_populate(pgd, __pa(pud), PUD_TYPE_TABLE);
+       __pgd_populate(pgdp, __pa(pudp), PUD_TYPE_TABLE);
 }
 #else
-static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pud, pgdval_t prot)
+static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot)
 {
        BUILD_BUG();
 }
 #endif /* CONFIG_PGTABLE_LEVELS > 3 */
 
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
-extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgdp);
 
 static inline pte_t *
 pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
@@ -114,10 +114,10 @@ pte_alloc_one(struct mm_struct *mm, unsigned long addr)
 /*
  * Free a PTE table.
  */
-static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *ptep)
 {
-       if (pte)
-               free_page((unsigned long)pte);
+       if (ptep)
+               free_page((unsigned long)ptep);
 }
 
 static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
@@ -126,10 +126,10 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pte)
        __free_page(pte);
 }
 
-static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t pte,
+static inline void __pmd_populate(pmd_t *pmdp, phys_addr_t ptep,
                                  pmdval_t prot)
 {
-       set_pmd(pmdp, __pmd(__phys_to_pmd_val(pte) | prot));
+       set_pmd(pmdp, __pmd(__phys_to_pmd_val(ptep) | prot));
 }
 
 /*
index 094374c..7e2c27e 100644 (file)
@@ -218,7 +218,7 @@ static inline pmd_t pmd_mkcont(pmd_t pmd)
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
-       *ptep = pte;
+       WRITE_ONCE(*ptep, pte);
 
        /*
         * Only if the new pte is valid and kernel, otherwise TLB maintenance
@@ -250,6 +250,8 @@ extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pte)
 {
+       pte_t old_pte;
+
        if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
                __sync_icache_dcache(pte, addr);
 
@@ -258,14 +260,15 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
         * hardware updates of the pte (ptep_set_access_flags safely changes
         * valid ptes without going through an invalid entry).
         */
-       if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(*ptep) && pte_valid(pte) &&
+       old_pte = READ_ONCE(*ptep);
+       if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(old_pte) && pte_valid(pte) &&
           (mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) {
                VM_WARN_ONCE(!pte_young(pte),
                             "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
-                            __func__, pte_val(*ptep), pte_val(pte));
-               VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte),
+                            __func__, pte_val(old_pte), pte_val(pte));
+               VM_WARN_ONCE(pte_write(old_pte) && !pte_dirty(pte),
                             "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
-                            __func__, pte_val(*ptep), pte_val(pte));
+                            __func__, pte_val(old_pte), pte_val(pte));
        }
 
        set_pte(ptep, pte);
@@ -431,7 +434,7 @@ extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
-       *pmdp = pmd;
+       WRITE_ONCE(*pmdp, pmd);
        dsb(ishst);
        isb();
 }
@@ -482,7 +485,7 @@ static inline phys_addr_t pmd_page_paddr(pmd_t pmd)
 
 static inline void set_pud(pud_t *pudp, pud_t pud)
 {
-       *pudp = pud;
+       WRITE_ONCE(*pudp, pud);
        dsb(ishst);
        isb();
 }
@@ -500,7 +503,7 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
 /* Find an entry in the second-level page table. */
 #define pmd_index(addr)                (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
 
-#define pmd_offset_phys(dir, addr)     (pud_page_paddr(*(dir)) + pmd_index(addr) * sizeof(pmd_t))
+#define pmd_offset_phys(dir, addr)     (pud_page_paddr(READ_ONCE(*(dir))) + pmd_index(addr) * sizeof(pmd_t))
 #define pmd_offset(dir, addr)          ((pmd_t *)__va(pmd_offset_phys((dir), (addr))))
 
 #define pmd_set_fixmap(addr)           ((pmd_t *)set_fixmap_offset(FIX_PMD, addr))
@@ -535,7 +538,7 @@ static inline phys_addr_t pud_page_paddr(pud_t pud)
 
 static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
 {
-       *pgdp = pgd;
+       WRITE_ONCE(*pgdp, pgd);
        dsb(ishst);
 }
 
@@ -552,7 +555,7 @@ static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
 /* Find an entry in the frst-level page table. */
 #define pud_index(addr)                (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
 
-#define pud_offset_phys(dir, addr)     (pgd_page_paddr(*(dir)) + pud_index(addr) * sizeof(pud_t))
+#define pud_offset_phys(dir, addr)     (pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
 #define pud_offset(dir, addr)          ((pud_t *)__va(pud_offset_phys((dir), (addr))))
 
 #define pud_set_fixmap(addr)           ((pud_t *)set_fixmap_offset(FIX_PUD, addr))
index 472ef94..902f9ed 100644 (file)
@@ -28,7 +28,7 @@ struct stackframe {
        unsigned long fp;
        unsigned long pc;
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       unsigned int graph;
+       int graph;
 #endif
 };
 
index 543e11f..e66b0fc 100644 (file)
@@ -72,15 +72,15 @@ static inline void set_fs(mm_segment_t fs)
  * This is equivalent to the following test:
  * (u65)addr + (u65)size <= (u65)current->addr_limit + 1
  */
-static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
+static inline unsigned long __range_ok(const void __user *addr, unsigned long size)
 {
-       unsigned long limit = current_thread_info()->addr_limit;
+       unsigned long ret, limit = current_thread_info()->addr_limit;
 
        __chk_user_ptr(addr);
        asm volatile(
        // A + B <= C + 1 for all A,B,C, in four easy steps:
        // 1: X = A + B; X' = X % 2^64
-       "       adds    %0, %0, %2\n"
+       "       adds    %0, %3, %2\n"
        // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4
        "       csel    %1, xzr, %1, hi\n"
        // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X'
@@ -92,9 +92,9 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
        //    testing X' - C == 0, subject to the previous adjustments.
        "       sbcs    xzr, %0, %1\n"
        "       cset    %0, ls\n"
-       : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc");
+       : "=&r" (ret), "+r" (limit) : "Ir" (size), "0" (addr) : "cc");
 
-       return addr;
+       return ret;
 }
 
 /*
@@ -104,7 +104,7 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size)
  */
 #define untagged_addr(addr)            sign_extend64(addr, 55)
 
-#define access_ok(type, addr, size)    __range_ok((unsigned long)(addr), size)
+#define access_ok(type, addr, size)    __range_ok(addr, size)
 #define user_addr_max                  get_fs
 
 #define _ASM_EXTABLE(from, to)                                         \
index c33b5e4..68450e9 100644 (file)
@@ -370,6 +370,7 @@ static unsigned int __kprobes aarch32_check_condition(u32 opcode, u32 psr)
 static int swp_handler(struct pt_regs *regs, u32 instr)
 {
        u32 destreg, data, type, address = 0;
+       const void __user *user_ptr;
        int rn, rt2, res = 0;
 
        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
@@ -401,7 +402,8 @@ static int swp_handler(struct pt_regs *regs, u32 instr)
                aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
 
        /* Check access in reasonable access range for both SWP and SWPB */
-       if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
+       user_ptr = (const void __user *)(unsigned long)(address & ~3);
+       if (!access_ok(VERIFY_WRITE, user_ptr, 4)) {
                pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
                        address);
                goto fault;
index 0782359..b5a2833 100644 (file)
@@ -178,7 +178,7 @@ static int enable_smccc_arch_workaround_1(void *data)
        case PSCI_CONDUIT_HVC:
                arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
                                  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
-               if (res.a0)
+               if ((int)res.a0 < 0)
                        return 0;
                cb = call_hvc_arch_workaround_1;
                smccc_start = __smccc_workaround_1_hvc_start;
@@ -188,7 +188,7 @@ static int enable_smccc_arch_workaround_1(void *data)
        case PSCI_CONDUIT_SMC:
                arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
                                  ARM_SMCCC_ARCH_WORKAROUND_1, &res);
-               if (res.a0)
+               if ((int)res.a0 < 0)
                        return 0;
                cb = call_smc_arch_workaround_1;
                smccc_start = __smccc_workaround_1_smc_start;
@@ -408,6 +408,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
        },
        {
                .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
+               MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
+               .enable = qcom_enable_link_stack_sanitization,
+       },
+       {
+               .capability = ARM64_HARDEN_BP_POST_GUEST_EXIT,
+               MIDR_ALL_VERSIONS(MIDR_QCOM_FALKOR),
+       },
+       {
+               .capability = ARM64_HARDEN_BRANCH_PREDICTOR,
                MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN),
                .enable = enable_smccc_arch_workaround_1,
        },
index 29b1f87..2985a06 100644 (file)
@@ -199,9 +199,11 @@ static const struct arm64_ftr_bits ftr_id_aa64mmfr2[] = {
 };
 
 static const struct arm64_ftr_bits ftr_ctr[] = {
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1),   /* RAO */
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_EXACT, 31, 1, 1),           /* RES1 */
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 29, 1, 1),      /* DIC */
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 28, 1, 1),      /* IDC */
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0),     /* CWG */
-       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0),      /* ERG */
+       ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_HIGHER_SAFE, 20, 4, 0),     /* ERG */
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1),      /* DminLine */
        /*
         * Linux can handle differing I-cache policies. Userspace JITs will
index f85ac58..a8bf1c8 100644 (file)
@@ -90,7 +90,7 @@ static int __init set_permissions(pte_t *ptep, pgtable_t token,
                                  unsigned long addr, void *data)
 {
        efi_memory_desc_t *md = data;
-       pte_t pte = *ptep;
+       pte_t pte = READ_ONCE(*ptep);
 
        if (md->attribute & EFI_MEMORY_RO)
                pte = set_pte_bit(pte, __pgprot(PTE_RDONLY));
index f20cf7e..1ec5f28 100644 (file)
@@ -202,10 +202,10 @@ static int create_safe_exec_page(void *src_start, size_t length,
                                 gfp_t mask)
 {
        int rc = 0;
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
+       pte_t *ptep;
        unsigned long dst = (unsigned long)allocator(mask);
 
        if (!dst) {
@@ -216,38 +216,38 @@ static int create_safe_exec_page(void *src_start, size_t length,
        memcpy((void *)dst, src_start, length);
        flush_icache_range(dst, dst + length);
 
-       pgd = pgd_offset_raw(allocator(mask), dst_addr);
-       if (pgd_none(*pgd)) {
-               pud = allocator(mask);
-               if (!pud) {
+       pgdp = pgd_offset_raw(allocator(mask), dst_addr);
+       if (pgd_none(READ_ONCE(*pgdp))) {
+               pudp = allocator(mask);
+               if (!pudp) {
                        rc = -ENOMEM;
                        goto out;
                }
-               pgd_populate(&init_mm, pgd, pud);
+               pgd_populate(&init_mm, pgdp, pudp);
        }
 
-       pud = pud_offset(pgd, dst_addr);
-       if (pud_none(*pud)) {
-               pmd = allocator(mask);
-               if (!pmd) {
+       pudp = pud_offset(pgdp, dst_addr);
+       if (pud_none(READ_ONCE(*pudp))) {
+               pmdp = allocator(mask);
+               if (!pmdp) {
                        rc = -ENOMEM;
                        goto out;
                }
-               pud_populate(&init_mm, pud, pmd);
+               pud_populate(&init_mm, pudp, pmdp);
        }
 
-       pmd = pmd_offset(pud, dst_addr);
-       if (pmd_none(*pmd)) {
-               pte = allocator(mask);
-               if (!pte) {
+       pmdp = pmd_offset(pudp, dst_addr);
+       if (pmd_none(READ_ONCE(*pmdp))) {
+               ptep = allocator(mask);
+               if (!ptep) {
                        rc = -ENOMEM;
                        goto out;
                }
-               pmd_populate_kernel(&init_mm, pmd, pte);
+               pmd_populate_kernel(&init_mm, pmdp, ptep);
        }
 
-       pte = pte_offset_kernel(pmd, dst_addr);
-       set_pte(pte, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC));
+       ptep = pte_offset_kernel(pmdp, dst_addr);
+       set_pte(ptep, pfn_pte(virt_to_pfn(dst), PAGE_KERNEL_EXEC));
 
        /*
         * Load our new page tables. A strict BBM approach requires that we
@@ -263,7 +263,7 @@ static int create_safe_exec_page(void *src_start, size_t length,
         */
        cpu_set_reserved_ttbr0();
        local_flush_tlb_all();
-       write_sysreg(phys_to_ttbr(virt_to_phys(pgd)), ttbr0_el1);
+       write_sysreg(phys_to_ttbr(virt_to_phys(pgdp)), ttbr0_el1);
        isb();
 
        *phys_dst_addr = virt_to_phys((void *)dst);
@@ -320,9 +320,9 @@ int swsusp_arch_suspend(void)
        return ret;
 }
 
-static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr)
+static void _copy_pte(pte_t *dst_ptep, pte_t *src_ptep, unsigned long addr)
 {
-       pte_t pte = *src_pte;
+       pte_t pte = READ_ONCE(*src_ptep);
 
        if (pte_valid(pte)) {
                /*
@@ -330,7 +330,7 @@ static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr)
                 * read only (code, rodata). Clear the RDONLY bit from
                 * the temporary mappings we use during restore.
                 */
-               set_pte(dst_pte, pte_mkwrite(pte));
+               set_pte(dst_ptep, pte_mkwrite(pte));
        } else if (debug_pagealloc_enabled() && !pte_none(pte)) {
                /*
                 * debug_pagealloc will removed the PTE_VALID bit if
@@ -343,112 +343,116 @@ static void _copy_pte(pte_t *dst_pte, pte_t *src_pte, unsigned long addr)
                 */
                BUG_ON(!pfn_valid(pte_pfn(pte)));
 
-               set_pte(dst_pte, pte_mkpresent(pte_mkwrite(pte)));
+               set_pte(dst_ptep, pte_mkpresent(pte_mkwrite(pte)));
        }
 }
 
-static int copy_pte(pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long start,
+static int copy_pte(pmd_t *dst_pmdp, pmd_t *src_pmdp, unsigned long start,
                    unsigned long end)
 {
-       pte_t *src_pte;
-       pte_t *dst_pte;
+       pte_t *src_ptep;
+       pte_t *dst_ptep;
        unsigned long addr = start;
 
-       dst_pte = (pte_t *)get_safe_page(GFP_ATOMIC);
-       if (!dst_pte)
+       dst_ptep = (pte_t *)get_safe_page(GFP_ATOMIC);
+       if (!dst_ptep)
                return -ENOMEM;
-       pmd_populate_kernel(&init_mm, dst_pmd, dst_pte);
-       dst_pte = pte_offset_kernel(dst_pmd, start);
+       pmd_populate_kernel(&init_mm, dst_pmdp, dst_ptep);
+       dst_ptep = pte_offset_kernel(dst_pmdp, start);
 
-       src_pte = pte_offset_kernel(src_pmd, start);
+       src_ptep = pte_offset_kernel(src_pmdp, start);
        do {
-               _copy_pte(dst_pte, src_pte, addr);
-       } while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
+               _copy_pte(dst_ptep, src_ptep, addr);
+       } while (dst_ptep++, src_ptep++, addr += PAGE_SIZE, addr != end);
 
        return 0;
 }
 
-static int copy_pmd(pud_t *dst_pud, pud_t *src_pud, unsigned long start,
+static int copy_pmd(pud_t *dst_pudp, pud_t *src_pudp, unsigned long start,
                    unsigned long end)
 {
-       pmd_t *src_pmd;
-       pmd_t *dst_pmd;
+       pmd_t *src_pmdp;
+       pmd_t *dst_pmdp;
        unsigned long next;
        unsigned long addr = start;
 
-       if (pud_none(*dst_pud)) {
-               dst_pmd = (pmd_t *)get_safe_page(GFP_ATOMIC);
-               if (!dst_pmd)
+       if (pud_none(READ_ONCE(*dst_pudp))) {
+               dst_pmdp = (pmd_t *)get_safe_page(GFP_ATOMIC);
+               if (!dst_pmdp)
                        return -ENOMEM;
-               pud_populate(&init_mm, dst_pud, dst_pmd);
+               pud_populate(&init_mm, dst_pudp, dst_pmdp);
        }
-       dst_pmd = pmd_offset(dst_pud, start);
+       dst_pmdp = pmd_offset(dst_pudp, start);
 
-       src_pmd = pmd_offset(src_pud, start);
+       src_pmdp = pmd_offset(src_pudp, start);
        do {
+               pmd_t pmd = READ_ONCE(*src_pmdp);
+
                next = pmd_addr_end(addr, end);
-               if (pmd_none(*src_pmd))
+               if (pmd_none(pmd))
                        continue;
-               if (pmd_table(*src_pmd)) {
-                       if (copy_pte(dst_pmd, src_pmd, addr, next))
+               if (pmd_table(pmd)) {
+                       if (copy_pte(dst_pmdp, src_pmdp, addr, next))
                                return -ENOMEM;
                } else {
-                       set_pmd(dst_pmd,
-                               __pmd(pmd_val(*src_pmd) & ~PMD_SECT_RDONLY));
+                       set_pmd(dst_pmdp,
+                               __pmd(pmd_val(pmd) & ~PMD_SECT_RDONLY));
                }
-       } while (dst_pmd++, src_pmd++, addr = next, addr != end);
+       } while (dst_pmdp++, src_pmdp++, addr = next, addr != end);
 
        return 0;
 }
 
-static int copy_pud(pgd_t *dst_pgd, pgd_t *src_pgd, unsigned long start,
+static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
                    unsigned long end)
 {
-       pud_t *dst_pud;
-       pud_t *src_pud;
+       pud_t *dst_pudp;
+       pud_t *src_pudp;
        unsigned long next;
        unsigned long addr = start;
 
-       if (pgd_none(*dst_pgd)) {
-               dst_pud = (pud_t *)get_safe_page(GFP_ATOMIC);
-               if (!dst_pud)
+       if (pgd_none(READ_ONCE(*dst_pgdp))) {
+               dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC);
+               if (!dst_pudp)
                        return -ENOMEM;
-               pgd_populate(&init_mm, dst_pgd, dst_pud);
+               pgd_populate(&init_mm, dst_pgdp, dst_pudp);
        }
-       dst_pud = pud_offset(dst_pgd, start);
+       dst_pudp = pud_offset(dst_pgdp, start);
 
-       src_pud = pud_offset(src_pgd, start);
+       src_pudp = pud_offset(src_pgdp, start);
        do {
+               pud_t pud = READ_ONCE(*src_pudp);
+
                next = pud_addr_end(addr, end);
-               if (pud_none(*src_pud))
+               if (pud_none(pud))
                        continue;
-               if (pud_table(*(src_pud))) {
-                       if (copy_pmd(dst_pud, src_pud, addr, next))
+               if (pud_table(pud)) {
+                       if (copy_pmd(dst_pudp, src_pudp, addr, next))
                                return -ENOMEM;
                } else {
-                       set_pud(dst_pud,
-                               __pud(pud_val(*src_pud) & ~PMD_SECT_RDONLY));
+                       set_pud(dst_pudp,
+                               __pud(pud_val(pud) & ~PMD_SECT_RDONLY));
                }
-       } while (dst_pud++, src_pud++, addr = next, addr != end);
+       } while (dst_pudp++, src_pudp++, addr = next, addr != end);
 
        return 0;
 }
 
-static int copy_page_tables(pgd_t *dst_pgd, unsigned long start,
+static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
                            unsigned long end)
 {
        unsigned long next;
        unsigned long addr = start;
-       pgd_t *src_pgd = pgd_offset_k(start);
+       pgd_t *src_pgdp = pgd_offset_k(start);
 
-       dst_pgd = pgd_offset_raw(dst_pgd, start);
+       dst_pgdp = pgd_offset_raw(dst_pgdp, start);
        do {
                next = pgd_addr_end(addr, end);
-               if (pgd_none(*src_pgd))
+               if (pgd_none(READ_ONCE(*src_pgdp)))
                        continue;
-               if (copy_pud(dst_pgd, src_pgd, addr, next))
+               if (copy_pud(dst_pgdp, src_pgdp, addr, next))
                        return -ENOMEM;
-       } while (dst_pgd++, src_pgd++, addr = next, addr != end);
+       } while (dst_pgdp++, src_pgdp++, addr = next, addr != end);
 
        return 0;
 }
index 75b220b..85a251b 100644 (file)
@@ -908,9 +908,9 @@ static void __armv8pmu_probe_pmu(void *info)
        int pmuver;
 
        dfr0 = read_sysreg(id_aa64dfr0_el1);
-       pmuver = cpuid_feature_extract_signed_field(dfr0,
+       pmuver = cpuid_feature_extract_unsigned_field(dfr0,
                        ID_AA64DFR0_PMUVER_SHIFT);
-       if (pmuver < 1)
+       if (pmuver == 0xf || pmuver == 0)
                return;
 
        probe->present = true;
index ad8aeb0..c0da6ef 100644 (file)
@@ -220,8 +220,15 @@ void __show_regs(struct pt_regs *regs)
 
        show_regs_print_info(KERN_DEFAULT);
        print_pstate(regs);
-       printk("pc : %pS\n", (void *)regs->pc);
-       printk("lr : %pS\n", (void *)lr);
+
+       if (!user_mode(regs)) {
+               printk("pc : %pS\n", (void *)regs->pc);
+               printk("lr : %pS\n", (void *)lr);
+       } else {
+               printk("pc : %016llx\n", regs->pc);
+               printk("lr : %016llx\n", lr);
+       }
+
        printk("sp : %016llx\n", sp);
 
        i = top_reg;
index 6618036..9ae31f7 100644 (file)
@@ -1419,7 +1419,7 @@ static int compat_ptrace_hbp_get(unsigned int note_type,
        u64 addr = 0;
        u32 ctrl = 0;
 
-       int err, idx = compat_ptrace_hbp_num_to_idx(num);;
+       int err, idx = compat_ptrace_hbp_num_to_idx(num);
 
        if (num & 1) {
                err = ptrace_hbp_get_addr(note_type, tsk, idx, &addr);
index 76809cc..d5718a0 100644 (file)
@@ -59,6 +59,11 @@ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        if (tsk->ret_stack &&
                        (frame->pc == (unsigned long)return_to_handler)) {
+               if (WARN_ON_ONCE(frame->graph == -1))
+                       return -EINVAL;
+               if (frame->graph < -1)
+                       frame->graph += FTRACE_NOTRACE_DEPTH;
+
                /*
                 * This is a case where function graph tracer has
                 * modified a return address (LR) in a stack frame
index 8b8bbd3..a382b2a 100644 (file)
@@ -57,7 +57,7 @@ do_compat_cache_op(unsigned long start, unsigned long end, int flags)
        if (end < start || flags)
                return -EINVAL;
 
-       if (!access_ok(VERIFY_READ, start, end - start))
+       if (!access_ok(VERIFY_READ, (const void __user *)start, end - start))
                return -EFAULT;
 
        return __do_compat_cache_op(start, end);
index a439128..f258636 100644 (file)
@@ -52,7 +52,7 @@ unsigned long profile_pc(struct pt_regs *regs)
        frame.fp = regs->regs[29];
        frame.pc = regs->pc;
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       frame.graph = -1; /* no task info */
+       frame.graph = current->curr_ret_stack;
 #endif
        do {
                int ret = unwind_frame(NULL, &frame);
index bbb0fde..eb2d151 100644 (file)
@@ -57,7 +57,7 @@ static const char *handler[]= {
        "Error"
 };
 
-int show_unhandled_signals = 1;
+int show_unhandled_signals = 0;
 
 static void dump_backtrace_entry(unsigned long where)
 {
@@ -526,14 +526,6 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs)
        }
 #endif
 
-       if (show_unhandled_signals_ratelimited()) {
-               pr_info("%s[%d]: syscall %d\n", current->comm,
-                       task_pid_nr(current), regs->syscallno);
-               dump_instr("", regs);
-               if (user_mode(regs))
-                       __show_regs(regs);
-       }
-
        return sys_ni_syscall();
 }
 
index d7e3299..959e50d 100644 (file)
@@ -363,8 +363,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
 {
        int ret = 0;
 
-       vcpu_load(vcpu);
-
        trace_kvm_set_guest_debug(vcpu, dbg->control);
 
        if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) {
@@ -386,7 +384,6 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
        }
 
 out:
-       vcpu_put(vcpu);
        return ret;
 }
 
index 116252a..870f4b1 100644 (file)
@@ -407,8 +407,10 @@ again:
                u32 midr = read_cpuid_id();
 
                /* Apply BTAC predictors mitigation to all Falkor chips */
-               if ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)
+               if (((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR) ||
+                   ((midr & MIDR_CPU_MODEL_MASK) == MIDR_QCOM_FALKOR_V1)) {
                        __qcom_hyp_sanitize_btac_predictors();
+               }
        }
 
        fp_enabled = __fpsimd_enabled();
index 7b60d62..65dfc85 100644 (file)
@@ -286,48 +286,52 @@ static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
 
 }
 
-static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
+static void walk_pte(struct pg_state *st, pmd_t *pmdp, unsigned long start)
 {
-       pte_t *pte = pte_offset_kernel(pmd, 0UL);
+       pte_t *ptep = pte_offset_kernel(pmdp, 0UL);
        unsigned long addr;
        unsigned i;
 
-       for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
+       for (i = 0; i < PTRS_PER_PTE; i++, ptep++) {
                addr = start + i * PAGE_SIZE;
-               note_page(st, addr, 4, pte_val(*pte));
+               note_page(st, addr, 4, READ_ONCE(pte_val(*ptep)));
        }
 }
 
-static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
+static void walk_pmd(struct pg_state *st, pud_t *pudp, unsigned long start)
 {
-       pmd_t *pmd = pmd_offset(pud, 0UL);
+       pmd_t *pmdp = pmd_offset(pudp, 0UL);
        unsigned long addr;
        unsigned i;
 
-       for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
+       for (i = 0; i < PTRS_PER_PMD; i++, pmdp++) {
+               pmd_t pmd = READ_ONCE(*pmdp);
+
                addr = start + i * PMD_SIZE;
-               if (pmd_none(*pmd) || pmd_sect(*pmd)) {
-                       note_page(st, addr, 3, pmd_val(*pmd));
+               if (pmd_none(pmd) || pmd_sect(pmd)) {
+                       note_page(st, addr, 3, pmd_val(pmd));
                } else {
-                       BUG_ON(pmd_bad(*pmd));
-                       walk_pte(st, pmd, addr);
+                       BUG_ON(pmd_bad(pmd));
+                       walk_pte(st, pmdp, addr);
                }
        }
 }
 
-static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
+static void walk_pud(struct pg_state *st, pgd_t *pgdp, unsigned long start)
 {
-       pud_t *pud = pud_offset(pgd, 0UL);
+       pud_t *pudp = pud_offset(pgdp, 0UL);
        unsigned long addr;
        unsigned i;
 
-       for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
+       for (i = 0; i < PTRS_PER_PUD; i++, pudp++) {
+               pud_t pud = READ_ONCE(*pudp);
+
                addr = start + i * PUD_SIZE;
-               if (pud_none(*pud) || pud_sect(*pud)) {
-                       note_page(st, addr, 2, pud_val(*pud));
+               if (pud_none(pud) || pud_sect(pud)) {
+                       note_page(st, addr, 2, pud_val(pud));
                } else {
-                       BUG_ON(pud_bad(*pud));
-                       walk_pmd(st, pud, addr);
+                       BUG_ON(pud_bad(pud));
+                       walk_pmd(st, pudp, addr);
                }
        }
 }
@@ -335,17 +339,19 @@ static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
 static void walk_pgd(struct pg_state *st, struct mm_struct *mm,
                     unsigned long start)
 {
-       pgd_t *pgd = pgd_offset(mm, 0UL);
+       pgd_t *pgdp = pgd_offset(mm, 0UL);
        unsigned i;
        unsigned long addr;
 
-       for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
+       for (i = 0; i < PTRS_PER_PGD; i++, pgdp++) {
+               pgd_t pgd = READ_ONCE(*pgdp);
+
                addr = start + i * PGDIR_SIZE;
-               if (pgd_none(*pgd)) {
-                       note_page(st, addr, 1, pgd_val(*pgd));
+               if (pgd_none(pgd)) {
+                       note_page(st, addr, 1, pgd_val(pgd));
                } else {
-                       BUG_ON(pgd_bad(*pgd));
-                       walk_pud(st, pgd, addr);
+                       BUG_ON(pgd_bad(pgd));
+                       walk_pud(st, pgdp, addr);
                }
        }
 }
index f76bb2c..bff1155 100644 (file)
@@ -130,7 +130,8 @@ static void mem_abort_decode(unsigned int esr)
 void show_pte(unsigned long addr)
 {
        struct mm_struct *mm;
-       pgd_t *pgd;
+       pgd_t *pgdp;
+       pgd_t pgd;
 
        if (addr < TASK_SIZE) {
                /* TTBR0 */
@@ -149,33 +150,37 @@ void show_pte(unsigned long addr)
                return;
        }
 
-       pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgd = %p\n",
+       pr_alert("%s pgtable: %luk pages, %u-bit VAs, pgdp = %p\n",
                 mm == &init_mm ? "swapper" : "user", PAGE_SIZE / SZ_1K,
                 VA_BITS, mm->pgd);
-       pgd = pgd_offset(mm, addr);
-       pr_alert("[%016lx] *pgd=%016llx", addr, pgd_val(*pgd));
+       pgdp = pgd_offset(mm, addr);
+       pgd = READ_ONCE(*pgdp);
+       pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd));
 
        do {
-               pud_t *pud;
-               pmd_t *pmd;
-               pte_t *pte;
+               pud_t *pudp, pud;
+               pmd_t *pmdp, pmd;
+               pte_t *ptep, pte;
 
-               if (pgd_none(*pgd) || pgd_bad(*pgd))
+               if (pgd_none(pgd) || pgd_bad(pgd))
                        break;
 
-               pud = pud_offset(pgd, addr);
-               pr_cont(", *pud=%016llx", pud_val(*pud));
-               if (pud_none(*pud) || pud_bad(*pud))
+               pudp = pud_offset(pgdp, addr);
+               pud = READ_ONCE(*pudp);
+               pr_cont(", pud=%016llx", pud_val(pud));
+               if (pud_none(pud) || pud_bad(pud))
                        break;
 
-               pmd = pmd_offset(pud, addr);
-               pr_cont(", *pmd=%016llx", pmd_val(*pmd));
-               if (pmd_none(*pmd) || pmd_bad(*pmd))
+               pmdp = pmd_offset(pudp, addr);
+               pmd = READ_ONCE(*pmdp);
+               pr_cont(", pmd=%016llx", pmd_val(pmd));
+               if (pmd_none(pmd) || pmd_bad(pmd))
                        break;
 
-               pte = pte_offset_map(pmd, addr);
-               pr_cont(", *pte=%016llx", pte_val(*pte));
-               pte_unmap(pte);
+               ptep = pte_offset_map(pmdp, addr);
+               pte = READ_ONCE(*ptep);
+               pr_cont(", pte=%016llx", pte_val(pte));
+               pte_unmap(ptep);
        } while(0);
 
        pr_cont("\n");
@@ -196,8 +201,9 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
                          pte_t entry, int dirty)
 {
        pteval_t old_pteval, pteval;
+       pte_t pte = READ_ONCE(*ptep);
 
-       if (pte_same(*ptep, entry))
+       if (pte_same(pte, entry))
                return 0;
 
        /* only preserve the access flags and write permission */
@@ -210,7 +216,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
         * (calculated as: a & b == ~(~a | ~b)).
         */
        pte_val(entry) ^= PTE_RDONLY;
-       pteval = READ_ONCE(pte_val(*ptep));
+       pteval = pte_val(pte);
        do {
                old_pteval = pteval;
                pteval ^= PTE_RDONLY;
index 6cb0fa9..ecc6818 100644 (file)
@@ -54,14 +54,14 @@ static inline pgprot_t pte_pgprot(pte_t pte)
 static int find_num_contig(struct mm_struct *mm, unsigned long addr,
                           pte_t *ptep, size_t *pgsize)
 {
-       pgd_t *pgd = pgd_offset(mm, addr);
-       pud_t *pud;
-       pmd_t *pmd;
+       pgd_t *pgdp = pgd_offset(mm, addr);
+       pud_t *pudp;
+       pmd_t *pmdp;
 
        *pgsize = PAGE_SIZE;
-       pud = pud_offset(pgd, addr);
-       pmd = pmd_offset(pud, addr);
-       if ((pte_t *)pmd == ptep) {
+       pudp = pud_offset(pgdp, addr);
+       pmdp = pmd_offset(pudp, addr);
+       if ((pte_t *)pmdp == ptep) {
                *pgsize = PMD_SIZE;
                return CONT_PMDS;
        }
@@ -181,11 +181,8 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
 
        clear_flush(mm, addr, ptep, pgsize, ncontig);
 
-       for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn) {
-               pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep,
-                        pte_val(pfn_pte(pfn, hugeprot)));
+       for (i = 0; i < ncontig; i++, ptep++, addr += pgsize, pfn += dpfn)
                set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot));
-       }
 }
 
 void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr,
@@ -203,20 +200,20 @@ void set_huge_swap_pte_at(struct mm_struct *mm, unsigned long addr,
 pte_t *huge_pte_alloc(struct mm_struct *mm,
                      unsigned long addr, unsigned long sz)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pte_t *pte = NULL;
-
-       pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz);
-       pgd = pgd_offset(mm, addr);
-       pud = pud_alloc(mm, pgd, addr);
-       if (!pud)
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
+       pte_t *ptep = NULL;
+
+       pgdp = pgd_offset(mm, addr);
+       pudp = pud_alloc(mm, pgdp, addr);
+       if (!pudp)
                return NULL;
 
        if (sz == PUD_SIZE) {
-               pte = (pte_t *)pud;
+               ptep = (pte_t *)pudp;
        } else if (sz == (PAGE_SIZE * CONT_PTES)) {
-               pmd_t *pmd = pmd_alloc(mm, pud, addr);
+               pmdp = pmd_alloc(mm, pudp, addr);
 
                WARN_ON(addr & (sz - 1));
                /*
@@ -226,60 +223,55 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
                 * will be no pte_unmap() to correspond with this
                 * pte_alloc_map().
                 */
-               pte = pte_alloc_map(mm, pmd, addr);
+               ptep = pte_alloc_map(mm, pmdp, addr);
        } else if (sz == PMD_SIZE) {
                if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) &&
-                   pud_none(*pud))
-                       pte = huge_pmd_share(mm, addr, pud);
+                   pud_none(READ_ONCE(*pudp)))
+                       ptep = huge_pmd_share(mm, addr, pudp);
                else
-                       pte = (pte_t *)pmd_alloc(mm, pud, addr);
+                       ptep = (pte_t *)pmd_alloc(mm, pudp, addr);
        } else if (sz == (PMD_SIZE * CONT_PMDS)) {
-               pmd_t *pmd;
-
-               pmd = pmd_alloc(mm, pud, addr);
+               pmdp = pmd_alloc(mm, pudp, addr);
                WARN_ON(addr & (sz - 1));
-               return (pte_t *)pmd;
+               return (pte_t *)pmdp;
        }
 
-       pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr,
-              sz, pte, pte_val(*pte));
-       return pte;
+       return ptep;
 }
 
 pte_t *huge_pte_offset(struct mm_struct *mm,
                       unsigned long addr, unsigned long sz)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
+       pgd_t *pgdp;
+       pud_t *pudp, pud;
+       pmd_t *pmdp, pmd;
 
-       pgd = pgd_offset(mm, addr);
-       pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd);
-       if (!pgd_present(*pgd))
+       pgdp = pgd_offset(mm, addr);
+       if (!pgd_present(READ_ONCE(*pgdp)))
                return NULL;
 
-       pud = pud_offset(pgd, addr);
-       if (sz != PUD_SIZE && pud_none(*pud))
+       pudp = pud_offset(pgdp, addr);
+       pud = READ_ONCE(*pudp);
+       if (sz != PUD_SIZE && pud_none(pud))
                return NULL;
        /* hugepage or swap? */
-       if (pud_huge(*pud) || !pud_present(*pud))
-               return (pte_t *)pud;
+       if (pud_huge(pud) || !pud_present(pud))
+               return (pte_t *)pudp;
        /* table; check the next level */
 
        if (sz == CONT_PMD_SIZE)
                addr &= CONT_PMD_MASK;
 
-       pmd = pmd_offset(pud, addr);
+       pmdp = pmd_offset(pudp, addr);
+       pmd = READ_ONCE(*pmdp);
        if (!(sz == PMD_SIZE || sz == CONT_PMD_SIZE) &&
-           pmd_none(*pmd))
+           pmd_none(pmd))
                return NULL;
-       if (pmd_huge(*pmd) || !pmd_present(*pmd))
-               return (pte_t *)pmd;
+       if (pmd_huge(pmd) || !pmd_present(pmd))
+               return (pte_t *)pmdp;
 
-       if (sz == CONT_PTE_SIZE) {
-               pte_t *pte = pte_offset_kernel(pmd, (addr & CONT_PTE_MASK));
-               return pte;
-       }
+       if (sz == CONT_PTE_SIZE)
+               return pte_offset_kernel(pmdp, (addr & CONT_PTE_MASK));
 
        return NULL;
 }
@@ -367,7 +359,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
        size_t pgsize;
        pte_t pte;
 
-       if (!pte_cont(*ptep)) {
+       if (!pte_cont(READ_ONCE(*ptep))) {
                ptep_set_wrprotect(mm, addr, ptep);
                return;
        }
@@ -391,7 +383,7 @@ void huge_ptep_clear_flush(struct vm_area_struct *vma,
        size_t pgsize;
        int ncontig;
 
-       if (!pte_cont(*ptep)) {
+       if (!pte_cont(READ_ONCE(*ptep))) {
                ptep_clear_flush(vma, addr, ptep);
                return;
        }
index 6e02e6f..dabfc1e 100644 (file)
@@ -44,92 +44,92 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node)
        return __pa(p);
 }
 
-static pte_t *__init kasan_pte_offset(pmd_t *pmd, unsigned long addr, int node,
+static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,
                                      bool early)
 {
-       if (pmd_none(*pmd)) {
+       if (pmd_none(READ_ONCE(*pmdp))) {
                phys_addr_t pte_phys = early ? __pa_symbol(kasan_zero_pte)
                                             : kasan_alloc_zeroed_page(node);
-               __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE);
+               __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE);
        }
 
-       return early ? pte_offset_kimg(pmd, addr)
-                    : pte_offset_kernel(pmd, addr);
+       return early ? pte_offset_kimg(pmdp, addr)
+                    : pte_offset_kernel(pmdp, addr);
 }
 
-static pmd_t *__init kasan_pmd_offset(pud_t *pud, unsigned long addr, int node,
+static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,
                                      bool early)
 {
-       if (pud_none(*pud)) {
+       if (pud_none(READ_ONCE(*pudp))) {
                phys_addr_t pmd_phys = early ? __pa_symbol(kasan_zero_pmd)
                                             : kasan_alloc_zeroed_page(node);
-               __pud_populate(pud, pmd_phys, PMD_TYPE_TABLE);
+               __pud_populate(pudp, pmd_phys, PMD_TYPE_TABLE);
        }
 
-       return early ? pmd_offset_kimg(pud, addr) : pmd_offset(pud, addr);
+       return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr);
 }
 
-static pud_t *__init kasan_pud_offset(pgd_t *pgd, unsigned long addr, int node,
+static pud_t *__init kasan_pud_offset(pgd_t *pgdp, unsigned long addr, int node,
                                      bool early)
 {
-       if (pgd_none(*pgd)) {
+       if (pgd_none(READ_ONCE(*pgdp))) {
                phys_addr_t pud_phys = early ? __pa_symbol(kasan_zero_pud)
                                             : kasan_alloc_zeroed_page(node);
-               __pgd_populate(pgd, pud_phys, PMD_TYPE_TABLE);
+               __pgd_populate(pgdp, pud_phys, PMD_TYPE_TABLE);
        }
 
-       return early ? pud_offset_kimg(pgd, addr) : pud_offset(pgd, addr);
+       return early ? pud_offset_kimg(pgdp, addr) : pud_offset(pgdp, addr);
 }
 
-static void __init kasan_pte_populate(pmd_t *pmd, unsigned long addr,
+static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
                                      unsigned long end, int node, bool early)
 {
        unsigned long next;
-       pte_t *pte = kasan_pte_offset(pmd, addr, node, early);
+       pte_t *ptep = kasan_pte_offset(pmdp, addr, node, early);
 
        do {
                phys_addr_t page_phys = early ? __pa_symbol(kasan_zero_page)
                                              : kasan_alloc_zeroed_page(node);
                next = addr + PAGE_SIZE;
-               set_pte(pte, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL));
-       } while (pte++, addr = next, addr != end && pte_none(*pte));
+               set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL));
+       } while (ptep++, addr = next, addr != end && pte_none(READ_ONCE(*ptep)));
 }
 
-static void __init kasan_pmd_populate(pud_t *pud, unsigned long addr,
+static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
                                      unsigned long end, int node, bool early)
 {
        unsigned long next;
-       pmd_t *pmd = kasan_pmd_offset(pud, addr, node, early);
+       pmd_t *pmdp = kasan_pmd_offset(pudp, addr, node, early);
 
        do {
                next = pmd_addr_end(addr, end);
-               kasan_pte_populate(pmd, addr, next, node, early);
-       } while (pmd++, addr = next, addr != end && pmd_none(*pmd));
+               kasan_pte_populate(pmdp, addr, next, node, early);
+       } while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp)));
 }
 
-static void __init kasan_pud_populate(pgd_t *pgd, unsigned long addr,
+static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr,
                                      unsigned long end, int node, bool early)
 {
        unsigned long next;
-       pud_t *pud = kasan_pud_offset(pgd, addr, node, early);
+       pud_t *pudp = kasan_pud_offset(pgdp, addr, node, early);
 
        do {
                next = pud_addr_end(addr, end);
-               kasan_pmd_populate(pud, addr, next, node, early);
-       } while (pud++, addr = next, addr != end && pud_none(*pud));
+               kasan_pmd_populate(pudp, addr, next, node, early);
+       } while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp)));
 }
 
 static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
                                      int node, bool early)
 {
        unsigned long next;
-       pgd_t *pgd;
+       pgd_t *pgdp;
 
-       pgd = pgd_offset_k(addr);
+       pgdp = pgd_offset_k(addr);
        do {
                next = pgd_addr_end(addr, end);
-               kasan_pud_populate(pgd, addr, next, node, early);
-       } while (pgd++, addr = next, addr != end);
+               kasan_pud_populate(pgdp, addr, next, node, early);
+       } while (pgdp++, addr = next, addr != end);
 }
 
 /* The early shadow maps everything to a single page of zeroes */
@@ -155,14 +155,14 @@ static void __init kasan_map_populate(unsigned long start, unsigned long end,
  */
 void __init kasan_copy_shadow(pgd_t *pgdir)
 {
-       pgd_t *pgd, *pgd_new, *pgd_end;
+       pgd_t *pgdp, *pgdp_new, *pgdp_end;
 
-       pgd = pgd_offset_k(KASAN_SHADOW_START);
-       pgd_end = pgd_offset_k(KASAN_SHADOW_END);
-       pgd_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START);
+       pgdp = pgd_offset_k(KASAN_SHADOW_START);
+       pgdp_end = pgd_offset_k(KASAN_SHADOW_END);
+       pgdp_new = pgd_offset_raw(pgdir, KASAN_SHADOW_START);
        do {
-               set_pgd(pgd_new, *pgd);
-       } while (pgd++, pgd_new++, pgd != pgd_end);
+               set_pgd(pgdp_new, READ_ONCE(*pgdp));
+       } while (pgdp++, pgdp_new++, pgdp != pgdp_end);
 }
 
 static void __init clear_pgds(unsigned long start,
index 4694cda..2dbb2c9 100644 (file)
@@ -108,7 +108,7 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
         * The following mapping attributes may be updated in live
         * kernel mappings without the need for break-before-make.
         */
-       static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE;
+       static const pteval_t mask = PTE_PXN | PTE_RDONLY | PTE_WRITE | PTE_NG;
 
        /* creating or taking down mappings is always safe */
        if (old == 0 || new == 0)
@@ -118,52 +118,55 @@ static bool pgattr_change_is_safe(u64 old, u64 new)
        if ((old | new) & PTE_CONT)
                return false;
 
-       /* Transitioning from Global to Non-Global is safe */
-       if (((old ^ new) == PTE_NG) && (new & PTE_NG))
-               return true;
+       /* Transitioning from Non-Global to Global is unsafe */
+       if (old & ~new & PTE_NG)
+               return false;
 
        return ((old ^ new) & ~mask) == 0;
 }
 
-static void init_pte(pmd_t *pmd, unsigned long addr, unsigned long end,
+static void init_pte(pmd_t *pmdp, unsigned long addr, unsigned long end,
                     phys_addr_t phys, pgprot_t prot)
 {
-       pte_t *pte;
+       pte_t *ptep;
 
-       pte = pte_set_fixmap_offset(pmd, addr);
+       ptep = pte_set_fixmap_offset(pmdp, addr);
        do {
-               pte_t old_pte = *pte;
+               pte_t old_pte = READ_ONCE(*ptep);
 
-               set_pte(pte, pfn_pte(__phys_to_pfn(phys), prot));
+               set_pte(ptep, pfn_pte(__phys_to_pfn(phys), prot));
 
                /*
                 * After the PTE entry has been populated once, we
                 * only allow updates to the permission attributes.
                 */
-               BUG_ON(!pgattr_change_is_safe(pte_val(old_pte), pte_val(*pte)));
+               BUG_ON(!pgattr_change_is_safe(pte_val(old_pte),
+                                             READ_ONCE(pte_val(*ptep))));
 
                phys += PAGE_SIZE;
-       } while (pte++, addr += PAGE_SIZE, addr != end);
+       } while (ptep++, addr += PAGE_SIZE, addr != end);
 
        pte_clear_fixmap();
 }
 
-static void alloc_init_cont_pte(pmd_t *pmd, unsigned long addr,
+static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
                                unsigned long end, phys_addr_t phys,
                                pgprot_t prot,
                                phys_addr_t (*pgtable_alloc)(void),
                                int flags)
 {
        unsigned long next;
+       pmd_t pmd = READ_ONCE(*pmdp);
 
-       BUG_ON(pmd_sect(*pmd));
-       if (pmd_none(*pmd)) {
+       BUG_ON(pmd_sect(pmd));
+       if (pmd_none(pmd)) {
                phys_addr_t pte_phys;
                BUG_ON(!pgtable_alloc);
                pte_phys = pgtable_alloc();
-               __pmd_populate(pmd, pte_phys, PMD_TYPE_TABLE);
+               __pmd_populate(pmdp, pte_phys, PMD_TYPE_TABLE);
+               pmd = READ_ONCE(*pmdp);
        }
-       BUG_ON(pmd_bad(*pmd));
+       BUG_ON(pmd_bad(pmd));
 
        do {
                pgprot_t __prot = prot;
@@ -175,67 +178,69 @@ static void alloc_init_cont_pte(pmd_t *pmd, unsigned long addr,
                    (flags & NO_CONT_MAPPINGS) == 0)
                        __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
 
-               init_pte(pmd, addr, next, phys, __prot);
+               init_pte(pmdp, addr, next, phys, __prot);
 
                phys += next - addr;
        } while (addr = next, addr != end);
 }
 
-static void init_pmd(pud_t *pud, unsigned long addr, unsigned long end,
+static void init_pmd(pud_t *pudp, unsigned long addr, unsigned long end,
                     phys_addr_t phys, pgprot_t prot,
                     phys_addr_t (*pgtable_alloc)(void), int flags)
 {
        unsigned long next;
-       pmd_t *pmd;
+       pmd_t *pmdp;
 
-       pmd = pmd_set_fixmap_offset(pud, addr);
+       pmdp = pmd_set_fixmap_offset(pudp, addr);
        do {
-               pmd_t old_pmd = *pmd;
+               pmd_t old_pmd = READ_ONCE(*pmdp);
 
                next = pmd_addr_end(addr, end);
 
                /* try section mapping first */
                if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
                    (flags & NO_BLOCK_MAPPINGS) == 0) {
-                       pmd_set_huge(pmd, phys, prot);
+                       pmd_set_huge(pmdp, phys, prot);
 
                        /*
                         * After the PMD entry has been populated once, we
                         * only allow updates to the permission attributes.
                         */
                        BUG_ON(!pgattr_change_is_safe(pmd_val(old_pmd),
-                                                     pmd_val(*pmd)));
+                                                     READ_ONCE(pmd_val(*pmdp))));
                } else {
-                       alloc_init_cont_pte(pmd, addr, next, phys, prot,
+                       alloc_init_cont_pte(pmdp, addr, next, phys, prot,
                                            pgtable_alloc, flags);
 
                        BUG_ON(pmd_val(old_pmd) != 0 &&
-                              pmd_val(old_pmd) != pmd_val(*pmd));
+                              pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
                }
                phys += next - addr;
-       } while (pmd++, addr = next, addr != end);
+       } while (pmdp++, addr = next, addr != end);
 
        pmd_clear_fixmap();
 }
 
-static void alloc_init_cont_pmd(pud_t *pud, unsigned long addr,
+static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
                                unsigned long end, phys_addr_t phys,
                                pgprot_t prot,
                                phys_addr_t (*pgtable_alloc)(void), int flags)
 {
        unsigned long next;
+       pud_t pud = READ_ONCE(*pudp);
 
        /*
         * Check for initial section mappings in the pgd/pud.
         */
-       BUG_ON(pud_sect(*pud));
-       if (pud_none(*pud)) {
+       BUG_ON(pud_sect(pud));
+       if (pud_none(pud)) {
                phys_addr_t pmd_phys;
                BUG_ON(!pgtable_alloc);
                pmd_phys = pgtable_alloc();
-               __pud_populate(pud, pmd_phys, PUD_TYPE_TABLE);
+               __pud_populate(pudp, pmd_phys, PUD_TYPE_TABLE);
+               pud = READ_ONCE(*pudp);
        }
-       BUG_ON(pud_bad(*pud));
+       BUG_ON(pud_bad(pud));
 
        do {
                pgprot_t __prot = prot;
@@ -247,7 +252,7 @@ static void alloc_init_cont_pmd(pud_t *pud, unsigned long addr,
                    (flags & NO_CONT_MAPPINGS) == 0)
                        __prot = __pgprot(pgprot_val(prot) | PTE_CONT);
 
-               init_pmd(pud, addr, next, phys, __prot, pgtable_alloc, flags);
+               init_pmd(pudp, addr, next, phys, __prot, pgtable_alloc, flags);
 
                phys += next - addr;
        } while (addr = next, addr != end);
@@ -265,25 +270,27 @@ static inline bool use_1G_block(unsigned long addr, unsigned long next,
        return true;
 }
 
-static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
-                                 phys_addr_t phys, pgprot_t prot,
-                                 phys_addr_t (*pgtable_alloc)(void),
-                                 int flags)
+static void alloc_init_pud(pgd_t *pgdp, unsigned long addr, unsigned long end,
+                          phys_addr_t phys, pgprot_t prot,
+                          phys_addr_t (*pgtable_alloc)(void),
+                          int flags)
 {
-       pud_t *pud;
        unsigned long next;
+       pud_t *pudp;
+       pgd_t pgd = READ_ONCE(*pgdp);
 
-       if (pgd_none(*pgd)) {
+       if (pgd_none(pgd)) {
                phys_addr_t pud_phys;
                BUG_ON(!pgtable_alloc);
                pud_phys = pgtable_alloc();
-               __pgd_populate(pgd, pud_phys, PUD_TYPE_TABLE);
+               __pgd_populate(pgdp, pud_phys, PUD_TYPE_TABLE);
+               pgd = READ_ONCE(*pgdp);
        }
-       BUG_ON(pgd_bad(*pgd));
+       BUG_ON(pgd_bad(pgd));
 
-       pud = pud_set_fixmap_offset(pgd, addr);
+       pudp = pud_set_fixmap_offset(pgdp, addr);
        do {
-               pud_t old_pud = *pud;
+               pud_t old_pud = READ_ONCE(*pudp);
 
                next = pud_addr_end(addr, end);
 
@@ -292,23 +299,23 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long addr, unsigned long end,
                 */
                if (use_1G_block(addr, next, phys) &&
                    (flags & NO_BLOCK_MAPPINGS) == 0) {
-                       pud_set_huge(pud, phys, prot);
+                       pud_set_huge(pudp, phys, prot);
 
                        /*
                         * After the PUD entry has been populated once, we
                         * only allow updates to the permission attributes.
                         */
                        BUG_ON(!pgattr_change_is_safe(pud_val(old_pud),
-                                                     pud_val(*pud)));
+                                                     READ_ONCE(pud_val(*pudp))));
                } else {
-                       alloc_init_cont_pmd(pud, addr, next, phys, prot,
+                       alloc_init_cont_pmd(pudp, addr, next, phys, prot,
                                            pgtable_alloc, flags);
 
                        BUG_ON(pud_val(old_pud) != 0 &&
-                              pud_val(old_pud) != pud_val(*pud));
+                              pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
                }
                phys += next - addr;
-       } while (pud++, addr = next, addr != end);
+       } while (pudp++, addr = next, addr != end);
 
        pud_clear_fixmap();
 }
@@ -320,7 +327,7 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
                                 int flags)
 {
        unsigned long addr, length, end, next;
-       pgd_t *pgd = pgd_offset_raw(pgdir, virt);
+       pgd_t *pgdp = pgd_offset_raw(pgdir, virt);
 
        /*
         * If the virtual and physical address don't have the same offset
@@ -336,10 +343,10 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
        end = addr + length;
        do {
                next = pgd_addr_end(addr, end);
-               alloc_init_pud(pgd, addr, next, phys, prot, pgtable_alloc,
+               alloc_init_pud(pgdp, addr, next, phys, prot, pgtable_alloc,
                               flags);
                phys += next - addr;
-       } while (pgd++, addr = next, addr != end);
+       } while (pgdp++, addr = next, addr != end);
 }
 
 static phys_addr_t pgd_pgtable_alloc(void)
@@ -401,10 +408,10 @@ static void update_mapping_prot(phys_addr_t phys, unsigned long virt,
        flush_tlb_kernel_range(virt, virt + size);
 }
 
-static void __init __map_memblock(pgd_t *pgd, phys_addr_t start,
+static void __init __map_memblock(pgd_t *pgdp, phys_addr_t start,
                                  phys_addr_t end, pgprot_t prot, int flags)
 {
-       __create_pgd_mapping(pgd, start, __phys_to_virt(start), end - start,
+       __create_pgd_mapping(pgdp, start, __phys_to_virt(start), end - start,
                             prot, early_pgtable_alloc, flags);
 }
 
@@ -418,7 +425,7 @@ void __init mark_linear_text_alias_ro(void)
                            PAGE_KERNEL_RO);
 }
 
-static void __init map_mem(pgd_t *pgd)
+static void __init map_mem(pgd_t *pgdp)
 {
        phys_addr_t kernel_start = __pa_symbol(_text);
        phys_addr_t kernel_end = __pa_symbol(__init_begin);
@@ -451,7 +458,7 @@ static void __init map_mem(pgd_t *pgd)
                if (memblock_is_nomap(reg))
                        continue;
 
-               __map_memblock(pgd, start, end, PAGE_KERNEL, flags);
+               __map_memblock(pgdp, start, end, PAGE_KERNEL, flags);
        }
 
        /*
@@ -464,7 +471,7 @@ static void __init map_mem(pgd_t *pgd)
         * Note that contiguous mappings cannot be remapped in this way,
         * so we should avoid them here.
         */
-       __map_memblock(pgd, kernel_start, kernel_end,
+       __map_memblock(pgdp, kernel_start, kernel_end,
                       PAGE_KERNEL, NO_CONT_MAPPINGS);
        memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
 
@@ -475,7 +482,7 @@ static void __init map_mem(pgd_t *pgd)
         * through /sys/kernel/kexec_crash_size interface.
         */
        if (crashk_res.end) {
-               __map_memblock(pgd, crashk_res.start, crashk_res.end + 1,
+               __map_memblock(pgdp, crashk_res.start, crashk_res.end + 1,
                               PAGE_KERNEL,
                               NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS);
                memblock_clear_nomap(crashk_res.start,
@@ -499,7 +506,7 @@ void mark_rodata_ro(void)
        debug_checkwx();
 }
 
-static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
+static void __init map_kernel_segment(pgd_t *pgdp, void *va_start, void *va_end,
                                      pgprot_t prot, struct vm_struct *vma,
                                      int flags, unsigned long vm_flags)
 {
@@ -509,7 +516,7 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end,
        BUG_ON(!PAGE_ALIGNED(pa_start));
        BUG_ON(!PAGE_ALIGNED(size));
 
-       __create_pgd_mapping(pgd, pa_start, (unsigned long)va_start, size, prot,
+       __create_pgd_mapping(pgdp, pa_start, (unsigned long)va_start, size, prot,
                             early_pgtable_alloc, flags);
 
        if (!(vm_flags & VM_NO_GUARD))
@@ -562,7 +569,7 @@ core_initcall(map_entry_trampoline);
 /*
  * Create fine-grained mappings for the kernel.
  */
-static void __init map_kernel(pgd_t *pgd)
+static void __init map_kernel(pgd_t *pgdp)
 {
        static struct vm_struct vmlinux_text, vmlinux_rodata, vmlinux_inittext,
                                vmlinux_initdata, vmlinux_data;
@@ -578,24 +585,24 @@ static void __init map_kernel(pgd_t *pgd)
         * Only rodata will be remapped with different permissions later on,
         * all other segments are allowed to use contiguous mappings.
         */
-       map_kernel_segment(pgd, _text, _etext, text_prot, &vmlinux_text, 0,
+       map_kernel_segment(pgdp, _text, _etext, text_prot, &vmlinux_text, 0,
                           VM_NO_GUARD);
-       map_kernel_segment(pgd, __start_rodata, __inittext_begin, PAGE_KERNEL,
+       map_kernel_segment(pgdp, __start_rodata, __inittext_begin, PAGE_KERNEL,
                           &vmlinux_rodata, NO_CONT_MAPPINGS, VM_NO_GUARD);
-       map_kernel_segment(pgd, __inittext_begin, __inittext_end, text_prot,
+       map_kernel_segment(pgdp, __inittext_begin, __inittext_end, text_prot,
                           &vmlinux_inittext, 0, VM_NO_GUARD);
-       map_kernel_segment(pgd, __initdata_begin, __initdata_end, PAGE_KERNEL,
+       map_kernel_segment(pgdp, __initdata_begin, __initdata_end, PAGE_KERNEL,
                           &vmlinux_initdata, 0, VM_NO_GUARD);
-       map_kernel_segment(pgd, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
+       map_kernel_segment(pgdp, _data, _end, PAGE_KERNEL, &vmlinux_data, 0, 0);
 
-       if (!pgd_val(*pgd_offset_raw(pgd, FIXADDR_START))) {
+       if (!READ_ONCE(pgd_val(*pgd_offset_raw(pgdp, FIXADDR_START)))) {
                /*
                 * The fixmap falls in a separate pgd to the kernel, and doesn't
                 * live in the carveout for the swapper_pg_dir. We can simply
                 * re-use the existing dir for the fixmap.
                 */
-               set_pgd(pgd_offset_raw(pgd, FIXADDR_START),
-                       *pgd_offset_k(FIXADDR_START));
+               set_pgd(pgd_offset_raw(pgdp, FIXADDR_START),
+                       READ_ONCE(*pgd_offset_k(FIXADDR_START)));
        } else if (CONFIG_PGTABLE_LEVELS > 3) {
                /*
                 * The fixmap shares its top level pgd entry with the kernel
@@ -604,14 +611,15 @@ static void __init map_kernel(pgd_t *pgd)
                 * entry instead.
                 */
                BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
-               pud_populate(&init_mm, pud_set_fixmap_offset(pgd, FIXADDR_START),
+               pud_populate(&init_mm,
+                            pud_set_fixmap_offset(pgdp, FIXADDR_START),
                             lm_alias(bm_pmd));
                pud_clear_fixmap();
        } else {
                BUG();
        }
 
-       kasan_copy_shadow(pgd);
+       kasan_copy_shadow(pgdp);
 }
 
 /*
@@ -621,10 +629,10 @@ static void __init map_kernel(pgd_t *pgd)
 void __init paging_init(void)
 {
        phys_addr_t pgd_phys = early_pgtable_alloc();
-       pgd_t *pgd = pgd_set_fixmap(pgd_phys);
+       pgd_t *pgdp = pgd_set_fixmap(pgd_phys);
 
-       map_kernel(pgd);
-       map_mem(pgd);
+       map_kernel(pgdp);
+       map_mem(pgdp);
 
        /*
         * We want to reuse the original swapper_pg_dir so we don't have to
@@ -635,7 +643,7 @@ void __init paging_init(void)
         * To do this we need to go via a temporary pgd.
         */
        cpu_replace_ttbr1(__va(pgd_phys));
-       memcpy(swapper_pg_dir, pgd, PGD_SIZE);
+       memcpy(swapper_pg_dir, pgdp, PGD_SIZE);
        cpu_replace_ttbr1(lm_alias(swapper_pg_dir));
 
        pgd_clear_fixmap();
@@ -655,37 +663,40 @@ void __init paging_init(void)
  */
 int kern_addr_valid(unsigned long addr)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
+       pgd_t *pgdp;
+       pud_t *pudp, pud;
+       pmd_t *pmdp, pmd;
+       pte_t *ptep, pte;
 
        if ((((long)addr) >> VA_BITS) != -1UL)
                return 0;
 
-       pgd = pgd_offset_k(addr);
-       if (pgd_none(*pgd))
+       pgdp = pgd_offset_k(addr);
+       if (pgd_none(READ_ONCE(*pgdp)))
                return 0;
 
-       pud = pud_offset(pgd, addr);
-       if (pud_none(*pud))
+       pudp = pud_offset(pgdp, addr);
+       pud = READ_ONCE(*pudp);
+       if (pud_none(pud))
                return 0;
 
-       if (pud_sect(*pud))
-               return pfn_valid(pud_pfn(*pud));
+       if (pud_sect(pud))
+               return pfn_valid(pud_pfn(pud));
 
-       pmd = pmd_offset(pud, addr);
-       if (pmd_none(*pmd))
+       pmdp = pmd_offset(pudp, addr);
+       pmd = READ_ONCE(*pmdp);
+       if (pmd_none(pmd))
                return 0;
 
-       if (pmd_sect(*pmd))
-               return pfn_valid(pmd_pfn(*pmd));
+       if (pmd_sect(pmd))
+               return pfn_valid(pmd_pfn(pmd));
 
-       pte = pte_offset_kernel(pmd, addr);
-       if (pte_none(*pte))
+       ptep = pte_offset_kernel(pmdp, addr);
+       pte = READ_ONCE(*ptep);
+       if (pte_none(pte))
                return 0;
 
-       return pfn_valid(pte_pfn(*pte));
+       return pfn_valid(pte_pfn(pte));
 }
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 #if !ARM64_SWAPPER_USES_SECTION_MAPS
@@ -700,32 +711,32 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 {
        unsigned long addr = start;
        unsigned long next;
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
+       pgd_t *pgdp;
+       pud_t *pudp;
+       pmd_t *pmdp;
 
        do {
                next = pmd_addr_end(addr, end);
 
-               pgd = vmemmap_pgd_populate(addr, node);
-               if (!pgd)
+               pgdp = vmemmap_pgd_populate(addr, node);
+               if (!pgdp)
                        return -ENOMEM;
 
-               pud = vmemmap_pud_populate(pgd, addr, node);
-               if (!pud)
+               pudp = vmemmap_pud_populate(pgdp, addr, node);
+               if (!pudp)
                        return -ENOMEM;
 
-               pmd = pmd_offset(pud, addr);
-               if (pmd_none(*pmd)) {
+               pmdp = pmd_offset(pudp, addr);
+               if (pmd_none(READ_ONCE(*pmdp))) {
                        void *p = NULL;
 
                        p = vmemmap_alloc_block_buf(PMD_SIZE, node);
                        if (!p)
                                return -ENOMEM;
 
-                       pmd_set_huge(pmd, __pa(p), __pgprot(PROT_SECT_NORMAL));
+                       pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
                } else
-                       vmemmap_verify((pte_t *)pmd, node, addr, next);
+                       vmemmap_verify((pte_t *)pmdp, node, addr, next);
        } while (addr = next, addr != end);
 
        return 0;
@@ -739,20 +750,22 @@ void vmemmap_free(unsigned long start, unsigned long end,
 
 static inline pud_t * fixmap_pud(unsigned long addr)
 {
-       pgd_t *pgd = pgd_offset_k(addr);
+       pgd_t *pgdp = pgd_offset_k(addr);
+       pgd_t pgd = READ_ONCE(*pgdp);
 
-       BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
+       BUG_ON(pgd_none(pgd) || pgd_bad(pgd));
 
-       return pud_offset_kimg(pgd, addr);
+       return pud_offset_kimg(pgdp, addr);
 }
 
 static inline pmd_t * fixmap_pmd(unsigned long addr)
 {
-       pud_t *pud = fixmap_pud(addr);
+       pud_t *pudp = fixmap_pud(addr);
+       pud_t pud = READ_ONCE(*pudp);
 
-       BUG_ON(pud_none(*pud) || pud_bad(*pud));
+       BUG_ON(pud_none(pud) || pud_bad(pud));
 
-       return pmd_offset_kimg(pud, addr);
+       return pmd_offset_kimg(pudp, addr);
 }
 
 static inline pte_t * fixmap_pte(unsigned long addr)
@@ -768,30 +781,31 @@ static inline pte_t * fixmap_pte(unsigned long addr)
  */
 void __init early_fixmap_init(void)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
+       pgd_t *pgdp, pgd;
+       pud_t *pudp;
+       pmd_t *pmdp;
        unsigned long addr = FIXADDR_START;
 
-       pgd = pgd_offset_k(addr);
+       pgdp = pgd_offset_k(addr);
+       pgd = READ_ONCE(*pgdp);
        if (CONFIG_PGTABLE_LEVELS > 3 &&
-           !(pgd_none(*pgd) || pgd_page_paddr(*pgd) == __pa_symbol(bm_pud))) {
+           !(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) {
                /*
                 * We only end up here if the kernel mapping and the fixmap
                 * share the top level pgd entry, which should only happen on
                 * 16k/4 levels configurations.
                 */
                BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
-               pud = pud_offset_kimg(pgd, addr);
+               pudp = pud_offset_kimg(pgdp, addr);
        } else {
-               if (pgd_none(*pgd))
-                       __pgd_populate(pgd, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
-               pud = fixmap_pud(addr);
+               if (pgd_none(pgd))
+                       __pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
+               pudp = fixmap_pud(addr);
        }
-       if (pud_none(*pud))
-               __pud_populate(pud, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
-       pmd = fixmap_pmd(addr);
-       __pmd_populate(pmd, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
+       if (pud_none(READ_ONCE(*pudp)))
+               __pud_populate(pudp, __pa_symbol(bm_pmd), PMD_TYPE_TABLE);
+       pmdp = fixmap_pmd(addr);
+       __pmd_populate(pmdp, __pa_symbol(bm_pte), PMD_TYPE_TABLE);
 
        /*
         * The boot-ioremap range spans multiple pmds, for which
@@ -800,11 +814,11 @@ void __init early_fixmap_init(void)
        BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
                     != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
 
-       if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
-            || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
+       if ((pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
+            || pmdp != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
                WARN_ON(1);
-               pr_warn("pmd %p != %p, %p\n",
-                       pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
+               pr_warn("pmdp %p != %p, %p\n",
+                       pmdp, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
                        fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
                pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
                        fix_to_virt(FIX_BTMAP_BEGIN));
@@ -824,16 +838,16 @@ void __set_fixmap(enum fixed_addresses idx,
                               phys_addr_t phys, pgprot_t flags)
 {
        unsigned long addr = __fix_to_virt(idx);
-       pte_t *pte;
+       pte_t *ptep;
 
        BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
 
-       pte = fixmap_pte(addr);
+       ptep = fixmap_pte(addr);
 
        if (pgprot_val(flags)) {
-               set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
+               set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, flags));
        } else {
-               pte_clear(&init_mm, addr, pte);
+               pte_clear(&init_mm, addr, ptep);
                flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
        }
 }
@@ -915,36 +929,56 @@ int __init arch_ioremap_pmd_supported(void)
        return 1;
 }
 
-int pud_set_huge(pud_t *pud, phys_addr_t phys, pgprot_t prot)
+int pud_set_huge(pud_t *pudp, phys_addr_t phys, pgprot_t prot)
 {
        pgprot_t sect_prot = __pgprot(PUD_TYPE_SECT |
                                        pgprot_val(mk_sect_prot(prot)));
+
+       /* ioremap_page_range doesn't honour BBM */
+       if (pud_present(READ_ONCE(*pudp)))
+               return 0;
+
        BUG_ON(phys & ~PUD_MASK);
-       set_pud(pud, pfn_pud(__phys_to_pfn(phys), sect_prot));
+       set_pud(pudp, pfn_pud(__phys_to_pfn(phys), sect_prot));
        return 1;
 }
 
-int pmd_set_huge(pmd_t *pmd, phys_addr_t phys, pgprot_t prot)
+int pmd_set_huge(pmd_t *pmdp, phys_addr_t phys, pgprot_t prot)
 {
        pgprot_t sect_prot = __pgprot(PMD_TYPE_SECT |
                                        pgprot_val(mk_sect_prot(prot)));
+
+       /* ioremap_page_range doesn't honour BBM */
+       if (pmd_present(READ_ONCE(*pmdp)))
+               return 0;
+
        BUG_ON(phys & ~PMD_MASK);
-       set_pmd(pmd, pfn_pmd(__phys_to_pfn(phys), sect_prot));
+       set_pmd(pmdp, pfn_pmd(__phys_to_pfn(phys), sect_prot));
        return 1;
 }
 
-int pud_clear_huge(pud_t *pud)
+int pud_clear_huge(pud_t *pudp)
 {
-       if (!pud_sect(*pud))
+       if (!pud_sect(READ_ONCE(*pudp)))
                return 0;
-       pud_clear(pud);
+       pud_clear(pudp);
        return 1;
 }
 
-int pmd_clear_huge(pmd_t *pmd)
+int pmd_clear_huge(pmd_t *pmdp)
 {
-       if (!pmd_sect(*pmd))
+       if (!pmd_sect(READ_ONCE(*pmdp)))
                return 0;
-       pmd_clear(pmd);
+       pmd_clear(pmdp);
        return 1;
 }
+
+int pud_free_pmd_page(pud_t *pud)
+{
+       return pud_none(*pud);
+}
+
+int pmd_free_pte_page(pmd_t *pmd)
+{
+       return pmd_none(*pmd);
+}
index a682a0a..a563593 100644 (file)
@@ -29,7 +29,7 @@ static int change_page_range(pte_t *ptep, pgtable_t token, unsigned long addr,
                        void *data)
 {
        struct page_change_data *cdata = data;
-       pte_t pte = *ptep;
+       pte_t pte = READ_ONCE(*ptep);
 
        pte = clear_pte_bit(pte, cdata->clear_mask);
        pte = set_pte_bit(pte, cdata->set_mask);
@@ -156,30 +156,32 @@ void __kernel_map_pages(struct page *page, int numpages, int enable)
  */
 bool kernel_page_present(struct page *page)
 {
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
+       pgd_t *pgdp;
+       pud_t *pudp, pud;
+       pmd_t *pmdp, pmd;
+       pte_t *ptep;
        unsigned long addr = (unsigned long)page_address(page);
 
-       pgd = pgd_offset_k(addr);
-       if (pgd_none(*pgd))
+       pgdp = pgd_offset_k(addr);
+       if (pgd_none(READ_ONCE(*pgdp)))
                return false;
 
-       pud = pud_offset(pgd, addr);
-       if (pud_none(*pud))
+       pudp = pud_offset(pgdp, addr);
+       pud = READ_ONCE(*pudp);
+       if (pud_none(pud))
                return false;
-       if (pud_sect(*pud))
+       if (pud_sect(pud))
                return true;
 
-       pmd = pmd_offset(pud, addr);
-       if (pmd_none(*pmd))
+       pmdp = pmd_offset(pudp, addr);
+       pmd = READ_ONCE(*pmdp);
+       if (pmd_none(pmd))
                return false;
-       if (pmd_sect(*pmd))
+       if (pmd_sect(pmd))
                return true;
 
-       pte = pte_offset_kernel(pmd, addr);
-       return pte_valid(*pte);
+       ptep = pte_offset_kernel(pmdp, addr);
+       return pte_valid(READ_ONCE(*ptep));
 }
 #endif /* CONFIG_HIBERNATION */
 #endif /* CONFIG_DEBUG_PAGEALLOC */
index 71baed7..c0af476 100644 (file)
@@ -205,7 +205,8 @@ ENDPROC(idmap_cpu_replace_ttbr1)
        dc      cvac, cur_\()\type\()p          // Ensure any existing dirty
        dmb     sy                              // lines are written back before
        ldr     \type, [cur_\()\type\()p]       // loading the entry
-       tbz     \type, #0, next_\()\type        // Skip invalid entries
+       tbz     \type, #0, skip_\()\type        // Skip invalid and
+       tbnz    \type, #11, skip_\()\type       // non-global entries
        .endm
 
        .macro __idmap_kpti_put_pgtable_ent_ng, type
@@ -265,8 +266,9 @@ ENTRY(idmap_kpti_install_ng_mappings)
        add     end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8)
 do_pgd:        __idmap_kpti_get_pgtable_ent    pgd
        tbnz    pgd, #1, walk_puds
-       __idmap_kpti_put_pgtable_ent_ng pgd
 next_pgd:
+       __idmap_kpti_put_pgtable_ent_ng pgd
+skip_pgd:
        add     cur_pgdp, cur_pgdp, #8
        cmp     cur_pgdp, end_pgdp
        b.ne    do_pgd
@@ -294,8 +296,9 @@ walk_puds:
        add     end_pudp, cur_pudp, #(PTRS_PER_PUD * 8)
 do_pud:        __idmap_kpti_get_pgtable_ent    pud
        tbnz    pud, #1, walk_pmds
-       __idmap_kpti_put_pgtable_ent_ng pud
 next_pud:
+       __idmap_kpti_put_pgtable_ent_ng pud
+skip_pud:
        add     cur_pudp, cur_pudp, 8
        cmp     cur_pudp, end_pudp
        b.ne    do_pud
@@ -314,8 +317,9 @@ walk_pmds:
        add     end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8)
 do_pmd:        __idmap_kpti_get_pgtable_ent    pmd
        tbnz    pmd, #1, walk_ptes
-       __idmap_kpti_put_pgtable_ent_ng pmd
 next_pmd:
+       __idmap_kpti_put_pgtable_ent_ng pmd
+skip_pmd:
        add     cur_pmdp, cur_pmdp, #8
        cmp     cur_pmdp, end_pmdp
        b.ne    do_pmd
@@ -333,7 +337,7 @@ walk_ptes:
        add     end_ptep, cur_ptep, #(PTRS_PER_PTE * 8)
 do_pte:        __idmap_kpti_get_pgtable_ent    pte
        __idmap_kpti_put_pgtable_ent_ng pte
-next_pte:
+skip_pte:
        add     cur_ptep, cur_ptep, #8
        cmp     cur_ptep, end_ptep
        b.ne    do_pte
index 1d4f1da..a933504 100644 (file)
@@ -250,8 +250,9 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
        off = offsetof(struct bpf_array, map.max_entries);
        emit_a64_mov_i64(tmp, off, ctx);
        emit(A64_LDR32(tmp, r2, tmp), ctx);
+       emit(A64_MOV(0, r3, r3), ctx);
        emit(A64_CMP(0, r3, tmp), ctx);
-       emit(A64_B_(A64_COND_GE, jmp_offset), ctx);
+       emit(A64_B_(A64_COND_CS, jmp_offset), ctx);
 
        /* if (tail_call_cnt > MAX_TAIL_CALL_CNT)
         *     goto out;
@@ -259,7 +260,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx)
         */
        emit_a64_mov_i64(tmp, MAX_TAIL_CALL_CNT, ctx);
        emit(A64_CMP(1, tcc, tmp), ctx);
-       emit(A64_B_(A64_COND_GT, jmp_offset), ctx);
+       emit(A64_B_(A64_COND_HI, jmp_offset), ctx);
        emit(A64_ADD_I(1, tcc, tcc, 1), ctx);
 
        /* prog = array->ptrs[index];
index 905afea..06da9d4 100644 (file)
@@ -44,18 +44,25 @@ struct bug_frame {
  * not be used like this with newer versions of gcc.
  */
 #define BUG()                                                          \
+do {                                                                   \
        __asm__ __volatile__ ("clear.d [" __stringify(BUG_MAGIC) "]\n\t"\
                              "movu.w " __stringify(__LINE__) ",$r0\n\t"\
                              "jump 0f\n\t"                             \
                              ".section .rodata\n"                      \
                              "0:\t.string \"" __FILE__ "\"\n\t"        \
-                             ".previous")
+                             ".previous");                             \
+       unreachable();                                                  \
+} while (0)
 #endif
 
 #else
 
 /* This just causes an oops. */
-#define BUG() (*(int *)0 = 0)
+#define BUG()                                                          \
+do {                                                                   \
+       barrier_before_unreachable();                                   \
+       __builtin_trap();                                               \
+} while (0)
 
 #endif
 
index ecff2d1..6eaa7ad 100644 (file)
@@ -2,7 +2,6 @@
 #ifndef __H8300_BYTEORDER_H__
 #define __H8300_BYTEORDER_H__
 
-#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
 #include <linux/byteorder/big_endian.h>
 
 #endif
index 762eeb0..2524fb6 100644 (file)
@@ -66,38 +66,35 @@ ATOMIC_OPS(add, +)
 ATOMIC_OPS(sub, -)
 
 #ifdef __OPTIMIZE__
-#define __ia64_atomic_const(i) __builtin_constant_p(i) ?               \
+#define __ia64_atomic_const(i)                                         \
+       static const int __ia64_atomic_p = __builtin_constant_p(i) ?    \
                ((i) == 1 || (i) == 4 || (i) == 8 || (i) == 16 ||       \
-                (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0
+                (i) == -1 || (i) == -4 || (i) == -8 || (i) == -16) : 0;\
+       __ia64_atomic_p
+#else
+#define __ia64_atomic_const(i) 0
+#endif
 
-#define atomic_add_return(i, v)                                                \
+#define atomic_add_return(i,v)                                         \
 ({                                                                     \
-       int __i = (i);                                                  \
-       static const int __ia64_atomic_p = __ia64_atomic_const(i);      \
-       __ia64_atomic_p ? ia64_fetch_and_add(__i, &(v)->counter) :      \
-                               ia64_atomic_add(__i, v);                \
+       int __ia64_aar_i = (i);                                         \
+       __ia64_atomic_const(i)                                          \
+               ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
+               : ia64_atomic_add(__ia64_aar_i, v);                     \
 })
 
-#define atomic_sub_return(i, v)                                                \
+#define atomic_sub_return(i,v)                                         \
 ({                                                                     \
-       int __i = (i);                                                  \
-       static const int __ia64_atomic_p = __ia64_atomic_const(i);      \
-       __ia64_atomic_p ? ia64_fetch_and_add(-__i, &(v)->counter) :     \
-                               ia64_atomic_sub(__i, v);                \
+       int __ia64_asr_i = (i);                                         \
+       __ia64_atomic_const(i)                                          \
+               ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
+               : ia64_atomic_sub(__ia64_asr_i, v);                     \
 })
-#else
-#define atomic_add_return(i, v)        ia64_atomic_add(i, v)
-#define atomic_sub_return(i, v)        ia64_atomic_sub(i, v)
-#endif
 
 #define atomic_fetch_add(i,v)                                          \
 ({                                                                     \
        int __ia64_aar_i = (i);                                         \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
-            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
-            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
-            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)       \
                : ia64_atomic_fetch_add(__ia64_aar_i, v);               \
 })
@@ -105,11 +102,7 @@ ATOMIC_OPS(sub, -)
 #define atomic_fetch_sub(i,v)                                          \
 ({                                                                     \
        int __ia64_asr_i = (i);                                         \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
-            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
-            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
-            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)      \
                : ia64_atomic_fetch_sub(__ia64_asr_i, v);               \
 })
@@ -170,11 +163,7 @@ ATOMIC64_OPS(sub, -)
 #define atomic64_add_return(i,v)                                       \
 ({                                                                     \
        long __ia64_aar_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
-            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
-            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
-            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)       \
                : ia64_atomic64_add(__ia64_aar_i, v);                   \
 })
@@ -182,11 +171,7 @@ ATOMIC64_OPS(sub, -)
 #define atomic64_sub_return(i,v)                                       \
 ({                                                                     \
        long __ia64_asr_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
-            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
-            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
-            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)      \
                : ia64_atomic64_sub(__ia64_asr_i, v);                   \
 })
@@ -194,11 +179,7 @@ ATOMIC64_OPS(sub, -)
 #define atomic64_fetch_add(i,v)                                                \
 ({                                                                     \
        long __ia64_aar_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)           \
-            || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)           \
-            || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)           \
-            || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))         \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetchadd(__ia64_aar_i, &(v)->counter, acq)       \
                : ia64_atomic64_fetch_add(__ia64_aar_i, v);             \
 })
@@ -206,11 +187,7 @@ ATOMIC64_OPS(sub, -)
 #define atomic64_fetch_sub(i,v)                                                \
 ({                                                                     \
        long __ia64_asr_i = (i);                                        \
-       (__builtin_constant_p(i)                                        \
-        && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)          \
-            || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)          \
-            || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)          \
-            || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))        \
+       __ia64_atomic_const(i)                                          \
                ? ia64_fetchadd(-__ia64_asr_i, &(v)->counter, acq)      \
                : ia64_atomic64_fetch_sub(__ia64_asr_i, v);             \
 })
index bd3eeb8..66b37a5 100644 (file)
@@ -4,7 +4,11 @@
 
 #ifdef CONFIG_BUG
 #define ia64_abort()   __builtin_trap()
-#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
+#define BUG() do {                                             \
+       printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__);   \
+       barrier_before_unreachable();                           \
+       ia64_abort();                                           \
+} while (0)
 
 /* should this BUG be made generic? */
 #define HAVE_ARCH_BUG
index 0b4c65a..498f3da 100644 (file)
@@ -41,7 +41,6 @@ ifneq ($(CONFIG_IA64_ESI),)
 obj-y                          += esi_stub.o   # must be in kernel proper
 endif
 obj-$(CONFIG_INTEL_IOMMU)      += pci-dma.o
-obj-$(CONFIG_SWIOTLB)          += pci-swiotlb.o
 
 obj-$(CONFIG_BINFMT_ELF)       += elfcore.o
 
index 85bba43..8b5b8e6 100644 (file)
@@ -117,7 +117,7 @@ store_call_start(struct device *dev, struct device_attribute *attr,
 
 #ifdef ERR_INJ_DEBUG
        printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
-       printk(KERN_DEBUG "capapbilities=%lx,\n", capabilities[cpu]);
+       printk(KERN_DEBUG "capabilities=%lx,\n", capabilities[cpu]);
        printk(KERN_DEBUG "resources=%lx\n", resources[cpu]);
 #endif
        return size;
@@ -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, FOLL_WRITE, NULL, NULL);
+       ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL);
        if (ret<=0) {
 #ifdef ERR_INJ_DEBUG
                printk("Virtual address %lx is not existing.\n",virt_addr);
index 89f3a14..c55276e 100644 (file)
@@ -16,7 +16,7 @@ import re
 import sys
 
 if len(sys.argv) != 2:
-    print "Usage: %s FILE" % sys.argv[0]
+    print("Usage: %s FILE" % sys.argv[0])
     sys.exit(2)
 
 readelf = os.getenv("READELF", "readelf")
@@ -29,7 +29,7 @@ def check_func (func, slots, rlen_sum):
         global num_errors
         num_errors += 1
         if not func: func = "[%#x-%#x]" % (start, end)
-        print "ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum)
+        print("ERROR: %s: %lu slots, total region length = %lu" % (func, slots, rlen_sum))
     return
 
 num_funcs = 0
@@ -43,23 +43,23 @@ for line in os.popen("%s -u %s" % (readelf, sys.argv[1])):
         check_func(func, slots, rlen_sum)
 
         func  = m.group(1)
-        start = long(m.group(2), 16)
-        end   = long(m.group(3), 16)
+        start = int(m.group(2), 16)
+        end   = int(m.group(3), 16)
         slots = 3 * (end - start) / 16
-        rlen_sum = 0L
+        rlen_sum = 0
         num_funcs += 1
     else:
         m = rlen_pattern.match(line)
         if m:
-            rlen_sum += long(m.group(1))
+            rlen_sum += int(m.group(1))
 check_func(func, slots, rlen_sum)
 
 if num_errors == 0:
-    print "No errors detected in %u functions." % num_funcs
+    print("No errors detected in %u functions." % num_funcs)
 else:
     if num_errors > 1:
         err="errors"
     else:
         err="error"
-    print "%u %s detected in %u functions." % (num_errors, err, num_funcs)
+    print("%u %s detected in %u functions." % (num_errors, err, num_funcs))
     sys.exit(1)
index b7e2bf1..275dca1 100644 (file)
@@ -8,16 +8,19 @@
 #ifndef CONFIG_SUN3
 #define BUG() do { \
        pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       barrier_before_unreachable(); \
        __builtin_trap(); \
 } while (0)
 #else
 #define BUG() do { \
        pr_crit("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+       barrier_before_unreachable(); \
        panic("BUG!"); \
 } while (0)
 #endif
 #else
 #define BUG() do { \
+       barrier_before_unreachable(); \
        __builtin_trap(); \
 } while (0)
 #endif
index 4f798aa..3817a3e 100644 (file)
@@ -24,6 +24,7 @@ config MICROBLAZE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
+       select NO_BOOTMEM
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_OPROFILE
index 6996f39..f7f1739 100644 (file)
@@ -8,7 +8,6 @@ menu "Platform options"
 
 config OPT_LIB_FUNCTION
        bool "Optimalized lib function"
-       depends on CPU_LITTLE_ENDIAN
        default y
        help
          Allows turn on optimalized library function (memcpy and memmove).
@@ -21,6 +20,7 @@ config OPT_LIB_FUNCTION
 config OPT_LIB_ASM
        bool "Optimalized lib function ASM"
        depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1)
+       depends on CPU_BIG_ENDIAN
        default n
        help
          Allows turn on optimalized library function (memcpy and memmove).
index be84a4d..7c968c1 100644 (file)
@@ -44,7 +44,6 @@ void machine_shutdown(void);
 void machine_halt(void);
 void machine_power_off(void);
 
-extern void *alloc_maybe_bootmem(size_t size, gfp_t mask);
 extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
 
 # endif /* __ASSEMBLY__ */
index 62021d7..fdc48bb 100644 (file)
  *     between mem locations with size of xfer spec'd in bytes
  */
 
-#ifdef __MICROBLAZEEL__
-#error Microblaze LE not support ASM optimized lib func. Disable OPT_LIB_ASM.
-#endif
-
 #include <linux/linkage.h>
        .text
        .globl  memcpy
index 434639f..df6de7c 100644 (file)
@@ -32,9 +32,6 @@ int mem_init_done;
 #ifndef CONFIG_MMU
 unsigned int __page_offset;
 EXPORT_SYMBOL(__page_offset);
-
-#else
-static int init_bootmem_done;
 #endif /* CONFIG_MMU */
 
 char *klimit = _end;
@@ -117,7 +114,6 @@ static void __init paging_init(void)
 
 void __init setup_memory(void)
 {
-       unsigned long map_size;
        struct memblock_region *reg;
 
 #ifndef CONFIG_MMU
@@ -174,17 +170,6 @@ void __init setup_memory(void)
        pr_info("%s: max_low_pfn: %#lx\n", __func__, max_low_pfn);
        pr_info("%s: max_pfn: %#lx\n", __func__, max_pfn);
 
-       /*
-        * Find an area to use for the bootmem bitmap.
-        * We look for the first area which is at least
-        * 128kB in length (128kB is enough for a bitmap
-        * for 4GB of memory, using 4kB pages), plus 1 page
-        * (in case the address isn't page-aligned).
-        */
-       map_size = init_bootmem_node(NODE_DATA(0),
-               PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
-       memblock_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
-
        /* Add active regions with valid PFNs */
        for_each_memblock(memory, reg) {
                unsigned long start_pfn, end_pfn;
@@ -196,32 +181,9 @@ void __init setup_memory(void)
                                  &memblock.memory, 0);
        }
 
-       /* free bootmem is whole main memory */
-       free_bootmem_with_active_regions(0, max_low_pfn);
-
-       /* reserve allocate blocks */
-       for_each_memblock(reserved, reg) {
-               unsigned long top = reg->base + reg->size - 1;
-
-               pr_debug("reserved - 0x%08x-0x%08x, %lx, %lx\n",
-                        (u32) reg->base, (u32) reg->size, top,
-                                               memory_start + lowmem_size - 1);
-
-               if (top <= (memory_start + lowmem_size - 1)) {
-                       reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-               } else if (reg->base < (memory_start + lowmem_size - 1)) {
-                       unsigned long trunc_size = memory_start + lowmem_size -
-                                                               reg->base;
-                       reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
-               }
-       }
-
        /* XXX need to clip this if using highmem? */
        sparse_memory_present_with_active_regions(0);
 
-#ifdef CONFIG_MMU
-       init_bootmem_done = 1;
-#endif
        paging_init();
 }
 
@@ -398,30 +360,16 @@ asmlinkage void __init mmu_init(void)
 /* This is only called until mem_init is done. */
 void __init *early_get_page(void)
 {
-       void *p;
-       if (init_bootmem_done) {
-               p = alloc_bootmem_pages(PAGE_SIZE);
-       } else {
-               /*
-                * Mem start + kernel_tlb -> here is limit
-                * because of mem mapping from head.S
-                */
-               p = __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
-                                       memory_start + kernel_tlb));
-       }
-       return p;
+       /*
+        * Mem start + kernel_tlb -> here is limit
+        * because of mem mapping from head.S
+        */
+       return __va(memblock_alloc_base(PAGE_SIZE, PAGE_SIZE,
+                               memory_start + kernel_tlb));
 }
 
 #endif /* CONFIG_MMU */
 
-void * __ref alloc_maybe_bootmem(size_t size, gfp_t mask)
-{
-       if (mem_init_done)
-               return kmalloc(size, mask);
-       else
-               return alloc_bootmem(size);
-}
-
 void * __ref zalloc_maybe_bootmem(size_t size, gfp_t mask)
 {
        void *p;
index 9ab48ff..6d11ae5 100644 (file)
@@ -135,6 +135,8 @@ int __init ath25_find_config(phys_addr_t base, unsigned long size)
        }
 
        board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL);
+       if (!board_data)
+               goto error;
        ath25_board.config = (struct ath25_boarddata *)board_data;
        memcpy_fromio(board_data, bcfg, 0x100);
        if (broken_boarddata) {
index 1bd5c4f..c22da16 100644 (file)
@@ -126,6 +126,7 @@ $(obj)/vmlinux.its.S: $(addprefix $(srctree)/arch/mips/$(PLATFORM)/,$(ITS_INPUTS
 
 quiet_cmd_cpp_its_S = ITS     $@
       cmd_cpp_its_S = $(CPP) $(cpp_flags) -P -C -o $@ $< \
+                       -D__ASSEMBLY__ \
                        -DKERNEL_NAME="\"Linux $(KERNELRELEASE)\"" \
                        -DVMLINUX_BINARY="\"$(3)\"" \
                        -DVMLINUX_COMPRESSION="\"$(2)\"" \
index 5b3a3f6..d99f524 100644 (file)
@@ -2277,6 +2277,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node,
        }
 
        host_data = kzalloc(sizeof(*host_data), GFP_KERNEL);
+       if (!host_data)
+               return -ENOMEM;
        raw_spin_lock_init(&host_data->lock);
 
        addr = of_get_address(ciu_node, 0, NULL, NULL);
index 946681d..9a0fa66 100644 (file)
@@ -86,7 +86,6 @@ struct compat_flock {
        compat_off_t    l_len;
        s32             l_sysid;
        compat_pid_t    l_pid;
-       short           __unused;
        s32             pad[4];
 };
 
index 85bc601..5f8b0a9 100644 (file)
@@ -375,6 +375,7 @@ static void __init bootmem_init(void)
        unsigned long reserved_end;
        unsigned long mapstart = ~0UL;
        unsigned long bootmap_size;
+       phys_addr_t ramstart = (phys_addr_t)ULLONG_MAX;
        bool bootmap_valid = false;
        int i;
 
@@ -395,7 +396,8 @@ static void __init bootmem_init(void)
        max_low_pfn = 0;
 
        /*
-        * Find the highest page frame number we have available.
+        * Find the highest page frame number we have available
+        * and the lowest used RAM address
         */
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                unsigned long start, end;
@@ -407,6 +409,8 @@ static void __init bootmem_init(void)
                end = PFN_DOWN(boot_mem_map.map[i].addr
                                + boot_mem_map.map[i].size);
 
+               ramstart = min(ramstart, boot_mem_map.map[i].addr);
+
 #ifndef CONFIG_HIGHMEM
                /*
                 * Skip highmem here so we get an accurate max_low_pfn if low
@@ -436,6 +440,13 @@ static void __init bootmem_init(void)
                mapstart = max(reserved_end, start);
        }
 
+       /*
+        * Reserve any memory between the start of RAM and PHYS_OFFSET
+        */
+       if (ramstart > PHYS_OFFSET)
+               add_memory_region(PHYS_OFFSET, ramstart - PHYS_OFFSET,
+                                 BOOT_MEM_RESERVED);
+
        if (min_low_pfn >= max_low_pfn)
                panic("Incorrect memory mapping !!!");
        if (min_low_pfn > ARCH_PFN_OFFSET) {
@@ -664,9 +675,6 @@ static int __init early_parse_mem(char *p)
 
        add_memory_region(start, size, BOOT_MEM_RAM);
 
-       if (start && start > PHYS_OFFSET)
-               add_memory_region(PHYS_OFFSET, start - PHYS_OFFSET,
-                               BOOT_MEM_RESERVED);
        return 0;
 }
 early_param("mem", early_parse_mem);
index 87dcac2..159e83a 100644 (file)
@@ -168,11 +168,11 @@ static void bmips_prepare_cpus(unsigned int max_cpus)
                return;
        }
 
-       if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
-                       "smp_ipi0", NULL))
+       if (request_irq(IPI0_IRQ, bmips_ipi_interrupt,
+                       IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL))
                panic("Can't request IPI0 interrupt");
-       if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
-                       "smp_ipi1", NULL))
+       if (request_irq(IPI1_IRQ, bmips_ipi_interrupt,
+                       IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL))
                panic("Can't request IPI1 interrupt");
 }
 
@@ -572,7 +572,7 @@ asmlinkage void __weak plat_wired_tlb_setup(void)
         */
 }
 
-void __init bmips_cpu_setup(void)
+void bmips_cpu_setup(void)
 {
        void __iomem __maybe_unused *cbr = BMIPS_GET_CBR();
        u32 __maybe_unused cfg;
index 692ae85..8e3a1fc 100644 (file)
@@ -13,6 +13,8 @@ choice
 config SOC_AMAZON_SE
        bool "Amazon SE"
        select SOC_TYPE_XWAY
+       select MFD_SYSCON
+       select MFD_CORE
 
 config SOC_XWAY
        bool "XWAY"
index 52500d3..e0af39b 100644 (file)
@@ -549,9 +549,9 @@ void __init ltq_soc_init(void)
                clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
                                ltq_ar9_fpi_hz(), CLOCK_250M);
                clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P);
-               clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM);
                clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P);
-               clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1);
+               clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM);
                clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH);
                clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
                clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
@@ -560,7 +560,7 @@ void __init ltq_soc_init(void)
        } else {
                clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
                                ltq_danube_fpi_hz(), ltq_danube_pp32_hz());
-               clkdev_add_pmu("1f203018.usb2-phy", "ctrl", 1, 0, PMU_USB0);
+               clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM);
                clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P);
                clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
                clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
index bc2fdbf..72af0c1 100644 (file)
@@ -7,6 +7,8 @@ choice
 config LEMOTE_FULOONG2E
        bool "Lemote Fuloong(2e) mini-PC"
        select ARCH_SPARSEMEM_ENABLE
+       select ARCH_MIGHT_HAVE_PC_PARPORT
+       select ARCH_MIGHT_HAVE_PC_SERIO
        select CEVT_R4K
        select CSRC_R4K
        select SYS_HAS_CPU_LOONGSON2E
@@ -33,6 +35,8 @@ config LEMOTE_FULOONG2E
 config LEMOTE_MACH2F
        bool "Lemote Loongson 2F family machines"
        select ARCH_SPARSEMEM_ENABLE
+       select ARCH_MIGHT_HAVE_PC_PARPORT
+       select ARCH_MIGHT_HAVE_PC_SERIO
        select BOARD_SCACHE
        select BOOT_ELF32
        select CEVT_R4K if ! MIPS_EXTERNAL_TIMER
@@ -62,6 +66,8 @@ config LEMOTE_MACH2F
 config LOONGSON_MACH3X
        bool "Generic Loongson 3 family machines"
        select ARCH_SPARSEMEM_ENABLE
+       select ARCH_MIGHT_HAVE_PC_PARPORT
+       select ARCH_MIGHT_HAVE_PC_SERIO
        select GENERIC_ISA_DMA_SUPPORT_BROKEN
        select BOOT_ELF32
        select BOARD_SCACHE
index 1b27474..d2718de 100644 (file)
@@ -170,6 +170,28 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
        u32 n1;
        u32 rev;
 
+       /* Early detection of CMP support */
+       mips_cm_probe();
+       mips_cpc_probe();
+
+       if (mips_cps_numiocu(0)) {
+               /*
+                * mips_cm_probe() wipes out bootloader
+                * config for CM regions and we have to configure them
+                * again. This SoC cannot talk to pamlbus devices
+                * witout proper iocu region set up.
+                *
+                * FIXME: it would be better to do this with values
+                * from DT, but we need this very early because
+                * without this we cannot talk to pretty much anything
+                * including serial.
+                */
+               write_gcr_reg0_base(MT7621_PALMBUS_BASE);
+               write_gcr_reg0_mask(~MT7621_PALMBUS_SIZE |
+                                   CM_GCR_REGn_MASK_CMTGT_IOCU0);
+               __sync();
+       }
+
        n0 = __raw_readl(sysc + SYSC_REG_CHIP_NAME0);
        n1 = __raw_readl(sysc + SYSC_REG_CHIP_NAME1);
 
@@ -194,26 +216,6 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
 
        rt2880_pinmux_data = mt7621_pinmux_data;
 
-       /* Early detection of CMP support */
-       mips_cm_probe();
-       mips_cpc_probe();
-
-       if (mips_cps_numiocu(0)) {
-               /*
-                * mips_cm_probe() wipes out bootloader
-                * config for CM regions and we have to configure them
-                * again. This SoC cannot talk to pamlbus devices
-                * witout proper iocu region set up.
-                *
-                * FIXME: it would be better to do this with values
-                * from DT, but we need this very early because
-                * without this we cannot talk to pretty much anything
-                * including serial.
-                */
-               write_gcr_reg0_base(MT7621_PALMBUS_BASE);
-               write_gcr_reg0_mask(~MT7621_PALMBUS_SIZE |
-                                   CM_GCR_REGn_MASK_CMTGT_IOCU0);
-       }
 
        if (!register_cps_smp_ops())
                return;
index 64543d6..e9531fe 100644 (file)
@@ -96,16 +96,9 @@ static void ralink_restart(char *command)
        unreachable();
 }
 
-static void ralink_halt(void)
-{
-       local_irq_disable();
-       unreachable();
-}
-
 static int __init mips_reboot_setup(void)
 {
        _machine_restart = ralink_restart;
-       _machine_halt = ralink_halt;
 
        return 0;
 }
index 3742508..bd5ce31 100644 (file)
@@ -26,6 +26,7 @@ void flush_user_icache_range_asm(unsigned long, unsigned long);
 void flush_kernel_icache_range_asm(unsigned long, unsigned long);
 void flush_user_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
+void purge_kernel_dcache_range_asm(unsigned long, unsigned long);
 void flush_kernel_dcache_page_asm(void *);
 void flush_kernel_icache_page(void *);
 
index 0e6ab6e..2dbe558 100644 (file)
@@ -316,6 +316,8 @@ extern int _parisc_requires_coherency;
 #define parisc_requires_coherency()    (0)
 #endif
 
+extern int running_on_qemu;
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_PARISC_PROCESSOR_H */
index 19c0c14..e3b4554 100644 (file)
@@ -465,10 +465,10 @@ EXPORT_SYMBOL(copy_user_page);
 int __flush_tlb_range(unsigned long sid, unsigned long start,
                      unsigned long end)
 {
-       unsigned long flags, size;
+       unsigned long flags;
 
-       size = (end - start);
-       if (size >= parisc_tlb_flush_threshold) {
+       if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+           end - start >= parisc_tlb_flush_threshold) {
                flush_tlb_all();
                return 1;
        }
@@ -539,13 +539,12 @@ void flush_cache_mm(struct mm_struct *mm)
        struct vm_area_struct *vma;
        pgd_t *pgd;
 
-       /* Flush the TLB to avoid speculation if coherency is required. */
-       if (parisc_requires_coherency())
-               flush_tlb_all();
-
        /* Flushing the whole cache on each cpu takes forever on
           rp3440, etc.  So, avoid it if the mm isn't too big.  */
-       if (mm_total_size(mm) >= parisc_cache_flush_threshold) {
+       if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+           mm_total_size(mm) >= parisc_cache_flush_threshold) {
+               if (mm->context)
+                       flush_tlb_all();
                flush_cache_all();
                return;
        }
@@ -553,9 +552,9 @@ void flush_cache_mm(struct mm_struct *mm)
        if (mm->context == mfsp(3)) {
                for (vma = mm->mmap; vma; vma = vma->vm_next) {
                        flush_user_dcache_range_asm(vma->vm_start, vma->vm_end);
-                       if ((vma->vm_flags & VM_EXEC) == 0)
-                               continue;
-                       flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
+                       if (vma->vm_flags & VM_EXEC)
+                               flush_user_icache_range_asm(vma->vm_start, vma->vm_end);
+                       flush_tlb_range(vma, vma->vm_start, vma->vm_end);
                }
                return;
        }
@@ -573,6 +572,8 @@ void flush_cache_mm(struct mm_struct *mm)
                        pfn = pte_pfn(*ptep);
                        if (!pfn_valid(pfn))
                                continue;
+                       if (unlikely(mm->context))
+                               flush_tlb_page(vma, addr);
                        __flush_cache_page(vma, addr, PFN_PHYS(pfn));
                }
        }
@@ -581,30 +582,45 @@ void flush_cache_mm(struct mm_struct *mm)
 void flush_cache_range(struct vm_area_struct *vma,
                unsigned long start, unsigned long end)
 {
-       BUG_ON(!vma->vm_mm->context);
-
-       /* Flush the TLB to avoid speculation if coherency is required. */
-       if (parisc_requires_coherency())
-               flush_tlb_range(vma, start, end);
+       pgd_t *pgd;
+       unsigned long addr;
 
-       if ((end - start) >= parisc_cache_flush_threshold
-           || vma->vm_mm->context != mfsp(3)) {
+       if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+           end - start >= parisc_cache_flush_threshold) {
+               if (vma->vm_mm->context)
+                       flush_tlb_range(vma, start, end);
                flush_cache_all();
                return;
        }
 
-       flush_user_dcache_range_asm(start, end);
-       if (vma->vm_flags & VM_EXEC)
-               flush_user_icache_range_asm(start, end);
+       if (vma->vm_mm->context == mfsp(3)) {
+               flush_user_dcache_range_asm(start, end);
+               if (vma->vm_flags & VM_EXEC)
+                       flush_user_icache_range_asm(start, end);
+               flush_tlb_range(vma, start, end);
+               return;
+       }
+
+       pgd = vma->vm_mm->pgd;
+       for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) {
+               unsigned long pfn;
+               pte_t *ptep = get_ptep(pgd, addr);
+               if (!ptep)
+                       continue;
+               pfn = pte_pfn(*ptep);
+               if (pfn_valid(pfn)) {
+                       if (unlikely(vma->vm_mm->context))
+                               flush_tlb_page(vma, addr);
+                       __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+               }
+       }
 }
 
 void
 flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
 {
-       BUG_ON(!vma->vm_mm->context);
-
        if (pfn_valid(pfn)) {
-               if (parisc_requires_coherency())
+               if (likely(vma->vm_mm->context))
                        flush_tlb_page(vma, vmaddr);
                __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
        }
@@ -613,21 +629,33 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
 void flush_kernel_vmap_range(void *vaddr, int size)
 {
        unsigned long start = (unsigned long)vaddr;
+       unsigned long end = start + size;
 
-       if ((unsigned long)size > parisc_cache_flush_threshold)
+       if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+           (unsigned long)size >= parisc_cache_flush_threshold) {
+               flush_tlb_kernel_range(start, end);
                flush_data_cache();
-       else
-               flush_kernel_dcache_range_asm(start, start + size);
+               return;
+       }
+
+       flush_kernel_dcache_range_asm(start, end);
+       flush_tlb_kernel_range(start, end);
 }
 EXPORT_SYMBOL(flush_kernel_vmap_range);
 
 void invalidate_kernel_vmap_range(void *vaddr, int size)
 {
        unsigned long start = (unsigned long)vaddr;
+       unsigned long end = start + size;
 
-       if ((unsigned long)size > parisc_cache_flush_threshold)
+       if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+           (unsigned long)size >= parisc_cache_flush_threshold) {
+               flush_tlb_kernel_range(start, end);
                flush_data_cache();
-       else
-               flush_kernel_dcache_range_asm(start, start + size);
+               return;
+       }
+
+       purge_kernel_dcache_range_asm(start, end);
+       flush_tlb_kernel_range(start, end);
 }
 EXPORT_SYMBOL(invalidate_kernel_vmap_range);
index bbbe360..fbb4e43 100644 (file)
@@ -138,6 +138,16 @@ $pgt_fill_loop:
        std             %dp,0x18(%r10)
 #endif
 
+#ifdef CONFIG_64BIT
+       /* Get PDCE_PROC for monarch CPU. */
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+       ldw             MEM_PDC_LO(%r0),%r3
+       ldw             MEM_PDC_HI(%r0),%r10
+       depd            %r10, 31, 32, %r3        /* move to upper word */
+#endif
+
+
 #ifdef CONFIG_SMP
        /* Set the smp rendezvous address into page zero.
        ** It would be safer to do this in init_smp_config() but
@@ -196,12 +206,6 @@ common_stext:
         ** Someday, palo might not do this for the Monarch either.
         */
 2:
-#define MEM_PDC_LO 0x388
-#define MEM_PDC_HI 0x35C
-       ldw             MEM_PDC_LO(%r0),%r3
-       ldw             MEM_PDC_HI(%r0),%r6
-       depd            %r6, 31, 32, %r3        /* move to upper word */
-
        mfctl           %cr30,%r6               /* PCX-W2 firmware bug */
 
        ldo             PDC_PSW(%r0),%arg0              /* 21 */
@@ -268,6 +272,8 @@ $install_iva:
 aligned_rfi:
        pcxt_ssm_bug
 
+       copy            %r3, %arg0      /* PDCE_PROC for smp_callin() */
+
        rsm             PSW_SM_QUIET,%r0        /* off troublesome PSW bits */
        /* Don't need NOPs, have 8 compliant insn before rfi */
 
index 2d40c4f..67b0f75 100644 (file)
@@ -1110,6 +1110,28 @@ ENTRY_CFI(flush_kernel_dcache_range_asm)
        .procend
 ENDPROC_CFI(flush_kernel_dcache_range_asm)
 
+ENTRY_CFI(purge_kernel_dcache_range_asm)
+       .proc
+       .callinfo NO_CALLS
+       .entry
+
+       ldil            L%dcache_stride, %r1
+       ldw             R%dcache_stride(%r1), %r23
+       ldo             -1(%r23), %r21
+       ANDCM           %r26, %r21, %r26
+
+1:      cmpb,COND(<<),n        %r26, %r25,1b
+       pdc,m           %r23(%r26)
+
+       sync
+       syncdma
+       bv              %r0(%r2)
+       nop
+       .exit
+
+       .procend
+ENDPROC_CFI(purge_kernel_dcache_range_asm)
+
 ENTRY_CFI(flush_user_icache_range_asm)
        .proc
        .callinfo NO_CALLS
index 30c28ab..4065b5e 100644 (file)
@@ -292,10 +292,15 @@ smp_cpu_init(int cpunum)
  * Slaves start using C here. Indirectly called from smp_slave_stext.
  * Do what start_kernel() and main() do for boot strap processor (aka monarch)
  */
-void __init smp_callin(void)
+void __init smp_callin(unsigned long pdce_proc)
 {
        int slave_id = cpu_now_booting;
 
+#ifdef CONFIG_64BIT
+       WARN_ON(((unsigned long)(PAGE0->mem_pdc_hi) << 32
+                       | PAGE0->mem_pdc) != pdce_proc);
+#endif
+
        smp_cpu_init(slave_id);
        preempt_disable();
 
index 4b8fd6d..f7e6845 100644 (file)
@@ -76,10 +76,10 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
        next_tick = cpuinfo->it_value;
 
        /* Calculate how many ticks have elapsed. */
+       now = mfctl(16);
        do {
                ++ticks_elapsed;
                next_tick += cpt;
-               now = mfctl(16);
        } while (next_tick - now > cpt);
 
        /* Store (in CR16 cycles) up to when we are accounting right now. */
@@ -103,16 +103,17 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
         * if one or the other wrapped. If "now" is "bigger" we'll end up
         * with a very large unsigned number.
         */
-       while (next_tick - mfctl(16) > cpt)
+       now = mfctl(16);
+       while (next_tick - now > cpt)
                next_tick += cpt;
 
        /* Program the IT when to deliver the next interrupt.
         * Only bottom 32-bits of next_tick are writable in CR16!
         * Timer interrupt will be delivered at least a few hundred cycles
-        * after the IT fires, so if we are too close (<= 500 cycles) to the
+        * after the IT fires, so if we are too close (<= 8000 cycles) to the
         * next cycle, simply skip it.
         */
-       if (next_tick - mfctl(16) <= 500)
+       if (next_tick - now <= 8000)
                next_tick += cpt;
        mtctl(next_tick, 16);
 
@@ -248,7 +249,7 @@ static int __init init_cr16_clocksource(void)
         * different sockets, so mark them unstable and lower rating on
         * multi-socket SMP systems.
         */
-       if (num_online_cpus() > 1) {
+       if (num_online_cpus() > 1 && !running_on_qemu) {
                int cpu;
                unsigned long cpu0_loc;
                cpu0_loc = per_cpu(cpu_data, 0).cpu_loc;
index 48f4139..cab32ee 100644 (file)
@@ -629,7 +629,12 @@ void __init mem_init(void)
 #endif
 
        mem_init_print_info(NULL);
-#ifdef CONFIG_DEBUG_KERNEL /* double-sanity-check paranoia */
+
+#if 0
+       /*
+        * Do not expose the virtual kernel memory layout to userspace.
+        * But keep code for debugging purposes.
+        */
        printk("virtual kernel memory layout:\n"
               "    vmalloc : 0x%px - 0x%px   (%4ld MB)\n"
               "    memory  : 0x%px - 0x%px   (%4ld MB)\n"
index ef6549e..26d5d2a 100644 (file)
@@ -101,7 +101,8 @@ $(addprefix $(obj)/,$(zlib-y)): \
 libfdt       := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
 libfdtheader := fdt.h libfdt.h libfdt_internal.h
 
-$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o): \
+$(addprefix $(obj)/,$(libfdt) libfdt-wrapper.o simpleboot.o epapr.o opal.o \
+       treeboot-akebono.o treeboot-currituck.o treeboot-iss4xx.o): \
        $(addprefix $(obj)/,$(libfdtheader))
 
 src-wlib-y := string.S crt0.S stdio.c decompress.c main.c \
index 0abeb0e..37671fe 100644 (file)
@@ -87,6 +87,9 @@ typedef struct {
        /* Number of bits in the mm_cpumask */
        atomic_t active_cpus;
 
+       /* Number of users of the external (Nest) MMU */
+       atomic_t copros;
+
        /* NPU NMMU context */
        struct npu_context *npu_context;
 
index 8eea90f..19b45ba 100644 (file)
@@ -47,9 +47,6 @@ extern void radix__flush_tlb_page_psize(struct mm_struct *mm, unsigned long vmad
 #endif
 extern void radix__flush_tlb_pwc(struct mmu_gather *tlb, unsigned long addr);
 extern void radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr);
-extern void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
-                                    unsigned long page_size);
-extern void radix__flush_tlb_lpid(unsigned long lpid);
 extern void radix__flush_tlb_all(void);
 extern void radix__flush_tlb_pte_p9_dd1(unsigned long old_pte, struct mm_struct *mm,
                                        unsigned long address);
index a2c5c95..2e2bacb 100644 (file)
@@ -203,6 +203,7 @@ static inline void cpu_feature_keys_init(void) { }
 #define CPU_FTR_DAWR                   LONG_ASM_CONST(0x0400000000000000)
 #define CPU_FTR_DABRX                  LONG_ASM_CONST(0x0800000000000000)
 #define CPU_FTR_PMAO_BUG               LONG_ASM_CONST(0x1000000000000000)
+#define CPU_FTR_P9_TLBIE_BUG           LONG_ASM_CONST(0x2000000000000000)
 #define CPU_FTR_POWER9_DD1             LONG_ASM_CONST(0x4000000000000000)
 #define CPU_FTR_POWER9_DD2_1           LONG_ASM_CONST(0x8000000000000000)
 
@@ -465,7 +466,7 @@ static inline void cpu_feature_keys_init(void) { }
            CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
            CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \
            CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300 | \
-           CPU_FTR_PKEY)
+           CPU_FTR_PKEY | CPU_FTR_P9_TLBIE_BUG)
 #define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \
                             (~CPU_FTR_SAO))
 #define CPU_FTRS_POWER9_DD2_0 CPU_FTRS_POWER9
index 511acfd..535add3 100644 (file)
@@ -52,7 +52,7 @@
 #define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)
 #define FW_FEATURE_PRRN                ASM_CONST(0x0000000200000000)
 #define FW_FEATURE_DRMEM_V2    ASM_CONST(0x0000000400000000)
-#define FW_FEATURE_DRC_INFO    ASM_CONST(0x0000000400000000)
+#define FW_FEATURE_DRC_INFO    ASM_CONST(0x0000000800000000)
 
 #ifndef __ASSEMBLY__
 
index 051b3d6..3a15b6d 100644 (file)
@@ -92,15 +92,23 @@ static inline void dec_mm_active_cpus(struct mm_struct *mm)
 static inline void mm_context_add_copro(struct mm_struct *mm)
 {
        /*
-        * On hash, should only be called once over the lifetime of
-        * the context, as we can't decrement the active cpus count
-        * and flush properly for the time being.
+        * If any copro is in use, increment the active CPU count
+        * in order to force TLB invalidations to be global as to
+        * propagate to the Nest MMU.
         */
-       inc_mm_active_cpus(mm);
+       if (atomic_inc_return(&mm->context.copros) == 1)
+               inc_mm_active_cpus(mm);
 }
 
 static inline void mm_context_remove_copro(struct mm_struct *mm)
 {
+       int c;
+
+       c = atomic_dec_if_positive(&mm->context.copros);
+
+       /* Detect imbalance between add and remove */
+       WARN_ON(c < 0);
+
        /*
         * Need to broadcast a global flush of the full mm before
         * decrementing active_cpus count, as the next TLBI may be
@@ -111,7 +119,7 @@ static inline void mm_context_remove_copro(struct mm_struct *mm)
         * for the time being. Invalidations will remain global if
         * used on hash.
         */
-       if (radix_enabled()) {
+       if (c == 0 && radix_enabled()) {
                flush_all_mm(mm);
                dec_mm_active_cpus(mm);
        }
index 5932481..9f42164 100644 (file)
@@ -81,6 +81,9 @@ static inline int numa_update_cpu_topology(bool cpus_locked)
 {
        return 0;
 }
+
+static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) {}
+
 #endif /* CONFIG_NUMA */
 
 #if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
index 945e2c2..8ca5d5b 100644 (file)
@@ -709,6 +709,9 @@ static __init void cpufeatures_cpu_quirks(void)
                cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD1;
        else if ((version & 0xffffefff) == 0x004e0201)
                cur_cpu_spec->cpu_features |= CPU_FTR_POWER9_DD2_1;
+
+       if ((version & 0xffff0000) == 0x004e0000)
+               cur_cpu_spec->cpu_features |= CPU_FTR_P9_TLBIE_BUG;
 }
 
 static void __init cpufeatures_setup_finished(void)
@@ -720,6 +723,9 @@ static void __init cpufeatures_setup_finished(void)
                cur_cpu_spec->cpu_features |= CPU_FTR_HVMODE;
        }
 
+       /* Make sure powerpc_base_platform is non-NULL */
+       powerpc_base_platform = cur_cpu_spec->platform;
+
        system_registers.lpcr = mfspr(SPRN_LPCR);
        system_registers.hfscr = mfspr(SPRN_HFSCR);
        system_registers.fscr = mfspr(SPRN_FSCR);
index beea218..0c0b66f 100644 (file)
@@ -384,7 +384,8 @@ static void *eeh_report_resume(void *data, void *userdata)
        eeh_pcid_put(dev);
        pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
 #ifdef CONFIG_PCI_IOV
-       eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
+       if (eeh_ops->notify_resume && eeh_dev_to_pdn(edev))
+               eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
 #endif
        return NULL;
 }
index 3ac87e5..1ecfd8f 100644 (file)
@@ -706,7 +706,7 @@ EXC_COMMON_BEGIN(bad_addr_slb)
        ld      r3, PACA_EXSLB+EX_DAR(r13)
        std     r3, _DAR(r1)
        beq     cr6, 2f
-       li      r10, 0x480              /* fix trap number for I-SLB miss */
+       li      r10, 0x481              /* fix trap number for I-SLB miss */
        std     r10, _TRAP(r1)
 2:     bl      save_nvgprs
        addi    r3, r1, STACK_FRAME_OVERHEAD
index f880388..061aa0f 100644 (file)
@@ -476,6 +476,14 @@ void force_external_irq_replay(void)
         */
        WARN_ON(!arch_irqs_disabled());
 
+       /*
+        * Interrupts must always be hard disabled before irq_happened is
+        * modified (to prevent lost update in case of interrupt between
+        * load and store).
+        */
+       __hard_irq_disable();
+       local_paca->irq_happened |= PACA_IRQ_HARD_DIS;
+
        /* Indicate in the PACA that we have an interrupt to replay */
        local_paca->irq_happened |= PACA_IRQ_EE;
 }
index adf044d..acf4b2e 100644 (file)
@@ -874,7 +874,6 @@ struct ibm_arch_vec __cacheline_aligned ibm_architecture_vec = {
                .mmu = 0,
                .hash_ext = 0,
                .radix_ext = 0,
-               .byte22 = OV5_FEAT(OV5_DRC_INFO),
        },
 
        /* option vector 6: IBM PAPR hints */
index 5a8bfee..04d0bbd 100644 (file)
@@ -788,7 +788,8 @@ static int register_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2))
                device_create_file(s, &dev_attr_pir);
 
-       if (cpu_has_feature(CPU_FTR_ARCH_206))
+       if (cpu_has_feature(CPU_FTR_ARCH_206) &&
+               !firmware_has_feature(FW_FEATURE_LPAR))
                device_create_file(s, &dev_attr_tscr);
 #endif /* CONFIG_PPC64 */
 
@@ -873,7 +874,8 @@ static int unregister_cpu_online(unsigned int cpu)
        if (cpu_has_feature(CPU_FTR_PPCAS_ARCH_V2))
                device_remove_file(s, &dev_attr_pir);
 
-       if (cpu_has_feature(CPU_FTR_ARCH_206))
+       if (cpu_has_feature(CPU_FTR_ARCH_206) &&
+               !firmware_has_feature(FW_FEATURE_LPAR))
                device_remove_file(s, &dev_attr_tscr);
 #endif /* CONFIG_PPC64 */
 
index 0c85481..5d9bafe 100644 (file)
@@ -157,6 +157,9 @@ static void kvmppc_radix_tlbie_page(struct kvm *kvm, unsigned long addr,
        asm volatile("ptesync": : :"memory");
        asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
                     : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG))
+               asm volatile(PPC_TLBIE_5(%0, %1, 0, 0, 1)
+                            : : "r" (addr), "r" (kvm->arch.lpid) : "memory");
        asm volatile("ptesync": : :"memory");
 }
 
@@ -195,6 +198,12 @@ static void kvmppc_pte_free(pte_t *ptep)
        kmem_cache_free(kvm_pte_cache, ptep);
 }
 
+/* Like pmd_huge() and pmd_large(), but works regardless of config options */
+static inline int pmd_is_leaf(pmd_t pmd)
+{
+       return !!(pmd_val(pmd) & _PAGE_PTE);
+}
+
 static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
                             unsigned int level, unsigned long mmu_seq)
 {
@@ -219,7 +228,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
        else
                new_pmd = pmd_alloc_one(kvm->mm, gpa);
 
-       if (level == 0 && !(pmd && pmd_present(*pmd)))
+       if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd)))
                new_ptep = kvmppc_pte_alloc();
 
        /* Check if we might have been invalidated; let the guest retry if so */
@@ -244,12 +253,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
                new_pmd = NULL;
        }
        pmd = pmd_offset(pud, gpa);
-       if (pmd_large(*pmd)) {
-               /* Someone else has instantiated a large page here; retry */
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-       if (level == 1 && !pmd_none(*pmd)) {
+       if (pmd_is_leaf(*pmd)) {
+               unsigned long lgpa = gpa & PMD_MASK;
+
+               /*
+                * If we raced with another CPU which has just put
+                * a 2MB pte in after we saw a pte page, try again.
+                */
+               if (level == 0 && !new_ptep) {
+                       ret = -EAGAIN;
+                       goto out_unlock;
+               }
+               /* Valid 2MB page here already, remove it */
+               old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
+                                             ~0UL, 0, lgpa, PMD_SHIFT);
+               kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT);
+               if (old & _PAGE_DIRTY) {
+                       unsigned long gfn = lgpa >> PAGE_SHIFT;
+                       struct kvm_memory_slot *memslot;
+                       memslot = gfn_to_memslot(kvm, gfn);
+                       if (memslot && memslot->dirty_bitmap)
+                               kvmppc_update_dirty_map(memslot,
+                                                       gfn, PMD_SIZE);
+               }
+       } else if (level == 1 && !pmd_none(*pmd)) {
                /*
                 * There's a page table page here, but we wanted
                 * to install a large page.  Tell the caller and let
@@ -412,28 +439,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        } else {
                page = pages[0];
                pfn = page_to_pfn(page);
-               if (PageHuge(page)) {
-                       page = compound_head(page);
-                       pte_size <<= compound_order(page);
+               if (PageCompound(page)) {
+                       pte_size <<= compound_order(compound_head(page));
                        /* See if we can insert a 2MB large-page PTE here */
                        if (pte_size >= PMD_SIZE &&
-                           (gpa & PMD_MASK & PAGE_MASK) ==
-                           (hva & PMD_MASK & PAGE_MASK)) {
+                           (gpa & (PMD_SIZE - PAGE_SIZE)) ==
+                           (hva & (PMD_SIZE - PAGE_SIZE))) {
                                level = 1;
                                pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1);
                        }
                }
                /* See if we can provide write access */
                if (writing) {
-                       /*
-                        * We assume gup_fast has set dirty on the host PTE.
-                        */
                        pgflags |= _PAGE_WRITE;
                } else {
                        local_irq_save(flags);
                        ptep = find_current_mm_pte(current->mm->pgd,
                                                   hva, NULL, NULL);
-                       if (ptep && pte_write(*ptep) && pte_dirty(*ptep))
+                       if (ptep && pte_write(*ptep))
                                pgflags |= _PAGE_WRITE;
                        local_irq_restore(flags);
                }
@@ -459,18 +482,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                pte = pfn_pte(pfn, __pgprot(pgflags));
                ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq);
        }
-       if (ret == 0 || ret == -EAGAIN)
-               ret = RESUME_GUEST;
 
        if (page) {
-               /*
-                * We drop pages[0] here, not page because page might
-                * have been set to the head page of a compound, but
-                * we have to drop the reference on the correct tail
-                * page to match the get inside gup()
-                */
-               put_page(pages[0]);
+               if (!ret && (pgflags & _PAGE_WRITE))
+                       set_page_dirty_lock(page);
+               put_page(page);
        }
+
+       if (ret == 0 || ret == -EAGAIN)
+               ret = RESUME_GUEST;
        return ret;
 }
 
@@ -644,7 +664,7 @@ void kvmppc_free_radix(struct kvm *kvm)
                                continue;
                        pmd = pmd_offset(pud, 0);
                        for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) {
-                               if (pmd_huge(*pmd)) {
+                               if (pmd_is_leaf(*pmd)) {
                                        pmd_clear(pmd);
                                        continue;
                                }
index 8970735..9cb9448 100644 (file)
@@ -2885,7 +2885,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
         */
        trace_hardirqs_on();
 
-       guest_enter();
+       guest_enter_irqoff();
 
        srcu_idx = srcu_read_lock(&vc->kvm->srcu);
 
@@ -2893,8 +2893,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
 
        srcu_read_unlock(&vc->kvm->srcu, srcu_idx);
 
-       guest_exit();
-
        trace_hardirqs_off();
        set_irq_happened(trap);
 
@@ -2937,6 +2935,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
        kvmppc_set_host_core(pcpu);
 
        local_irq_enable();
+       guest_exit();
 
        /* Let secondaries go back to the offline loop */
        for (i = 0; i < controlled_threads; ++i) {
@@ -3656,15 +3655,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
                goto up_out;
 
        psize = vma_kernel_pagesize(vma);
-       porder = __ilog2(psize);
 
        up_read(&current->mm->mmap_sem);
 
        /* We can handle 4k, 64k or 16M pages in the VRMA */
-       err = -EINVAL;
-       if (!(psize == 0x1000 || psize == 0x10000 ||
-             psize == 0x1000000))
-               goto out_srcu;
+       if (psize >= 0x1000000)
+               psize = 0x1000000;
+       else if (psize >= 0x10000)
+               psize = 0x10000;
+       else
+               psize = 0x1000;
+       porder = __ilog2(psize);
 
        senc = slb_pgsize_encoding(psize);
        kvm->arch.vrma_slb_v = senc | SLB_VSID_B_1T |
index 8888e62..e1c083f 100644 (file)
@@ -473,6 +473,17 @@ static void do_tlbies(struct kvm *kvm, unsigned long *rbvalues,
                        trace_tlbie(kvm->arch.lpid, 0, rbvalues[i],
                                kvm->arch.lpid, 0, 0, 0);
                }
+
+               if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
+                       /*
+                        * Need the extra ptesync to make sure we don't
+                        * re-order the tlbie
+                        */
+                       asm volatile("ptesync": : :"memory");
+                       asm volatile(PPC_TLBIE_5(%0,%1,0,0,0) : :
+                                    "r" (rbvalues[0]), "r" (kvm->arch.lpid));
+               }
+
                asm volatile("eieio; tlbsync; ptesync" : : : "memory");
                kvm->arch.tlbie_lock = 0;
        } else {
index f31f357..f86a202 100644 (file)
@@ -320,7 +320,6 @@ kvm_novcpu_exit:
        stw     r12, STACK_SLOT_TRAP(r1)
        bl      kvmhv_commence_exit
        nop
-       lwz     r12, STACK_SLOT_TRAP(r1)
        b       kvmhv_switch_to_host
 
 /*
@@ -1220,6 +1219,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
 
 secondary_too_late:
        li      r12, 0
+       stw     r12, STACK_SLOT_TRAP(r1)
        cmpdi   r4, 0
        beq     11f
        stw     r12, VCPU_TRAP(r4)
@@ -1557,13 +1557,31 @@ mc_cont:
        ptesync
 3:     stw     r5,VCPU_SLB_MAX(r9)
 
+       /* load host SLB entries */
+BEGIN_MMU_FTR_SECTION
+       b       0f
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
+       ld      r8,PACA_SLBSHADOWPTR(r13)
+
+       .rept   SLB_NUM_BOLTED
+       li      r3, SLBSHADOW_SAVEAREA
+       LDX_BE  r5, r8, r3
+       addi    r3, r3, 8
+       LDX_BE  r6, r8, r3
+       andis.  r7,r5,SLB_ESID_V@h
+       beq     1f
+       slbmte  r6,r5
+1:     addi    r8,r8,16
+       .endr
+0:
+
 guest_bypass:
+       stw     r12, STACK_SLOT_TRAP(r1)
        mr      r3, r12
        /* Increment exit count, poke other threads to exit */
        bl      kvmhv_commence_exit
        nop
        ld      r9, HSTATE_KVM_VCPU(r13)
-       lwz     r12, VCPU_TRAP(r9)
 
        /* Stop others sending VCPU interrupts to this physical CPU */
        li      r0, -1
@@ -1898,6 +1916,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_POWER9_DD1)
         * POWER7/POWER8 guest -> host partition switch code.
         * We don't have to lock against tlbies but we do
         * have to coordinate the hardware threads.
+        * Here STACK_SLOT_TRAP(r1) contains the trap number.
         */
 kvmhv_switch_to_host:
        /* Secondary threads wait for primary to do partition switch */
@@ -1950,12 +1969,12 @@ BEGIN_FTR_SECTION
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
        /* If HMI, call kvmppc_realmode_hmi_handler() */
+       lwz     r12, STACK_SLOT_TRAP(r1)
        cmpwi   r12, BOOK3S_INTERRUPT_HMI
        bne     27f
        bl      kvmppc_realmode_hmi_handler
        nop
        cmpdi   r3, 0
-       li      r12, BOOK3S_INTERRUPT_HMI
        /*
         * At this point kvmppc_realmode_hmi_handler may have resync-ed
         * the TB, and if it has, we must not subtract the guest timebase
@@ -2008,10 +2027,8 @@ BEGIN_FTR_SECTION
        lwz     r8, KVM_SPLIT_DO_RESTORE(r3)
        cmpwi   r8, 0
        beq     47f
-       stw     r12, STACK_SLOT_TRAP(r1)
        bl      kvmhv_p9_restore_lpcr
        nop
-       lwz     r12, STACK_SLOT_TRAP(r1)
        b       48f
 47:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
@@ -2019,23 +2036,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_300)
        mtspr   SPRN_LPCR,r8
        isync
 48:
-       /* load host SLB entries */
-BEGIN_MMU_FTR_SECTION
-       b       0f
-END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
-       ld      r8,PACA_SLBSHADOWPTR(r13)
-
-       .rept   SLB_NUM_BOLTED
-       li      r3, SLBSHADOW_SAVEAREA
-       LDX_BE  r5, r8, r3
-       addi    r3, r3, 8
-       LDX_BE  r6, r8, r3
-       andis.  r7,r5,SLB_ESID_V@h
-       beq     1f
-       slbmte  r6,r5
-1:     addi    r8,r8,16
-       .endr
-0:
 #ifdef CONFIG_KVM_BOOK3S_HV_EXIT_TIMING
        /* Finish timing, if we have a vcpu */
        ld      r4, HSTATE_KVM_VCPU(r13)
@@ -2049,6 +2049,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_RADIX)
        li      r0, KVM_GUEST_MODE_NONE
        stb     r0, HSTATE_IN_GUEST(r13)
 
+       lwz     r12, STACK_SLOT_TRAP(r1)        /* return trap # in r12 */
        ld      r0, SFS+PPC_LR_STKOFF(r1)
        addi    r1, r1, SFS
        mtlr    r0
index f0f5cd4..f9818d7 100644 (file)
@@ -188,7 +188,7 @@ static int xive_provision_queue(struct kvm_vcpu *vcpu, u8 prio)
        if (!qpage) {
                pr_err("Failed to allocate queue %d for VCPU %d\n",
                       prio, xc->server_num);
-               return -ENOMEM;;
+               return -ENOMEM;
        }
        memset(qpage, 0, 1 << xive->q_order);
 
index 403e642..52c2053 100644 (file)
@@ -1345,7 +1345,7 @@ static int kvmppc_emulate_mmio_vsx_loadstore(struct kvm_vcpu *vcpu,
 int kvmppc_handle_load128_by2x64(struct kvm_run *run, struct kvm_vcpu *vcpu,
                unsigned int rt, int is_default_endian)
 {
-       enum emulation_result emulated;
+       enum emulation_result emulated = EMULATE_DONE;
 
        while (vcpu->arch.mmio_vmx_copy_nums) {
                emulated = __kvmppc_handle_load(run, vcpu, rt, 8,
@@ -1608,7 +1608,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
        kvm_sigset_deactivate(vcpu);
 
+#ifdef CONFIG_ALTIVEC
 out:
+#endif
        vcpu_put(vcpu);
        return r;
 }
index 1604110..3f18036 100644 (file)
@@ -98,7 +98,7 @@ static void init_drconf_v2_cell(struct of_drconf_cell_v2 *dr_cell,
        dr_cell->base_addr = cpu_to_be64(lmb->base_addr);
        dr_cell->drc_index = cpu_to_be32(lmb->drc_index);
        dr_cell->aa_index = cpu_to_be32(lmb->aa_index);
-       dr_cell->flags = cpu_to_be32(lmb->flags);
+       dr_cell->flags = cpu_to_be32(drmem_lmb_flags(lmb));
 }
 
 static int drmem_update_dt_v2(struct device_node *memory,
@@ -121,7 +121,7 @@ static int drmem_update_dt_v2(struct device_node *memory,
                }
 
                if (prev_lmb->aa_index != lmb->aa_index ||
-                   prev_lmb->flags != lmb->flags)
+                   drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb))
                        lmb_sets++;
 
                prev_lmb = lmb;
@@ -150,7 +150,7 @@ static int drmem_update_dt_v2(struct device_node *memory,
                }
 
                if (prev_lmb->aa_index != lmb->aa_index ||
-                   prev_lmb->flags != lmb->flags) {
+                   drmem_lmb_flags(prev_lmb) != drmem_lmb_flags(lmb)) {
                        /* end of one set, start of another */
                        dr_cell->seq_lmbs = cpu_to_be32(seq_lmbs);
                        dr_cell++;
@@ -216,6 +216,8 @@ static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
        u32 i, n_lmbs;
 
        n_lmbs = of_read_number(prop++, 1);
+       if (n_lmbs == 0)
+               return;
 
        for (i = 0; i < n_lmbs; i++) {
                read_drconf_v1_cell(&lmb, &prop);
@@ -245,6 +247,8 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
        u32 i, j, lmb_sets;
 
        lmb_sets = of_read_number(prop++, 1);
+       if (lmb_sets == 0)
+               return;
 
        for (i = 0; i < lmb_sets; i++) {
                read_drconf_v2_cell(&dr_cell, &prop);
@@ -354,6 +358,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)
        struct drmem_lmb *lmb;
 
        drmem_info->n_lmbs = of_read_number(prop++, 1);
+       if (drmem_info->n_lmbs == 0)
+               return;
 
        drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb),
                                   GFP_KERNEL);
@@ -373,6 +379,8 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop)
        int lmb_index;
 
        lmb_sets = of_read_number(prop++, 1);
+       if (lmb_sets == 0)
+               return;
 
        /* first pass, calculate the number of LMBs */
        p = prop;
index a0675e9..656933c 100644 (file)
@@ -201,6 +201,15 @@ static inline unsigned long  ___tlbie(unsigned long vpn, int psize,
        return va;
 }
 
+static inline void fixup_tlbie(unsigned long vpn, int psize, int apsize, int ssize)
+{
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
+               /* Need the extra ptesync to ensure we don't reorder tlbie*/
+               asm volatile("ptesync": : :"memory");
+               ___tlbie(vpn, psize, apsize, ssize);
+       }
+}
+
 static inline void __tlbie(unsigned long vpn, int psize, int apsize, int ssize)
 {
        unsigned long rb;
@@ -278,6 +287,7 @@ static inline void tlbie(unsigned long vpn, int psize, int apsize,
                asm volatile("ptesync": : :"memory");
        } else {
                __tlbie(vpn, psize, apsize, ssize);
+               fixup_tlbie(vpn, psize, apsize, ssize);
                asm volatile("eieio; tlbsync; ptesync": : :"memory");
        }
        if (lock_tlbie && !use_local)
@@ -771,7 +781,7 @@ static void native_hpte_clear(void)
  */
 static void native_flush_hash_range(unsigned long number, int local)
 {
-       unsigned long vpn;
+       unsigned long vpn = 0;
        unsigned long hash, index, hidx, shift, slot;
        struct hash_pte *hptep;
        unsigned long hpte_v;
@@ -843,6 +853,10 @@ static void native_flush_hash_range(unsigned long number, int local)
                                __tlbie(vpn, psize, psize, ssize);
                        } pte_iterate_hashed_end();
                }
+               /*
+                * Just do one more with the last used values.
+                */
+               fixup_tlbie(vpn, psize, psize, ssize);
                asm volatile("eieio; tlbsync; ptesync":::"memory");
 
                if (lock_tlbie)
index 929d9ef..3f980ba 100644 (file)
@@ -173,6 +173,7 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
        mm_iommu_init(mm);
 #endif
        atomic_set(&mm->context.active_cpus, 0);
+       atomic_set(&mm->context.copros, 0);
 
        return 0;
 }
index 28c980e..adf469f 100644 (file)
@@ -481,6 +481,7 @@ void mmu_partition_table_set_entry(unsigned int lpid, unsigned long dw0,
                             "r" (TLBIEL_INVAL_SET_LPID), "r" (lpid));
                trace_tlbie(lpid, 0, TLBIEL_INVAL_SET_LPID, lpid, 2, 0, 0);
        }
+       /* do we need fixup here ?*/
        asm volatile("eieio; tlbsync; ptesync" : : : "memory");
 }
 EXPORT_SYMBOL_GPL(mmu_partition_table_set_entry);
index 71d1b19..a07f537 100644 (file)
@@ -119,6 +119,49 @@ static inline void __tlbie_pid(unsigned long pid, unsigned long ric)
        trace_tlbie(0, 0, rb, rs, ric, prs, r);
 }
 
+static inline void __tlbiel_va(unsigned long va, unsigned long pid,
+                              unsigned long ap, unsigned long ric)
+{
+       unsigned long rb,rs,prs,r;
+
+       rb = va & ~(PPC_BITMASK(52, 63));
+       rb |= ap << PPC_BITLSHIFT(58);
+       rs = pid << PPC_BITLSHIFT(31);
+       prs = 1; /* process scoped */
+       r = 1;   /* raidx format */
+
+       asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
+       trace_tlbie(0, 1, rb, rs, ric, prs, r);
+}
+
+static inline void __tlbie_va(unsigned long va, unsigned long pid,
+                             unsigned long ap, unsigned long ric)
+{
+       unsigned long rb,rs,prs,r;
+
+       rb = va & ~(PPC_BITMASK(52, 63));
+       rb |= ap << PPC_BITLSHIFT(58);
+       rs = pid << PPC_BITLSHIFT(31);
+       prs = 1; /* process scoped */
+       r = 1;   /* raidx format */
+
+       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
+                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
+       trace_tlbie(0, 0, rb, rs, ric, prs, r);
+}
+
+static inline void fixup_tlbie(void)
+{
+       unsigned long pid = 0;
+       unsigned long va = ((1UL << 52) - 1);
+
+       if (cpu_has_feature(CPU_FTR_P9_TLBIE_BUG)) {
+               asm volatile("ptesync": : :"memory");
+               __tlbie_va(va, pid, mmu_get_ap(MMU_PAGE_64K), RIC_FLUSH_TLB);
+       }
+}
+
 /*
  * We use 128 set in radix mode and 256 set in hpt mode.
  */
@@ -151,24 +194,25 @@ static inline void _tlbiel_pid(unsigned long pid, unsigned long ric)
 static inline void _tlbie_pid(unsigned long pid, unsigned long ric)
 {
        asm volatile("ptesync": : :"memory");
-       __tlbie_pid(pid, ric);
-       asm volatile("eieio; tlbsync; ptesync": : :"memory");
-}
 
-static inline void __tlbiel_va(unsigned long va, unsigned long pid,
-                              unsigned long ap, unsigned long ric)
-{
-       unsigned long rb,rs,prs,r;
-
-       rb = va & ~(PPC_BITMASK(52, 63));
-       rb |= ap << PPC_BITLSHIFT(58);
-       rs = pid << PPC_BITLSHIFT(31);
-       prs = 1; /* process scoped */
-       r = 1;   /* raidx format */
-
-       asm volatile(PPC_TLBIEL(%0, %4, %3, %2, %1)
-                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
-       trace_tlbie(0, 1, rb, rs, ric, prs, r);
+       /*
+        * Workaround the fact that the "ric" argument to __tlbie_pid
+        * must be a compile-time contraint to match the "i" constraint
+        * in the asm statement.
+        */
+       switch (ric) {
+       case RIC_FLUSH_TLB:
+               __tlbie_pid(pid, RIC_FLUSH_TLB);
+               break;
+       case RIC_FLUSH_PWC:
+               __tlbie_pid(pid, RIC_FLUSH_PWC);
+               break;
+       case RIC_FLUSH_ALL:
+       default:
+               __tlbie_pid(pid, RIC_FLUSH_ALL);
+       }
+       fixup_tlbie();
+       asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 
 static inline void __tlbiel_va_range(unsigned long start, unsigned long end,
@@ -203,22 +247,6 @@ static inline void _tlbiel_va_range(unsigned long start, unsigned long end,
        asm volatile("ptesync": : :"memory");
 }
 
-static inline void __tlbie_va(unsigned long va, unsigned long pid,
-                            unsigned long ap, unsigned long ric)
-{
-       unsigned long rb,rs,prs,r;
-
-       rb = va & ~(PPC_BITMASK(52, 63));
-       rb |= ap << PPC_BITLSHIFT(58);
-       rs = pid << PPC_BITLSHIFT(31);
-       prs = 1; /* process scoped */
-       r = 1;   /* raidx format */
-
-       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
-                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
-       trace_tlbie(0, 0, rb, rs, ric, prs, r);
-}
-
 static inline void __tlbie_va_range(unsigned long start, unsigned long end,
                                    unsigned long pid, unsigned long page_size,
                                    unsigned long psize)
@@ -237,6 +265,7 @@ static inline void _tlbie_va(unsigned long va, unsigned long pid,
 
        asm volatile("ptesync": : :"memory");
        __tlbie_va(va, pid, ap, ric);
+       fixup_tlbie();
        asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 
@@ -248,6 +277,7 @@ static inline void _tlbie_va_range(unsigned long start, unsigned long end,
        if (also_pwc)
                __tlbie_pid(pid, RIC_FLUSH_PWC);
        __tlbie_va_range(start, end, pid, page_size, psize);
+       fixup_tlbie();
        asm volatile("eieio; tlbsync; ptesync": : :"memory");
 }
 
@@ -311,6 +341,16 @@ void radix__local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmadd
 }
 EXPORT_SYMBOL(radix__local_flush_tlb_page);
 
+static bool mm_needs_flush_escalation(struct mm_struct *mm)
+{
+       /*
+        * P9 nest MMU has issues with the page walk cache
+        * caching PTEs and not flushing them properly when
+        * RIC = 0 for a PID/LPID invalidate
+        */
+       return atomic_read(&mm->context.copros) != 0;
+}
+
 #ifdef CONFIG_SMP
 void radix__flush_tlb_mm(struct mm_struct *mm)
 {
@@ -321,9 +361,12 @@ void radix__flush_tlb_mm(struct mm_struct *mm)
                return;
 
        preempt_disable();
-       if (!mm_is_thread_local(mm))
-               _tlbie_pid(pid, RIC_FLUSH_TLB);
-       else
+       if (!mm_is_thread_local(mm)) {
+               if (mm_needs_flush_escalation(mm))
+                       _tlbie_pid(pid, RIC_FLUSH_ALL);
+               else
+                       _tlbie_pid(pid, RIC_FLUSH_TLB);
+       } else
                _tlbiel_pid(pid, RIC_FLUSH_TLB);
        preempt_enable();
 }
@@ -435,10 +478,14 @@ void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        }
 
        if (full) {
-               if (local)
+               if (local) {
                        _tlbiel_pid(pid, RIC_FLUSH_TLB);
-               else
-                       _tlbie_pid(pid, RIC_FLUSH_TLB);
+               } else {
+                       if (mm_needs_flush_escalation(mm))
+                               _tlbie_pid(pid, RIC_FLUSH_ALL);
+                       else
+                               _tlbie_pid(pid, RIC_FLUSH_TLB);
+               }
        } else {
                bool hflush = false;
                unsigned long hstart, hend;
@@ -465,6 +512,7 @@ void radix__flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                        if (hflush)
                                __tlbie_va_range(hstart, hend, pid,
                                                HPAGE_PMD_SIZE, MMU_PAGE_2M);
+                       fixup_tlbie();
                        asm volatile("eieio; tlbsync; ptesync": : :"memory");
                }
        }
@@ -548,6 +596,9 @@ static inline void __radix__flush_tlb_range_psize(struct mm_struct *mm,
        }
 
        if (full) {
+               if (!local && mm_needs_flush_escalation(mm))
+                       also_pwc = true;
+
                if (local)
                        _tlbiel_pid(pid, also_pwc ? RIC_FLUSH_ALL : RIC_FLUSH_TLB);
                else
@@ -603,46 +654,6 @@ void radix__flush_tlb_collapsed_pmd(struct mm_struct *mm, unsigned long addr)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-void radix__flush_tlb_lpid_va(unsigned long lpid, unsigned long gpa,
-                             unsigned long page_size)
-{
-       unsigned long rb,rs,prs,r;
-       unsigned long ap;
-       unsigned long ric = RIC_FLUSH_TLB;
-
-       ap = mmu_get_ap(radix_get_mmu_psize(page_size));
-       rb = gpa & ~(PPC_BITMASK(52, 63));
-       rb |= ap << PPC_BITLSHIFT(58);
-       rs = lpid & ((1UL << 32) - 1);
-       prs = 0; /* process scoped */
-       r = 1;   /* raidx format */
-
-       asm volatile("ptesync": : :"memory");
-       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
-                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
-       asm volatile("eieio; tlbsync; ptesync": : :"memory");
-       trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
-}
-EXPORT_SYMBOL(radix__flush_tlb_lpid_va);
-
-void radix__flush_tlb_lpid(unsigned long lpid)
-{
-       unsigned long rb,rs,prs,r;
-       unsigned long ric = RIC_FLUSH_ALL;
-
-       rb = 0x2 << PPC_BITLSHIFT(53); /* IS = 2 */
-       rs = lpid & ((1UL << 32) - 1);
-       prs = 0; /* partition scoped */
-       r = 1;   /* raidx format */
-
-       asm volatile("ptesync": : :"memory");
-       asm volatile(PPC_TLBIE_5(%0, %4, %3, %2, %1)
-                    : : "r"(rb), "i"(r), "i"(prs), "i"(ric), "r"(rs) : "memory");
-       asm volatile("eieio; tlbsync; ptesync": : :"memory");
-       trace_tlbie(lpid, 0, rb, rs, ric, prs, r);
-}
-EXPORT_SYMBOL(radix__flush_tlb_lpid);
-
 void radix__flush_pmd_tlb_range(struct vm_area_struct *vma,
                                unsigned long start, unsigned long end)
 {
index 872d1f6..a9636d8 100644 (file)
@@ -327,6 +327,9 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,
                        BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
                        PPC_LWZ_OFFS(r_A, r_skb, offsetof(struct sk_buff, len));
                        break;
+               case BPF_LDX | BPF_W | BPF_ABS: /* A = *((u32 *)(seccomp_data + K)); */
+                       PPC_LWZ_OFFS(r_A, r_skb, K);
+                       break;
                case BPF_LDX | BPF_W | BPF_LEN: /* X = skb->len; */
                        PPC_LWZ_OFFS(r_X, r_skb, offsetof(struct sk_buff, len));
                        break;
index 0a34b0c..0ef3d95 100644 (file)
@@ -240,6 +240,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32
         *   goto out;
         */
        PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries));
+       PPC_RLWINM(b2p_index, b2p_index, 0, 0, 31);
        PPC_CMPLW(b2p_index, b2p[TMP_REG_1]);
        PPC_BCC(COND_GE, out);
 
index dd4c9b8..f6f55ab 100644 (file)
@@ -199,9 +199,11 @@ static void disable_nest_pmu_counters(void)
        const struct cpumask *l_cpumask;
 
        get_online_cpus();
-       for_each_online_node(nid) {
+       for_each_node_with_cpus(nid) {
                l_cpumask = cpumask_of_node(nid);
-               cpu = cpumask_first(l_cpumask);
+               cpu = cpumask_first_and(l_cpumask, cpu_online_mask);
+               if (cpu >= nr_cpu_ids)
+                       continue;
                opal_imc_counters_stop(OPAL_IMC_COUNTERS_NEST,
                                       get_hard_smp_processor_id(cpu));
        }
index 496e476..a6c92c7 100644 (file)
@@ -1854,7 +1854,7 @@ static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
        s64 rc;
 
        if (WARN_ON(!pdn || pdn->pe_number == IODA_INVALID_PE))
-               return -ENODEV;;
+               return -ENODEV;
 
        pe = &phb->ioda.pe_array[pdn->pe_number];
        if (pe->tce_bypass_enabled) {
index 4fb21e1..092715b 100644 (file)
@@ -80,6 +80,10 @@ static void pnv_setup_rfi_flush(void)
                if (np && of_property_read_bool(np, "disabled"))
                        enable--;
 
+               np = of_get_child_by_name(fw_features, "speculation-policy-favor-security");
+               if (np && of_property_read_bool(np, "disabled"))
+                       enable = 0;
+
                of_node_put(np);
                of_node_put(fw_features);
        }
index 372d7ad..1a52762 100644 (file)
@@ -482,7 +482,8 @@ static void pseries_setup_rfi_flush(void)
                if (types == L1D_FLUSH_NONE)
                        types = L1D_FLUSH_FALLBACK;
 
-               if (!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR))
+               if ((!(result.behaviour & H_CPU_BEHAV_L1D_FLUSH_PR)) ||
+                   (!(result.behaviour & H_CPU_BEHAV_FAVOUR_SECURITY)))
                        enable = false;
        } else {
                /* Default to fallback if case hcall is not available */
index d9c4c93..091f1d0 100644 (file)
@@ -356,7 +356,8 @@ static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio,
 
        rc = plpar_int_get_queue_info(0, target, prio, &esn_page, &esn_size);
        if (rc) {
-               pr_err("Error %lld getting queue info prio %d\n", rc, prio);
+               pr_err("Error %lld getting queue info CPU %d prio %d\n", rc,
+                      target, prio);
                rc = -EIO;
                goto fail;
        }
@@ -370,7 +371,8 @@ static int xive_spapr_configure_queue(u32 target, struct xive_q *q, u8 prio,
        /* Configure and enable the queue in HW */
        rc = plpar_int_set_queue_config(flags, target, prio, qpage_phys, order);
        if (rc) {
-               pr_err("Error %lld setting queue for prio %d\n", rc, prio);
+               pr_err("Error %lld setting queue for CPU %d prio %d\n", rc,
+                      target, prio);
                rc = -EIO;
        } else {
                q->qpage = qpage;
@@ -389,8 +391,8 @@ static int xive_spapr_setup_queue(unsigned int cpu, struct xive_cpu *xc,
        if (IS_ERR(qpage))
                return PTR_ERR(qpage);
 
-       return xive_spapr_configure_queue(cpu, q, prio, qpage,
-                                         xive_queue_shift);
+       return xive_spapr_configure_queue(get_hard_smp_processor_id(cpu),
+                                         q, prio, qpage, xive_queue_shift);
 }
 
 static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc,
@@ -399,10 +401,12 @@ static void xive_spapr_cleanup_queue(unsigned int cpu, struct xive_cpu *xc,
        struct xive_q *q = &xc->queue[prio];
        unsigned int alloc_order;
        long rc;
+       int hw_cpu = get_hard_smp_processor_id(cpu);
 
-       rc = plpar_int_set_queue_config(0, cpu, prio, 0, 0);
+       rc = plpar_int_set_queue_config(0, hw_cpu, prio, 0, 0);
        if (rc)
-               pr_err("Error %ld setting queue for prio %d\n", rc, prio);
+               pr_err("Error %ld setting queue for CPU %d prio %d\n", rc,
+                      hw_cpu, prio);
 
        alloc_order = xive_alloc_order(xive_queue_shift);
        free_pages((unsigned long)q->qpage, alloc_order);
index b6722c2..04807c7 100644 (file)
@@ -8,7 +8,6 @@ config RISCV
        select OF
        select OF_EARLY_FLATTREE
        select OF_IRQ
-       select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select ARCH_WANT_FRAME_POINTERS
        select CLONE_BACKWARDS
        select COMMON_CLK
@@ -20,7 +19,6 @@ config RISCV
        select GENERIC_STRNLEN_USER
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_ATOMIC64 if !64BIT || !RISCV_ISA_A
-       select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_DMA_API_DEBUG
@@ -34,7 +32,6 @@ config RISCV
        select HAVE_ARCH_TRACEHOOK
        select MODULES_USE_ELF_RELA if MODULES
        select THREAD_INFO_IN_TASK
-       select RISCV_IRQ_INTC
        select RISCV_TIMER
 
 config MMU
index c0319cb..5510366 100644 (file)
@@ -34,9 +34,9 @@
 #define wmb()          RISCV_FENCE(ow,ow)
 
 /* These barriers do not need to enforce ordering on devices, just memory. */
-#define smp_mb()       RISCV_FENCE(rw,rw)
-#define smp_rmb()      RISCV_FENCE(r,r)
-#define smp_wmb()      RISCV_FENCE(w,w)
+#define __smp_mb()     RISCV_FENCE(rw,rw)
+#define __smp_rmb()    RISCV_FENCE(r,r)
+#define __smp_wmb()    RISCV_FENCE(w,w)
 
 /*
  * This is a very specific barrier: it's currently only used in two places in
index 87fc045..56fa592 100644 (file)
@@ -172,6 +172,9 @@ ENTRY(handle_exception)
        move a1, sp /* pt_regs */
        tail do_IRQ
 1:
+       /* Exceptions run with interrupts enabled */
+       csrs sstatus, SR_SIE
+
        /* Handle syscalls */
        li t0, EXC_SYSCALL
        beq s4, t0, handle_syscall
@@ -198,8 +201,6 @@ handle_syscall:
         */
        addi s2, s2, 0x4
        REG_S s2, PT_SEPC(sp)
-       /* System calls run with interrupts enabled */
-       csrs sstatus, SR_SIE
        /* Trace syscalls, but only if requested by the user. */
        REG_L t0, TASK_TI_FLAGS(tp)
        andi t0, t0, _TIF_SYSCALL_TRACE
index 226eeb1..6e07ed3 100644 (file)
@@ -64,7 +64,7 @@ ENTRY(_start)
        /* Start the kernel */
        mv a0, s0
        mv a1, s1
-       call sbi_save
+       call parse_dtb
        tail start_kernel
 
 relocate:
index 09f7064..c11f40c 100644 (file)
@@ -144,7 +144,7 @@ asmlinkage void __init setup_vm(void)
 #endif
 }
 
-void __init sbi_save(unsigned int hartid, void *dtb)
+void __init parse_dtb(unsigned int hartid, void *dtb)
 {
        early_init_dt_scan(__va(dtb));
 }
index 65154ea..6c8ce15 100644 (file)
@@ -63,6 +63,7 @@ static inline int init_new_context(struct task_struct *tsk,
                                   _ASCE_USER_BITS | _ASCE_TYPE_SEGMENT;
                /* pgd_alloc() did not account this pmd */
                mm_inc_nr_pmds(mm);
+               mm_inc_nr_puds(mm);
        }
        crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
        return 0;
index 13a133a..a5621ea 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/processor.h>
 #include <asm/cache.h>
 #include <asm/ctl_reg.h>
+#include <asm/dwarf.h>
 #include <asm/errno.h>
 #include <asm/ptrace.h>
 #include <asm/thread_info.h>
@@ -230,7 +231,7 @@ _PIF_WORK   = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
        .hidden \name
        .type \name,@function
 \name:
-       .cfi_startproc
+       CFI_STARTPROC
 #ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
        exrl    0,0f
 #else
@@ -239,7 +240,7 @@ _PIF_WORK   = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
 #endif
        j       .
 0:     br      \reg
-       .cfi_endproc
+       CFI_ENDPROC
        .endm
 
        GEN_BR_THUNK __s390x_indirect_jump_r1use_r9,%r9,%r1
@@ -426,13 +427,13 @@ ENTRY(system_call)
        UPDATE_VTIME %r8,%r9,__LC_SYNC_ENTER_TIMER
        BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
        stmg    %r0,%r7,__PT_R0(%r11)
-       # clear user controlled register to prevent speculative use
-       xgr     %r0,%r0
        mvc     __PT_R8(64,%r11),__LC_SAVE_AREA_SYNC
        mvc     __PT_PSW(16,%r11),__LC_SVC_OLD_PSW
        mvc     __PT_INT_CODE(4,%r11),__LC_SVC_ILC
        stg     %r14,__PT_FLAGS(%r11)
 .Lsysc_do_svc:
+       # clear user controlled register to prevent speculative use
+       xgr     %r0,%r0
        # load address of system call table
        lg      %r10,__THREAD_sysc_table(%r13,%r12)
        llgh    %r8,__PT_INT_CODE+2(%r11)
@@ -1439,6 +1440,7 @@ cleanup_critical:
        stg     %r15,__LC_SYSTEM_TIMER
 0:     # update accounting time stamp
        mvc     __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+       BPENTER __TI_flags(%r12),_TIF_ISOLATE_BP
        # set up saved register r11
        lg      %r15,__LC_KERNEL_STACK
        la      %r9,STACK_FRAME_OVERHEAD(%r15)
index 69d7fcf..9aff72d 100644 (file)
@@ -2,8 +2,8 @@
 #include <linux/module.h>
 #include <asm/nospec-branch.h>
 
-int nospec_call_disable = IS_ENABLED(EXPOLINE_OFF);
-int nospec_return_disable = !IS_ENABLED(EXPOLINE_FULL);
+int nospec_call_disable = IS_ENABLED(CONFIG_EXPOLINE_OFF);
+int nospec_return_disable = !IS_ENABLED(CONFIG_EXPOLINE_FULL);
 
 static int __init nospectre_v2_setup_early(char *str)
 {
index 9c7d707..07c6e81 100644 (file)
 #include "trace.h"
 #include "trace-s390.h"
 
-
-static const intercept_handler_t instruction_handlers[256] = {
-       [0x01] = kvm_s390_handle_01,
-       [0x82] = kvm_s390_handle_lpsw,
-       [0x83] = kvm_s390_handle_diag,
-       [0xaa] = kvm_s390_handle_aa,
-       [0xae] = kvm_s390_handle_sigp,
-       [0xb2] = kvm_s390_handle_b2,
-       [0xb6] = kvm_s390_handle_stctl,
-       [0xb7] = kvm_s390_handle_lctl,
-       [0xb9] = kvm_s390_handle_b9,
-       [0xe3] = kvm_s390_handle_e3,
-       [0xe5] = kvm_s390_handle_e5,
-       [0xeb] = kvm_s390_handle_eb,
-};
-
 u8 kvm_s390_get_ilen(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
@@ -129,16 +113,39 @@ static int handle_validity(struct kvm_vcpu *vcpu)
 
 static int handle_instruction(struct kvm_vcpu *vcpu)
 {
-       intercept_handler_t handler;
-
        vcpu->stat.exit_instruction++;
        trace_kvm_s390_intercept_instruction(vcpu,
                                             vcpu->arch.sie_block->ipa,
                                             vcpu->arch.sie_block->ipb);
-       handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8];
-       if (handler)
-               return handler(vcpu);
-       return -EOPNOTSUPP;
+
+       switch (vcpu->arch.sie_block->ipa >> 8) {
+       case 0x01:
+               return kvm_s390_handle_01(vcpu);
+       case 0x82:
+               return kvm_s390_handle_lpsw(vcpu);
+       case 0x83:
+               return kvm_s390_handle_diag(vcpu);
+       case 0xaa:
+               return kvm_s390_handle_aa(vcpu);
+       case 0xae:
+               return kvm_s390_handle_sigp(vcpu);
+       case 0xb2:
+               return kvm_s390_handle_b2(vcpu);
+       case 0xb6:
+               return kvm_s390_handle_stctl(vcpu);
+       case 0xb7:
+               return kvm_s390_handle_lctl(vcpu);
+       case 0xb9:
+               return kvm_s390_handle_b9(vcpu);
+       case 0xe3:
+               return kvm_s390_handle_e3(vcpu);
+       case 0xe5:
+               return kvm_s390_handle_e5(vcpu);
+       case 0xeb:
+               return kvm_s390_handle_eb(vcpu);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static int inject_prog_on_prog_intercept(struct kvm_vcpu *vcpu)
index aabf46f..b04616b 100644 (file)
@@ -169,8 +169,15 @@ static int ckc_interrupts_enabled(struct kvm_vcpu *vcpu)
 
 static int ckc_irq_pending(struct kvm_vcpu *vcpu)
 {
-       if (vcpu->arch.sie_block->ckc >= kvm_s390_get_tod_clock_fast(vcpu->kvm))
+       const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
+       const u64 ckc = vcpu->arch.sie_block->ckc;
+
+       if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) {
+               if ((s64)ckc >= (s64)now)
+                       return 0;
+       } else if (ckc >= now) {
                return 0;
+       }
        return ckc_interrupts_enabled(vcpu);
 }
 
@@ -187,12 +194,6 @@ static int cpu_timer_irq_pending(struct kvm_vcpu *vcpu)
        return kvm_s390_get_cpu_timer(vcpu) >> 63;
 }
 
-static inline int is_ioirq(unsigned long irq_type)
-{
-       return ((irq_type >= IRQ_PEND_IO_ISC_7) &&
-               (irq_type <= IRQ_PEND_IO_ISC_0));
-}
-
 static uint64_t isc_to_isc_bits(int isc)
 {
        return (0x80 >> isc) << 24;
@@ -236,10 +237,15 @@ static inline int kvm_s390_gisa_tac_ipm_gisc(struct kvm_s390_gisa *gisa, u32 gis
        return test_and_clear_bit_inv(IPM_BIT_OFFSET + gisc, (unsigned long *) gisa);
 }
 
-static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
+static inline unsigned long pending_irqs_no_gisa(struct kvm_vcpu *vcpu)
 {
        return vcpu->kvm->arch.float_int.pending_irqs |
-               vcpu->arch.local_int.pending_irqs |
+               vcpu->arch.local_int.pending_irqs;
+}
+
+static inline unsigned long pending_irqs(struct kvm_vcpu *vcpu)
+{
+       return pending_irqs_no_gisa(vcpu) |
                kvm_s390_gisa_get_ipm(vcpu->kvm->arch.gisa) << IRQ_PEND_IO_ISC_7;
 }
 
@@ -337,7 +343,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu)
 
 static void set_intercept_indicators_io(struct kvm_vcpu *vcpu)
 {
-       if (!(pending_irqs(vcpu) & IRQ_PEND_IO_MASK))
+       if (!(pending_irqs_no_gisa(vcpu) & IRQ_PEND_IO_MASK))
                return;
        else if (psw_ioint_disabled(vcpu))
                kvm_s390_set_cpuflags(vcpu, CPUSTAT_IO_INT);
@@ -1011,24 +1017,6 @@ out:
        return rc;
 }
 
-typedef int (*deliver_irq_t)(struct kvm_vcpu *vcpu);
-
-static const deliver_irq_t deliver_irq_funcs[] = {
-       [IRQ_PEND_MCHK_EX]        = __deliver_machine_check,
-       [IRQ_PEND_MCHK_REP]       = __deliver_machine_check,
-       [IRQ_PEND_PROG]           = __deliver_prog,
-       [IRQ_PEND_EXT_EMERGENCY]  = __deliver_emergency_signal,
-       [IRQ_PEND_EXT_EXTERNAL]   = __deliver_external_call,
-       [IRQ_PEND_EXT_CLOCK_COMP] = __deliver_ckc,
-       [IRQ_PEND_EXT_CPU_TIMER]  = __deliver_cpu_timer,
-       [IRQ_PEND_RESTART]        = __deliver_restart,
-       [IRQ_PEND_SET_PREFIX]     = __deliver_set_prefix,
-       [IRQ_PEND_PFAULT_INIT]    = __deliver_pfault_init,
-       [IRQ_PEND_EXT_SERVICE]    = __deliver_service,
-       [IRQ_PEND_PFAULT_DONE]    = __deliver_pfault_done,
-       [IRQ_PEND_VIRTIO]         = __deliver_virtio,
-};
-
 /* Check whether an external call is pending (deliverable or not) */
 int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
 {
@@ -1066,13 +1054,19 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu)
 
 static u64 __calculate_sltime(struct kvm_vcpu *vcpu)
 {
-       u64 now, cputm, sltime = 0;
+       const u64 now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
+       const u64 ckc = vcpu->arch.sie_block->ckc;
+       u64 cputm, sltime = 0;
 
        if (ckc_interrupts_enabled(vcpu)) {
-               now = kvm_s390_get_tod_clock_fast(vcpu->kvm);
-               sltime = tod_to_ns(vcpu->arch.sie_block->ckc - now);
-               /* already expired or overflow? */
-               if (!sltime || vcpu->arch.sie_block->ckc <= now)
+               if (vcpu->arch.sie_block->gcr[0] & 0x0020000000000000ul) {
+                       if ((s64)now < (s64)ckc)
+                               sltime = tod_to_ns((s64)ckc - (s64)now);
+               } else if (now < ckc) {
+                       sltime = tod_to_ns(ckc - now);
+               }
+               /* already expired */
+               if (!sltime)
                        return 0;
                if (cpu_timer_interrupts_enabled(vcpu)) {
                        cputm = kvm_s390_get_cpu_timer(vcpu);
@@ -1192,7 +1186,6 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
 int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
-       deliver_irq_t func;
        int rc = 0;
        unsigned long irq_type;
        unsigned long irqs;
@@ -1212,16 +1205,57 @@ int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
        while ((irqs = deliverable_irqs(vcpu)) && !rc) {
                /* bits are in the reverse order of interrupt priority */
                irq_type = find_last_bit(&irqs, IRQ_PEND_COUNT);
-               if (is_ioirq(irq_type)) {
+               switch (irq_type) {
+               case IRQ_PEND_IO_ISC_0:
+               case IRQ_PEND_IO_ISC_1:
+               case IRQ_PEND_IO_ISC_2:
+               case IRQ_PEND_IO_ISC_3:
+               case IRQ_PEND_IO_ISC_4:
+               case IRQ_PEND_IO_ISC_5:
+               case IRQ_PEND_IO_ISC_6:
+               case IRQ_PEND_IO_ISC_7:
                        rc = __deliver_io(vcpu, irq_type);
-               } else {
-                       func = deliver_irq_funcs[irq_type];
-                       if (!func) {
-                               WARN_ON_ONCE(func == NULL);
-                               clear_bit(irq_type, &li->pending_irqs);
-                               continue;
-                       }
-                       rc = func(vcpu);
+                       break;
+               case IRQ_PEND_MCHK_EX:
+               case IRQ_PEND_MCHK_REP:
+                       rc = __deliver_machine_check(vcpu);
+                       break;
+               case IRQ_PEND_PROG:
+                       rc = __deliver_prog(vcpu);
+                       break;
+               case IRQ_PEND_EXT_EMERGENCY:
+                       rc = __deliver_emergency_signal(vcpu);
+                       break;
+               case IRQ_PEND_EXT_EXTERNAL:
+                       rc = __deliver_external_call(vcpu);
+                       break;
+               case IRQ_PEND_EXT_CLOCK_COMP:
+                       rc = __deliver_ckc(vcpu);
+                       break;
+               case IRQ_PEND_EXT_CPU_TIMER:
+                       rc = __deliver_cpu_timer(vcpu);
+                       break;
+               case IRQ_PEND_RESTART:
+                       rc = __deliver_restart(vcpu);
+                       break;
+               case IRQ_PEND_SET_PREFIX:
+                       rc = __deliver_set_prefix(vcpu);
+                       break;
+               case IRQ_PEND_PFAULT_INIT:
+                       rc = __deliver_pfault_init(vcpu);
+                       break;
+               case IRQ_PEND_EXT_SERVICE:
+                       rc = __deliver_service(vcpu);
+                       break;
+               case IRQ_PEND_PFAULT_DONE:
+                       rc = __deliver_pfault_done(vcpu);
+                       break;
+               case IRQ_PEND_VIRTIO:
+                       rc = __deliver_virtio(vcpu);
+                       break;
+               default:
+                       WARN_ONCE(1, "Unknown pending irq type %ld", irq_type);
+                       clear_bit(irq_type, &li->pending_irqs);
                }
        }
 
@@ -1701,7 +1735,8 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type)
                kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_STOP_INT);
                break;
        case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX:
-               kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
+               if (!(type & KVM_S390_INT_IO_AI_MASK && kvm->arch.gisa))
+                       kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_IO_INT);
                break;
        default:
                kvm_s390_set_cpuflags(dst_vcpu, CPUSTAT_EXT_INT);
index ba4c709..339ac09 100644 (file)
@@ -86,6 +86,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "deliver_prefix_signal", VCPU_STAT(deliver_prefix_signal) },
        { "deliver_restart_signal", VCPU_STAT(deliver_restart_signal) },
        { "deliver_program_interruption", VCPU_STAT(deliver_program_int) },
+       { "deliver_io_interrupt", VCPU_STAT(deliver_io_int) },
        { "exit_wait_state", VCPU_STAT(exit_wait_state) },
        { "instruction_epsw", VCPU_STAT(instruction_epsw) },
        { "instruction_gs", VCPU_STAT(instruction_gs) },
@@ -179,6 +180,28 @@ int kvm_arch_hardware_enable(void)
 static void kvm_gmap_notifier(struct gmap *gmap, unsigned long start,
                              unsigned long end);
 
+static void kvm_clock_sync_scb(struct kvm_s390_sie_block *scb, u64 delta)
+{
+       u8 delta_idx = 0;
+
+       /*
+        * The TOD jumps by delta, we have to compensate this by adding
+        * -delta to the epoch.
+        */
+       delta = -delta;
+
+       /* sign-extension - we're adding to signed values below */
+       if ((s64)delta < 0)
+               delta_idx = -1;
+
+       scb->epoch += delta;
+       if (scb->ecd & ECD_MEF) {
+               scb->epdx += delta_idx;
+               if (scb->epoch < delta)
+                       scb->epdx += 1;
+       }
+}
+
 /*
  * This callback is executed during stop_machine(). All CPUs are therefore
  * temporarily stopped. In order not to change guest behavior, we have to
@@ -194,13 +217,17 @@ static int kvm_clock_sync(struct notifier_block *notifier, unsigned long val,
        unsigned long long *delta = v;
 
        list_for_each_entry(kvm, &vm_list, vm_list) {
-               kvm->arch.epoch -= *delta;
                kvm_for_each_vcpu(i, vcpu, kvm) {
-                       vcpu->arch.sie_block->epoch -= *delta;
+                       kvm_clock_sync_scb(vcpu->arch.sie_block, *delta);
+                       if (i == 0) {
+                               kvm->arch.epoch = vcpu->arch.sie_block->epoch;
+                               kvm->arch.epdx = vcpu->arch.sie_block->epdx;
+                       }
                        if (vcpu->arch.cputm_enabled)
                                vcpu->arch.cputm_start += *delta;
                        if (vcpu->arch.vsie_block)
-                               vcpu->arch.vsie_block->epoch -= *delta;
+                               kvm_clock_sync_scb(vcpu->arch.vsie_block,
+                                                  *delta);
                }
        }
        return NOTIFY_OK;
@@ -902,12 +929,9 @@ static int kvm_s390_set_tod_ext(struct kvm *kvm, struct kvm_device_attr *attr)
        if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
                return -EFAULT;
 
-       if (test_kvm_facility(kvm, 139))
-               kvm_s390_set_tod_clock_ext(kvm, &gtod);
-       else if (gtod.epoch_idx == 0)
-               kvm_s390_set_tod_clock(kvm, gtod.tod);
-       else
+       if (!test_kvm_facility(kvm, 139) && gtod.epoch_idx)
                return -EINVAL;
+       kvm_s390_set_tod_clock(kvm, &gtod);
 
        VM_EVENT(kvm, 3, "SET: TOD extension: 0x%x, TOD base: 0x%llx",
                gtod.epoch_idx, gtod.tod);
@@ -932,13 +956,14 @@ static int kvm_s390_set_tod_high(struct kvm *kvm, struct kvm_device_attr *attr)
 
 static int kvm_s390_set_tod_low(struct kvm *kvm, struct kvm_device_attr *attr)
 {
-       u64 gtod;
+       struct kvm_s390_vm_tod_clock gtod = { 0 };
 
-       if (copy_from_user(&gtod, (void __user *)attr->addr, sizeof(gtod)))
+       if (copy_from_user(&gtod.tod, (void __user *)attr->addr,
+                          sizeof(gtod.tod)))
                return -EFAULT;
 
-       kvm_s390_set_tod_clock(kvm, gtod);
-       VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod);
+       kvm_s390_set_tod_clock(kvm, &gtod);
+       VM_EVENT(kvm, 3, "SET: TOD base: 0x%llx", gtod.tod);
        return 0;
 }
 
@@ -2122,6 +2147,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu)
                /* we still need the basic sca for the ipte control */
                vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
                vcpu->arch.sie_block->scaol = (__u32)(__u64)sca;
+               return;
        }
        read_lock(&vcpu->kvm->arch.sca_lock);
        if (vcpu->kvm->arch.use_esca) {
@@ -2389,6 +2415,7 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
        mutex_lock(&vcpu->kvm->lock);
        preempt_disable();
        vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
+       vcpu->arch.sie_block->epdx = vcpu->kvm->arch.epdx;
        preempt_enable();
        mutex_unlock(&vcpu->kvm->lock);
        if (!kvm_is_ucontrol(vcpu->kvm)) {
@@ -3021,8 +3048,8 @@ retry:
        return 0;
 }
 
-void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
-                                const struct kvm_s390_vm_tod_clock *gtod)
+void kvm_s390_set_tod_clock(struct kvm *kvm,
+                           const struct kvm_s390_vm_tod_clock *gtod)
 {
        struct kvm_vcpu *vcpu;
        struct kvm_s390_tod_clock_ext htod;
@@ -3034,10 +3061,12 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
        get_tod_clock_ext((char *)&htod);
 
        kvm->arch.epoch = gtod->tod - htod.tod;
-       kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
-
-       if (kvm->arch.epoch > gtod->tod)
-               kvm->arch.epdx -= 1;
+       kvm->arch.epdx = 0;
+       if (test_kvm_facility(kvm, 139)) {
+               kvm->arch.epdx = gtod->epoch_idx - htod.epoch_idx;
+               if (kvm->arch.epoch > gtod->tod)
+                       kvm->arch.epdx -= 1;
+       }
 
        kvm_s390_vcpu_block_all(kvm);
        kvm_for_each_vcpu(i, vcpu, kvm) {
@@ -3050,22 +3079,6 @@ void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
        mutex_unlock(&kvm->lock);
 }
 
-void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod)
-{
-       struct kvm_vcpu *vcpu;
-       int i;
-
-       mutex_lock(&kvm->lock);
-       preempt_disable();
-       kvm->arch.epoch = tod - get_tod_clock();
-       kvm_s390_vcpu_block_all(kvm);
-       kvm_for_each_vcpu(i, vcpu, kvm)
-               vcpu->arch.sie_block->epoch = kvm->arch.epoch;
-       kvm_s390_vcpu_unblock_all(kvm);
-       preempt_enable();
-       mutex_unlock(&kvm->lock);
-}
-
 /**
  * kvm_arch_fault_in_page - fault-in guest page if necessary
  * @vcpu: The corresponding virtual cpu
index bd31b37..f55ac0e 100644 (file)
@@ -19,8 +19,6 @@
 #include <asm/processor.h>
 #include <asm/sclp.h>
 
-typedef int (*intercept_handler_t)(struct kvm_vcpu *vcpu);
-
 /* Transactional Memory Execution related macros */
 #define IS_TE_ENABLED(vcpu)    ((vcpu->arch.sie_block->ecb & ECB_TE))
 #define TDB_FORMAT1            1
@@ -283,9 +281,8 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu);
 int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu);
 
 /* implemented in kvm-s390.c */
-void kvm_s390_set_tod_clock_ext(struct kvm *kvm,
-                                const struct kvm_s390_vm_tod_clock *gtod);
-void kvm_s390_set_tod_clock(struct kvm *kvm, u64 tod);
+void kvm_s390_set_tod_clock(struct kvm *kvm,
+                           const struct kvm_s390_vm_tod_clock *gtod);
 long kvm_arch_fault_in_page(struct kvm_vcpu *vcpu, gpa_t gpa, int writable);
 int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long addr);
 int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr);
index c4c4e15..f0b4185 100644 (file)
@@ -85,9 +85,10 @@ int kvm_s390_handle_e3(struct kvm_vcpu *vcpu)
 /* Handle SCK (SET CLOCK) interception */
 static int handle_set_clock(struct kvm_vcpu *vcpu)
 {
+       struct kvm_s390_vm_tod_clock gtod = { 0 };
        int rc;
        u8 ar;
-       u64 op2, val;
+       u64 op2;
 
        vcpu->stat.instruction_sck++;
 
@@ -97,12 +98,12 @@ static int handle_set_clock(struct kvm_vcpu *vcpu)
        op2 = kvm_s390_get_base_disp_s(vcpu, &ar);
        if (op2 & 7)    /* Operand must be on a doubleword boundary */
                return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-       rc = read_guest(vcpu, op2, ar, &val, sizeof(val));
+       rc = read_guest(vcpu, op2, ar, &gtod.tod, sizeof(gtod.tod));
        if (rc)
                return kvm_s390_inject_prog_cond(vcpu, rc);
 
-       VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", val);
-       kvm_s390_set_tod_clock(vcpu->kvm, val);
+       VCPU_EVENT(vcpu, 3, "SCK: setting guest TOD to 0x%llx", gtod.tod);
+       kvm_s390_set_tod_clock(vcpu->kvm, &gtod);
 
        kvm_s390_set_psw_cc(vcpu, 0);
        return 0;
@@ -795,55 +796,60 @@ out:
        return rc;
 }
 
-static const intercept_handler_t b2_handlers[256] = {
-       [0x02] = handle_stidp,
-       [0x04] = handle_set_clock,
-       [0x10] = handle_set_prefix,
-       [0x11] = handle_store_prefix,
-       [0x12] = handle_store_cpu_address,
-       [0x14] = kvm_s390_handle_vsie,
-       [0x21] = handle_ipte_interlock,
-       [0x29] = handle_iske,
-       [0x2a] = handle_rrbe,
-       [0x2b] = handle_sske,
-       [0x2c] = handle_test_block,
-       [0x30] = handle_io_inst,
-       [0x31] = handle_io_inst,
-       [0x32] = handle_io_inst,
-       [0x33] = handle_io_inst,
-       [0x34] = handle_io_inst,
-       [0x35] = handle_io_inst,
-       [0x36] = handle_io_inst,
-       [0x37] = handle_io_inst,
-       [0x38] = handle_io_inst,
-       [0x39] = handle_io_inst,
-       [0x3a] = handle_io_inst,
-       [0x3b] = handle_io_inst,
-       [0x3c] = handle_io_inst,
-       [0x50] = handle_ipte_interlock,
-       [0x56] = handle_sthyi,
-       [0x5f] = handle_io_inst,
-       [0x74] = handle_io_inst,
-       [0x76] = handle_io_inst,
-       [0x7d] = handle_stsi,
-       [0xb1] = handle_stfl,
-       [0xb2] = handle_lpswe,
-};
-
 int kvm_s390_handle_b2(struct kvm_vcpu *vcpu)
 {
-       intercept_handler_t handler;
-
-       /*
-        * A lot of B2 instructions are priviledged. Here we check for
-        * the privileged ones, that we can handle in the kernel.
-        * Anything else goes to userspace.
-        */
-       handler = b2_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-       if (handler)
-               return handler(vcpu);
-
-       return -EOPNOTSUPP;
+       switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+       case 0x02:
+               return handle_stidp(vcpu);
+       case 0x04:
+               return handle_set_clock(vcpu);
+       case 0x10:
+               return handle_set_prefix(vcpu);
+       case 0x11:
+               return handle_store_prefix(vcpu);
+       case 0x12:
+               return handle_store_cpu_address(vcpu);
+       case 0x14:
+               return kvm_s390_handle_vsie(vcpu);
+       case 0x21:
+       case 0x50:
+               return handle_ipte_interlock(vcpu);
+       case 0x29:
+               return handle_iske(vcpu);
+       case 0x2a:
+               return handle_rrbe(vcpu);
+       case 0x2b:
+               return handle_sske(vcpu);
+       case 0x2c:
+               return handle_test_block(vcpu);
+       case 0x30:
+       case 0x31:
+       case 0x32:
+       case 0x33:
+       case 0x34:
+       case 0x35:
+       case 0x36:
+       case 0x37:
+       case 0x38:
+       case 0x39:
+       case 0x3a:
+       case 0x3b:
+       case 0x3c:
+       case 0x5f:
+       case 0x74:
+       case 0x76:
+               return handle_io_inst(vcpu);
+       case 0x56:
+               return handle_sthyi(vcpu);
+       case 0x7d:
+               return handle_stsi(vcpu);
+       case 0xb1:
+               return handle_stfl(vcpu);
+       case 0xb2:
+               return handle_lpswe(vcpu);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static int handle_epsw(struct kvm_vcpu *vcpu)
@@ -1105,25 +1111,22 @@ static int handle_essa(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static const intercept_handler_t b9_handlers[256] = {
-       [0x8a] = handle_ipte_interlock,
-       [0x8d] = handle_epsw,
-       [0x8e] = handle_ipte_interlock,
-       [0x8f] = handle_ipte_interlock,
-       [0xab] = handle_essa,
-       [0xaf] = handle_pfmf,
-};
-
 int kvm_s390_handle_b9(struct kvm_vcpu *vcpu)
 {
-       intercept_handler_t handler;
-
-       /* This is handled just as for the B2 instructions. */
-       handler = b9_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-       if (handler)
-               return handler(vcpu);
-
-       return -EOPNOTSUPP;
+       switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+       case 0x8a:
+       case 0x8e:
+       case 0x8f:
+               return handle_ipte_interlock(vcpu);
+       case 0x8d:
+               return handle_epsw(vcpu);
+       case 0xab:
+               return handle_essa(vcpu);
+       case 0xaf:
+               return handle_pfmf(vcpu);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu)
@@ -1271,22 +1274,20 @@ static int handle_stctg(struct kvm_vcpu *vcpu)
        return rc ? kvm_s390_inject_prog_cond(vcpu, rc) : 0;
 }
 
-static const intercept_handler_t eb_handlers[256] = {
-       [0x2f] = handle_lctlg,
-       [0x25] = handle_stctg,
-       [0x60] = handle_ri,
-       [0x61] = handle_ri,
-       [0x62] = handle_ri,
-};
-
 int kvm_s390_handle_eb(struct kvm_vcpu *vcpu)
 {
-       intercept_handler_t handler;
-
-       handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff];
-       if (handler)
-               return handler(vcpu);
-       return -EOPNOTSUPP;
+       switch (vcpu->arch.sie_block->ipb & 0x000000ff) {
+       case 0x25:
+               return handle_stctg(vcpu);
+       case 0x2f:
+               return handle_lctlg(vcpu);
+       case 0x60:
+       case 0x61:
+       case 0x62:
+               return handle_ri(vcpu);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static int handle_tprot(struct kvm_vcpu *vcpu)
@@ -1346,10 +1347,12 @@ out_unlock:
 
 int kvm_s390_handle_e5(struct kvm_vcpu *vcpu)
 {
-       /* For e5xx... instructions we only handle TPROT */
-       if ((vcpu->arch.sie_block->ipa & 0x00ff) == 0x01)
+       switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+       case 0x01:
                return handle_tprot(vcpu);
-       return -EOPNOTSUPP;
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 static int handle_sckpf(struct kvm_vcpu *vcpu)
@@ -1380,17 +1383,14 @@ static int handle_ptff(struct kvm_vcpu *vcpu)
        return 0;
 }
 
-static const intercept_handler_t x01_handlers[256] = {
-       [0x04] = handle_ptff,
-       [0x07] = handle_sckpf,
-};
-
 int kvm_s390_handle_01(struct kvm_vcpu *vcpu)
 {
-       intercept_handler_t handler;
-
-       handler = x01_handlers[vcpu->arch.sie_block->ipa & 0x00ff];
-       if (handler)
-               return handler(vcpu);
-       return -EOPNOTSUPP;
+       switch (vcpu->arch.sie_block->ipa & 0x00ff) {
+       case 0x04:
+               return handle_ptff(vcpu);
+       case 0x07:
+               return handle_sckpf(vcpu);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
index ec77270..8961e39 100644 (file)
@@ -821,6 +821,7 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
 {
        struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
        struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
+       int guest_bp_isolation;
        int rc;
 
        handle_last_fault(vcpu, vsie_page);
@@ -831,6 +832,20 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
                s390_handle_mcck();
 
        srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
+
+       /* save current guest state of bp isolation override */
+       guest_bp_isolation = test_thread_flag(TIF_ISOLATE_BP_GUEST);
+
+       /*
+        * The guest is running with BPBC, so we have to force it on for our
+        * nested guest. This is done by enabling BPBC globally, so the BPBC
+        * control in the SCB (which the nested guest can modify) is simply
+        * ignored.
+        */
+       if (test_kvm_facility(vcpu->kvm, 82) &&
+           vcpu->arch.sie_block->fpf & FPF_BPBC)
+               set_thread_flag(TIF_ISOLATE_BP_GUEST);
+
        local_irq_disable();
        guest_enter_irqoff();
        local_irq_enable();
@@ -840,6 +855,11 @@ static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
        local_irq_disable();
        guest_exit_irqoff();
        local_irq_enable();
+
+       /* restore guest state for bp isolation override */
+       if (!guest_bp_isolation)
+               clear_thread_flag(TIF_ISOLATE_BP_GUEST);
+
        vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
 
        if (rc == -EINTR) {
index 715def0..01d0f7f 100644 (file)
@@ -1 +1,3 @@
-obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+ifneq ($(CONFIG_BUILTIN_DTB_SOURCE),"")
+obj-y += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
+endif
index 6bf594a..8767e45 100644 (file)
@@ -430,6 +430,8 @@ config SPARC_LEON
        depends on SPARC32
        select USB_EHCI_BIG_ENDIAN_MMIO
        select USB_EHCI_BIG_ENDIAN_DESC
+       select USB_UHCI_BIG_ENDIAN_MMIO
+       select USB_UHCI_BIG_ENDIAN_DESC
        ---help---
          If you say Y here if you are running on a SPARC-LEON processor.
          The LEON processor is a synthesizable VHDL model of the
index 6f17528..ea53e41 100644 (file)
@@ -9,10 +9,14 @@
 void do_BUG(const char *file, int line);
 #define BUG() do {                                     \
        do_BUG(__FILE__, __LINE__);                     \
+       barrier_before_unreachable();                   \
        __builtin_trap();                               \
 } while (0)
 #else
-#define BUG()          __builtin_trap()
+#define BUG() do {                                     \
+       barrier_before_unreachable();                   \
+       __builtin_trap();                               \
+} while (0)
 #endif
 
 #define HAVE_ARCH_BUG
index 847ddff..b5cfab7 100644 (file)
@@ -163,13 +163,10 @@ static void tlb_batch_pmd_scan(struct mm_struct *mm, unsigned long vaddr,
        pte_unmap(pte);
 }
 
-void set_pmd_at(struct mm_struct *mm, unsigned long addr,
-               pmd_t *pmdp, pmd_t pmd)
-{
-       pmd_t orig = *pmdp;
-
-       *pmdp = pmd;
 
+static void __set_pmd_acct(struct mm_struct *mm, unsigned long addr,
+                          pmd_t orig, pmd_t pmd)
+{
        if (mm == &init_mm)
                return;
 
@@ -219,6 +216,15 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
        }
 }
 
+void set_pmd_at(struct mm_struct *mm, unsigned long addr,
+               pmd_t *pmdp, pmd_t pmd)
+{
+       pmd_t orig = *pmdp;
+
+       *pmdp = pmd;
+       __set_pmd_acct(mm, addr, orig, pmd);
+}
+
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmdp, pmd_t pmd)
 {
@@ -227,6 +233,7 @@ static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
        do {
                old = *pmdp;
        } while (cmpxchg64(&pmdp->pmd, old.pmd, pmd.pmd) != old.pmd);
+       __set_pmd_acct(vma->vm_mm, address, old, pmd);
 
        return old;
 }
index aff152c..5a82bac 100644 (file)
@@ -1,6 +1,7 @@
 boot/compressed/vmlinux
 tools/test_get_len
 tools/insn_sanity
+tools/insn_decoder_test
 purgatory/kexec-purgatory.c
 purgatory/purgatory.ro
 
index 09c599e..0fa71a7 100644 (file)
@@ -423,12 +423,6 @@ config X86_MPPARSE
          For old smp systems that do not have proper acpi support. Newer systems
          (esp with 64bit cpus) with acpi support, MADT and DSDT will override it
 
-config X86_BIGSMP
-       bool "Support for big SMP systems with more than 8 CPUs"
-       depends on X86_32 && SMP
-       ---help---
-         This option is needed for the systems that have more than 8 CPUs
-
 config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
@@ -461,6 +455,12 @@ config INTEL_RDT
          Say N if unsure.
 
 if X86_32
+config X86_BIGSMP
+       bool "Support for big SMP systems with more than 8 CPUs"
+       depends on SMP
+       ---help---
+         This option is needed for the systems that have more than 8 CPUs
+
 config X86_EXTENDED_PLATFORM
        bool "Support for extended (non-PC) x86 platforms"
        default y
@@ -950,25 +950,66 @@ config MAXSMP
          Enable maximum number of CPUS and NUMA Nodes for this architecture.
          If unsure, say N.
 
+#
+# The maximum number of CPUs supported:
+#
+# The main config value is NR_CPUS, which defaults to NR_CPUS_DEFAULT,
+# and which can be configured interactively in the
+# [NR_CPUS_RANGE_BEGIN ... NR_CPUS_RANGE_END] range.
+#
+# The ranges are different on 32-bit and 64-bit kernels, depending on
+# hardware capabilities and scalability features of the kernel.
+#
+# ( If MAXSMP is enabled we just use the highest possible value and disable
+#   interactive configuration. )
+#
+
+config NR_CPUS_RANGE_BEGIN
+       int
+       default NR_CPUS_RANGE_END if MAXSMP
+       default    1 if !SMP
+       default    2
+
+config NR_CPUS_RANGE_END
+       int
+       depends on X86_32
+       default   64 if  SMP &&  X86_BIGSMP
+       default    8 if  SMP && !X86_BIGSMP
+       default    1 if !SMP
+
+config NR_CPUS_RANGE_END
+       int
+       depends on X86_64
+       default 8192 if  SMP && ( MAXSMP ||  CPUMASK_OFFSTACK)
+       default  512 if  SMP && (!MAXSMP && !CPUMASK_OFFSTACK)
+       default    1 if !SMP
+
+config NR_CPUS_DEFAULT
+       int
+       depends on X86_32
+       default   32 if  X86_BIGSMP
+       default    8 if  SMP
+       default    1 if !SMP
+
+config NR_CPUS_DEFAULT
+       int
+       depends on X86_64
+       default 8192 if  MAXSMP
+       default   64 if  SMP
+       default    1 if !SMP
+
 config NR_CPUS
        int "Maximum number of CPUs" if SMP && !MAXSMP
-       range 2 8 if SMP && X86_32 && !X86_BIGSMP
-       range 2 64 if SMP && X86_32 && X86_BIGSMP
-       range 2 512 if SMP && !MAXSMP && !CPUMASK_OFFSTACK && X86_64
-       range 2 8192 if SMP && !MAXSMP && CPUMASK_OFFSTACK && X86_64
-       default "1" if !SMP
-       default "8192" if MAXSMP
-       default "32" if SMP && X86_BIGSMP
-       default "8" if SMP && X86_32
-       default "64" if SMP
+       range NR_CPUS_RANGE_BEGIN NR_CPUS_RANGE_END
+       default NR_CPUS_DEFAULT
        ---help---
          This allows you to specify the maximum number of CPUs which this
          kernel will support.  If CPUMASK_OFFSTACK is enabled, the maximum
          supported value is 8192, otherwise the maximum value is 512.  The
          minimum value which makes sense is 2.
 
-         This is purely to save memory - each supported CPU adds
-         approximately eight kilobytes to the kernel image.
+         This is purely to save memory: each supported CPU adds about 8KB
+         to the kernel image.
 
 config SCHED_SMT
        bool "SMT (Hyperthreading) scheduler support"
@@ -1364,7 +1405,7 @@ config HIGHMEM4G
 
 config HIGHMEM64G
        bool "64GB"
-       depends on !M486
+       depends on !M486 && !M586 && !M586TSC && !M586MMX && !MGEODE_LX && !MGEODEGX1 && !MCYRIXIII && !MELAN && !MWINCHIPC6 && !WINCHIP3D && !MK6
        select X86_PAE
        ---help---
          Select this if you have a 32-bit processor and more than 4
index f0c5ef5..638411f 100644 (file)
@@ -361,7 +361,7 @@ config X86_TSC
 
 config X86_CMPXCHG64
        def_bool y
-       depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
+       depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586TSC || M586MMX || MATOM || MGEODE_LX || MGEODEGX1 || MK6 || MK7 || MK8
 
 # this should be set for all -march=.. options where the compiler
 # generates cmov.
@@ -372,7 +372,7 @@ config X86_CMOV
 config X86_MINIMUM_CPU_FAMILY
        int
        default "64" if X86_64
-       default "6" if X86_32 && X86_P6_NOP
+       default "6" if X86_32 && (MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MEFFICEON || MATOM || MCRUSOE || MCORE2 || MK7 || MK8)
        default "5" if X86_32 && X86_CMPXCHG64
        default "4"
 
index 353e20c..886a911 100644 (file)
@@ -439,7 +439,7 @@ setup_uga32(void **uga_handle, unsigned long size, u32 *width, u32 *height)
        struct efi_uga_draw_protocol *uga = NULL, *first_uga;
        efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
        unsigned long nr_ugas;
-       u32 *handles = (u32 *)uga_handle;;
+       u32 *handles = (u32 *)uga_handle;
        efi_status_t status = EFI_INVALID_PARAMETER;
        int i;
 
@@ -484,7 +484,7 @@ setup_uga64(void **uga_handle, unsigned long size, u32 *width, u32 *height)
        struct efi_uga_draw_protocol *uga = NULL, *first_uga;
        efi_guid_t uga_proto = EFI_UGA_PROTOCOL_GUID;
        unsigned long nr_ugas;
-       u64 *handles = (u64 *)uga_handle;;
+       u64 *handles = (u64 *)uga_handle;
        efi_status_t status = EFI_INVALID_PARAMETER;
        int i;
 
index 9b11467..18ed349 100644 (file)
@@ -55,7 +55,7 @@ END(native_usergs_sysret64)
 
 .macro TRACE_IRQS_FLAGS flags:req
 #ifdef CONFIG_TRACE_IRQFLAGS
-       bt      $9, \flags              /* interrupts off? */
+       btl     $9, \flags              /* interrupts off? */
        jnc     1f
        TRACE_IRQS_ON
 1:
index 140d332..88797c8 100644 (file)
@@ -2118,7 +2118,8 @@ static int x86_pmu_event_init(struct perf_event *event)
                        event->destroy(event);
        }
 
-       if (READ_ONCE(x86_pmu.attr_rdpmc))
+       if (READ_ONCE(x86_pmu.attr_rdpmc) &&
+           !(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS))
                event->hw.flags |= PERF_X86_EVENT_RDPMC_ALLOWED;
 
        return err;
index 56457cb..1e41d75 100644 (file)
@@ -2952,9 +2952,9 @@ static void intel_pebs_aliases_skl(struct perf_event *event)
        return intel_pebs_aliases_precdist(event);
 }
 
-static unsigned long intel_pmu_free_running_flags(struct perf_event *event)
+static unsigned long intel_pmu_large_pebs_flags(struct perf_event *event)
 {
-       unsigned long flags = x86_pmu.free_running_flags;
+       unsigned long flags = x86_pmu.large_pebs_flags;
 
        if (event->attr.use_clockid)
                flags &= ~PERF_SAMPLE_TIME;
@@ -2976,8 +2976,8 @@ static int intel_pmu_hw_config(struct perf_event *event)
                if (!event->attr.freq) {
                        event->hw.flags |= PERF_X86_EVENT_AUTO_RELOAD;
                        if (!(event->attr.sample_type &
-                             ~intel_pmu_free_running_flags(event)))
-                               event->hw.flags |= PERF_X86_EVENT_FREERUNNING;
+                             ~intel_pmu_large_pebs_flags(event)))
+                               event->hw.flags |= PERF_X86_EVENT_LARGE_PEBS;
                }
                if (x86_pmu.pebs_aliases)
                        x86_pmu.pebs_aliases(event);
@@ -3194,7 +3194,7 @@ static unsigned bdw_limit_period(struct perf_event *event, unsigned left)
                        X86_CONFIG(.event=0xc0, .umask=0x01)) {
                if (left < 128)
                        left = 128;
-               left &= ~0x3fu;
+               left &= ~0x3fULL;
        }
        return left;
 }
@@ -3460,7 +3460,7 @@ static __initconst const struct x86_pmu core_pmu = {
        .event_map              = intel_pmu_event_map,
        .max_events             = ARRAY_SIZE(intel_perfmon_event_map),
        .apic                   = 1,
-       .free_running_flags     = PEBS_FREERUNNING_FLAGS,
+       .large_pebs_flags       = LARGE_PEBS_FLAGS,
 
        /*
         * Intel PMCs cannot be accessed sanely above 32-bit width,
@@ -3502,7 +3502,7 @@ static __initconst const struct x86_pmu intel_pmu = {
        .event_map              = intel_pmu_event_map,
        .max_events             = ARRAY_SIZE(intel_perfmon_event_map),
        .apic                   = 1,
-       .free_running_flags     = PEBS_FREERUNNING_FLAGS,
+       .large_pebs_flags       = LARGE_PEBS_FLAGS,
        /*
         * Intel PMCs cannot be accessed sanely above 32 bit width,
         * so we install an artificial 1<<31 period regardless of
index 18c25ab..d801523 100644 (file)
@@ -935,7 +935,7 @@ void intel_pmu_pebs_add(struct perf_event *event)
        bool needed_cb = pebs_needs_sched_cb(cpuc);
 
        cpuc->n_pebs++;
-       if (hwc->flags & PERF_X86_EVENT_FREERUNNING)
+       if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
                cpuc->n_large_pebs++;
 
        pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
@@ -975,7 +975,7 @@ void intel_pmu_pebs_del(struct perf_event *event)
        bool needed_cb = pebs_needs_sched_cb(cpuc);
 
        cpuc->n_pebs--;
-       if (hwc->flags & PERF_X86_EVENT_FREERUNNING)
+       if (hwc->flags & PERF_X86_EVENT_LARGE_PEBS)
                cpuc->n_large_pebs--;
 
        pebs_update_state(needed_cb, cpuc, event->ctx->pmu);
@@ -1530,7 +1530,7 @@ void __init intel_ds_init(void)
                        x86_pmu.pebs_record_size =
                                                sizeof(struct pebs_record_skl);
                        x86_pmu.drain_pebs = intel_pmu_drain_pebs_nhm;
-                       x86_pmu.free_running_flags |= PERF_SAMPLE_TIME;
+                       x86_pmu.large_pebs_flags |= PERF_SAMPLE_TIME;
                        break;
 
                default:
index 6d8044a..c98b943 100644 (file)
@@ -3343,6 +3343,7 @@ static struct extra_reg skx_uncore_cha_extra_regs[] = {
        SNBEP_CBO_EVENT_EXTRA_REG(0x9134, 0xffff, 0x4),
        SNBEP_CBO_EVENT_EXTRA_REG(0x35, 0xff, 0x8),
        SNBEP_CBO_EVENT_EXTRA_REG(0x36, 0xff, 0x8),
+       SNBEP_CBO_EVENT_EXTRA_REG(0x38, 0xff, 0x3),
        EVENT_EXTRA_END
 };
 
@@ -3562,24 +3563,27 @@ static struct intel_uncore_type *skx_msr_uncores[] = {
        NULL,
 };
 
+/*
+ * To determine the number of CHAs, it should read bits 27:0 in the CAPID6
+ * register which located at Device 30, Function 3, Offset 0x9C. PCI ID 0x2083.
+ */
+#define SKX_CAPID6             0x9c
+#define SKX_CHA_BIT_MASK       GENMASK(27, 0)
+
 static int skx_count_chabox(void)
 {
-       struct pci_dev *chabox_dev = NULL;
-       int bus, count = 0;
+       struct pci_dev *dev = NULL;
+       u32 val = 0;
 
-       while (1) {
-               chabox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x208d, chabox_dev);
-               if (!chabox_dev)
-                       break;
-               if (count == 0)
-                       bus = chabox_dev->bus->number;
-               if (bus != chabox_dev->bus->number)
-                       break;
-               count++;
-       }
+       dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x2083, dev);
+       if (!dev)
+               goto out;
 
-       pci_dev_put(chabox_dev);
-       return count;
+       pci_read_config_dword(dev, SKX_CAPID6, &val);
+       val &= SKX_CHA_BIT_MASK;
+out:
+       pci_dev_put(dev);
+       return hweight32(val);
 }
 
 void skx_uncore_cpu_init(void)
@@ -3606,7 +3610,7 @@ static struct intel_uncore_type skx_uncore_imc = {
 };
 
 static struct attribute *skx_upi_uncore_formats_attr[] = {
-       &format_attr_event_ext.attr,
+       &format_attr_event.attr,
        &format_attr_umask_ext.attr,
        &format_attr_edge.attr,
        &format_attr_inv.attr,
index 78f91ec..39cd061 100644 (file)
@@ -69,7 +69,7 @@ struct event_constraint {
 #define PERF_X86_EVENT_RDPMC_ALLOWED   0x0100 /* grant rdpmc permission */
 #define PERF_X86_EVENT_EXCL_ACCT       0x0200 /* accounted EXCL event */
 #define PERF_X86_EVENT_AUTO_RELOAD     0x0400 /* use PEBS auto-reload */
-#define PERF_X86_EVENT_FREERUNNING     0x0800 /* use freerunning PEBS */
+#define PERF_X86_EVENT_LARGE_PEBS      0x0800 /* use large PEBS */
 
 
 struct amd_nb {
@@ -88,7 +88,7 @@ struct amd_nb {
  * REGS_USER can be handled for events limited to ring 3.
  *
  */
-#define PEBS_FREERUNNING_FLAGS \
+#define LARGE_PEBS_FLAGS \
        (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_ADDR | \
        PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_STREAM_ID | \
        PERF_SAMPLE_DATA_SRC | PERF_SAMPLE_IDENTIFIER | \
@@ -608,7 +608,7 @@ struct x86_pmu {
        struct event_constraint *pebs_constraints;
        void            (*pebs_aliases)(struct perf_event *event);
        int             max_pebs_events;
-       unsigned long   free_running_flags;
+       unsigned long   large_pebs_flags;
 
        /*
         * Intel LBR
index 3fa0398..9f645ba 100644 (file)
@@ -78,7 +78,7 @@ set_bit(long nr, volatile unsigned long *addr)
                        : "iq" ((u8)CONST_MASK(nr))
                        : "memory");
        } else {
-               asm volatile(LOCK_PREFIX "bts %1,%0"
+               asm volatile(LOCK_PREFIX __ASM_SIZE(bts) " %1,%0"
                        : BITOP_ADDR(addr) : "Ir" (nr) : "memory");
        }
 }
@@ -94,7 +94,7 @@ set_bit(long nr, volatile unsigned long *addr)
  */
 static __always_inline void __set_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("bts %1,%0" : ADDR : "Ir" (nr) : "memory");
+       asm volatile(__ASM_SIZE(bts) " %1,%0" : ADDR : "Ir" (nr) : "memory");
 }
 
 /**
@@ -115,7 +115,7 @@ clear_bit(long nr, volatile unsigned long *addr)
                        : CONST_MASK_ADDR(nr, addr)
                        : "iq" ((u8)~CONST_MASK(nr)));
        } else {
-               asm volatile(LOCK_PREFIX "btr %1,%0"
+               asm volatile(LOCK_PREFIX __ASM_SIZE(btr) " %1,%0"
                        : BITOP_ADDR(addr)
                        : "Ir" (nr));
        }
@@ -137,7 +137,7 @@ static __always_inline void clear_bit_unlock(long nr, volatile unsigned long *ad
 
 static __always_inline void __clear_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("btr %1,%0" : ADDR : "Ir" (nr));
+       asm volatile(__ASM_SIZE(btr) " %1,%0" : ADDR : "Ir" (nr));
 }
 
 static __always_inline bool clear_bit_unlock_is_negative_byte(long nr, volatile unsigned long *addr)
@@ -182,7 +182,7 @@ static __always_inline void __clear_bit_unlock(long nr, volatile unsigned long *
  */
 static __always_inline void __change_bit(long nr, volatile unsigned long *addr)
 {
-       asm volatile("btc %1,%0" : ADDR : "Ir" (nr));
+       asm volatile(__ASM_SIZE(btc) " %1,%0" : ADDR : "Ir" (nr));
 }
 
 /**
@@ -201,7 +201,7 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr)
                        : CONST_MASK_ADDR(nr, addr)
                        : "iq" ((u8)CONST_MASK(nr)));
        } else {
-               asm volatile(LOCK_PREFIX "btc %1,%0"
+               asm volatile(LOCK_PREFIX __ASM_SIZE(btc) " %1,%0"
                        : BITOP_ADDR(addr)
                        : "Ir" (nr));
        }
@@ -217,7 +217,8 @@ static __always_inline void change_bit(long nr, volatile unsigned long *addr)
  */
 static __always_inline bool test_and_set_bit(long nr, volatile unsigned long *addr)
 {
-       GEN_BINARY_RMWcc(LOCK_PREFIX "bts", *addr, "Ir", nr, "%0", c);
+       GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(bts),
+                        *addr, "Ir", nr, "%0", c);
 }
 
 /**
@@ -246,7 +247,7 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *
 {
        bool oldbit;
 
-       asm("bts %2,%1"
+       asm(__ASM_SIZE(bts) " %2,%1"
            CC_SET(c)
            : CC_OUT(c) (oldbit), ADDR
            : "Ir" (nr));
@@ -263,7 +264,8 @@ static __always_inline bool __test_and_set_bit(long nr, volatile unsigned long *
  */
 static __always_inline bool test_and_clear_bit(long nr, volatile unsigned long *addr)
 {
-       GEN_BINARY_RMWcc(LOCK_PREFIX "btr", *addr, "Ir", nr, "%0", c);
+       GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btr),
+                        *addr, "Ir", nr, "%0", c);
 }
 
 /**
@@ -286,7 +288,7 @@ static __always_inline bool __test_and_clear_bit(long nr, volatile unsigned long
 {
        bool oldbit;
 
-       asm volatile("btr %2,%1"
+       asm volatile(__ASM_SIZE(btr) " %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit), ADDR
                     : "Ir" (nr));
@@ -298,7 +300,7 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon
 {
        bool oldbit;
 
-       asm volatile("btc %2,%1"
+       asm volatile(__ASM_SIZE(btc) " %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit), ADDR
                     : "Ir" (nr) : "memory");
@@ -316,7 +318,8 @@ static __always_inline bool __test_and_change_bit(long nr, volatile unsigned lon
  */
 static __always_inline bool test_and_change_bit(long nr, volatile unsigned long *addr)
 {
-       GEN_BINARY_RMWcc(LOCK_PREFIX "btc", *addr, "Ir", nr, "%0", c);
+       GEN_BINARY_RMWcc(LOCK_PREFIX __ASM_SIZE(btc),
+                        *addr, "Ir", nr, "%0", c);
 }
 
 static __always_inline bool constant_test_bit(long nr, const volatile unsigned long *addr)
@@ -329,7 +332,7 @@ static __always_inline bool variable_test_bit(long nr, volatile const unsigned l
 {
        bool oldbit;
 
-       asm volatile("bt %2,%1"
+       asm volatile(__ASM_SIZE(bt) " %2,%1"
                     CC_SET(c)
                     : CC_OUT(c) (oldbit)
                     : "m" (*(unsigned long *)addr), "Ir" (nr));
index 70eddb3..736771c 100644 (file)
@@ -148,45 +148,46 @@ extern void clear_cpu_cap(struct cpuinfo_x86 *c, unsigned int bit);
  */
 static __always_inline __pure bool _static_cpu_has(u16 bit)
 {
-               asm_volatile_goto("1: jmp 6f\n"
-                        "2:\n"
-                        ".skip -(((5f-4f) - (2b-1b)) > 0) * "
-                                "((5f-4f) - (2b-1b)),0x90\n"
-                        "3:\n"
-                        ".section .altinstructions,\"a\"\n"
-                        " .long 1b - .\n"              /* src offset */
-                        " .long 4f - .\n"              /* repl offset */
-                        " .word %P1\n"                 /* always replace */
-                        " .byte 3b - 1b\n"             /* src len */
-                        " .byte 5f - 4f\n"             /* repl len */
-                        " .byte 3b - 2b\n"             /* pad len */
-                        ".previous\n"
-                        ".section .altinstr_replacement,\"ax\"\n"
-                        "4: jmp %l[t_no]\n"
-                        "5:\n"
-                        ".previous\n"
-                        ".section .altinstructions,\"a\"\n"
-                        " .long 1b - .\n"              /* src offset */
-                        " .long 0\n"                   /* no replacement */
-                        " .word %P0\n"                 /* feature bit */
-                        " .byte 3b - 1b\n"             /* src len */
-                        " .byte 0\n"                   /* repl len */
-                        " .byte 0\n"                   /* pad len */
-                        ".previous\n"
-                        ".section .altinstr_aux,\"ax\"\n"
-                        "6:\n"
-                        " testb %[bitnum],%[cap_byte]\n"
-                        " jnz %l[t_yes]\n"
-                        " jmp %l[t_no]\n"
-                        ".previous\n"
-                        : : "i" (bit), "i" (X86_FEATURE_ALWAYS),
-                            [bitnum] "i" (1 << (bit & 7)),
-                            [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3])
-                        : : t_yes, t_no);
-       t_yes:
-               return true;
-       t_no:
-               return false;
+       asm_volatile_goto("1: jmp 6f\n"
+                "2:\n"
+                ".skip -(((5f-4f) - (2b-1b)) > 0) * "
+                        "((5f-4f) - (2b-1b)),0x90\n"
+                "3:\n"
+                ".section .altinstructions,\"a\"\n"
+                " .long 1b - .\n"              /* src offset */
+                " .long 4f - .\n"              /* repl offset */
+                " .word %P[always]\n"          /* always replace */
+                " .byte 3b - 1b\n"             /* src len */
+                " .byte 5f - 4f\n"             /* repl len */
+                " .byte 3b - 2b\n"             /* pad len */
+                ".previous\n"
+                ".section .altinstr_replacement,\"ax\"\n"
+                "4: jmp %l[t_no]\n"
+                "5:\n"
+                ".previous\n"
+                ".section .altinstructions,\"a\"\n"
+                " .long 1b - .\n"              /* src offset */
+                " .long 0\n"                   /* no replacement */
+                " .word %P[feature]\n"         /* feature bit */
+                " .byte 3b - 1b\n"             /* src len */
+                " .byte 0\n"                   /* repl len */
+                " .byte 0\n"                   /* pad len */
+                ".previous\n"
+                ".section .altinstr_aux,\"ax\"\n"
+                "6:\n"
+                " testb %[bitnum],%[cap_byte]\n"
+                " jnz %l[t_yes]\n"
+                " jmp %l[t_no]\n"
+                ".previous\n"
+                : : [feature]  "i" (bit),
+                    [always]   "i" (X86_FEATURE_ALWAYS),
+                    [bitnum]   "i" (1 << (bit & 7)),
+                    [cap_byte] "m" (((const char *)boot_cpu_data.x86_capability)[bit >> 3])
+                : : t_yes, t_no);
+t_yes:
+       return true;
+t_no:
+       return false;
 }
 
 #define static_cpu_has(bit)                                    \
index dd6f57a..b605a5b 100644 (file)
@@ -507,6 +507,7 @@ struct kvm_vcpu_arch {
        u64 smi_count;
        bool tpr_access_reporting;
        u64 ia32_xss;
+       u64 microcode_version;
 
        /*
         * Paging state of the vcpu
@@ -1095,6 +1096,8 @@ struct kvm_x86_ops {
        int (*mem_enc_op)(struct kvm *kvm, void __user *argp);
        int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
        int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
+
+       int (*get_msr_feature)(struct kvm_msr_entry *entry);
 };
 
 struct kvm_arch_async_pf {
@@ -1464,7 +1467,4 @@ static inline int kvm_cpu_get_apicid(int mps_cpu)
 #define put_smstate(type, buf, offset, val)                      \
        *(type *)((buf) + (offset) - 0x7e00) = val
 
-void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
-               unsigned long start, unsigned long end);
-
 #endif /* _ASM_X86_KVM_HOST_H */
index b3996d6..f928ad9 100644 (file)
@@ -278,4 +278,41 @@ do {                                                                       \
 } while (0)
 
 #endif /* __ASSEMBLY__ */
+
+/*
+ * Below is used in the eBPF JIT compiler and emits the byte sequence
+ * for the following assembly:
+ *
+ * With retpolines configured:
+ *
+ *    callq do_rop
+ *  spec_trap:
+ *    pause
+ *    lfence
+ *    jmp spec_trap
+ *  do_rop:
+ *    mov %rax,(%rsp)
+ *    retq
+ *
+ * Without retpolines configured:
+ *
+ *    jmp *%rax
+ */
+#ifdef CONFIG_RETPOLINE
+# define RETPOLINE_RAX_BPF_JIT_SIZE    17
+# define RETPOLINE_RAX_BPF_JIT()                               \
+       EMIT1_off32(0xE8, 7);    /* callq do_rop */             \
+       /* spec_trap: */                                        \
+       EMIT2(0xF3, 0x90);       /* pause */                    \
+       EMIT3(0x0F, 0xAE, 0xE8); /* lfence */                   \
+       EMIT2(0xEB, 0xF9);       /* jmp spec_trap */            \
+       /* do_rop: */                                           \
+       EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */    \
+       EMIT1(0xC3);             /* retq */
+#else
+# define RETPOLINE_RAX_BPF_JIT_SIZE    2
+# define RETPOLINE_RAX_BPF_JIT()                               \
+       EMIT2(0xFF, 0xE0);       /* jmp *%rax */
+#endif
+
 #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */
index 4baa6bc..d652a38 100644 (file)
@@ -52,10 +52,6 @@ static inline void clear_page(void *page)
 
 void copy_page(void *to, void *from);
 
-#ifdef CONFIG_X86_MCE
-#define arch_unmap_kpfn arch_unmap_kpfn
-#endif
-
 #endif /* !__ASSEMBLY__ */
 
 #ifdef CONFIG_X86_VSYSCALL_EMULATION
index ba3c523..a06b073 100644 (file)
@@ -526,7 +526,7 @@ static inline bool x86_this_cpu_variable_test_bit(int nr,
 {
        bool oldbit;
 
-       asm volatile("bt "__percpu_arg(2)",%1"
+       asm volatile("btl "__percpu_arg(2)",%1"
                        CC_SET(c)
                        : CC_OUT(c) (oldbit)
                        : "m" (*(unsigned long __percpu *)addr), "Ir" (nr));
index d651711..4cf11d8 100644 (file)
@@ -17,7 +17,7 @@
 #define _REFCOUNT_EXCEPTION                            \
        ".pushsection .text..refcount\n"                \
        "111:\tlea %[counter], %%" _ASM_CX "\n"         \
-       "112:\t" ASM_UD0 "\n"                           \
+       "112:\t" ASM_UD2 "\n"                           \
        ASM_UNREACHABLE                                 \
        ".popsection\n"                                 \
        "113:\n"                                        \
index 461f53d..a418976 100644 (file)
@@ -129,6 +129,7 @@ static inline void arch_send_call_function_ipi_mask(const struct cpumask *mask)
 void cpu_disable_common(void);
 void native_smp_prepare_boot_cpu(void);
 void native_smp_prepare_cpus(unsigned int max_cpus);
+void calculate_max_logical_packages(void);
 void native_smp_cpus_done(unsigned int max_cpus);
 void common_cpu_up(unsigned int cpunum, struct task_struct *tidle);
 int native_cpu_up(unsigned int cpunum, struct task_struct *tidle);
index 8b67807..5db8b0b 100644 (file)
@@ -352,6 +352,7 @@ enum vmcs_field {
 #define INTR_TYPE_NMI_INTR             (2 << 8) /* NMI */
 #define INTR_TYPE_HARD_EXCEPTION       (3 << 8) /* processor exception */
 #define INTR_TYPE_SOFT_INTR             (4 << 8) /* software interrupt */
+#define INTR_TYPE_PRIV_SW_EXCEPTION    (5 << 8) /* ICE breakpoint - undocumented */
 #define INTR_TYPE_SOFT_EXCEPTION       (6 << 8) /* software exception */
 
 /* GUEST_INTERRUPTIBILITY_INFO flags. */
index 197c2e6..0994143 100644 (file)
 #define HV_X64_MSR_REENLIGHTENMENT_CONTROL     0x40000106
 
 struct hv_reenlightenment_control {
-       u64 vector:8;
-       u64 reserved1:8;
-       u64 enabled:1;
-       u64 reserved2:15;
-       u64 target_vp:32;
+       __u64 vector:8;
+       __u64 reserved1:8;
+       __u64 enabled:1;
+       __u64 reserved2:15;
+       __u64 target_vp:32;
 };
 
 #define HV_X64_MSR_TSC_EMULATION_CONTROL       0x40000107
 #define HV_X64_MSR_TSC_EMULATION_STATUS                0x40000108
 
 struct hv_tsc_emulation_control {
-       u64 enabled:1;
-       u64 reserved:63;
+       __u64 enabled:1;
+       __u64 reserved:63;
 };
 
 struct hv_tsc_emulation_status {
-       u64 inprogress:1;
-       u64 reserved:63;
+       __u64 inprogress:1;
+       __u64 reserved:63;
 };
 
 #define HV_X64_MSR_HYPERCALL_ENABLE            0x00000001
index 7a2ade4..6cfa9c8 100644 (file)
@@ -26,6 +26,7 @@
 #define KVM_FEATURE_PV_EOI             6
 #define KVM_FEATURE_PV_UNHALT          7
 #define KVM_FEATURE_PV_TLB_FLUSH       9
+#define KVM_FEATURE_ASYNC_PF_VMEXIT    10
 
 /* The last 8 bits are used to indicate how to interpret the flags field
  * in pvclock structure. If no bits are set, all flags are ignored.
index 9172346..435db58 100644 (file)
@@ -30,6 +30,7 @@ struct mce {
        __u64 synd;     /* MCA_SYND MSR: only valid on SMCA systems */
        __u64 ipid;     /* MCA_IPID MSR: only valid on SMCA systems */
        __u64 ppin;     /* Protected Processor Inventory Number */
+       __u32 microcode;/* Microcode revision */
 };
 
 #define MCE_GET_RECORD_LEN   _IOR('M', 1, int)
index 3cc471b..bb6f7a2 100644 (file)
@@ -134,21 +134,40 @@ static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
 {
        struct apic_chip_data *apicd = apic_chip_data(irqd);
        struct irq_desc *desc = irq_data_to_desc(irqd);
+       bool managed = irqd_affinity_is_managed(irqd);
 
        lockdep_assert_held(&vector_lock);
 
        trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector,
                            apicd->cpu);
 
-       /* Setup the vector move, if required  */
-       if (apicd->vector && cpu_online(apicd->cpu)) {
+       /*
+        * If there is no vector associated or if the associated vector is
+        * the shutdown vector, which is associated to make PCI/MSI
+        * shutdown mode work, then there is nothing to release. Clear out
+        * prev_vector for this and the offlined target case.
+        */
+       apicd->prev_vector = 0;
+       if (!apicd->vector || apicd->vector == MANAGED_IRQ_SHUTDOWN_VECTOR)
+               goto setnew;
+       /*
+        * If the target CPU of the previous vector is online, then mark
+        * the vector as move in progress and store it for cleanup when the
+        * first interrupt on the new vector arrives. If the target CPU is
+        * offline then the regular release mechanism via the cleanup
+        * vector is not possible and the vector can be immediately freed
+        * in the underlying matrix allocator.
+        */
+       if (cpu_online(apicd->cpu)) {
                apicd->move_in_progress = true;
                apicd->prev_vector = apicd->vector;
                apicd->prev_cpu = apicd->cpu;
        } else {
-               apicd->prev_vector = 0;
+               irq_matrix_free(vector_matrix, apicd->cpu, apicd->vector,
+                               managed);
        }
 
+setnew:
        apicd->vector = newvec;
        apicd->cpu = newcpu;
        BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));
index 46b675a..f11910b 100644 (file)
@@ -1176,16 +1176,25 @@ static void __init decode_gam_rng_tbl(unsigned long ptr)
 
        uv_gre_table = gre;
        for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
+               unsigned long size = ((unsigned long)(gre->limit - lgre)
+                                       << UV_GAM_RANGE_SHFT);
+               int order = 0;
+               char suffix[] = " KMGTPE";
+
+               while (size > 9999 && order < sizeof(suffix)) {
+                       size /= 1024;
+                       order++;
+               }
+
                if (!index) {
                        pr_info("UV: GAM Range Table...\n");
                        pr_info("UV:  # %20s %14s %5s %4s %5s %3s %2s\n", "Range", "", "Size", "Type", "NASID", "SID", "PN");
                }
-               pr_info("UV: %2d: 0x%014lx-0x%014lx %5luG %3d   %04x  %02x %02x\n",
+               pr_info("UV: %2d: 0x%014lx-0x%014lx %5lu%c %3d   %04x  %02x %02x\n",
                        index++,
                        (unsigned long)lgre << UV_GAM_RANGE_SHFT,
                        (unsigned long)gre->limit << UV_GAM_RANGE_SHFT,
-                       ((unsigned long)(gre->limit - lgre)) >>
-                               (30 - UV_GAM_RANGE_SHFT), /* 64M -> 1G */
+                       size, suffix[order],
                        gre->type, gre->nasid, gre->sockid, gre->pnode);
 
                lgre = gre->limit;
index bdab7d2..fca759d 100644 (file)
@@ -1804,6 +1804,7 @@ static int rdtgroup_mkdir_ctrl_mon(struct kernfs_node *parent_kn,
                goto out_common_fail;
        }
        closid = ret;
+       ret = 0;
 
        rdtgrp->closid = closid;
        list_add(&rdtgrp->rdtgroup_list, &rdt_all_groups);
index aa0d5df..e956eb2 100644 (file)
@@ -115,4 +115,19 @@ static inline void mce_unregister_injector_chain(struct notifier_block *nb)        { }
 
 extern struct mca_config mca_cfg;
 
+#ifndef CONFIG_X86_64
+/*
+ * On 32-bit systems it would be difficult to safely unmap a poison page
+ * from the kernel 1:1 map because there are no non-canonical addresses that
+ * we can use to refer to the address without risking a speculative access.
+ * However, this isn't much of an issue because:
+ * 1) Few unmappable pages are in the 1:1 map. Most are in HIGHMEM which
+ *    are only mapped into the kernel as needed
+ * 2) Few people would run a 32-bit kernel on a machine that supports
+ *    recoverable errors because they have too much memory to boot 32-bit.
+ */
+static inline void mce_unmap_kpfn(unsigned long pfn) {}
+#define mce_unmap_kpfn mce_unmap_kpfn
+#endif
+
 #endif /* __X86_MCE_INTERNAL_H__ */
index 3a8e88a..466f473 100644 (file)
@@ -56,6 +56,9 @@
 
 static DEFINE_MUTEX(mce_log_mutex);
 
+/* sysfs synchronization */
+static DEFINE_MUTEX(mce_sysfs_mutex);
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/mce.h>
 
@@ -105,6 +108,10 @@ static struct irq_work mce_irq_work;
 
 static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
 
+#ifndef mce_unmap_kpfn
+static void mce_unmap_kpfn(unsigned long pfn);
+#endif
+
 /*
  * CPU/chipset specific EDAC code can register a notifier call here to print
  * MCE errors in a human-readable form.
@@ -126,6 +133,8 @@ void mce_setup(struct mce *m)
 
        if (this_cpu_has(X86_FEATURE_INTEL_PPIN))
                rdmsrl(MSR_PPIN, m->ppin);
+
+       m->microcode = boot_cpu_data.microcode;
 }
 
 DEFINE_PER_CPU(struct mce, injectm);
@@ -234,7 +243,7 @@ static void __print_mce(struct mce *m)
                        m->cs, m->ip);
 
                if (m->cs == __KERNEL_CS)
-                       pr_cont("{%pS}", (void *)m->ip);
+                       pr_cont("{%pS}", (void *)(unsigned long)m->ip);
                pr_cont("\n");
        }
 
@@ -258,7 +267,7 @@ static void __print_mce(struct mce *m)
         */
        pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
                m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
-               cpu_data(m->extcpu).microcode);
+               m->microcode);
 }
 
 static void print_mce(struct mce *m)
@@ -590,7 +599,8 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
 
        if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
                pfn = mce->addr >> PAGE_SHIFT;
-               memory_failure(pfn, 0);
+               if (!memory_failure(pfn, 0))
+                       mce_unmap_kpfn(pfn);
        }
 
        return NOTIFY_OK;
@@ -1057,12 +1067,13 @@ static int do_memory_failure(struct mce *m)
        ret = memory_failure(m->addr >> PAGE_SHIFT, flags);
        if (ret)
                pr_err("Memory error not recovered");
+       else
+               mce_unmap_kpfn(m->addr >> PAGE_SHIFT);
        return ret;
 }
 
-#if defined(arch_unmap_kpfn) && defined(CONFIG_MEMORY_FAILURE)
-
-void arch_unmap_kpfn(unsigned long pfn)
+#ifndef mce_unmap_kpfn
+static void mce_unmap_kpfn(unsigned long pfn)
 {
        unsigned long decoy_addr;
 
@@ -1073,7 +1084,7 @@ void arch_unmap_kpfn(unsigned long pfn)
         * We would like to just call:
         *      set_memory_np((unsigned long)pfn_to_kaddr(pfn), 1);
         * but doing that would radically increase the odds of a
-        * speculative access to the posion page because we'd have
+        * speculative access to the poison page because we'd have
         * the virtual address of the kernel 1:1 mapping sitting
         * around in registers.
         * Instead we get tricky.  We create a non-canonical address
@@ -1098,7 +1109,6 @@ void arch_unmap_kpfn(unsigned long pfn)
 
        if (set_memory_np(decoy_addr, 1))
                pr_warn("Could not invalidate pfn=0x%lx from 1:1 map\n", pfn);
-
 }
 #endif
 
@@ -2081,6 +2091,7 @@ static ssize_t set_ignore_ce(struct device *s,
        if (kstrtou64(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mca_cfg.ignore_ce ^ !!new) {
                if (new) {
                        /* disable ce features */
@@ -2093,6 +2104,8 @@ static ssize_t set_ignore_ce(struct device *s,
                        on_each_cpu(mce_enable_ce, (void *)1, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -2105,6 +2118,7 @@ static ssize_t set_cmci_disabled(struct device *s,
        if (kstrtou64(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mca_cfg.cmci_disabled ^ !!new) {
                if (new) {
                        /* disable cmci */
@@ -2116,6 +2130,8 @@ static ssize_t set_cmci_disabled(struct device *s,
                        on_each_cpu(mce_enable_ce, NULL, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -2123,8 +2139,19 @@ static ssize_t store_int_with_restart(struct device *s,
                                      struct device_attribute *attr,
                                      const char *buf, size_t size)
 {
-       ssize_t ret = device_store_int(s, attr, buf, size);
+       unsigned long old_check_interval = check_interval;
+       ssize_t ret = device_store_ulong(s, attr, buf, size);
+
+       if (check_interval == old_check_interval)
+               return ret;
+
+       if (check_interval < 1)
+               check_interval = 1;
+
+       mutex_lock(&mce_sysfs_mutex);
        mce_restart();
+       mutex_unlock(&mce_sysfs_mutex);
+
        return ret;
 }
 
index 4e37d1a..fae86e3 100644 (file)
@@ -49,7 +49,7 @@
 
 static int kvmapf = 1;
 
-static int parse_no_kvmapf(char *arg)
+static int __init parse_no_kvmapf(char *arg)
 {
         kvmapf = 0;
         return 0;
@@ -58,7 +58,7 @@ static int parse_no_kvmapf(char *arg)
 early_param("no-kvmapf", parse_no_kvmapf);
 
 static int steal_acc = 1;
-static int parse_no_stealacc(char *arg)
+static int __init parse_no_stealacc(char *arg)
 {
         steal_acc = 0;
         return 0;
@@ -67,7 +67,7 @@ static int parse_no_stealacc(char *arg)
 early_param("no-steal-acc", parse_no_stealacc);
 
 static int kvmclock_vsyscall = 1;
-static int parse_no_kvmclock_vsyscall(char *arg)
+static int __init parse_no_kvmclock_vsyscall(char *arg)
 {
         kvmclock_vsyscall = 0;
         return 0;
@@ -341,10 +341,10 @@ static void kvm_guest_cpu_init(void)
 #endif
                pa |= KVM_ASYNC_PF_ENABLED;
 
-               /* Async page fault support for L1 hypervisor is optional */
-               if (wrmsr_safe(MSR_KVM_ASYNC_PF_EN,
-                       (pa | KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT) & 0xffffffff, pa >> 32) < 0)
-                       wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
+               if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_VMEXIT))
+                       pa |= KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT;
+
+               wrmsrl(MSR_KVM_ASYNC_PF_EN, pa);
                __this_cpu_write(apf_reason.enabled, 1);
                printk(KERN_INFO"KVM setup async PF for cpu %d\n",
                       smp_processor_id());
@@ -545,7 +545,8 @@ static void __init kvm_guest_init(void)
                pv_time_ops.steal_clock = kvm_steal_clock;
        }
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH))
+       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME))
                pv_mmu_ops.flush_tlb_others = kvm_flush_tlb_others;
 
        if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
@@ -633,7 +634,8 @@ static __init int kvm_setup_pv_tlb_flush(void)
 {
        int cpu;
 
-       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH)) {
+       if (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
+           kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) {
                for_each_possible_cpu(cpu) {
                        zalloc_cpumask_var_node(per_cpu_ptr(&__pv_tlb_mask, cpu),
                                GFP_KERNEL, cpu_to_node(cpu));
index 1f790cf..3b7427a 100644 (file)
@@ -542,6 +542,7 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr,
                                goto overflow;
                        break;
                case R_X86_64_PC32:
+               case R_X86_64_PLT32:
                        value -= (u64)address;
                        *(u32 *)location = value;
                        break;
index da0c160..f58336a 100644 (file)
@@ -191,6 +191,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
                                goto overflow;
                        break;
                case R_X86_64_PC32:
+               case R_X86_64_PLT32:
                        if (*(u32 *)loc != 0)
                                goto invalid_relocation;
                        val -= (u64)loc;
index ac057f9..0d930d8 100644 (file)
@@ -43,6 +43,13 @@ static inline void signal_compat_build_tests(void)
        BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields) != 3 * sizeof(int));
 #define CHECK_CSI_OFFSET(name)   BUILD_BUG_ON(_sifields_offset != offsetof(compat_siginfo_t, _sifields.name))
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_signo) != 0);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_errno) != 4);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_code)  != 8);
+
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_signo) != 0);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_errno) != 4);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_code)  != 8);
         /*
         * Ensure that the size of each si_field never changes.
         * If it does, it is a sign that the
@@ -63,36 +70,94 @@ static inline void signal_compat_build_tests(void)
        CHECK_CSI_SIZE  (_kill, 2*sizeof(int));
        CHECK_SI_SIZE   (_kill, 2*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_pid) != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_uid) != 0x14);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid) != 0xC);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid) != 0x10);
+
        CHECK_CSI_OFFSET(_timer);
        CHECK_CSI_SIZE  (_timer, 3*sizeof(int));
        CHECK_SI_SIZE   (_timer, 6*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_tid)     != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_overrun) != 0x14);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_value)   != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_tid)     != 0x0C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_overrun) != 0x10);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value)   != 0x14);
+
        CHECK_CSI_OFFSET(_rt);
        CHECK_CSI_SIZE  (_rt, 3*sizeof(int));
        CHECK_SI_SIZE   (_rt, 4*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_pid)   != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_uid)   != 0x14);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_value) != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid)   != 0x0C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid)   != 0x10);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_value) != 0x14);
+
        CHECK_CSI_OFFSET(_sigchld);
        CHECK_CSI_SIZE  (_sigchld, 5*sizeof(int));
        CHECK_SI_SIZE   (_sigchld, 8*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_pid)    != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_uid)    != 0x14);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_status) != 0x18);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_utime)  != 0x20);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_stime)  != 0x28);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pid)    != 0x0C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_uid)    != 0x10);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_status) != 0x14);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_utime)  != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_stime)  != 0x1C);
+
 #ifdef CONFIG_X86_X32_ABI
        CHECK_CSI_OFFSET(_sigchld_x32);
        CHECK_CSI_SIZE  (_sigchld_x32, 7*sizeof(int));
        /* no _sigchld_x32 in the generic siginfo_t */
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._utime)  != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, _sifields._sigchld_x32._stime)  != 0x20);
 #endif
 
        CHECK_CSI_OFFSET(_sigfault);
        CHECK_CSI_SIZE  (_sigfault, 4*sizeof(int));
        CHECK_SI_SIZE   (_sigfault, 8*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_addr) != 0x10);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr) != 0x0C);
+
+       BUILD_BUG_ON(offsetof(siginfo_t, si_addr_lsb) != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_addr_lsb) != 0x10);
+
+       BUILD_BUG_ON(offsetof(siginfo_t, si_lower) != 0x20);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_upper) != 0x28);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_lower) != 0x14);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_upper) != 0x18);
+
+       BUILD_BUG_ON(offsetof(siginfo_t, si_pkey) != 0x20);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_pkey) != 0x14);
+
        CHECK_CSI_OFFSET(_sigpoll);
        CHECK_CSI_SIZE  (_sigpoll, 2*sizeof(int));
        CHECK_SI_SIZE   (_sigpoll, 4*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_band)   != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_fd)     != 0x18);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_band) != 0x0C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_fd)   != 0x10);
+
        CHECK_CSI_OFFSET(_sigsys);
        CHECK_CSI_SIZE  (_sigsys, 3*sizeof(int));
        CHECK_SI_SIZE   (_sigsys, 4*sizeof(int));
 
+       BUILD_BUG_ON(offsetof(siginfo_t, si_call_addr) != 0x10);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_syscall)   != 0x18);
+       BUILD_BUG_ON(offsetof(siginfo_t, si_arch)      != 0x1C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_call_addr) != 0x0C);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_syscall)   != 0x10);
+       BUILD_BUG_ON(offsetof(compat_siginfo_t, si_arch)      != 0x14);
+
        /* any new si_fields should be added here */
 }
 
index 6f27fac..ff99e2b 100644 (file)
@@ -1281,11 +1281,10 @@ void __init native_smp_prepare_boot_cpu(void)
        cpu_set_state_online(me);
 }
 
-void __init native_smp_cpus_done(unsigned int max_cpus)
+void __init calculate_max_logical_packages(void)
 {
        int ncpus;
 
-       pr_debug("Boot done\n");
        /*
         * Today neither Intel nor AMD support heterogenous systems so
         * extrapolate the boot cpu's data to all packages.
@@ -1293,6 +1292,13 @@ void __init native_smp_cpus_done(unsigned int max_cpus)
        ncpus = cpu_data(0).booted_cores * topology_max_smt_threads();
        __max_logical_packages = DIV_ROUND_UP(nr_cpu_ids, ncpus);
        pr_info("Max logical packages: %u\n", __max_logical_packages);
+}
+
+void __init native_smp_cpus_done(unsigned int max_cpus)
+{
+       pr_debug("Boot done\n");
+
+       calculate_max_logical_packages();
 
        if (x86_has_numa_in_package)
                set_sched_topology(x86_numa_in_package_topology);
@@ -1430,8 +1436,8 @@ static void remove_siblinginfo(int cpu)
        cpumask_clear(cpu_llc_shared_mask(cpu));
        cpumask_clear(topology_sibling_cpumask(cpu));
        cpumask_clear(topology_core_cpumask(cpu));
-       c->phys_proc_id = 0;
        c->cpu_core_id = 0;
+       c->booted_cores = 0;
        cpumask_clear_cpu(cpu, cpu_sibling_setup_mask);
        recompute_smt_state();
 }
index a0c5a69..b671fc2 100644 (file)
@@ -607,7 +607,8 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                             (1 << KVM_FEATURE_PV_EOI) |
                             (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT) |
                             (1 << KVM_FEATURE_PV_UNHALT) |
-                            (1 << KVM_FEATURE_PV_TLB_FLUSH);
+                            (1 << KVM_FEATURE_PV_TLB_FLUSH) |
+                            (1 << KVM_FEATURE_ASYNC_PF_VMEXIT);
 
                if (sched_info_on())
                        entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
index 924ac8c..391dda8 100644 (file)
@@ -2002,14 +2002,13 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
 
 void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
-       struct kvm_lapic *apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
        int i;
 
-       apic_debug("%s\n", __func__);
+       if (!apic)
+               return;
 
-       ASSERT(vcpu);
-       apic = vcpu->arch.apic;
-       ASSERT(apic != NULL);
+       apic_debug("%s\n", __func__);
 
        /* Stop the timer in case it's a reset to an active apic */
        hrtimer_cancel(&apic->lapic_timer.timer);
@@ -2165,7 +2164,6 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
         */
        vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE;
        static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
-       kvm_lapic_reset(vcpu, false);
        kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
 
        return 0;
@@ -2569,7 +2567,6 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)
 
        pe = xchg(&apic->pending_events, 0);
        if (test_bit(KVM_APIC_INIT, &pe)) {
-               kvm_lapic_reset(vcpu, true);
                kvm_vcpu_reset(vcpu, true);
                if (kvm_vcpu_is_bsp(apic->vcpu))
                        vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE;
index 46ff304..763bb3b 100644 (file)
@@ -2770,8 +2770,10 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
        else
                pte_access &= ~ACC_WRITE_MASK;
 
+       if (!kvm_is_mmio_pfn(pfn))
+               spte |= shadow_me_mask;
+
        spte |= (u64)pfn << PAGE_SHIFT;
-       spte |= shadow_me_mask;
 
        if (pte_access & ACC_WRITE_MASK) {
 
@@ -3029,7 +3031,7 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
                return RET_PF_RETRY;
        }
 
-       return -EFAULT;
+       return RET_PF_EMULATE;
 }
 
 static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
index 24c9521..be9c839 100644 (file)
@@ -179,6 +179,8 @@ struct vcpu_svm {
        uint64_t sysenter_eip;
        uint64_t tsc_aux;
 
+       u64 msr_decfg;
+
        u64 next_rip;
 
        u64 host_user_msrs[NR_HOST_SAVE_USER_MSRS];
@@ -301,6 +303,8 @@ module_param(vgif, int, 0444);
 static int sev = IS_ENABLED(CONFIG_AMD_MEM_ENCRYPT_ACTIVE_BY_DEFAULT);
 module_param(sev, int, 0444);
 
+static u8 rsm_ins_bytes[] = "\x0f\xaa";
+
 static void svm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0);
 static void svm_flush_tlb(struct kvm_vcpu *vcpu, bool invalidate_gpa);
 static void svm_complete_interrupts(struct vcpu_svm *svm);
@@ -1384,6 +1388,7 @@ static void init_vmcb(struct vcpu_svm *svm)
        set_intercept(svm, INTERCEPT_SKINIT);
        set_intercept(svm, INTERCEPT_WBINVD);
        set_intercept(svm, INTERCEPT_XSETBV);
+       set_intercept(svm, INTERCEPT_RSM);
 
        if (!kvm_mwait_in_guest()) {
                set_intercept(svm, INTERCEPT_MONITOR);
@@ -1903,6 +1908,7 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        u32 dummy;
        u32 eax = 1;
 
+       vcpu->arch.microcode_version = 0x01000065;
        svm->spec_ctrl = 0;
 
        if (!init_event) {
@@ -3700,6 +3706,12 @@ static int emulate_on_interception(struct vcpu_svm *svm)
        return emulate_instruction(&svm->vcpu, 0) == EMULATE_DONE;
 }
 
+static int rsm_interception(struct vcpu_svm *svm)
+{
+       return x86_emulate_instruction(&svm->vcpu, 0, 0,
+                                      rsm_ins_bytes, 2) == EMULATE_DONE;
+}
+
 static int rdpmc_interception(struct vcpu_svm *svm)
 {
        int err;
@@ -3861,6 +3873,22 @@ static int cr8_write_interception(struct vcpu_svm *svm)
        return 0;
 }
 
+static int svm_get_msr_feature(struct kvm_msr_entry *msr)
+{
+       msr->data = 0;
+
+       switch (msr->index) {
+       case MSR_F10H_DECFG:
+               if (boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
+                       msr->data |= MSR_F10H_DECFG_LFENCE_SERIALIZE;
+               break;
+       default:
+               return 1;
+       }
+
+       return 0;
+}
+
 static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -3936,9 +3964,6 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
                msr_info->data = svm->spec_ctrl;
                break;
-       case MSR_IA32_UCODE_REV:
-               msr_info->data = 0x01000065;
-               break;
        case MSR_F15H_IC_CFG: {
 
                int family, model;
@@ -3956,6 +3981,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                        msr_info->data = 0x1E;
                }
                break;
+       case MSR_F10H_DECFG:
+               msr_info->data = svm->msr_decfg;
+               break;
        default:
                return kvm_get_msr_common(vcpu, msr_info);
        }
@@ -4134,6 +4162,24 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
        case MSR_VM_IGNNE:
                vcpu_unimpl(vcpu, "unimplemented wrmsr: 0x%x data 0x%llx\n", ecx, data);
                break;
+       case MSR_F10H_DECFG: {
+               struct kvm_msr_entry msr_entry;
+
+               msr_entry.index = msr->index;
+               if (svm_get_msr_feature(&msr_entry))
+                       return 1;
+
+               /* Check the supported bits */
+               if (data & ~msr_entry.data)
+                       return 1;
+
+               /* Don't allow the guest to change a bit, #GP */
+               if (!msr->host_initiated && (data ^ msr_entry.data))
+                       return 1;
+
+               svm->msr_decfg = data;
+               break;
+       }
        case MSR_IA32_APICBASE:
                if (kvm_vcpu_apicv_active(vcpu))
                        avic_update_vapic_bar(to_svm(vcpu), data);
@@ -4542,7 +4588,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
        [SVM_EXIT_MWAIT]                        = mwait_interception,
        [SVM_EXIT_XSETBV]                       = xsetbv_interception,
        [SVM_EXIT_NPF]                          = npf_interception,
-       [SVM_EXIT_RSM]                          = emulate_on_interception,
+       [SVM_EXIT_RSM]                          = rsm_interception,
        [SVM_EXIT_AVIC_INCOMPLETE_IPI]          = avic_incomplete_ipi_interception,
        [SVM_EXIT_AVIC_UNACCELERATED_ACCESS]    = avic_unaccelerated_access_interception,
 };
@@ -6237,16 +6283,18 @@ e_free:
 
 static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
 {
+       void __user *measure = (void __user *)(uintptr_t)argp->data;
        struct kvm_sev_info *sev = &kvm->arch.sev_info;
        struct sev_data_launch_measure *data;
        struct kvm_sev_launch_measure params;
+       void __user *p = NULL;
        void *blob = NULL;
        int ret;
 
        if (!sev_guest(kvm))
                return -ENOTTY;
 
-       if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
+       if (copy_from_user(&params, measure, sizeof(params)))
                return -EFAULT;
 
        data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -6257,17 +6305,13 @@ static int sev_launch_measure(struct kvm *kvm, struct kvm_sev_cmd *argp)
        if (!params.len)
                goto cmd;
 
-       if (params.uaddr) {
+       p = (void __user *)(uintptr_t)params.uaddr;
+       if (p) {
                if (params.len > SEV_FW_BLOB_MAX_SIZE) {
                        ret = -EINVAL;
                        goto e_free;
                }
 
-               if (!access_ok(VERIFY_WRITE, params.uaddr, params.len)) {
-                       ret = -EFAULT;
-                       goto e_free;
-               }
-
                ret = -ENOMEM;
                blob = kmalloc(params.len, GFP_KERNEL);
                if (!blob)
@@ -6291,13 +6335,13 @@ cmd:
                goto e_free_blob;
 
        if (blob) {
-               if (copy_to_user((void __user *)(uintptr_t)params.uaddr, blob, params.len))
+               if (copy_to_user(p, blob, params.len))
                        ret = -EFAULT;
        }
 
 done:
        params.len = data->len;
-       if (copy_to_user((void __user *)(uintptr_t)argp->data, &params, sizeof(params)))
+       if (copy_to_user(measure, &params, sizeof(params)))
                ret = -EFAULT;
 e_free_blob:
        kfree(blob);
@@ -6598,7 +6642,7 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
        struct page **pages;
        void *blob, *hdr;
        unsigned long n;
-       int ret;
+       int ret, offset;
 
        if (!sev_guest(kvm))
                return -ENOTTY;
@@ -6624,6 +6668,10 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
        if (!data)
                goto e_unpin_memory;
 
+       offset = params.guest_uaddr & (PAGE_SIZE - 1);
+       data->guest_address = __sme_page_pa(pages[0]) + offset;
+       data->guest_len = params.guest_len;
+
        blob = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
        if (IS_ERR(blob)) {
                ret = PTR_ERR(blob);
@@ -6638,8 +6686,8 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
                ret = PTR_ERR(hdr);
                goto e_free_blob;
        }
-       data->trans_address = __psp_pa(blob);
-       data->trans_len = params.trans_len;
+       data->hdr_address = __psp_pa(hdr);
+       data->hdr_len = params.hdr_len;
 
        data->handle = sev->handle;
        ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_SECRET, data, &argp->error);
@@ -6822,6 +6870,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .vcpu_unblocking = svm_vcpu_unblocking,
 
        .update_bp_intercept = update_bp_intercept,
+       .get_msr_feature = svm_get_msr_feature,
        .get_msr = svm_get_msr,
        .set_msr = svm_set_msr,
        .get_segment_base = svm_get_segment_base,
index 7f8401d..657c934 100644 (file)
@@ -1045,6 +1045,13 @@ static inline bool is_machine_check(u32 intr_info)
                (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK);
 }
 
+/* Undocumented: icebp/int1 */
+static inline bool is_icebp(u32 intr_info)
+{
+       return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK))
+               == (INTR_TYPE_PRIV_SW_EXCEPTION | INTR_INFO_VALID_MASK);
+}
+
 static inline bool cpu_has_vmx_msr_bitmap(void)
 {
        return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS;
@@ -3227,6 +3234,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
        return !(val & ~valid_bits);
 }
 
+static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
+{
+       return 1;
+}
+
 /*
  * Reads an msr value (of 'msr_index') into 'pdata'.
  * Returns 0 on success, non-0 otherwise.
@@ -4486,7 +4498,8 @@ static int vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
                vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
                              SECONDARY_EXEC_DESC);
                hw_cr4 &= ~X86_CR4_UMIP;
-       } else
+       } else if (!is_guest_mode(vcpu) ||
+                  !nested_cpu_has2(get_vmcs12(vcpu), SECONDARY_EXEC_DESC))
                vmcs_clear_bits(SECONDARY_VM_EXEC_CONTROL,
                                SECONDARY_EXEC_DESC);
 
@@ -5766,6 +5779,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
        vmx->rmode.vm86_active = 0;
        vmx->spec_ctrl = 0;
 
+       vcpu->arch.microcode_version = 0x100000000ULL;
        vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
        kvm_set_cr8(vcpu, 0);
 
@@ -6172,7 +6186,7 @@ static int handle_exception(struct kvm_vcpu *vcpu)
                      (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) {
                        vcpu->arch.dr6 &= ~15;
                        vcpu->arch.dr6 |= dr6 | DR6_RTM;
-                       if (!(dr6 & ~DR6_RESERVED)) /* icebp */
+                       if (is_icebp(intr_info))
                                skip_emulated_instruction(vcpu);
 
                        kvm_queue_exception(vcpu, DB_VECTOR);
@@ -10697,6 +10711,11 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        u32 exec_control, vmcs12_exec_ctrl;
 
+       if (vmx->nested.dirty_vmcs12) {
+               prepare_vmcs02_full(vcpu, vmcs12, from_vmentry);
+               vmx->nested.dirty_vmcs12 = false;
+       }
+
        /*
         * First, the fields that are shadowed.  This must be kept in sync
         * with vmx_shadow_fields.h.
@@ -10934,11 +10953,6 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        /* Note: modifies VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */
        vmx_set_efer(vcpu, vcpu->arch.efer);
 
-       if (vmx->nested.dirty_vmcs12) {
-               prepare_vmcs02_full(vcpu, vmcs12, from_vmentry);
-               vmx->nested.dirty_vmcs12 = false;
-       }
-
        /* Shadow page tables on either EPT or shadow page tables. */
        if (nested_vmx_load_cr3(vcpu, vmcs12->guest_cr3, nested_cpu_has_ept(vmcs12),
                                entry_failure_code))
@@ -11200,7 +11214,12 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
        if (ret)
                return ret;
 
-       if (vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT)
+       /*
+        * If we're entering a halted L2 vcpu and the L2 vcpu won't be woken
+        * by event injection, halt vcpu.
+        */
+       if ((vmcs12->guest_activity_state == GUEST_ACTIVITY_HLT) &&
+           !(vmcs12->vm_entry_intr_info_field & INTR_INFO_VALID_MASK))
                return kvm_vcpu_halt(vcpu);
 
        vmx->nested.nested_run_pending = 1;
@@ -12291,6 +12310,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .vcpu_put = vmx_vcpu_put,
 
        .update_bp_intercept = update_exception_bitmap,
+       .get_msr_feature = vmx_get_msr_feature,
        .get_msr = vmx_get_msr,
        .set_msr = vmx_set_msr,
        .get_segment_base = vmx_get_segment_base,
index c8a0b54..18b5ca7 100644 (file)
@@ -1049,6 +1049,45 @@ static u32 emulated_msrs[] = {
 
 static unsigned num_emulated_msrs;
 
+/*
+ * List of msr numbers which are used to expose MSR-based features that
+ * can be used by a hypervisor to validate requested CPU features.
+ */
+static u32 msr_based_features[] = {
+       MSR_F10H_DECFG,
+       MSR_IA32_UCODE_REV,
+};
+
+static unsigned int num_msr_based_features;
+
+static int kvm_get_msr_feature(struct kvm_msr_entry *msr)
+{
+       switch (msr->index) {
+       case MSR_IA32_UCODE_REV:
+               rdmsrl(msr->index, msr->data);
+               break;
+       default:
+               if (kvm_x86_ops->get_msr_feature(msr))
+                       return 1;
+       }
+       return 0;
+}
+
+static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
+{
+       struct kvm_msr_entry msr;
+       int r;
+
+       msr.index = index;
+       r = kvm_get_msr_feature(&msr);
+       if (r)
+               return r;
+
+       *data = msr.data;
+
+       return 0;
+}
+
 bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
 {
        if (efer & efer_reserved_bits)
@@ -2222,7 +2261,6 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 
        switch (msr) {
        case MSR_AMD64_NB_CFG:
-       case MSR_IA32_UCODE_REV:
        case MSR_IA32_UCODE_WRITE:
        case MSR_VM_HSAVE_PA:
        case MSR_AMD64_PATCH_LOADER:
@@ -2230,6 +2268,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case MSR_AMD64_DC_CFG:
                break;
 
+       case MSR_IA32_UCODE_REV:
+               if (msr_info->host_initiated)
+                       vcpu->arch.microcode_version = data;
+               break;
        case MSR_EFER:
                return set_efer(vcpu, data);
        case MSR_K7_HWCR:
@@ -2525,7 +2567,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
                msr_info->data = 0;
                break;
        case MSR_IA32_UCODE_REV:
-               msr_info->data = 0x100000000ULL;
+               msr_info->data = vcpu->arch.microcode_version;
                break;
        case MSR_MTRRcap:
        case 0x200 ... 0x2ff:
@@ -2680,13 +2722,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
                    int (*do_msr)(struct kvm_vcpu *vcpu,
                                  unsigned index, u64 *data))
 {
-       int i, idx;
+       int i;
 
-       idx = srcu_read_lock(&vcpu->kvm->srcu);
        for (i = 0; i < msrs->nmsrs; ++i)
                if (do_msr(vcpu, entries[i].index, &entries[i].data))
                        break;
-       srcu_read_unlock(&vcpu->kvm->srcu, idx);
 
        return i;
 }
@@ -2785,6 +2825,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
        case KVM_CAP_SET_BOOT_CPU_ID:
        case KVM_CAP_SPLIT_IRQCHIP:
        case KVM_CAP_IMMEDIATE_EXIT:
+       case KVM_CAP_GET_MSR_FEATURES:
                r = 1;
                break;
        case KVM_CAP_ADJUST_CLOCK:
@@ -2899,6 +2940,31 @@ long kvm_arch_dev_ioctl(struct file *filp,
                        goto out;
                r = 0;
                break;
+       case KVM_GET_MSR_FEATURE_INDEX_LIST: {
+               struct kvm_msr_list __user *user_msr_list = argp;
+               struct kvm_msr_list msr_list;
+               unsigned int n;
+
+               r = -EFAULT;
+               if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list)))
+                       goto out;
+               n = msr_list.nmsrs;
+               msr_list.nmsrs = num_msr_based_features;
+               if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list)))
+                       goto out;
+               r = -E2BIG;
+               if (n < msr_list.nmsrs)
+                       goto out;
+               r = -EFAULT;
+               if (copy_to_user(user_msr_list->indices, &msr_based_features,
+                                num_msr_based_features * sizeof(u32)))
+                       goto out;
+               r = 0;
+               break;
+       }
+       case KVM_GET_MSRS:
+               r = msr_io(NULL, argp, do_get_msr_feature, 1);
+               break;
        }
        default:
                r = -EINVAL;
@@ -3636,12 +3702,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = 0;
                break;
        }
-       case KVM_GET_MSRS:
+       case KVM_GET_MSRS: {
+               int idx = srcu_read_lock(&vcpu->kvm->srcu);
                r = msr_io(vcpu, argp, do_get_msr, 1);
+               srcu_read_unlock(&vcpu->kvm->srcu, idx);
                break;
-       case KVM_SET_MSRS:
+       }
+       case KVM_SET_MSRS: {
+               int idx = srcu_read_lock(&vcpu->kvm->srcu);
                r = msr_io(vcpu, argp, do_set_msr, 0);
+               srcu_read_unlock(&vcpu->kvm->srcu, idx);
                break;
+       }
        case KVM_TPR_ACCESS_REPORTING: {
                struct kvm_tpr_access_ctl tac;
 
@@ -4464,6 +4536,19 @@ static void kvm_init_msr_list(void)
                j++;
        }
        num_emulated_msrs = j;
+
+       for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) {
+               struct kvm_msr_entry msr;
+
+               msr.index = msr_based_features[i];
+               if (kvm_get_msr_feature(&msr))
+                       continue;
+
+               if (j < i)
+                       msr_based_features[j] = msr_based_features[i];
+               j++;
+       }
+       num_msr_based_features = j;
 }
 
 static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
@@ -8017,6 +8102,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 
 void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 {
+       kvm_lapic_reset(vcpu, init_event);
+
        vcpu->arch.hflags = 0;
 
        vcpu->arch.smi_pending = 0;
@@ -8460,10 +8547,8 @@ int __x86_set_memory_region(struct kvm *kvm, int id, gpa_t gpa, u32 size)
                        return r;
        }
 
-       if (!size) {
-               r = vm_munmap(old.userspace_addr, old.npages * PAGE_SIZE);
-               WARN_ON(r < 0);
-       }
+       if (!size)
+               vm_munmap(old.userspace_addr, old.npages * PAGE_SIZE);
 
        return 0;
 }
index 7b881d0..3cdf061 100644 (file)
@@ -7,6 +7,7 @@ asmlinkage void just_return_func(void);
 
 asm(
        ".type just_return_func, @function\n"
+       ".globl just_return_func\n"
        "just_return_func:\n"
        "       ret\n"
        ".size just_return_func, .-just_return_func\n"
index c88573d..25a30b5 100644 (file)
@@ -330,7 +330,7 @@ static noinline int vmalloc_fault(unsigned long address)
        if (!pmd_k)
                return -1;
 
-       if (pmd_huge(*pmd_k))
+       if (pmd_large(*pmd_k))
                return 0;
 
        pte_k = pte_offset_kernel(pmd_k, address);
@@ -475,7 +475,7 @@ static noinline int vmalloc_fault(unsigned long address)
        if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref))
                BUG();
 
-       if (pud_huge(*pud))
+       if (pud_large(*pud))
                return 0;
 
        pmd = pmd_offset(pud, address);
@@ -486,7 +486,7 @@ static noinline int vmalloc_fault(unsigned long address)
        if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref))
                BUG();
 
-       if (pmd_huge(*pmd))
+       if (pmd_large(*pmd))
                return 0;
 
        pte_ref = pte_offset_kernel(pmd_ref, address);
index fecb0c0..af11a28 100644 (file)
@@ -800,17 +800,11 @@ int arch_add_memory(int nid, u64 start, u64 size, struct vmem_altmap *altmap,
 
 #define PAGE_INUSE 0xFD
 
-static void __meminit free_pagetable(struct page *page, int order,
-               struct vmem_altmap *altmap)
+static void __meminit free_pagetable(struct page *page, int order)
 {
        unsigned long magic;
        unsigned int nr_pages = 1 << order;
 
-       if (altmap) {
-               vmem_altmap_free(altmap, nr_pages);
-               return;
-       }
-
        /* bootmem page has reserved flag */
        if (PageReserved(page)) {
                __ClearPageReserved(page);
@@ -826,9 +820,17 @@ static void __meminit free_pagetable(struct page *page, int order,
                free_pages((unsigned long)page_address(page), order);
 }
 
-static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd,
+static void __meminit free_hugepage_table(struct page *page,
                struct vmem_altmap *altmap)
 {
+       if (altmap)
+               vmem_altmap_free(altmap, PMD_SIZE / PAGE_SIZE);
+       else
+               free_pagetable(page, get_order(PMD_SIZE));
+}
+
+static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd)
+{
        pte_t *pte;
        int i;
 
@@ -839,14 +841,13 @@ static void __meminit free_pte_table(pte_t *pte_start, pmd_t *pmd,
        }
 
        /* free a pte talbe */
-       free_pagetable(pmd_page(*pmd), 0, altmap);
+       free_pagetable(pmd_page(*pmd), 0);
        spin_lock(&init_mm.page_table_lock);
        pmd_clear(pmd);
        spin_unlock(&init_mm.page_table_lock);
 }
 
-static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud,
-               struct vmem_altmap *altmap)
+static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud)
 {
        pmd_t *pmd;
        int i;
@@ -858,14 +859,13 @@ static void __meminit free_pmd_table(pmd_t *pmd_start, pud_t *pud,
        }
 
        /* free a pmd talbe */
-       free_pagetable(pud_page(*pud), 0, altmap);
+       free_pagetable(pud_page(*pud), 0);
        spin_lock(&init_mm.page_table_lock);
        pud_clear(pud);
        spin_unlock(&init_mm.page_table_lock);
 }
 
-static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d,
-               struct vmem_altmap *altmap)
+static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d)
 {
        pud_t *pud;
        int i;
@@ -877,7 +877,7 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d,
        }
 
        /* free a pud talbe */
-       free_pagetable(p4d_page(*p4d), 0, altmap);
+       free_pagetable(p4d_page(*p4d), 0);
        spin_lock(&init_mm.page_table_lock);
        p4d_clear(p4d);
        spin_unlock(&init_mm.page_table_lock);
@@ -885,7 +885,7 @@ static void __meminit free_pud_table(pud_t *pud_start, p4d_t *p4d,
 
 static void __meminit
 remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
-                struct vmem_altmap *altmap, bool direct)
+                bool direct)
 {
        unsigned long next, pages = 0;
        pte_t *pte;
@@ -916,7 +916,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
                         * freed when offlining, or simplely not in use.
                         */
                        if (!direct)
-                               free_pagetable(pte_page(*pte), 0, altmap);
+                               free_pagetable(pte_page(*pte), 0);
 
                        spin_lock(&init_mm.page_table_lock);
                        pte_clear(&init_mm, addr, pte);
@@ -939,7 +939,7 @@ remove_pte_table(pte_t *pte_start, unsigned long addr, unsigned long end,
 
                        page_addr = page_address(pte_page(*pte));
                        if (!memchr_inv(page_addr, PAGE_INUSE, PAGE_SIZE)) {
-                               free_pagetable(pte_page(*pte), 0, altmap);
+                               free_pagetable(pte_page(*pte), 0);
 
                                spin_lock(&init_mm.page_table_lock);
                                pte_clear(&init_mm, addr, pte);
@@ -974,9 +974,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
                        if (IS_ALIGNED(addr, PMD_SIZE) &&
                            IS_ALIGNED(next, PMD_SIZE)) {
                                if (!direct)
-                                       free_pagetable(pmd_page(*pmd),
-                                                      get_order(PMD_SIZE),
-                                                      altmap);
+                                       free_hugepage_table(pmd_page(*pmd),
+                                                           altmap);
 
                                spin_lock(&init_mm.page_table_lock);
                                pmd_clear(pmd);
@@ -989,9 +988,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
                                page_addr = page_address(pmd_page(*pmd));
                                if (!memchr_inv(page_addr, PAGE_INUSE,
                                                PMD_SIZE)) {
-                                       free_pagetable(pmd_page(*pmd),
-                                                      get_order(PMD_SIZE),
-                                                      altmap);
+                                       free_hugepage_table(pmd_page(*pmd),
+                                                           altmap);
 
                                        spin_lock(&init_mm.page_table_lock);
                                        pmd_clear(pmd);
@@ -1003,8 +1001,8 @@ remove_pmd_table(pmd_t *pmd_start, unsigned long addr, unsigned long end,
                }
 
                pte_base = (pte_t *)pmd_page_vaddr(*pmd);
-               remove_pte_table(pte_base, addr, next, altmap, direct);
-               free_pte_table(pte_base, pmd, altmap);
+               remove_pte_table(pte_base, addr, next, direct);
+               free_pte_table(pte_base, pmd);
        }
 
        /* Call free_pmd_table() in remove_pud_table(). */
@@ -1033,8 +1031,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
                            IS_ALIGNED(next, PUD_SIZE)) {
                                if (!direct)
                                        free_pagetable(pud_page(*pud),
-                                                      get_order(PUD_SIZE),
-                                                      altmap);
+                                                      get_order(PUD_SIZE));
 
                                spin_lock(&init_mm.page_table_lock);
                                pud_clear(pud);
@@ -1048,8 +1045,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
                                if (!memchr_inv(page_addr, PAGE_INUSE,
                                                PUD_SIZE)) {
                                        free_pagetable(pud_page(*pud),
-                                                      get_order(PUD_SIZE),
-                                                      altmap);
+                                                      get_order(PUD_SIZE));
 
                                        spin_lock(&init_mm.page_table_lock);
                                        pud_clear(pud);
@@ -1062,7 +1058,7 @@ remove_pud_table(pud_t *pud_start, unsigned long addr, unsigned long end,
 
                pmd_base = pmd_offset(pud, 0);
                remove_pmd_table(pmd_base, addr, next, direct, altmap);
-               free_pmd_table(pmd_base, pud, altmap);
+               free_pmd_table(pmd_base, pud);
        }
 
        if (direct)
@@ -1094,7 +1090,7 @@ remove_p4d_table(p4d_t *p4d_start, unsigned long addr, unsigned long end,
                 * to adapt for boot-time switching between 4 and 5 level page tables.
                 */
                if (CONFIG_PGTABLE_LEVELS == 5)
-                       free_pud_table(pud_base, p4d, altmap);
+                       free_pud_table(pud_base, p4d);
        }
 
        if (direct)
@@ -1193,8 +1189,8 @@ void __init mem_init(void)
        register_page_bootmem_info();
 
        /* Register memory areas for /proc/kcore */
-       kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR,
-                        PAGE_SIZE, KCORE_OTHER);
+       if (get_gate_vma(&init_mm))
+               kclist_add(&kcore_vsyscall, (void *)VSYSCALL_ADDR, PAGE_SIZE, KCORE_USER);
 
        mem_init_print_info(NULL);
 }
index 004abf9..34cda7e 100644 (file)
@@ -702,4 +702,52 @@ int pmd_clear_huge(pmd_t *pmd)
 
        return 0;
 }
+
+/**
+ * pud_free_pmd_page - Clear pud entry and free pmd page.
+ * @pud: Pointer to a PUD.
+ *
+ * Context: The pud range has been unmaped and TLB purged.
+ * Return: 1 if clearing the entry succeeded. 0 otherwise.
+ */
+int pud_free_pmd_page(pud_t *pud)
+{
+       pmd_t *pmd;
+       int i;
+
+       if (pud_none(*pud))
+               return 1;
+
+       pmd = (pmd_t *)pud_page_vaddr(*pud);
+
+       for (i = 0; i < PTRS_PER_PMD; i++)
+               if (!pmd_free_pte_page(&pmd[i]))
+                       return 0;
+
+       pud_clear(pud);
+       free_page((unsigned long)pmd);
+
+       return 1;
+}
+
+/**
+ * pmd_free_pte_page - Clear pmd entry and free pte page.
+ * @pmd: Pointer to a PMD.
+ *
+ * Context: The pmd range has been unmaped and TLB purged.
+ * Return: 1 if clearing the entry succeeded. 0 otherwise.
+ */
+int pmd_free_pte_page(pmd_t *pmd)
+{
+       pte_t *pte;
+
+       if (pmd_none(*pmd))
+               return 1;
+
+       pte = (pte_t *)pmd_page_vaddr(*pmd);
+       pmd_clear(pmd);
+       free_page((unsigned long)pte);
+
+       return 1;
+}
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
index 4923d92..ce5b2eb 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/if_vlan.h>
 #include <asm/cacheflush.h>
 #include <asm/set_memory.h>
+#include <asm/nospec-branch.h>
 #include <linux/bpf.h>
 
 /*
@@ -290,7 +291,7 @@ static void emit_bpf_tail_call(u8 **pprog)
        EMIT2(0x89, 0xD2);                        /* mov edx, edx */
        EMIT3(0x39, 0x56,                         /* cmp dword ptr [rsi + 16], edx */
              offsetof(struct bpf_array, map.max_entries));
-#define OFFSET1 43 /* number of bytes to jump */
+#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */
        EMIT2(X86_JBE, OFFSET1);                  /* jbe out */
        label1 = cnt;
 
@@ -299,7 +300,7 @@ static void emit_bpf_tail_call(u8 **pprog)
         */
        EMIT2_off32(0x8B, 0x85, 36);              /* mov eax, dword ptr [rbp + 36] */
        EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT);     /* cmp eax, MAX_TAIL_CALL_CNT */
-#define OFFSET2 32
+#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE)
        EMIT2(X86_JA, OFFSET2);                   /* ja out */
        label2 = cnt;
        EMIT3(0x83, 0xC0, 0x01);                  /* add eax, 1 */
@@ -313,7 +314,7 @@ static void emit_bpf_tail_call(u8 **pprog)
         *   goto out;
         */
        EMIT3(0x48, 0x85, 0xC0);                  /* test rax,rax */
-#define OFFSET3 10
+#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE)
        EMIT2(X86_JE, OFFSET3);                   /* je out */
        label3 = cnt;
 
@@ -326,7 +327,7 @@ static void emit_bpf_tail_call(u8 **pprog)
         * rdi == ctx (1st arg)
         * rax == prog->bpf_func + prologue_size
         */
-       EMIT2(0xFF, 0xE0);                        /* jmp rax */
+       RETPOLINE_RAX_BPF_JIT();
 
        /* out: */
        BUILD_BUG_ON(cnt - label1 != OFFSET1);
@@ -1187,7 +1188,7 @@ skip_init_addrs:
         * may converge on the last pass. In such case do one more
         * pass to emit the final image
         */
-       for (pass = 0; pass < 10 || image; pass++) {
+       for (pass = 0; pass < 20 || image; pass++) {
                proglen = do_jit(prog, addrs, image, oldproglen, &ctx);
                if (proglen <= 0) {
                        image = NULL;
@@ -1214,6 +1215,7 @@ skip_init_addrs:
                        }
                }
                oldproglen = proglen;
+               cond_resched();
        }
 
        if (bpf_jit_enable > 1)
index 174c597..a7a7677 100644 (file)
@@ -460,7 +460,7 @@ static int nmi_setup(void)
                goto fail;
 
        for_each_possible_cpu(cpu) {
-               if (!cpu)
+               if (!IS_ENABLED(CONFIG_SMP) || !cpu)
                        continue;
 
                memcpy(per_cpu(cpu_msrs, cpu).counters,
index 2c67bae..fb1df94 100644 (file)
@@ -79,7 +79,7 @@ static void intel_mid_power_off(void)
 
 static void intel_mid_reboot(void)
 {
-       intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0);
+       intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0);
 }
 
 static unsigned long __init intel_mid_calibrate_tsc(void)
index 5d73c44..220e978 100644 (file)
@@ -770,9 +770,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
                break;
 
        case R_X86_64_PC32:
+       case R_X86_64_PLT32:
                /*
                 * PC relative relocations don't need to be adjusted unless
                 * referencing a percpu symbol.
+                *
+                * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
                 */
                if (is_percpu_sym(sym, symname))
                        add_reloc(&relocs32neg, offset);
index c047f42..3c2c253 100644 (file)
@@ -1376,8 +1376,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
        if (!xen_initial_domain()) {
                add_preferred_console("xenboot", 0, NULL);
-               add_preferred_console("tty", 0, NULL);
-               add_preferred_console("hvc", 0, NULL);
                if (pci_xen)
                        x86_init.pci.arch_init = pci_xen_init;
        } else {
@@ -1410,6 +1408,10 @@ asmlinkage __visible void __init xen_start_kernel(void)
 
                xen_boot_params_init_edd();
        }
+
+       add_preferred_console("tty", 0, NULL);
+       add_preferred_console("hvc", 0, NULL);
+
 #ifdef CONFIG_PCI
        /* PCI BIOS service won't work from a PV guest. */
        pci_probe &= ~PCI_PROBE_BIOS;
index 77c959c..7a43b2a 100644 (file)
@@ -122,6 +122,8 @@ void __init xen_smp_cpus_done(unsigned int max_cpus)
 
        if (xen_hvm_domain())
                native_smp_cpus_done(max_cpus);
+       else
+               calculate_max_logical_packages();
 
        if (xen_have_vcpu_info_placement)
                return;
index 623720a..732631c 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/dma-contiguous.h>
+#include <linux/dma-direct.h>
 #include <linux/gfp.h>
 #include <linux/highmem.h>
 #include <linux/mm.h>
@@ -123,7 +124,7 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
                              unsigned long attrs)
 {
        unsigned long ret;
-       unsigned long uncached = 0;
+       unsigned long uncached;
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
        struct page *page = NULL;
 
@@ -144,15 +145,27 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
        if (!page)
                return NULL;
 
-       ret = (unsigned long)page_address(page);
+       *handle = phys_to_dma(dev, page_to_phys(page));
 
-       /* We currently don't support coherent memory outside KSEG */
+#ifdef CONFIG_MMU
+       if (PageHighMem(page)) {
+               void *p;
 
+               p = dma_common_contiguous_remap(page, size, VM_MAP,
+                                               pgprot_noncached(PAGE_KERNEL),
+                                               __builtin_return_address(0));
+               if (!p) {
+                       if (!dma_release_from_contiguous(dev, page, count))
+                               __free_pages(page, get_order(size));
+               }
+               return p;
+       }
+#endif
+       ret = (unsigned long)page_address(page);
        BUG_ON(ret < XCHAL_KSEG_CACHED_VADDR ||
               ret > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
 
        uncached = ret + XCHAL_KSEG_BYPASS_VADDR - XCHAL_KSEG_CACHED_VADDR;
-       *handle = virt_to_bus((void *)ret);
        __invalidate_dcache_range(ret, size);
 
        return (void *)uncached;
@@ -161,13 +174,20 @@ static void *xtensa_dma_alloc(struct device *dev, size_t size,
 static void xtensa_dma_free(struct device *dev, size_t size, void *vaddr,
                            dma_addr_t dma_handle, unsigned long attrs)
 {
-       unsigned long addr = (unsigned long)vaddr +
-               XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
-       struct page *page = virt_to_page(addr);
        unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
-
-       BUG_ON(addr < XCHAL_KSEG_CACHED_VADDR ||
-              addr > XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_SIZE - 1);
+       unsigned long addr = (unsigned long)vaddr;
+       struct page *page;
+
+       if (addr >= XCHAL_KSEG_BYPASS_VADDR &&
+           addr - XCHAL_KSEG_BYPASS_VADDR < XCHAL_KSEG_SIZE) {
+               addr += XCHAL_KSEG_CACHED_VADDR - XCHAL_KSEG_BYPASS_VADDR;
+               page = virt_to_page(addr);
+       } else {
+#ifdef CONFIG_MMU
+               dma_common_free_remap(vaddr, size, VM_MAP);
+#endif
+               page = pfn_to_page(PHYS_PFN(dma_to_phys(dev, dma_handle)));
+       }
 
        if (!dma_release_from_contiguous(dev, page, count))
                __free_pages(page, get_order(size));
index d776ec0..34aead7 100644 (file)
@@ -79,19 +79,75 @@ void __init zones_init(void)
        free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL);
 }
 
+#ifdef CONFIG_HIGHMEM
+static void __init free_area_high(unsigned long pfn, unsigned long end)
+{
+       for (; pfn < end; pfn++)
+               free_highmem_page(pfn_to_page(pfn));
+}
+
+static void __init free_highpages(void)
+{
+       unsigned long max_low = max_low_pfn;
+       struct memblock_region *mem, *res;
+
+       reset_all_zones_managed_pages();
+       /* set highmem page free */
+       for_each_memblock(memory, mem) {
+               unsigned long start = memblock_region_memory_base_pfn(mem);
+               unsigned long end = memblock_region_memory_end_pfn(mem);
+
+               /* Ignore complete lowmem entries */
+               if (end <= max_low)
+                       continue;
+
+               if (memblock_is_nomap(mem))
+                       continue;
+
+               /* Truncate partial highmem entries */
+               if (start < max_low)
+                       start = max_low;
+
+               /* Find and exclude any reserved regions */
+               for_each_memblock(reserved, res) {
+                       unsigned long res_start, res_end;
+
+                       res_start = memblock_region_reserved_base_pfn(res);
+                       res_end = memblock_region_reserved_end_pfn(res);
+
+                       if (res_end < start)
+                               continue;
+                       if (res_start < start)
+                               res_start = start;
+                       if (res_start > end)
+                               res_start = end;
+                       if (res_end > end)
+                               res_end = end;
+                       if (res_start != start)
+                               free_area_high(start, res_start);
+                       start = res_end;
+                       if (start == end)
+                               break;
+               }
+
+               /* And now free anything which remains */
+               if (start < end)
+                       free_area_high(start, end);
+       }
+}
+#else
+static void __init free_highpages(void)
+{
+}
+#endif
+
 /*
  * Initialize memory pages.
  */
 
 void __init mem_init(void)
 {
-#ifdef CONFIG_HIGHMEM
-       unsigned long tmp;
-
-       reset_all_zones_managed_pages();
-       for (tmp = max_low_pfn; tmp < max_pfn; tmp++)
-               free_highmem_page(pfn_to_page(tmp));
-#endif
+       free_highpages();
 
        max_mapnr = max_pfn - ARCH_PFN_OFFSET;
        high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT);
index 4117524..c2033a2 100644 (file)
@@ -812,7 +812,6 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
        struct gendisk *disk;
        struct request_queue *q;
        struct blkcg_gq *blkg;
-       struct module *owner;
        unsigned int major, minor;
        int key_len, part, ret;
        char *body;
@@ -904,9 +903,7 @@ fail_unlock:
        spin_unlock_irq(q->queue_lock);
        rcu_read_unlock();
 fail:
-       owner = disk->fops->owner;
-       put_disk(disk);
-       module_put(owner);
+       put_disk_and_module(disk);
        /*
         * If queue was bypassing, we should retry.  Do so after a
         * short msleep().  It isn't strictly necessary but queue
@@ -931,13 +928,9 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep);
 void blkg_conf_finish(struct blkg_conf_ctx *ctx)
        __releases(ctx->disk->queue->queue_lock) __releases(rcu)
 {
-       struct module *owner;
-
        spin_unlock_irq(ctx->disk->queue->queue_lock);
        rcu_read_unlock();
-       owner = ctx->disk->fops->owner;
-       put_disk(ctx->disk);
-       module_put(owner);
+       put_disk_and_module(ctx->disk);
 }
 EXPORT_SYMBOL_GPL(blkg_conf_finish);
 
index 2d1a7bb..6d82c4f 100644 (file)
@@ -2434,7 +2434,7 @@ blk_qc_t submit_bio(struct bio *bio)
                unsigned int count;
 
                if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME))
-                       count = queue_logical_block_size(bio->bi_disk->queue);
+                       count = queue_logical_block_size(bio->bi_disk->queue) >> 9;
                else
                        count = bio_sectors(bio);
 
index df93102..16e83e6 100644 (file)
@@ -712,7 +712,6 @@ static void __blk_mq_requeue_request(struct request *rq)
 
        trace_block_rq_requeue(q, rq);
        wbt_requeue(q->rq_wb, &rq->issue_stat);
-       blk_mq_sched_requeue_request(rq);
 
        if (blk_mq_rq_state(rq) != MQ_RQ_IDLE) {
                blk_mq_rq_update_state(rq, MQ_RQ_IDLE);
@@ -725,6 +724,9 @@ void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list)
 {
        __blk_mq_requeue_request(rq);
 
+       /* this request will be re-inserted to io scheduler queue */
+       blk_mq_sched_requeue_request(rq);
+
        BUG_ON(blk_queued_rq(rq));
        blk_mq_add_to_requeue_list(rq, true, kick_requeue_list);
 }
@@ -3164,6 +3166,7 @@ static bool __blk_mq_poll(struct blk_mq_hw_ctx *hctx, struct request *rq)
                cpu_relax();
        }
 
+       __set_current_state(TASK_RUNNING);
        return false;
 }
 
index 88a53c1..9656f9e 100644 (file)
@@ -547,7 +547,7 @@ static int exact_lock(dev_t devt, void *data)
 {
        struct gendisk *p = data;
 
-       if (!get_disk(p))
+       if (!get_disk_and_module(p))
                return -1;
        return 0;
 }
@@ -717,6 +717,11 @@ void del_gendisk(struct gendisk *disk)
        blk_integrity_del(disk);
        disk_del_events(disk);
 
+       /*
+        * Block lookups of the disk until all bdevs are unhashed and the
+        * disk is marked as dead (GENHD_FL_UP cleared).
+        */
+       down_write(&disk->lookup_sem);
        /* invalidate stuff */
        disk_part_iter_init(&piter, disk,
                             DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE);
@@ -731,6 +736,7 @@ void del_gendisk(struct gendisk *disk)
        bdev_unhash_inode(disk_devt(disk));
        set_capacity(disk, 0);
        disk->flags &= ~GENHD_FL_UP;
+       up_write(&disk->lookup_sem);
 
        if (!(disk->flags & GENHD_FL_HIDDEN))
                sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
@@ -809,16 +815,28 @@ struct gendisk *get_gendisk(dev_t devt, int *partno)
 
                spin_lock_bh(&ext_devt_lock);
                part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt)));
-               if (part && get_disk(part_to_disk(part))) {
+               if (part && get_disk_and_module(part_to_disk(part))) {
                        *partno = part->partno;
                        disk = part_to_disk(part);
                }
                spin_unlock_bh(&ext_devt_lock);
        }
 
-       if (disk && unlikely(disk->flags & GENHD_FL_HIDDEN)) {
-               put_disk(disk);
+       if (!disk)
+               return NULL;
+
+       /*
+        * Synchronize with del_gendisk() to not return disk that is being
+        * destroyed.
+        */
+       down_read(&disk->lookup_sem);
+       if (unlikely((disk->flags & GENHD_FL_HIDDEN) ||
+                    !(disk->flags & GENHD_FL_UP))) {
+               up_read(&disk->lookup_sem);
+               put_disk_and_module(disk);
                disk = NULL;
+       } else {
+               up_read(&disk->lookup_sem);
        }
        return disk;
 }
@@ -1418,6 +1436,7 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
                        kfree(disk);
                        return NULL;
                }
+               init_rwsem(&disk->lookup_sem);
                disk->node_id = node_id;
                if (disk_expand_part_tbl(disk, 0)) {
                        free_part_stats(&disk->part0);
@@ -1453,7 +1472,7 @@ struct gendisk *__alloc_disk_node(int minors, int node_id)
 }
 EXPORT_SYMBOL(__alloc_disk_node);
 
-struct kobject *get_disk(struct gendisk *disk)
+struct kobject *get_disk_and_module(struct gendisk *disk)
 {
        struct module *owner;
        struct kobject *kobj;
@@ -1471,17 +1490,30 @@ struct kobject *get_disk(struct gendisk *disk)
        return kobj;
 
 }
-
-EXPORT_SYMBOL(get_disk);
+EXPORT_SYMBOL(get_disk_and_module);
 
 void put_disk(struct gendisk *disk)
 {
        if (disk)
                kobject_put(&disk_to_dev(disk)->kobj);
 }
-
 EXPORT_SYMBOL(put_disk);
 
+/*
+ * This is a counterpart of get_disk_and_module() and thus also of
+ * get_gendisk().
+ */
+void put_disk_and_module(struct gendisk *disk)
+{
+       if (disk) {
+               struct module *owner = disk->fops->owner;
+
+               put_disk(disk);
+               module_put(owner);
+       }
+}
+EXPORT_SYMBOL(put_disk_and_module);
+
 static void set_disk_ro_uevent(struct gendisk *gd, int ro)
 {
        char event[] = "DISK_RO=1";
index 1668506..3884d81 100644 (file)
@@ -225,7 +225,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
 
        if (start + len > i_size_read(bdev->bd_inode))
                return -EINVAL;
-       truncate_inode_pages_range(mapping, start, start + len);
+       truncate_inode_pages_range(mapping, start, start + len - 1);
        return blkdev_issue_discard(bdev, start >> 9, len >> 9,
                                    GFP_KERNEL, flags);
 }
index f95c607..0d6d25e 100644 (file)
@@ -833,6 +833,7 @@ static struct elevator_type kyber_sched = {
                .limit_depth = kyber_limit_depth,
                .prepare_request = kyber_prepare_request,
                .finish_request = kyber_finish_request,
+               .requeue_request = kyber_finish_request,
                .completed_request = kyber_completed_request,
                .dispatch_request = kyber_dispatch_request,
                .has_work = kyber_has_work,
index c56f211..8ec0ba9 100644 (file)
@@ -536,12 +536,21 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx,
 }
 
 /*
+ * Nothing to do here. This is defined only to ensure that .finish_request
+ * method is called upon request completion.
+ */
+static void dd_prepare_request(struct request *rq, struct bio *bio)
+{
+}
+
+/*
  * For zoned block devices, write unlock the target zone of
  * completed write requests. Do this while holding the zone lock
  * spinlock so that the zone is never unlocked while deadline_fifo_request()
- * while deadline_next_request() are executing.
+ * or deadline_next_request() are executing. This function is called for
+ * all requests, whether or not these requests complete successfully.
  */
-static void dd_completed_request(struct request *rq)
+static void dd_finish_request(struct request *rq)
 {
        struct request_queue *q = rq->q;
 
@@ -756,7 +765,8 @@ static struct elevator_type mq_deadline = {
        .ops.mq = {
                .insert_requests        = dd_insert_requests,
                .dispatch_request       = dd_dispatch_request,
-               .completed_request      = dd_completed_request,
+               .prepare_request        = dd_prepare_request,
+               .finish_request         = dd_finish_request,
                .next_request           = elv_rb_latter_request,
                .former_request         = elv_rb_former_request,
                .bio_merge              = dd_bio_merge,
index 91622db..08dabcd 100644 (file)
@@ -51,6 +51,12 @@ const char *bdevname(struct block_device *bdev, char *buf)
 
 EXPORT_SYMBOL(bdevname);
 
+const char *bio_devname(struct bio *bio, char *buf)
+{
+       return disk_name(bio->bi_disk, bio->bi_partno, buf);
+}
+EXPORT_SYMBOL(bio_devname);
+
 /*
  * There's very little reason to use this, you should really
  * have a struct block_device just about everywhere and use
index 9ed51d0..e4929ee 100644 (file)
@@ -490,7 +490,7 @@ static int opal_discovery0_end(struct opal_dev *dev)
 
        if (!found_com_id) {
                pr_debug("Could not find OPAL comid for device. Returning early\n");
-               return -EOPNOTSUPP;;
+               return -EOPNOTSUPP;
        }
 
        dev->comid = comid;
index 73fd990..753b703 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include "blacklist.h"
 
-const char __initdata *const blacklist_hashes[] = {
+const char __initconst *const blacklist_hashes[] = {
        NULL
 };
index 1f4e25f..598906b 100644 (file)
@@ -106,6 +106,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
                pr_devel("sinfo %u: Direct signer is key %x\n",
                         sinfo->index, key_serial(key));
                x509 = NULL;
+               sig = sinfo->sig;
                goto matched;
        }
        if (PTR_ERR(key) != -ENOKEY)
index 39e6de0..97c77f6 100644 (file)
@@ -270,7 +270,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
                                sinfo->index);
                        return 0;
                }
-               ret = public_key_verify_signature(p->pub, p->sig);
+               ret = public_key_verify_signature(p->pub, x509->sig);
                if (ret < 0)
                        return ret;
                x509->signer = p;
@@ -366,8 +366,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *
  *  (*) -EBADMSG if some part of the message was invalid, or:
  *
- *  (*) 0 if no signature chains were found to be blacklisted or to contain
- *     unsupported crypto, or:
+ *  (*) 0 if a signature chain passed verification, or:
  *
  *  (*) -EKEYREJECTED if a blacklisted key was encountered, or:
  *
@@ -423,8 +422,11 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
 
        for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
                ret = pkcs7_verify_one(pkcs7, sinfo);
-               if (sinfo->blacklisted && actual_ret == -ENOPKG)
-                       actual_ret = -EKEYREJECTED;
+               if (sinfo->blacklisted) {
+                       if (actual_ret == -ENOPKG)
+                               actual_ret = -EKEYREJECTED;
+                       continue;
+               }
                if (ret < 0) {
                        if (ret == -ENOPKG) {
                                sinfo->unsupported_crypto = true;
index de99658..e929fe1 100644 (file)
@@ -79,9 +79,11 @@ int public_key_verify_signature(const struct public_key *pkey,
 
        BUG_ON(!pkey);
        BUG_ON(!sig);
-       BUG_ON(!sig->digest);
        BUG_ON(!sig->s);
 
+       if (!sig->digest)
+               return -ENOPKG;
+
        alg_name = sig->pkey_algo;
        if (strcmp(sig->pkey_algo, "rsa") == 0) {
                /* The data wangled by the RSA algorithm is typically padded
index 86fb685..7c93c77 100644 (file)
@@ -67,8 +67,9 @@ __setup("ca_keys=", ca_keys_setup);
  *
  * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a
  * matching parent certificate in the trusted list, -EKEYREJECTED if the
- * signature check fails or the key is blacklisted and some other error if
- * there is a matching certificate but the signature check cannot be performed.
+ * signature check fails or the key is blacklisted, -ENOPKG if the signature
+ * uses unsupported crypto, or some other error if there is a matching
+ * certificate but the signature check cannot be performed.
  */
 int restrict_link_by_signature(struct key *dest_keyring,
                               const struct key_type *type,
@@ -88,6 +89,8 @@ int restrict_link_by_signature(struct key *dest_keyring,
                return -EOPNOTSUPP;
 
        sig = payload->data[asym_auth];
+       if (!sig)
+               return -ENOPKG;
        if (!sig->auth_ids[0] && !sig->auth_ids[1])
                return -ENOKEY;
 
@@ -139,6 +142,8 @@ static int key_or_keyring_common(struct key *dest_keyring,
                return -EOPNOTSUPP;
 
        sig = payload->data[asym_auth];
+       if (!sig)
+               return -ENOPKG;
        if (!sig->auth_ids[0] && !sig->auth_ids[1])
                return -ENOKEY;
 
@@ -222,9 +227,9 @@ static int key_or_keyring_common(struct key *dest_keyring,
  *
  * Returns 0 if the new certificate was accepted, -ENOKEY if we
  * couldn't find a matching parent certificate in the trusted list,
- * -EKEYREJECTED if the signature check fails, and some other error if
- * there is a matching certificate but the signature check cannot be
- * performed.
+ * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses
+ * unsupported crypto, or some other error if there is a matching certificate
+ * but the signature check cannot be performed.
  */
 int restrict_link_by_key_or_keyring(struct key *dest_keyring,
                                    const struct key_type *type,
@@ -249,9 +254,9 @@ int restrict_link_by_key_or_keyring(struct key *dest_keyring,
  *
  * Returns 0 if the new certificate was accepted, -ENOKEY if we
  * couldn't find a matching parent certificate in the trusted list,
- * -EKEYREJECTED if the signature check fails, and some other error if
- * there is a matching certificate but the signature check cannot be
- * performed.
+ * -EKEYREJECTED if the signature check fails, -ENOPKG if the signature uses
+ * unsupported crypto, or some other error if there is a matching certificate
+ * but the signature check cannot be performed.
  */
 int restrict_link_by_key_or_keyring_chain(struct key *dest_keyring,
                                          const struct key_type *type,
index 11b113f..ebb626f 100644 (file)
@@ -74,10 +74,10 @@ void __init acpi_watchdog_init(void)
                res.start = gas->address;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        res.flags = IORESOURCE_MEM;
-                       res.end = res.start + ALIGN(gas->access_width, 4);
+                       res.end = res.start + ALIGN(gas->access_width, 4) - 1;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                        res.flags = IORESOURCE_IO;
-                       res.end = res.start + gas->access_width;
+                       res.end = res.start + gas->access_width - 1;
                } else {
                        pr_warn("Unsupported address space: %u\n",
                                gas->space_id);
index 7128488..f2eb6c3 100644 (file)
@@ -70,7 +70,6 @@ static async_cookie_t async_cookie;
 static bool battery_driver_registered;
 static int battery_bix_broken_package;
 static int battery_notification_delay_ms;
-static int battery_full_discharging;
 static unsigned int cache_time = 1000;
 module_param(cache_time, uint, 0644);
 MODULE_PARM_DESC(cache_time, "cache time in milliseconds");
@@ -215,12 +214,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
                return -ENODEV;
        switch (psp) {
        case POWER_SUPPLY_PROP_STATUS:
-               if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) {
-                       if (battery_full_discharging && battery->rate_now == 0)
-                               val->intval = POWER_SUPPLY_STATUS_FULL;
-                       else
-                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
-               } else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
+               if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
+                       val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
                else if (acpi_battery_is_charged(battery))
                        val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -1170,12 +1166,6 @@ battery_notification_delay_quirk(const struct dmi_system_id *d)
        return 0;
 }
 
-static int __init battery_full_discharging_quirk(const struct dmi_system_id *d)
-{
-       battery_full_discharging = 1;
-       return 0;
-}
-
 static const struct dmi_system_id bat_dmi_table[] __initconst = {
        {
                .callback = battery_bix_broken_package_quirk,
@@ -1193,38 +1183,6 @@ static const struct dmi_system_id bat_dmi_table[] __initconst = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-573G"),
                },
        },
-       {
-               .callback = battery_full_discharging_quirk,
-               .ident = "ASUS GL502VSK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "GL502VSK"),
-               },
-       },
-       {
-               .callback = battery_full_discharging_quirk,
-               .ident = "ASUS UX305LA",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "UX305LA"),
-               },
-       },
-       {
-               .callback = battery_full_discharging_quirk,
-               .ident = "ASUS UX360UA",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "UX360UA"),
-               },
-       },
-       {
-               .callback = battery_full_discharging_quirk,
-               .ident = "ASUS UX410UAK",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "UX410UAK"),
-               },
-       },
        {},
 };
 
index 676c978..0dad0bd 100644 (file)
@@ -660,13 +660,15 @@ struct acpi_device *acpi_companion_match(const struct device *dev)
  * acpi_of_match_device - Match device object using the "compatible" property.
  * @adev: ACPI device object to match.
  * @of_match_table: List of device IDs to match against.
+ * @of_id: OF ID if matched
  *
  * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of
  * identifiers and a _DSD object with the "compatible" property, use that
  * property to match against the given list of identifiers.
  */
 static bool acpi_of_match_device(struct acpi_device *adev,
-                                const struct of_device_id *of_match_table)
+                                const struct of_device_id *of_match_table,
+                                const struct of_device_id **of_id)
 {
        const union acpi_object *of_compatible, *obj;
        int i, nval;
@@ -690,8 +692,11 @@ static bool acpi_of_match_device(struct acpi_device *adev,
                const struct of_device_id *id;
 
                for (id = of_match_table; id->compatible[0]; id++)
-                       if (!strcasecmp(obj->string.pointer, id->compatible))
+                       if (!strcasecmp(obj->string.pointer, id->compatible)) {
+                               if (of_id)
+                                       *of_id = id;
                                return true;
+                       }
        }
 
        return false;
@@ -762,10 +767,11 @@ static bool __acpi_match_device_cls(const struct acpi_device_id *id,
        return true;
 }
 
-static const struct acpi_device_id *__acpi_match_device(
-       struct acpi_device *device,
-       const struct acpi_device_id *ids,
-       const struct of_device_id *of_ids)
+static bool __acpi_match_device(struct acpi_device *device,
+                               const struct acpi_device_id *acpi_ids,
+                               const struct of_device_id *of_ids,
+                               const struct acpi_device_id **acpi_id,
+                               const struct of_device_id **of_id)
 {
        const struct acpi_device_id *id;
        struct acpi_hardware_id *hwid;
@@ -775,30 +781,32 @@ static const struct acpi_device_id *__acpi_match_device(
         * driver for it.
         */
        if (!device || !device->status.present)
-               return NULL;
+               return false;
 
        list_for_each_entry(hwid, &device->pnp.ids, list) {
                /* First, check the ACPI/PNP IDs provided by the caller. */
-               for (id = ids; id->id[0] || id->cls; id++) {
-                       if (id->id[0] && !strcmp((char *) id->id, hwid->id))
-                               return id;
-                       else if (id->cls && __acpi_match_device_cls(id, hwid))
-                               return id;
+               if (acpi_ids) {
+                       for (id = acpi_ids; id->id[0] || id->cls; id++) {
+                               if (id->id[0] && !strcmp((char *)id->id, hwid->id))
+                                       goto out_acpi_match;
+                               if (id->cls && __acpi_match_device_cls(id, hwid))
+                                       goto out_acpi_match;
+                       }
                }
 
                /*
                 * Next, check ACPI_DT_NAMESPACE_HID and try to match the
                 * "compatible" property if found.
-                *
-                * The id returned by the below is not valid, but the only
-                * caller passing non-NULL of_ids here is only interested in
-                * whether or not the return value is NULL.
                 */
-               if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id)
-                   && acpi_of_match_device(device, of_ids))
-                       return id;
+               if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id))
+                       return acpi_of_match_device(device, of_ids, of_id);
        }
-       return NULL;
+       return false;
+
+out_acpi_match:
+       if (acpi_id)
+               *acpi_id = id;
+       return true;
 }
 
 /**
@@ -815,32 +823,29 @@ static const struct acpi_device_id *__acpi_match_device(
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                                               const struct device *dev)
 {
-       return __acpi_match_device(acpi_companion_match(dev), ids, NULL);
+       const struct acpi_device_id *id = NULL;
+
+       __acpi_match_device(acpi_companion_match(dev), ids, NULL, &id, NULL);
+       return id;
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
 
-void *acpi_get_match_data(const struct device *dev)
+const void *acpi_device_get_match_data(const struct device *dev)
 {
        const struct acpi_device_id *match;
 
-       if (!dev->driver)
-               return NULL;
-
-       if (!dev->driver->acpi_match_table)
-               return NULL;
-
        match = acpi_match_device(dev->driver->acpi_match_table, dev);
        if (!match)
                return NULL;
 
-       return (void *)match->driver_data;
+       return (const void *)match->driver_data;
 }
-EXPORT_SYMBOL_GPL(acpi_get_match_data);
+EXPORT_SYMBOL_GPL(acpi_device_get_match_data);
 
 int acpi_match_device_ids(struct acpi_device *device,
                          const struct acpi_device_id *ids)
 {
-       return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT;
+       return __acpi_match_device(device, ids, NULL, NULL, NULL) ? 0 : -ENOENT;
 }
 EXPORT_SYMBOL(acpi_match_device_ids);
 
@@ -849,10 +854,12 @@ bool acpi_driver_match_device(struct device *dev,
 {
        if (!drv->acpi_match_table)
                return acpi_of_match_device(ACPI_COMPANION(dev),
-                                           drv->of_match_table);
+                                           drv->of_match_table,
+                                           NULL);
 
-       return !!__acpi_match_device(acpi_companion_match(dev),
-                                    drv->acpi_match_table, drv->of_match_table);
+       return __acpi_match_device(acpi_companion_match(dev),
+                                  drv->acpi_match_table, drv->of_match_table,
+                                  NULL, NULL);
 }
 EXPORT_SYMBOL_GPL(acpi_driver_match_device);
 
index d9f38c6..30a5729 100644 (file)
@@ -1927,6 +1927,9 @@ static int acpi_ec_suspend_noirq(struct device *dev)
            ec->reference_count >= 1)
                acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
 
+       if (acpi_sleep_no_ec_events())
+               acpi_ec_enter_noirq(ec);
+
        return 0;
 }
 
@@ -1934,6 +1937,9 @@ static int acpi_ec_resume_noirq(struct device *dev)
 {
        struct acpi_ec *ec = acpi_driver_data(to_acpi_device(dev));
 
+       if (acpi_sleep_no_ec_events())
+               acpi_ec_leave_noirq(ec);
+
        if (ec_no_wakeup && test_bit(EC_FLAGS_STARTED, &ec->flags) &&
            ec->reference_count >= 1)
                acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
index bbe48ad..eb09ef5 100644 (file)
@@ -2675,10 +2675,14 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
        else
                ndr_desc->numa_node = NUMA_NO_NODE;
 
-       if(acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_CACHE_FLUSH)
+       /*
+        * Persistence domain bits are hierarchical, if
+        * ACPI_NFIT_CAPABILITY_CACHE_FLUSH is set then
+        * ACPI_NFIT_CAPABILITY_MEM_FLUSH is implied.
+        */
+       if (acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_CACHE_FLUSH)
                set_bit(ND_REGION_PERSIST_CACHE, &ndr_desc->flags);
-
-       if (acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_MEM_FLUSH)
+       else if (acpi_desc->platform_cap & ACPI_NFIT_CAPABILITY_MEM_FLUSH)
                set_bit(ND_REGION_PERSIST_MEMCTRL, &ndr_desc->flags);
 
        list_for_each_entry(nfit_memdev, &acpi_desc->memdevs, list) {
index 8ccaae3..8516760 100644 (file)
@@ -103,25 +103,27 @@ int acpi_map_pxm_to_node(int pxm)
  */
 int acpi_map_pxm_to_online_node(int pxm)
 {
-       int node, n, dist, min_dist;
+       int node, min_node;
 
        node = acpi_map_pxm_to_node(pxm);
 
        if (node == NUMA_NO_NODE)
                node = 0;
 
+       min_node = node;
        if (!node_online(node)) {
-               min_dist = INT_MAX;
+               int min_dist = INT_MAX, dist, n;
+
                for_each_online_node(n) {
                        dist = node_distance(node, n);
                        if (dist < min_dist) {
                                min_dist = dist;
-                               node = n;
+                               min_node = n;
                        }
                }
        }
 
-       return node;
+       return min_node;
 }
 EXPORT_SYMBOL(acpi_map_pxm_to_online_node);
 
index 466d150..5815356 100644 (file)
@@ -1271,11 +1271,11 @@ static int acpi_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
        return 0;
 }
 
-static void *
+static const void *
 acpi_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
                                  const struct device *dev)
 {
-       return acpi_get_match_data(dev);
+       return acpi_device_get_match_data(dev);
 }
 
 #define DECLARE_ACPI_FWNODE_OPS(ops) \
index 89e97d2..9d52743 100644 (file)
@@ -115,6 +115,7 @@ int __init acpi_parse_spcr(bool enable_earlycon, bool enable_console)
                        table->serial_port.access_width))) {
                default:
                        pr_err("Unexpected SPCR Access Width.  Defaulting to byte size\n");
+                       /* fall through */
                case 8:
                        iotype = "mmio";
                        break;
index 15e3d3c..764b63a 100644 (file)
@@ -1991,8 +1991,14 @@ static void binder_send_failed_reply(struct binder_transaction *t,
                                        &target_thread->reply_error.work);
                                wake_up_interruptible(&target_thread->wait);
                        } else {
-                               WARN(1, "Unexpected reply error: %u\n",
-                                               target_thread->reply_error.cmd);
+                               /*
+                                * Cannot get here for normal operation, but
+                                * we can if multiple synchronous transactions
+                                * are sent without blocking for responses.
+                                * Just ignore the 2nd error in this case.
+                                */
+                               pr_warn("Unexpected reply error: %u\n",
+                                       target_thread->reply_error.cmd);
                        }
                        binder_inner_proc_unlock(target_thread->proc);
                        binder_thread_dec_tmpref(target_thread);
@@ -2193,7 +2199,7 @@ static void binder_transaction_buffer_release(struct binder_proc *proc,
        int debug_id = buffer->debug_id;
 
        binder_debug(BINDER_DEBUG_TRANSACTION,
-                    "%d buffer release %d, size %zd-%zd, failed at %p\n",
+                    "%d buffer release %d, size %zd-%zd, failed at %pK\n",
                     proc->pid, buffer->debug_id,
                     buffer->data_size, buffer->offsets_size, failed_at);
 
@@ -3705,7 +3711,7 @@ static int binder_thread_write(struct binder_proc *proc,
                                }
                        }
                        binder_debug(BINDER_DEBUG_DEAD_BINDER,
-                                    "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
+                                    "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
                                     proc->pid, thread->pid, (u64)cookie,
                                     death);
                        if (death == NULL) {
@@ -4376,6 +4382,15 @@ static int binder_thread_release(struct binder_proc *proc,
 
        binder_inner_proc_unlock(thread->proc);
 
+       /*
+        * This is needed to avoid races between wake_up_poll() above and
+        * and ep_remove_waitqueue() called for other reasons (eg the epoll file
+        * descriptor being closed); ep_remove_waitqueue() holds an RCU read
+        * lock, so we can be sure it's done after calling synchronize_rcu().
+        */
+       if (thread->looper & BINDER_LOOPER_STATE_POLL)
+               synchronize_rcu();
+
        if (send_reply)
                binder_send_failed_reply(send_reply, BR_DEAD_REPLY);
        binder_release_work(proc, &thread->todo);
@@ -4391,6 +4406,8 @@ static __poll_t binder_poll(struct file *filp,
        bool wait_for_proc_work;
 
        thread = binder_get_thread(proc);
+       if (!thread)
+               return POLLERR;
 
        binder_inner_proc_lock(thread->proc);
        thread->looper |= BINDER_LOOPER_STATE_POLL;
@@ -5034,7 +5051,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
        spin_lock(&t->lock);
        to_proc = t->to_proc;
        seq_printf(m,
-                  "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+                  "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
                   prefix, t->debug_id, t,
                   t->from ? t->from->proc->pid : 0,
                   t->from ? t->from->pid : 0,
@@ -5058,7 +5075,7 @@ static void print_binder_transaction_ilocked(struct seq_file *m,
        }
        if (buffer->target_node)
                seq_printf(m, " node %d", buffer->target_node->debug_id);
-       seq_printf(m, " size %zd:%zd data %p\n",
+       seq_printf(m, " size %zd:%zd data %pK\n",
                   buffer->data_size, buffer->offsets_size,
                   buffer->data);
 }
index 355a95a..1ff1779 100644 (file)
@@ -550,7 +550,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
          .driver_data = board_ahci_yes_fbs },
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230),
          .driver_data = board_ahci_yes_fbs },
-       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642),
+       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */
+         .driver_data = board_ahci_yes_fbs },
+       { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */
          .driver_data = board_ahci_yes_fbs },
 
        /* Promise */
index a0de7a3..7adcf3c 100644 (file)
@@ -665,6 +665,16 @@ int ahci_stop_engine(struct ata_port *ap)
        if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
                return 0;
 
+       /*
+        * Don't try to issue commands but return with ENODEV if the
+        * AHCI controller not available anymore (e.g. due to PCIe hot
+        * unplugging). Otherwise a 500ms delay for each port is added.
+        */
+       if (tmp == 0xffffffff) {
+               dev_err(ap->host->dev, "AHCI controller unavailable!\n");
+               return -ENODEV;
+       }
+
        /* setting HBA to idle */
        tmp &= ~PORT_CMD_START;
        writel(tmp, port_mmio + PORT_CMD);
index 341d0ef..30cc8f1 100644 (file)
@@ -340,7 +340,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
  * 2) regulator for controlling the targets power (optional)
  * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
  *    or for non devicetree enabled platforms a single clock
- *     4) phys (optional)
+ * 4) phys (optional)
  *
  * RETURNS:
  * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
index 3c09122..7431ccd 100644 (file)
@@ -4530,6 +4530,25 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
        { "PIONEER DVD-RW  DVR-212D",   NULL,   ATA_HORKAGE_NOSETXFER },
        { "PIONEER DVD-RW  DVR-216D",   NULL,   ATA_HORKAGE_NOSETXFER },
 
+       /* Crucial BX100 SSD 500GB has broken LPM support */
+       { "CT500BX100SSD1",             NULL,   ATA_HORKAGE_NOLPM },
+
+       /* 512GB MX100 with MU01 firmware has both queued TRIM and LPM issues */
+       { "Crucial_CT512MX100*",        "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM |
+                                               ATA_HORKAGE_NOLPM, },
+       /* 512GB MX100 with newer firmware has only LPM issues */
+       { "Crucial_CT512MX100*",        NULL,   ATA_HORKAGE_ZERO_AFTER_TRIM |
+                                               ATA_HORKAGE_NOLPM, },
+
+       /* 480GB+ M500 SSDs have both queued TRIM and LPM issues */
+       { "Crucial_CT480M500*",         NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM |
+                                               ATA_HORKAGE_NOLPM, },
+       { "Crucial_CT960M500*",         NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM |
+                                               ATA_HORKAGE_NOLPM, },
+
        /* devices that don't properly handle queued TRIM commands */
        { "Micron_M500_*",              NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -4541,7 +4560,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "Crucial_CT*MX100*",          "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
-       { "Samsung SSD 8*",             NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+       { "Samsung SSD 840*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
+                                               ATA_HORKAGE_ZERO_AFTER_TRIM, },
+       { "Samsung SSD 850*",           NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
        { "FCCT*M500*",                 NULL,   ATA_HORKAGE_NO_NCQ_TRIM |
                                                ATA_HORKAGE_ZERO_AFTER_TRIM, },
@@ -5401,8 +5422,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
         * We guarantee to LLDs that they will have at least one
         * non-zero sg if the command is a data command.
         */
-       if (WARN_ON_ONCE(ata_is_data(prot) &&
-                        (!qc->sg || !qc->n_elem || !qc->nbytes)))
+       if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes))
                goto sys_err;
 
        if (ata_is_dma(prot) || (ata_is_pio(prot) &&
index 11c3137..c016829 100644 (file)
@@ -815,7 +815,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap)
 
        if (ap->pflags & ATA_PFLAG_LOADING)
                ap->pflags &= ~ATA_PFLAG_LOADING;
-       else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+       else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) &&
+               !(ap->flags & ATA_FLAG_SAS_HOST))
                schedule_delayed_work(&ap->hotplug_task, 0);
 
        if (ap->pflags & ATA_PFLAG_RECOVERED)
index 66be961..89a9d4a 100644 (file)
@@ -3316,6 +3316,12 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
                goto invalid_fld;
        }
 
+       /* We may not issue NCQ commands to devices not supporting NCQ */
+       if (ata_is_ncq(tf->protocol) && !ata_ncq_enabled(dev)) {
+               fp = 1;
+               goto invalid_fld;
+       }
+
        /* sanity check for pio multi commands */
        if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) {
                fp = 1;
@@ -4282,7 +4288,7 @@ static inline void ata_scsi_dump_cdb(struct ata_port *ap,
 #ifdef ATA_DEBUG
        struct scsi_device *scsidev = cmd->device;
 
-       DPRINTK("CDB (%u:%d,%d,%d) %9ph\n",
+       DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n",
                ap->print_id,
                scsidev->channel, scsidev->id, scsidev->lun,
                cmd->cmnd);
@@ -4309,7 +4315,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
                if (likely((scsi_op != ATA_16) || !atapi_passthru16)) {
                        /* relay SCSI command to ATAPI device */
                        int len = COMMAND_SIZE(scsi_op);
-                       if (unlikely(len > scmd->cmd_len || len > dev->cdb_len))
+                       if (unlikely(len > scmd->cmd_len ||
+                                    len > dev->cdb_len ||
+                                    scmd->cmd_len > ATAPI_CDB_LEN))
                                goto bad_cdb_len;
 
                        xlat_func = atapi_xlat;
index 80ee2f2..6456e07 100644 (file)
 enum sata_rcar_type {
        RCAR_GEN1_SATA,
        RCAR_GEN2_SATA,
+       RCAR_GEN3_SATA,
        RCAR_R8A7790_ES1_SATA,
 };
 
@@ -784,26 +785,11 @@ static void sata_rcar_setup_port(struct ata_host *host)
        ioaddr->command_addr    = ioaddr->cmd_addr + (ATA_REG_CMD << 2);
 }
 
-static void sata_rcar_init_controller(struct ata_host *host)
+static void sata_rcar_init_module(struct sata_rcar_priv *priv)
 {
-       struct sata_rcar_priv *priv = host->private_data;
        void __iomem *base = priv->base;
        u32 val;
 
-       /* reset and setup phy */
-       switch (priv->type) {
-       case RCAR_GEN1_SATA:
-               sata_rcar_gen1_phy_init(priv);
-               break;
-       case RCAR_GEN2_SATA:
-       case RCAR_R8A7790_ES1_SATA:
-               sata_rcar_gen2_phy_init(priv);
-               break;
-       default:
-               dev_warn(host->dev, "SATA phy is not initialized\n");
-               break;
-       }
-
        /* SATA-IP reset state */
        val = ioread32(base + ATAPI_CONTROL1_REG);
        val |= ATAPI_CONTROL1_RESET;
@@ -824,10 +810,33 @@ static void sata_rcar_init_controller(struct ata_host *host)
        /* ack and mask */
        iowrite32(0, base + SATAINTSTAT_REG);
        iowrite32(0x7ff, base + SATAINTMASK_REG);
+
        /* enable interrupts */
        iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
 }
 
+static void sata_rcar_init_controller(struct ata_host *host)
+{
+       struct sata_rcar_priv *priv = host->private_data;
+
+       /* reset and setup phy */
+       switch (priv->type) {
+       case RCAR_GEN1_SATA:
+               sata_rcar_gen1_phy_init(priv);
+               break;
+       case RCAR_GEN2_SATA:
+       case RCAR_GEN3_SATA:
+       case RCAR_R8A7790_ES1_SATA:
+               sata_rcar_gen2_phy_init(priv);
+               break;
+       default:
+               dev_warn(host->dev, "SATA phy is not initialized\n");
+               break;
+       }
+
+       sata_rcar_init_module(priv);
+}
+
 static const struct of_device_id sata_rcar_match[] = {
        {
                /* Deprecated by "renesas,sata-r8a7779" */
@@ -856,7 +865,7 @@ static const struct of_device_id sata_rcar_match[] = {
        },
        {
                .compatible = "renesas,sata-r8a7795",
-               .data = (void *)RCAR_GEN2_SATA
+               .data = (void *)RCAR_GEN3_SATA
        },
        {
                .compatible = "renesas,rcar-gen2-sata",
@@ -864,7 +873,7 @@ static const struct of_device_id sata_rcar_match[] = {
        },
        {
                .compatible = "renesas,rcar-gen3-sata",
-               .data = (void *)RCAR_GEN2_SATA
+               .data = (void *)RCAR_GEN3_SATA
        },
        { },
 };
@@ -982,11 +991,18 @@ static int sata_rcar_resume(struct device *dev)
        if (ret)
                return ret;
 
-       /* ack and mask */
-       iowrite32(0, base + SATAINTSTAT_REG);
-       iowrite32(0x7ff, base + SATAINTMASK_REG);
-       /* enable interrupts */
-       iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
+       if (priv->type == RCAR_GEN3_SATA) {
+               sata_rcar_gen2_phy_init(priv);
+               sata_rcar_init_module(priv);
+       } else {
+               /* ack and mask */
+               iowrite32(0, base + SATAINTSTAT_REG);
+               iowrite32(0x7ff, base + SATAINTMASK_REG);
+
+               /* enable interrupts */
+               iowrite32(ATAPI_INT_ENABLE_SATAINT,
+                         base + ATAPI_INT_ENABLE_REG);
+       }
 
        ata_host_resume(host);
 
index 98a3a43..44abb8a 100644 (file)
@@ -3147,7 +3147,7 @@ static int ia_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
                            "  Size of Tx Buffer  :  %u\n"
                            "  Number of Rx Buffer:  %u\n"
                            "  Size of Rx Buffer  :  %u\n"
-                           "  Packets Receiverd  :  %u\n"
+                           "  Packets Receive  :  %u\n"
                            "  Packets Transmitted:  %u\n"
                            "  Cells Received     :  %u\n"
                            "  Cells Transmitted  :  %u\n"
index 9180b9b..8345095 100644 (file)
@@ -97,7 +97,7 @@ static struct img_ascii_lcd_config boston_config = {
 static void malta_update(struct img_ascii_lcd_ctx *ctx)
 {
        unsigned int i;
-       int err;
+       int err = 0;
 
        for (i = 0; i < ctx->cfg->num_chars; i++) {
                err = regmap_write(ctx->regmap,
@@ -180,7 +180,7 @@ static int sead3_wait_lcd_idle(struct img_ascii_lcd_ctx *ctx)
 static void sead3_update(struct img_ascii_lcd_ctx *ctx)
 {
        unsigned int i;
-       int err;
+       int err = 0;
 
        for (i = 0; i < ctx->cfg->num_chars; i++) {
                err = sead3_wait_lcd_idle(ctx);
@@ -224,7 +224,7 @@ MODULE_DEVICE_TABLE(of, img_ascii_lcd_matches);
 
 /**
  * img_ascii_lcd_scroll() - scroll the display by a character
- * @arg: really a pointer to the private data structure
+ * @t: really a pointer to the private data structure
  *
  * Scroll the current message along the LCD by one character, rearming the
  * timer if required.
index ea7869c..ec5e880 100644 (file)
@@ -1372,7 +1372,7 @@ static void panel_process_inputs(void)
                                break;
                        input->rise_timer = 0;
                        input->state = INPUT_ST_RISING;
-                       /* no break here, fall through */
+                       /* fall through */
                case INPUT_ST_RISING:
                        if ((phys_curr & input->mask) != input->value) {
                                input->state = INPUT_ST_LOW;
@@ -1385,11 +1385,11 @@ static void panel_process_inputs(void)
                        }
                        input->high_timer = 0;
                        input->state = INPUT_ST_HIGH;
-                       /* no break here, fall through */
+                       /* fall through */
                case INPUT_ST_HIGH:
                        if (input_state_high(input))
                                break;
-                       /* no break here, fall through */
+                       /* fall through */
                case INPUT_ST_FALLING:
                        input_state_falling(input);
                }
index b2261f9..5847364 100644 (file)
@@ -310,6 +310,9 @@ static void __device_link_del(struct device_link *link)
        dev_info(link->consumer, "Dropping the link to %s\n",
                 dev_name(link->supplier));
 
+       if (link->flags & DL_FLAG_PM_RUNTIME)
+               pm_runtime_drop_link(link->consumer);
+
        list_del(&link->s_node);
        list_del(&link->c_node);
        device_link_free(link);
index a8ac86e..6637fc3 100644 (file)
@@ -321,7 +321,8 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq)
                return;
 
        if (device_may_wakeup(wirq->dev)) {
-               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED)
+               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
+                   !pm_runtime_status_suspended(wirq->dev))
                        enable_irq(wirq->irq);
 
                enable_irq_wake(wirq->irq);
@@ -343,7 +344,8 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq)
        if (device_may_wakeup(wirq->dev)) {
                disable_irq_wake(wirq->irq);
 
-               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED)
+               if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED &&
+                   !pm_runtime_status_suspended(wirq->dev))
                        disable_irq_nosync(wirq->irq);
        }
 }
index 3022362..8f205f6 100644 (file)
@@ -1410,9 +1410,8 @@ int fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL(fwnode_graph_parse_endpoint);
 
-void *device_get_match_data(struct device *dev)
+const void *device_get_match_data(struct device *dev)
 {
-       return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data,
-                                 dev);
+       return fwnode_call_ptr_op(dev_fwnode(dev), device_get_match_data, dev);
 }
 EXPORT_SYMBOL_GPL(device_get_match_data);
index e5aa62f..3aaf6af 100644 (file)
@@ -1758,7 +1758,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        if (unit[drive].type->code == FD_NODRIVE)
                return NULL;
        *part = 0;
-       return get_disk(unit[drive].gendisk);
+       return get_disk_and_module(unit[drive].gendisk);
 }
 
 static int __init amiga_floppy_probe(struct platform_device *pdev)
index 8bc3b9f..dfb2c26 100644 (file)
@@ -1917,7 +1917,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
                return NULL;
        *part = 0;
-       return get_disk(unit[drive].disk);
+       return get_disk_and_module(unit[drive].disk);
 }
 
 static int __init atari_floppy_init (void)
index 8028a3a..deea78e 100644 (file)
@@ -456,7 +456,7 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
 
        mutex_lock(&brd_devices_mutex);
        brd = brd_init_one(MINOR(dev) / max_part, &new);
-       kobj = brd ? get_disk(brd->brd_disk) : NULL;
+       kobj = brd ? get_disk_and_module(brd->brd_disk) : NULL;
        mutex_unlock(&brd_devices_mutex);
 
        if (new)
index eae484a..8ec7235 100644 (file)
@@ -4505,7 +4505,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
        if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
                return NULL;
        *part = 0;
-       return get_disk(disks[drive]);
+       return get_disk_and_module(disks[drive]);
 }
 
 static int __init do_floppy_init(void)
index d5fe720..ee62d2d 100644 (file)
@@ -266,7 +266,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos)
        struct iov_iter i;
        ssize_t bw;
 
-       iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len);
+       iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len);
 
        file_start_write(file);
        bw = vfs_iter_write(file, &i, ppos, 0);
@@ -1922,7 +1922,7 @@ static struct kobject *loop_probe(dev_t dev, int *part, void *data)
        if (err < 0)
                kobj = NULL;
        else
-               kobj = get_disk(lo->lo_disk);
+               kobj = get_disk_and_module(lo->lo_disk);
        mutex_unlock(&loop_index_mutex);
 
        *part = 0;
index 5f2a424..86258b0 100644 (file)
@@ -1591,7 +1591,7 @@ again:
                        if (new_index < 0) {
                                mutex_unlock(&nbd_index_mutex);
                                printk(KERN_ERR "nbd: failed to add new device\n");
-                               return ret;
+                               return new_index;
                        }
                        nbd = idr_find(&nbd_index_idr, new_index);
                }
index 531a091..c61d20c 100644 (file)
@@ -1122,7 +1122,7 @@ static int pkt_start_recovery(struct packet_data *pkt)
        pkt->sector = new_sector;
 
        bio_reset(pkt->bio);
-       bio_set_set(pkt->bio, pd->bdev);
+       bio_set_dev(pkt->bio, pd->bdev);
        bio_set_op_attrs(pkt->bio, REQ_OP_WRITE, 0);
        pkt->bio->bi_iter.bi_sector = new_sector;
        pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE;
index 84434d3..64e066e 100644 (file)
@@ -799,7 +799,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
                return NULL;
 
        *part = 0;
-       return get_disk(swd->unit[drive].disk);
+       return get_disk_and_module(swd->unit[drive].disk);
 }
 
 static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
index e126e4c..92ec1bb 100644 (file)
@@ -262,6 +262,7 @@ static DEFINE_SPINLOCK(minor_lock);
 
 static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo);
 static void blkfront_gather_backend_features(struct blkfront_info *info);
+static int negotiate_mq(struct blkfront_info *info);
 
 static int get_id_from_freelist(struct blkfront_ring_info *rinfo)
 {
@@ -1774,11 +1775,18 @@ static int talk_to_blkback(struct xenbus_device *dev,
        unsigned int i, max_page_order;
        unsigned int ring_page_order;
 
+       if (!info)
+               return -ENODEV;
+
        max_page_order = xenbus_read_unsigned(info->xbdev->otherend,
                                              "max-ring-page-order", 0);
        ring_page_order = min(xen_blkif_max_ring_order, max_page_order);
        info->nr_ring_pages = 1 << ring_page_order;
 
+       err = negotiate_mq(info);
+       if (err)
+               goto destroy_blkring;
+
        for (i = 0; i < info->nr_rings; i++) {
                struct blkfront_ring_info *rinfo = &info->rinfo[i];
 
@@ -1978,11 +1986,6 @@ static int blkfront_probe(struct xenbus_device *dev,
        }
 
        info->xbdev = dev;
-       err = negotiate_mq(info);
-       if (err) {
-               kfree(info);
-               return err;
-       }
 
        mutex_init(&info->mutex);
        info->vdevice = vdevice;
@@ -2099,10 +2102,6 @@ static int blkfront_resume(struct xenbus_device *dev)
 
        blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
 
-       err = negotiate_mq(info);
-       if (err)
-               return err;
-
        err = talk_to_blkback(dev, info);
        if (!err)
                blk_mq_update_nr_hw_queues(&info->tag_set, info->nr_rings);
index 41c95c9..8f9130a 100644 (file)
@@ -332,7 +332,7 @@ static const struct block_device_operations z2_fops =
 static struct kobject *z2_find(dev_t dev, int *part, void *data)
 {
        *part = 0;
-       return get_disk(z2ram_gendisk);
+       return get_disk_and_module(z2ram_gendisk);
 }
 
 static struct request_queue *z2_queue;
index 2a55380..366a49c 100644 (file)
@@ -21,6 +21,7 @@
  *
  */
 
+#include <linux/dmi.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb/quirks.h>
@@ -230,7 +231,6 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 },
-       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 },
@@ -263,6 +263,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
 
        /* QCA ROME chipset */
+       { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME },
        { USB_DEVICE(0x0cf3, 0xe010), .driver_info = BTUSB_QCA_ROME },
@@ -379,6 +380,21 @@ static const struct usb_device_id blacklist_table[] = {
        { }     /* Terminating entry */
 };
 
+/* The Bluetooth USB module build into some devices needs to be reset on resume,
+ * this is a problem with the platform (likely shutting off all power) not with
+ * the module itself. So we use a DMI list to match known broken platforms.
+ */
+static const struct dmi_system_id btusb_needs_reset_resume_table[] = {
+       {
+               /* Dell OptiPlex 3060 (QCA ROME device 0cf3:e007) */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 3060"),
+               },
+       },
+       {}
+};
+
 #define BTUSB_MAX_ISOC_FRAMES  10
 
 #define BTUSB_INTR_RUNNING     0
@@ -2945,6 +2961,9 @@ static int btusb_probe(struct usb_interface *intf,
        hdev->send   = btusb_send_frame;
        hdev->notify = btusb_notify;
 
+       if (dmi_check_system(btusb_needs_reset_resume_table))
+               interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
+
 #ifdef CONFIG_PM
        err = btusb_config_oob_wake(hdev);
        if (err)
@@ -3031,12 +3050,6 @@ static int btusb_probe(struct usb_interface *intf,
        if (id->driver_info & BTUSB_QCA_ROME) {
                data->setup_on_usb = btusb_setup_qca;
                hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
-
-               /* QCA Rome devices lose their updated firmware over suspend,
-                * but the USB hub doesn't notice any status change.
-                * explicitly request a device reset on resume.
-                */
-               interface_to_usbdev(intf)->quirks |= USB_QUIRK_RESET_RESUME;
        }
 
 #ifdef CONFIG_BT_HCIBTUSB_RTL
index 0438a64..40b9fb2 100644 (file)
@@ -244,7 +244,9 @@ static irqreturn_t bcm_host_wake(int irq, void *data)
 
        bt_dev_dbg(bdev, "Host wake IRQ");
 
-       pm_request_resume(bdev->dev);
+       pm_runtime_get(bdev->dev);
+       pm_runtime_mark_last_busy(bdev->dev);
+       pm_runtime_put_autosuspend(bdev->dev);
 
        return IRQ_HANDLED;
 }
@@ -301,7 +303,7 @@ static const struct bcm_set_sleep_mode default_sleep_params = {
        .usb_auto_sleep = 0,
        .usb_resume_timeout = 0,
        .break_to_host = 0,
-       .pulsed_host_wake = 0,
+       .pulsed_host_wake = 1,
 };
 
 static int bcm_setup_sleep(struct hci_uart *hu)
@@ -586,8 +588,11 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
        } else if (!bcm->rx_skb) {
                /* Delay auto-suspend when receiving completed packet */
                mutex_lock(&bcm_device_lock);
-               if (bcm->dev && bcm_device_exists(bcm->dev))
-                       pm_request_resume(bcm->dev->dev);
+               if (bcm->dev && bcm_device_exists(bcm->dev)) {
+                       pm_runtime_get(bcm->dev->dev);
+                       pm_runtime_mark_last_busy(bcm->dev->dev);
+                       pm_runtime_put_autosuspend(bcm->dev->dev);
+               }
                mutex_unlock(&bcm_device_lock);
        }
 
@@ -922,12 +927,13 @@ static int bcm_get_resources(struct bcm_device *dev)
 
        dev->clk = devm_clk_get(dev->dev, NULL);
 
-       dev->device_wakeup = devm_gpiod_get(dev->dev, "device-wakeup",
-                                           GPIOD_OUT_LOW);
+       dev->device_wakeup = devm_gpiod_get_optional(dev->dev, "device-wakeup",
+                                                    GPIOD_OUT_LOW);
        if (IS_ERR(dev->device_wakeup))
                return PTR_ERR(dev->device_wakeup);
 
-       dev->shutdown = devm_gpiod_get(dev->dev, "shutdown", GPIOD_OUT_LOW);
+       dev->shutdown = devm_gpiod_get_optional(dev->dev, "shutdown",
+                                               GPIOD_OUT_LOW);
        if (IS_ERR(dev->shutdown))
                return PTR_ERR(dev->shutdown);
 
index 4d46003..cdaeeea 100644 (file)
@@ -630,7 +630,7 @@ static int sysc_init_dts_quirks(struct sysc *ddata)
        for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
                prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
                if (!prop)
-                       break;
+                       continue;
 
                ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
        }
index 4d1dc8b..f95b9c7 100644 (file)
@@ -457,7 +457,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf,
                            size_t count)
 {
        int size = 0;
-       int expected;
+       u32 expected;
 
        if (!chip)
                return -EBUSY;
@@ -474,7 +474,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf,
        }
 
        expected = be32_to_cpu(*(__be32 *)(buf + 2));
-       if (expected > count) {
+       if (expected > count || expected < TPM_HEADER_SIZE) {
                size = -EIO;
                goto out;
        }
index 76df4fb..9e80a95 100644 (file)
@@ -1190,6 +1190,10 @@ int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
                        break;
 
                recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
+               if (recd > num_bytes) {
+                       total = -EFAULT;
+                       break;
+               }
 
                rlength = be32_to_cpu(tpm_cmd.header.out.length);
                if (rlength < offsetof(struct tpm_getrandom_out, rng_data) +
index c17e753..a700f8f 100644 (file)
@@ -683,6 +683,10 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip,
        if (!rc) {
                data_len = be16_to_cpup(
                        (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+               if (data_len < MIN_KEY_SIZE ||  data_len > MAX_KEY_SIZE + 1) {
+                       rc = -EFAULT;
+                       goto out;
+               }
 
                rlength = be32_to_cpu(((struct tpm2_cmd *)&buf)
                                        ->header.out.length);
index c1dd39e..6116cd0 100644 (file)
@@ -473,7 +473,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
 static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        int size = 0;
-       int expected, status;
+       int status;
+       u32 expected;
 
        if (count < TPM_HEADER_SIZE) {
                size = -EIO;
@@ -488,7 +489,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        }
 
        expected = be32_to_cpu(*(__be32 *)(buf + 2));
-       if ((size_t) expected > count) {
+       if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) {
                size = -EIO;
                goto out;
        }
index c642877..caa86b1 100644 (file)
@@ -281,7 +281,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        struct device *dev = chip->dev.parent;
        struct i2c_client *client = to_i2c_client(dev);
        s32 rc;
-       int expected, status, burst_count, retries, size = 0;
+       int status;
+       int burst_count;
+       int retries;
+       int size = 0;
+       u32 expected;
 
        if (count < TPM_HEADER_SIZE) {
                i2c_nuvoton_ready(chip);    /* return to idle */
@@ -323,7 +327,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
                 * to machine native
                 */
                expected = be32_to_cpu(*(__be32 *) (buf + 2));
-               if (expected > count) {
+               if (expected > count || expected < size) {
                        dev_err(dev, "%s() expected > count\n", __func__);
                        size = -EIO;
                        continue;
index 183a5f5..da074e3 100644 (file)
@@ -270,7 +270,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
 {
        struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
        int size = 0;
-       int expected, status;
+       int status;
+       u32 expected;
 
        if (count < TPM_HEADER_SIZE) {
                size = -EIO;
@@ -285,7 +286,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
        }
 
        expected = be32_to_cpu(*(__be32 *) (buf + 2));
-       if (expected > count) {
+       if (expected > count || expected < TPM_HEADER_SIZE) {
                size = -EIO;
                goto out;
        }
index 44301a3..a07f645 100644 (file)
@@ -449,17 +449,17 @@ struct bcm2835_pll_ana_bits {
 static const struct bcm2835_pll_ana_bits bcm2835_ana_default = {
        .mask0 = 0,
        .set0 = 0,
-       .mask1 = (u32)~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK),
+       .mask1 = A2W_PLL_KI_MASK | A2W_PLL_KP_MASK,
        .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT),
-       .mask3 = (u32)~A2W_PLL_KA_MASK,
+       .mask3 = A2W_PLL_KA_MASK,
        .set3 = (2 << A2W_PLL_KA_SHIFT),
        .fb_prediv_mask = BIT(14),
 };
 
 static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = {
-       .mask0 = (u32)~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK),
+       .mask0 = A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK,
        .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT),
-       .mask1 = (u32)~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK),
+       .mask1 = A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK,
        .set1 = (6 << A2W_PLLH_KP_SHIFT),
        .mask3 = 0,
        .set3 = 0,
@@ -623,8 +623,10 @@ static int bcm2835_pll_on(struct clk_hw *hw)
                     ~A2W_PLL_CTRL_PWRDN);
 
        /* Take the PLL out of reset. */
+       spin_lock(&cprman->regs_lock);
        cprman_write(cprman, data->cm_ctrl_reg,
                     cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST);
+       spin_unlock(&cprman->regs_lock);
 
        /* Wait for the PLL to lock. */
        timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS);
@@ -701,9 +703,11 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw,
        }
 
        /* Unmask the reference clock from the oscillator. */
+       spin_lock(&cprman->regs_lock);
        cprman_write(cprman, A2W_XOSC_CTRL,
                     cprman_read(cprman, A2W_XOSC_CTRL) |
                     data->reference_enable_mask);
+       spin_unlock(&cprman->regs_lock);
 
        if (do_ana_setup_first)
                bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana);
index 9f7f931..5eb50c3 100644 (file)
@@ -205,6 +205,18 @@ static const struct aspeed_clk_soc_data ast2400_data = {
        .calc_pll = aspeed_ast2400_calc_pll,
 };
 
+static int aspeed_clk_is_enabled(struct clk_hw *hw)
+{
+       struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
+       u32 clk = BIT(gate->clock_idx);
+       u32 enval = (gate->flags & CLK_GATE_SET_TO_DISABLE) ? 0 : clk;
+       u32 reg;
+
+       regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
+
+       return ((reg & clk) == enval) ? 1 : 0;
+}
+
 static int aspeed_clk_enable(struct clk_hw *hw)
 {
        struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
@@ -215,6 +227,11 @@ static int aspeed_clk_enable(struct clk_hw *hw)
 
        spin_lock_irqsave(gate->lock, flags);
 
+       if (aspeed_clk_is_enabled(hw)) {
+               spin_unlock_irqrestore(gate->lock, flags);
+               return 0;
+       }
+
        if (gate->reset_idx >= 0) {
                /* Put IP in reset */
                regmap_update_bits(gate->map, ASPEED_RESET_CTRL, rst, rst);
@@ -255,17 +272,6 @@ static void aspeed_clk_disable(struct clk_hw *hw)
        spin_unlock_irqrestore(gate->lock, flags);
 }
 
-static int aspeed_clk_is_enabled(struct clk_hw *hw)
-{
-       struct aspeed_clk_gate *gate = to_aspeed_clk_gate(hw);
-       u32 clk = BIT(gate->clock_idx);
-       u32 reg;
-
-       regmap_read(gate->map, ASPEED_CLK_STOP_CTRL, &reg);
-
-       return (reg & clk) ? 0 : 1;
-}
-
 static const struct clk_ops aspeed_clk_gate_ops = {
        .enable = aspeed_clk_enable,
        .disable = aspeed_clk_disable,
index 0f686a9..076d424 100644 (file)
@@ -1125,8 +1125,10 @@ static int clk_core_round_rate_nolock(struct clk_core *core,
 {
        lockdep_assert_held(&prepare_lock);
 
-       if (!core)
+       if (!core) {
+               req->rate = 0;
                return 0;
+       }
 
        clk_core_init_rate_req(core, req);
 
@@ -2309,8 +2311,11 @@ static int clk_core_set_phase_nolock(struct clk_core *core, int degrees)
 
        trace_clk_set_phase(core, degrees);
 
-       if (core->ops->set_phase)
+       if (core->ops->set_phase) {
                ret = core->ops->set_phase(core->hw, degrees);
+               if (!ret)
+                       core->phase = degrees;
+       }
 
        trace_clk_set_phase_complete(core, degrees);
 
@@ -2968,22 +2973,37 @@ static int __clk_core_init(struct clk_core *core)
        core->rate = core->req_rate = rate;
 
        /*
+        * Enable CLK_IS_CRITICAL clocks so newly added critical clocks
+        * don't get accidentally disabled when walking the orphan tree and
+        * reparenting clocks
+        */
+       if (core->flags & CLK_IS_CRITICAL) {
+               unsigned long flags;
+
+               clk_core_prepare(core);
+
+               flags = clk_enable_lock();
+               clk_core_enable(core);
+               clk_enable_unlock(flags);
+       }
+
+       /*
         * walk the list of orphan clocks and reparent any that newly finds a
         * parent.
         */
        hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
                struct clk_core *parent = __clk_init_parent(orphan);
-               unsigned long flags;
 
                /*
-                * we could call __clk_set_parent, but that would result in a
-                * redundant call to the .set_rate op, if it exists
+                * We need to use __clk_set_parent_before() and _after() to
+                * to properly migrate any prepare/enable count of the orphan
+                * clock. This is important for CLK_IS_CRITICAL clocks, which
+                * are enabled during init but might not have a parent yet.
                 */
                if (parent) {
                        /* update the clk tree topology */
-                       flags = clk_enable_lock();
-                       clk_reparent(orphan, parent);
-                       clk_enable_unlock(flags);
+                       __clk_set_parent_before(orphan, parent);
+                       __clk_set_parent_after(orphan, parent, NULL);
                        __clk_recalc_accuracies(orphan);
                        __clk_recalc_rates(orphan, 0);
                }
@@ -3000,16 +3020,6 @@ static int __clk_core_init(struct clk_core *core)
        if (core->ops->init)
                core->ops->init(core->hw);
 
-       if (core->flags & CLK_IS_CRITICAL) {
-               unsigned long flags;
-
-               clk_core_prepare(core);
-
-               flags = clk_enable_lock();
-               clk_core_enable(core);
-               clk_enable_unlock(flags);
-       }
-
        kref_init(&core->ref);
 out:
        clk_pm_runtime_put(core);
index 9b6c72b..e8b2c43 100644 (file)
@@ -149,6 +149,8 @@ static int hi3660_stub_clk_probe(struct platform_device *pdev)
                return PTR_ERR(stub_clk_chan.mbox);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
        freq_reg = devm_ioremap(dev, res->start, resource_size(res));
        if (!freq_reg)
                return -ENOMEM;
index c864992..caa8bd4 100644 (file)
@@ -131,7 +131,17 @@ static const char *ieee1588_sels[] = { "pll3_sw", "pll4_sw", "dummy" /* usbphy2_
 static struct clk *clk[IMX5_CLK_END];
 static struct clk_onecell_data clk_data;
 
-static struct clk ** const uart_clks[] __initconst = {
+static struct clk ** const uart_clks_mx51[] __initconst = {
+       &clk[IMX5_CLK_UART1_IPG_GATE],
+       &clk[IMX5_CLK_UART1_PER_GATE],
+       &clk[IMX5_CLK_UART2_IPG_GATE],
+       &clk[IMX5_CLK_UART2_PER_GATE],
+       &clk[IMX5_CLK_UART3_IPG_GATE],
+       &clk[IMX5_CLK_UART3_PER_GATE],
+       NULL
+};
+
+static struct clk ** const uart_clks_mx50_mx53[] __initconst = {
        &clk[IMX5_CLK_UART1_IPG_GATE],
        &clk[IMX5_CLK_UART1_PER_GATE],
        &clk[IMX5_CLK_UART2_IPG_GATE],
@@ -321,8 +331,6 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
        clk_prepare_enable(clk[IMX5_CLK_TMAX1]);
        clk_prepare_enable(clk[IMX5_CLK_TMAX2]); /* esdhc2, fec */
        clk_prepare_enable(clk[IMX5_CLK_TMAX3]); /* esdhc1, esdhc4 */
-
-       imx_register_uart_clocks(uart_clks);
 }
 
 static void __init mx50_clocks_init(struct device_node *np)
@@ -388,6 +396,8 @@ static void __init mx50_clocks_init(struct device_node *np)
 
        r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
        clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
+
+       imx_register_uart_clocks(uart_clks_mx50_mx53);
 }
 CLK_OF_DECLARE(imx50_ccm, "fsl,imx50-ccm", mx50_clocks_init);
 
@@ -477,6 +487,8 @@ static void __init mx51_clocks_init(struct device_node *np)
        val = readl(MXC_CCM_CLPCR);
        val |= 1 << 23;
        writel(val, MXC_CCM_CLPCR);
+
+       imx_register_uart_clocks(uart_clks_mx51);
 }
 CLK_OF_DECLARE(imx51_ccm, "fsl,imx51-ccm", mx51_clocks_init);
 
@@ -606,5 +618,7 @@ static void __init mx53_clocks_init(struct device_node *np)
 
        r = clk_round_rate(clk[IMX5_CLK_USBOH3_PER_GATE], 54000000);
        clk_set_rate(clk[IMX5_CLK_USBOH3_PER_GATE], r);
+
+       imx_register_uart_clocks(uart_clks_mx50_mx53);
 }
 CLK_OF_DECLARE(imx53_ccm, "fsl,imx53-ccm", mx53_clocks_init);
index 246957f..b1cc8db 100644 (file)
@@ -49,11 +49,10 @@ static int qcom_apcs_msm8916_clk_probe(struct platform_device *pdev)
        struct clk_regmap_mux_div *a53cc;
        struct regmap *regmap;
        struct clk_init_data init = { };
-       int ret;
+       int ret = -ENODEV;
 
        regmap = dev_get_regmap(parent, NULL);
-       if (IS_ERR(regmap)) {
-               ret = PTR_ERR(regmap);
+       if (!regmap) {
                dev_err(dev, "failed to get regmap: %d\n", ret);
                return ret;
        }
index 72b16ed..3b97f60 100644 (file)
@@ -762,7 +762,7 @@ static struct ccu_mp out_a_clk = {
                .features       = CCU_FEATURE_FIXED_PREDIV,
                .hw.init        = CLK_HW_INIT_PARENTS("out-a",
                                                      clk_out_parents,
-                                                     &ccu_div_ops,
+                                                     &ccu_mp_ops,
                                                      0),
        },
 };
@@ -783,7 +783,7 @@ static struct ccu_mp out_b_clk = {
                .features       = CCU_FEATURE_FIXED_PREDIV,
                .hw.init        = CLK_HW_INIT_PARENTS("out-b",
                                                      clk_out_parents,
-                                                     &ccu_div_ops,
+                                                     &ccu_mp_ops,
                                                      0),
        },
 };
@@ -804,7 +804,7 @@ static struct ccu_mp out_c_clk = {
                .features       = CCU_FEATURE_FIXED_PREDIV,
                .hw.init        = CLK_HW_INIT_PARENTS("out-c",
                                                      clk_out_parents,
-                                                     &ccu_div_ops,
+                                                     &ccu_mp_ops,
                                                      0),
        },
 };
index 612491a..12e0a2d 100644 (file)
@@ -45,7 +45,7 @@ static const struct omap_clkctrl_bit_data am3_gpio4_bit_data[] __initconst = {
 
 static const struct omap_clkctrl_reg_data am3_l4_per_clkctrl_regs[] __initconst = {
        { AM3_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
-       { AM3_LCDC_CLKCTRL, NULL, CLKF_SW_SUP, "lcd_gclk", "lcdc_clkdm" },
+       { AM3_LCDC_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "lcd_gclk", "lcdc_clkdm" },
        { AM3_USB_OTG_HS_CLKCTRL, NULL, CLKF_SW_SUP, "usbotg_fck", "l3s_clkdm" },
        { AM3_TPTC0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk", "l3_clkdm" },
        { AM3_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_div2_ck", "l3_clkdm" },
index 2b7c2e0..63c5ddb 100644 (file)
@@ -187,7 +187,7 @@ static const struct omap_clkctrl_reg_data am4_l4_per_clkctrl_regs[] __initconst
        { AM4_OCP2SCP0_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
        { AM4_OCP2SCP1_CLKCTRL, NULL, CLKF_SW_SUP, "l4ls_gclk" },
        { AM4_EMIF_CLKCTRL, NULL, CLKF_SW_SUP, "dpll_ddr_m2_ck", "emif_clkdm" },
-       { AM4_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP, "disp_clk", "dss_clkdm" },
+       { AM4_DSS_CORE_CLKCTRL, NULL, CLKF_SW_SUP | CLKF_SET_RATE_PARENT, "disp_clk", "dss_clkdm" },
        { AM4_CPGMAC0_CLKCTRL, NULL, CLKF_SW_SUP, "cpsw_125mhz_gclk", "cpsw_125mhz_clkdm" },
        { 0 },
 };
index afa0d6b..421b053 100644 (file)
@@ -537,6 +537,8 @@ static void __init _ti_omap4_clkctrl_setup(struct device_node *node)
                init.parent_names = &reg_data->parent;
                init.num_parents = 1;
                init.flags = 0;
+               if (reg_data->flags & CLKF_SET_RATE_PARENT)
+                       init.flags |= CLK_SET_RATE_PARENT;
                init.name = kasprintf(GFP_KERNEL, "%s:%s:%04x:%d",
                                      node->parent->name, node->name,
                                      reg_data->offset, 0);
index b3b4ed9..d2e5382 100644 (file)
@@ -386,6 +386,7 @@ config ATMEL_PIT
 
 config ATMEL_ST
        bool "Atmel ST timer support" if COMPILE_TEST
+       depends on HAS_IOMEM
        select TIMER_OF
        select MFD_SYSCON
        help
index 4927355..471b428 100644 (file)
@@ -251,9 +251,14 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
        int irq_reenable = clockevent_state_periodic(evt);
 
        /*
-        * Any write to CTRL reg ACks the interrupt, we rewrite the
-        * Count when [N]ot [H]alted bit.
-        * And re-arm it if perioid by [I]nterrupt [E]nable bit
+        * 1. ACK the interrupt
+        *    - For ARC700, any write to CTRL reg ACKs it, so just rewrite
+        *      Count when [N]ot [H]alted bit.
+        *    - For HS3x, it is a bit subtle. On taken count-down interrupt,
+        *      IP bit [3] is set, which needs to be cleared for ACK'ing.
+        *      The write below can only update the other two bits, hence
+        *      explicitly clears IP bit
+        * 2. Re-arm interrupt if periodic by writing to IE bit [0]
         */
        write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
 
index 3ee7e6f..846d18d 100644 (file)
@@ -281,7 +281,7 @@ static int __init __ftm_clk_init(struct device_node *np, char *cnt_name,
 
 static unsigned long __init ftm_clk_init(struct device_node *np)
 {
-       unsigned long freq;
+       long freq;
 
        freq = __ftm_clk_init(np, "ftm-evt-counter-en", "ftm-evt");
        if (freq <= 0)
index a04808a..986b679 100644 (file)
@@ -166,7 +166,7 @@ static int __init __gic_clocksource_init(void)
 
        /* Set clocksource mask. */
        count_width = read_gic_config() & GIC_CONFIG_COUNTBITS;
-       count_width >>= __fls(GIC_CONFIG_COUNTBITS);
+       count_width >>= __ffs(GIC_CONFIG_COUNTBITS);
        count_width *= 4;
        count_width += 32;
        gic_clocksource.mask = CLOCKSOURCE_MASK(count_width);
@@ -205,12 +205,12 @@ static int __init gic_clocksource_of_init(struct device_node *node)
        } else if (of_property_read_u32(node, "clock-frequency",
                                        &gic_frequency)) {
                pr_err("GIC frequency not specified.\n");
-               return -EINVAL;;
+               return -EINVAL;
        }
        gic_timer_irq = irq_of_parse_and_map(node, 0);
        if (!gic_timer_irq) {
                pr_err("GIC timer IRQ not specified.\n");
-               return -EINVAL;;
+               return -EINVAL;
        }
 
        ret = __gic_clocksource_init();
index 2a3fe83..3b56ea3 100644 (file)
@@ -334,7 +334,7 @@ static int __init sun5i_timer_init(struct device_node *node)
        timer_base = of_io_request_and_map(node, 0, of_node_full_name(node));
        if (IS_ERR(timer_base)) {
                pr_err("Can't map registers\n");
-               return PTR_ERR(timer_base);;
+               return PTR_ERR(timer_base);
        }
 
        irq = irq_of_parse_and_map(node, 0);
index 3a88e33..fb586e0 100644 (file)
@@ -44,10 +44,10 @@ config ARM_DT_BL_CPUFREQ
 
 config ARM_SCPI_CPUFREQ
        tristate "SCPI based CPUfreq driver"
-       depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
+       depends on ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
        help
-         This adds the CPUfreq driver support for ARM big.LITTLE platforms
-         using SCPI protocol for CPU power management.
+         This adds the CPUfreq driver support for ARM platforms using SCPI
+         protocol for CPU power management.
 
          This driver uses SCPI Message Protocol driver to interact with the
          firmware providing the CPU DVFS functionality.
index 7b596fa..6bebc1f 100644 (file)
@@ -351,7 +351,13 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
 static int s3c_cpufreq_init(struct cpufreq_policy *policy)
 {
        policy->clk = clk_arm;
-       return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency);
+
+       policy->cpuinfo.transition_latency = cpu_cur.info->latency;
+
+       if (ftab)
+               return cpufreq_table_validate_and_show(policy, ftab);
+
+       return 0;
 }
 
 static int __init s3c_cpufreq_initclks(void)
index c32a833..d300a16 100644 (file)
@@ -51,15 +51,23 @@ static unsigned int scpi_cpufreq_get_rate(unsigned int cpu)
 static int
 scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
 {
+       unsigned long freq = policy->freq_table[index].frequency;
        struct scpi_data *priv = policy->driver_data;
-       u64 rate = policy->freq_table[index].frequency * 1000;
+       u64 rate = freq * 1000;
        int ret;
 
        ret = clk_set_rate(priv->clk, rate);
-       if (!ret && (clk_get_rate(priv->clk) != rate))
-               ret = -EIO;
 
-       return ret;
+       if (ret)
+               return ret;
+
+       if (clk_get_rate(priv->clk) != rate)
+               return -EIO;
+
+       arch_set_freq_scale(policy->related_cpus, freq,
+                           policy->cpuinfo.max_freq);
+
+       return 0;
 }
 
 static int
index fcfa5b1..b3afb6c 100644 (file)
@@ -211,7 +211,7 @@ static int __sev_platform_shutdown_locked(int *error)
 {
        int ret;
 
-       ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, 0, error);
+       ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error);
        if (ret)
                return ret;
 
@@ -271,7 +271,7 @@ static int sev_ioctl_do_reset(struct sev_issue_cmd *argp)
                        return rc;
        }
 
-       return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, 0, &argp->error);
+       return __sev_do_cmd_locked(SEV_CMD_FACTORY_RESET, NULL, &argp->error);
 }
 
 static int sev_ioctl_do_platform_status(struct sev_issue_cmd *argp)
@@ -299,7 +299,7 @@ static int sev_ioctl_do_pek_pdh_gen(int cmd, struct sev_issue_cmd *argp)
                        return rc;
        }
 
-       return __sev_do_cmd_locked(cmd, 0, &argp->error);
+       return __sev_do_cmd_locked(cmd, NULL, &argp->error);
 }
 
 static int sev_ioctl_do_pek_csr(struct sev_issue_cmd *argp)
@@ -624,7 +624,7 @@ EXPORT_SYMBOL_GPL(sev_guest_decommission);
 
 int sev_guest_df_flush(int *error)
 {
-       return sev_do_cmd(SEV_CMD_DF_FLUSH, 0, error);
+       return sev_do_cmd(SEV_CMD_DF_FLUSH, NULL, error);
 }
 EXPORT_SYMBOL_GPL(sev_guest_df_flush);
 
index 188f44b..5d64c08 100644 (file)
@@ -1922,15 +1922,21 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
        uint32_t aes_control;
        unsigned long flags;
        int err;
+       u8 *iv;
 
        aes_control = SSS_AES_KEY_CHANGE_MODE;
        if (mode & FLAGS_AES_DECRYPT)
                aes_control |= SSS_AES_MODE_DECRYPT;
 
-       if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC)
+       if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CBC) {
                aes_control |= SSS_AES_CHAIN_MODE_CBC;
-       else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR)
+               iv = req->info;
+       } else if ((mode & FLAGS_AES_MODE_MASK) == FLAGS_AES_CTR) {
                aes_control |= SSS_AES_CHAIN_MODE_CTR;
+               iv = req->info;
+       } else {
+               iv = NULL; /* AES_ECB */
+       }
 
        if (dev->ctx->keylen == AES_KEYSIZE_192)
                aes_control |= SSS_AES_KEY_SIZE_192;
@@ -1961,7 +1967,7 @@ static void s5p_aes_crypt_start(struct s5p_aes_dev *dev, unsigned long mode)
                goto outdata_error;
 
        SSS_AES_WRITE(dev, AES_CONTROL, aes_control);
-       s5p_set_aes(dev, dev->ctx->aes_key, req->info, dev->ctx->keylen);
+       s5p_set_aes(dev, dev->ctx->aes_key, iv, dev->ctx->keylen);
 
        s5p_set_dma_indata(dev,  dev->sg_src);
        s5p_set_dma_outdata(dev, dev->sg_dst);
index 473af69..ecdc292 100644 (file)
@@ -246,12 +246,6 @@ long dax_direct_access(struct dax_device *dax_dev, pgoff_t pgoff, long nr_pages,
 {
        long avail;
 
-       /*
-        * The device driver is allowed to sleep, in order to make the
-        * memory directly accessible.
-        */
-       might_sleep();
-
        if (!dax_dev)
                return -EOPNOTSUPP;
 
index f652a0e..3548caa 100644 (file)
@@ -163,6 +163,7 @@ struct mv_xor_v2_device {
        void __iomem *dma_base;
        void __iomem *glob_base;
        struct clk *clk;
+       struct clk *reg_clk;
        struct tasklet_struct irq_tasklet;
        struct list_head free_sw_desc;
        struct dma_device dmadev;
@@ -749,13 +750,26 @@ static int mv_xor_v2_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       xor_dev->reg_clk = devm_clk_get(&pdev->dev, "reg");
+       if (PTR_ERR(xor_dev->reg_clk) != -ENOENT) {
+               if (!IS_ERR(xor_dev->reg_clk)) {
+                       ret = clk_prepare_enable(xor_dev->reg_clk);
+                       if (ret)
+                               return ret;
+               } else {
+                       return PTR_ERR(xor_dev->reg_clk);
+               }
+       }
+
        xor_dev->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER)
-               return -EPROBE_DEFER;
+       if (IS_ERR(xor_dev->clk) && PTR_ERR(xor_dev->clk) == -EPROBE_DEFER) {
+               ret = EPROBE_DEFER;
+               goto disable_reg_clk;
+       }
        if (!IS_ERR(xor_dev->clk)) {
                ret = clk_prepare_enable(xor_dev->clk);
                if (ret)
-                       return ret;
+                       goto disable_reg_clk;
        }
 
        ret = platform_msi_domain_alloc_irqs(&pdev->dev, 1,
@@ -866,8 +880,9 @@ free_hw_desq:
 free_msi_irqs:
        platform_msi_domain_free_irqs(&pdev->dev);
 disable_clk:
-       if (!IS_ERR(xor_dev->clk))
-               clk_disable_unprepare(xor_dev->clk);
+       clk_disable_unprepare(xor_dev->clk);
+disable_reg_clk:
+       clk_disable_unprepare(xor_dev->reg_clk);
        return ret;
 }
 
index e3ff162..d0cacdb 100644 (file)
@@ -917,7 +917,7 @@ rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl,
 
        rcar_dmac_chan_configure_desc(chan, desc);
 
-       max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift;
+       max_chunk_size = RCAR_DMATCR_MASK << desc->xfer_shift;
 
        /*
         * Allocate and fill the transfer chunk descriptors. We own the only
index 4dbb30c..b922db9 100644 (file)
@@ -118,14 +118,15 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec,
        spin_lock_irqsave(&dmamux->lock, flags);
        mux->chan_id = find_first_zero_bit(dmamux->dma_inuse,
                                           dmamux->dma_requests);
-       set_bit(mux->chan_id, dmamux->dma_inuse);
-       spin_unlock_irqrestore(&dmamux->lock, flags);
 
        if (mux->chan_id == dmamux->dma_requests) {
+               spin_unlock_irqrestore(&dmamux->lock, flags);
                dev_err(&pdev->dev, "Run out of free DMA requests\n");
                ret = -ENOMEM;
-               goto error;
+               goto error_chan_id;
        }
+       set_bit(mux->chan_id, dmamux->dma_inuse);
+       spin_unlock_irqrestore(&dmamux->lock, flags);
 
        /* Look for DMA Master */
        for (i = 1, min = 0, max = dmamux->dma_reqs[i];
@@ -173,6 +174,8 @@ static void *stm32_dmamux_route_allocate(struct of_phandle_args *dma_spec,
 
 error:
        clear_bit(mux->chan_id, dmamux->dma_inuse);
+
+error_chan_id:
        kfree(mux);
        return ERR_PTR(ret);
 }
index f34430f..8721002 100644 (file)
@@ -279,7 +279,7 @@ static const u32 correrrthrsld[] = {
  * sbridge structs
  */
 
-#define NUM_CHANNELS           4       /* Max channels per MC */
+#define NUM_CHANNELS           6       /* Max channels per MC */
 #define MAX_DIMMS              3       /* Max DIMMS per channel */
 #define KNL_MAX_CHAS           38      /* KNL max num. of Cache Home Agents */
 #define KNL_MAX_CHANNELS       6       /* KNL max num. of PCI channels */
index 0a44d43..3ec4c71 100644 (file)
@@ -1,7 +1,6 @@
 /*
  * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
  *
- * Copyright (C) 2016-2017 Hans de Goede <hdegoede@redhat.com>
  * Copyright (C) 2015 Intel Corporation
  * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
  *
@@ -98,15 +97,13 @@ struct axp288_extcon_info {
        struct device *dev;
        struct regmap *regmap;
        struct regmap_irq_chip_data *regmap_irqc;
-       struct delayed_work det_work;
        int irq[EXTCON_IRQ_END];
        struct extcon_dev *edev;
        unsigned int previous_cable;
-       bool first_detect_done;
 };
 
 /* Power up/down reason string array */
-static char *axp288_pwr_up_down_info[] = {
+static const char * const axp288_pwr_up_down_info[] = {
        "Last wake caused by user pressing the power button",
        "Last wake caused by a charger insertion",
        "Last wake caused by a battery insertion",
@@ -124,7 +121,7 @@ static char *axp288_pwr_up_down_info[] = {
  */
 static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
 {
-       char **rsi;
+       const char * const *rsi;
        unsigned int val, i, clear_mask = 0;
        int ret;
 
@@ -140,25 +137,6 @@ static void axp288_extcon_log_rsi(struct axp288_extcon_info *info)
        regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask);
 }
 
-static void axp288_chrg_detect_complete(struct axp288_extcon_info *info)
-{
-       /*
-        * We depend on other drivers to do things like mux the data lines,
-        * enable/disable vbus based on the id-pin, etc. Sometimes the BIOS has
-        * not set these things up correctly resulting in the initial charger
-        * cable type detection giving a wrong result and we end up not charging
-        * or charging at only 0.5A.
-        *
-        * So we schedule a second cable type detection after 2 seconds to
-        * give the other drivers time to load and do their thing.
-        */
-       if (!info->first_detect_done) {
-               queue_delayed_work(system_wq, &info->det_work,
-                                  msecs_to_jiffies(2000));
-               info->first_detect_done = true;
-       }
-}
-
 static int axp288_handle_chrg_det_event(struct axp288_extcon_info *info)
 {
        int ret, stat, cfg, pwr_stat;
@@ -223,8 +201,6 @@ no_vbus:
                info->previous_cable = cable;
        }
 
-       axp288_chrg_detect_complete(info);
-
        return 0;
 
 dev_det_ret:
@@ -246,11 +222,8 @@ static irqreturn_t axp288_extcon_isr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static void axp288_extcon_det_work(struct work_struct *work)
+static void axp288_extcon_enable(struct axp288_extcon_info *info)
 {
-       struct axp288_extcon_info *info =
-               container_of(work, struct axp288_extcon_info, det_work.work);
-
        regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG,
                                                BC_GLOBAL_RUN, 0);
        /* Enable the charger detection logic */
@@ -272,7 +245,6 @@ static int axp288_extcon_probe(struct platform_device *pdev)
        info->regmap = axp20x->regmap;
        info->regmap_irqc = axp20x->regmap_irqc;
        info->previous_cable = EXTCON_NONE;
-       INIT_DELAYED_WORK(&info->det_work, axp288_extcon_det_work);
 
        platform_set_drvdata(pdev, info);
 
@@ -318,7 +290,7 @@ static int axp288_extcon_probe(struct platform_device *pdev)
        }
 
        /* Start charger cable type detection */
-       queue_delayed_work(system_wq, &info->det_work, 0);
+       axp288_extcon_enable(info);
 
        return 0;
 }
index c8691b5..191e99f 100644 (file)
@@ -153,8 +153,9 @@ static int int3496_probe(struct platform_device *pdev)
                return ret;
        }
 
-       /* queue initial processing of id-pin */
+       /* process id-pin so that we start with the right status */
        queue_delayed_work(system_wq, &data->work, 0);
+       flush_delayed_work(&data->work);
 
        platform_set_drvdata(pdev, data);
 
index c16600f..0bdea60 100644 (file)
@@ -639,7 +639,7 @@ static void __exit dcdbas_exit(void)
        platform_driver_unregister(&dcdbas_driver);
 }
 
-module_init(dcdbas_init);
+subsys_initcall_sync(dcdbas_init);
 module_exit(dcdbas_exit);
 
 MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")");
index da661bf..13c1edd 100644 (file)
@@ -68,11 +68,11 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg)
        efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID;
        efi_status_t status;
        efi_physical_addr_t log_location, log_last_entry;
-       struct linux_efi_tpm_eventlog *log_tbl;
+       struct linux_efi_tpm_eventlog *log_tbl = NULL;
        unsigned long first_entry_addr, last_entry_addr;
        size_t log_size, last_entry_size;
        efi_bool_t truncated;
-       void *tcg2_protocol;
+       void *tcg2_protocol = NULL;
 
        status = efi_call_early(locate_protocol, &tcg2_guid, NULL,
                                &tcg2_protocol);
index e76de57..ebaea8b 100644 (file)
@@ -14,7 +14,6 @@
  * GNU General Public License for more details.
  */
 
-#include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/gpio.h>
 #include <linux/init.h>
@@ -37,10 +36,9 @@ struct gpio_rcar_priv {
        struct platform_device *pdev;
        struct gpio_chip gpio_chip;
        struct irq_chip irq_chip;
-       struct clk *clk;
        unsigned int irq_parent;
+       atomic_t wakeup_path;
        bool has_both_edge_trigger;
-       bool needs_clk;
 };
 
 #define IOINTSEL 0x00  /* General IO/Interrupt Switching Register */
@@ -186,13 +184,10 @@ static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)
                }
        }
 
-       if (!p->clk)
-               return 0;
-
        if (on)
-               clk_enable(p->clk);
+               atomic_inc(&p->wakeup_path);
        else
-               clk_disable(p->clk);
+               atomic_dec(&p->wakeup_path);
 
        return 0;
 }
@@ -330,17 +325,14 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
 
 struct gpio_rcar_info {
        bool has_both_edge_trigger;
-       bool needs_clk;
 };
 
 static const struct gpio_rcar_info gpio_rcar_info_gen1 = {
        .has_both_edge_trigger = false,
-       .needs_clk = false,
 };
 
 static const struct gpio_rcar_info gpio_rcar_info_gen2 = {
        .has_both_edge_trigger = true,
-       .needs_clk = true,
 };
 
 static const struct of_device_id gpio_rcar_of_table[] = {
@@ -403,7 +395,6 @@ static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)
        ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);
        *npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;
        p->has_both_edge_trigger = info->has_both_edge_trigger;
-       p->needs_clk = info->needs_clk;
 
        if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {
                dev_warn(&p->pdev->dev,
@@ -440,16 +431,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, p);
 
-       p->clk = devm_clk_get(dev, NULL);
-       if (IS_ERR(p->clk)) {
-               if (p->needs_clk) {
-                       dev_err(dev, "unable to get clock\n");
-                       ret = PTR_ERR(p->clk);
-                       goto err0;
-               }
-               p->clk = NULL;
-       }
-
        pm_runtime_enable(dev);
 
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -531,11 +512,24 @@ static int gpio_rcar_remove(struct platform_device *pdev)
        return 0;
 }
 
+static int __maybe_unused gpio_rcar_suspend(struct device *dev)
+{
+       struct gpio_rcar_priv *p = dev_get_drvdata(dev);
+
+       if (atomic_read(&p->wakeup_path))
+               device_set_wakeup_path(dev);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, NULL);
+
 static struct platform_driver gpio_rcar_device_driver = {
        .probe          = gpio_rcar_probe,
        .remove         = gpio_rcar_remove,
        .driver         = {
                .name   = "gpio_rcar",
+               .pm     = &gpio_rcar_pm_ops,
                .of_match_table = of_match_ptr(gpio_rcar_of_table),
        }
 };
index 564bb7a..84e5a9d 100644 (file)
@@ -241,6 +241,19 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
 
                desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
                                                &of_flags);
+               /*
+                * -EPROBE_DEFER in our case means that we found a
+                * valid GPIO property, but no controller has been
+                * registered so far.
+                *
+                * This means we don't need to look any further for
+                * alternate name conventions, and we should really
+                * preserve the return code for our user to be able to
+                * retry probing later.
+                */
+               if (IS_ERR(desc) && PTR_ERR(desc) == -EPROBE_DEFER)
+                       return desc;
+
                if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
                        break;
        }
@@ -250,7 +263,7 @@ struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
                desc = of_find_spi_gpio(dev, con_id, &of_flags);
 
        /* Special handling for regulator GPIOs if used */
-       if (IS_ERR(desc))
+       if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
                desc = of_find_regulator_gpio(dev, con_id, &of_flags);
 
        if (IS_ERR(desc))
index d5a2eef..74edba1 100644 (file)
@@ -1156,7 +1156,7 @@ static inline void amdgpu_set_ib_value(struct amdgpu_cs_parser *p,
 /*
  * Writeback
  */
-#define AMDGPU_MAX_WB 512      /* Reserve at most 512 WB slots for amdgpu-owned rings. */
+#define AMDGPU_MAX_WB 128      /* Reserve at most 128 WB slots for amdgpu-owned rings. */
 
 struct amdgpu_wb {
        struct amdgpu_bo        *wb_obj;
index 57afad7..8fa850a 100644 (file)
@@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev,
        size_t size;
        u32 retry = 3;
 
+       if (amdgpu_acpi_pcie_notify_device_ready(adev))
+               return -EINVAL;
+
        /* Get the device handle */
        handle = ACPI_HANDLE(&adev->pdev->dev);
        if (!handle)
index e2c3c5e..c53095b 100644 (file)
@@ -568,6 +568,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = {
        /* HG _PR3 doesn't seem to work on this A+A weston board */
        { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX },
+       { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX },
        { 0, 0, 0, 0, 0 },
 };
 
index 8ca3783..7a073ac 100644 (file)
@@ -69,25 +69,18 @@ void amdgpu_connector_hotplug(struct drm_connector *connector)
                /* don't do anything if sink is not display port, i.e.,
                 * passive dp->(dvi|hdmi) adaptor
                 */
-               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                       int saved_dpms = connector->dpms;
-                       /* Only turn off the display if it's physically disconnected */
-                       if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) {
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-                       } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
-                               /* Don't try to start link training before we
-                                * have the dpcd */
-                               if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
-                                       return;
-
-                               /* set it to OFF so that drm_helper_connector_dpms()
-                                * won't return immediately since the current state
-                                * is ON at this point.
-                                */
-                               connector->dpms = DRM_MODE_DPMS_OFF;
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-                       }
-                       connector->dpms = saved_dpms;
+               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
+                   amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) &&
+                   amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) {
+                       /* Don't start link training before we have the DPCD */
+                       if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector))
+                               return;
+
+                       /* Turn the connector off and back on immediately, which
+                        * will trigger link training
+                        */
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                }
        }
 }
@@ -736,9 +729,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (encoder) {
                struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
@@ -757,8 +752,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force)
        /* check acpi lid status ??? */
 
        amdgpu_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
+
        return ret;
 }
 
@@ -868,9 +867,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        encoder = amdgpu_connector_best_single_encoder(connector);
        if (!encoder)
@@ -924,8 +925,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force)
        amdgpu_connector_update_scratch_regs(connector, ret);
 
 out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
@@ -988,9 +991,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        bool dret = false, broken_edid = false;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
@@ -1115,8 +1120,10 @@ out:
        amdgpu_connector_update_scratch_regs(connector, ret);
 
 exit:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
@@ -1359,9 +1366,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
        struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector);
        int r;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
@@ -1429,8 +1438,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force)
 
        amdgpu_connector_update_scratch_regs(connector, ret);
 out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
index 00a50cc..66cb10c 100644 (file)
@@ -492,7 +492,7 @@ static int amdgpu_device_wb_init(struct amdgpu_device *adev)
                memset(&adev->wb.used, 0, sizeof(adev->wb.used));
 
                /* clear wb memory */
-               memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t));
+               memset((char *)adev->wb.wb, 0, AMDGPU_MAX_WB * sizeof(uint32_t) * 8);
        }
 
        return 0;
@@ -530,8 +530,9 @@ int amdgpu_device_wb_get(struct amdgpu_device *adev, u32 *wb)
  */
 void amdgpu_device_wb_free(struct amdgpu_device *adev, u32 wb)
 {
+       wb >>= 3;
        if (wb < adev->wb.num_wb)
-               __clear_bit(wb >> 3, adev->wb.used);
+               __clear_bit(wb, adev->wb.used);
 }
 
 /**
@@ -1455,11 +1456,6 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
                if (!adev->ip_blocks[i].status.hw)
                        continue;
-               if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
-                       amdgpu_free_static_csa(adev);
-                       amdgpu_device_wb_fini(adev);
-                       amdgpu_device_vram_scratch_fini(adev);
-               }
 
                if (adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_UVD &&
                        adev->ip_blocks[i].version->type != AMD_IP_BLOCK_TYPE_VCE) {
@@ -1486,6 +1482,13 @@ static int amdgpu_device_ip_fini(struct amdgpu_device *adev)
        for (i = adev->num_ip_blocks - 1; i >= 0; i--) {
                if (!adev->ip_blocks[i].status.sw)
                        continue;
+
+               if (adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_GMC) {
+                       amdgpu_free_static_csa(adev);
+                       amdgpu_device_wb_fini(adev);
+                       amdgpu_device_vram_scratch_fini(adev);
+               }
+
                r = adev->ip_blocks[i].version->funcs->sw_fini((void *)adev);
                /* XXX handle errors */
                if (r) {
@@ -2060,9 +2063,12 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
 
        DRM_INFO("amdgpu: finishing device.\n");
        adev->shutdown = true;
-       if (adev->mode_info.mode_config_initialized)
-               drm_crtc_force_disable_all(adev->ddev);
-
+       if (adev->mode_info.mode_config_initialized){
+               if (!amdgpu_device_has_dc_support(adev))
+                       drm_crtc_force_disable_all(adev->ddev);
+               else
+                       drm_atomic_helper_shutdown(adev->ddev);
+       }
        amdgpu_ib_pool_fini(adev);
        amdgpu_fence_driver_fini(adev);
        amdgpu_fbdev_fini(adev);
@@ -2284,14 +2290,6 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
                                drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                        }
                        drm_modeset_unlock_all(dev);
-               } else {
-                       /*
-                        * There is no equivalent atomic helper to turn on
-                        * display, so we defined our own function for this,
-                        * once suspend resume is supported by the atomic
-                        * framework this will be reworked
-                        */
-                       amdgpu_dm_display_resume(adev);
                }
        }
 
@@ -2726,7 +2724,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
        if (amdgpu_device_has_dc_support(adev)) {
                if (drm_atomic_helper_resume(adev->ddev, state))
                        dev_info(adev->dev, "drm resume failed:%d\n", r);
-               amdgpu_dm_display_resume(adev);
        } else {
                drm_helper_resume_force_mode(adev->ddev);
        }
index e48b4ec..ca6c931 100644 (file)
@@ -36,8 +36,6 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj)
        struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj);
 
        if (robj) {
-               if (robj->gem_base.import_attach)
-                       drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
                amdgpu_mn_unregister(robj);
                amdgpu_bo_unref(&robj);
        }
index e14ab34..7c2be32 100644 (file)
@@ -75,7 +75,7 @@ static int amdgpu_gtt_mgr_init(struct ttm_mem_type_manager *man,
 static int amdgpu_gtt_mgr_fini(struct ttm_mem_type_manager *man)
 {
        struct amdgpu_gtt_mgr *mgr = man->priv;
-
+       spin_lock(&mgr->lock);
        drm_mm_takedown(&mgr->mm);
        spin_unlock(&mgr->lock);
        kfree(mgr);
index 56bcd59..36483e0 100644 (file)
@@ -257,7 +257,8 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
        r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
        if (r) {
                adev->irq.installed = false;
-               flush_work(&adev->hotplug_work);
+               if (!amdgpu_device_has_dc_support(adev))
+                       flush_work(&adev->hotplug_work);
                cancel_work_sync(&adev->reset_work);
                return r;
        }
@@ -282,7 +283,8 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
                adev->irq.installed = false;
                if (adev->irq.msi_enabled)
                        pci_disable_msi(adev->pdev);
-               flush_work(&adev->hotplug_work);
+               if (!amdgpu_device_has_dc_support(adev))
+                       flush_work(&adev->hotplug_work);
                cancel_work_sync(&adev->reset_work);
        }
 
index 54f06c9..2264c5c 100644 (file)
@@ -352,6 +352,7 @@ struct amdgpu_mode_info {
        u16 firmware_flags;
        /* pointer to backlight encoder */
        struct amdgpu_encoder *bl_encoder;
+       u8 bl_level; /* saved backlight level */
        struct amdgpu_audio     audio; /* audio stuff */
        int                     num_crtc; /* number of crtcs */
        int                     num_hpd; /* number of hpd pins */
index 5c4c3e0..1220322 100644 (file)
@@ -56,6 +56,8 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
 
        amdgpu_bo_kunmap(bo);
 
+       if (bo->gem_base.import_attach)
+               drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg);
        drm_gem_object_release(&bo->gem_base);
        amdgpu_bo_unref(&bo->parent);
        if (!list_empty(&bo->shadow_list)) {
index 13044e6..561d331 100644 (file)
@@ -481,7 +481,7 @@ static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf,
        result = 0;
 
        if (*pos < 12) {
-               early[0] = amdgpu_ring_get_rptr(ring);
+               early[0] = amdgpu_ring_get_rptr(ring) & ring->buf_mask;
                early[1] = amdgpu_ring_get_wptr(ring) & ring->buf_mask;
                early[2] = ring->wptr & ring->buf_mask;
                for (i = *pos / 4; i < 3 && size; i++) {
index b2eae86..5c26a8e 100644 (file)
@@ -299,12 +299,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev)
 
        cancel_delayed_work_sync(&adev->uvd.idle_work);
 
-       for (i = 0; i < adev->uvd.max_handles; ++i)
-               if (atomic_read(&adev->uvd.handles[i]))
-                       break;
+       /* only valid for physical mode */
+       if (adev->asic_type < CHIP_POLARIS10) {
+               for (i = 0; i < adev->uvd.max_handles; ++i)
+                       if (atomic_read(&adev->uvd.handles[i]))
+                               break;
 
-       if (i == AMDGPU_MAX_UVD_HANDLES)
-               return 0;
+               if (i == adev->uvd.max_handles)
+                       return 0;
+       }
 
        size = amdgpu_bo_size(adev->uvd.vcpu_bo);
        ptr = adev->uvd.cpu_addr;
index 2af26d2..d702fb8 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/backlight.h>
 #include "bif/bif_4_1_d.h"
 
-static u8
+u8
 amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev)
 {
        u8 backlight_level;
@@ -48,7 +48,7 @@ amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev)
        return backlight_level;
 }
 
-static void
+void
 amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev,
                                            u8 backlight_level)
 {
index 2bdec40..f77cbde 100644 (file)
 #define __ATOMBIOS_ENCODER_H__
 
 u8
+amdgpu_atombios_encoder_get_backlight_level_from_reg(struct amdgpu_device *adev);
+void
+amdgpu_atombios_encoder_set_backlight_level_to_reg(struct amdgpu_device *adev,
+                                                  u8 backlight_level);
+u8
 amdgpu_atombios_encoder_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder);
 void
 amdgpu_atombios_encoder_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder,
index f34bc68..022f303 100644 (file)
@@ -2921,6 +2921,11 @@ 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;
+
+       adev->mode_info.bl_level =
+               amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+
        return dce_v10_0_hw_fini(handle);
 }
 
@@ -2929,6 +2934,9 @@ static int dce_v10_0_resume(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret;
 
+       amdgpu_atombios_encoder_set_backlight_level_to_reg(adev,
+                                                          adev->mode_info.bl_level);
+
        ret = dce_v10_0_hw_init(handle);
 
        /* turn on the BL */
index 26378bd..800a9f3 100644 (file)
@@ -3047,6 +3047,11 @@ 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;
+
+       adev->mode_info.bl_level =
+               amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+
        return dce_v11_0_hw_fini(handle);
 }
 
@@ -3055,6 +3060,9 @@ static int dce_v11_0_resume(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret;
 
+       amdgpu_atombios_encoder_set_backlight_level_to_reg(adev,
+                                                          adev->mode_info.bl_level);
+
        ret = dce_v11_0_hw_init(handle);
 
        /* turn on the BL */
index bd2c4f7..b8368f6 100644 (file)
@@ -2787,6 +2787,11 @@ 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;
+
+       adev->mode_info.bl_level =
+               amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+
        return dce_v6_0_hw_fini(handle);
 }
 
@@ -2795,6 +2800,9 @@ static int dce_v6_0_resume(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret;
 
+       amdgpu_atombios_encoder_set_backlight_level_to_reg(adev,
+                                                          adev->mode_info.bl_level);
+
        ret = dce_v6_0_hw_init(handle);
 
        /* turn on the BL */
@@ -3093,7 +3101,7 @@ static int dce_v6_0_hpd_irq(struct amdgpu_device *adev,
                tmp |= DC_HPD1_INT_CONTROL__DC_HPD1_INT_ACK_MASK;
                WREG32(mmDC_HPD1_INT_CONTROL + hpd_offsets[hpd], tmp);
                schedule_work(&adev->hotplug_work);
-               DRM_INFO("IH: HPD%d\n", hpd + 1);
+               DRM_DEBUG("IH: HPD%d\n", hpd + 1);
        }
 
        return 0;
index c008dc0..012e0a9 100644 (file)
@@ -2819,6 +2819,11 @@ 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;
+
+       adev->mode_info.bl_level =
+               amdgpu_atombios_encoder_get_backlight_level_from_reg(adev);
+
        return dce_v8_0_hw_fini(handle);
 }
 
@@ -2827,6 +2832,9 @@ static int dce_v8_0_resume(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        int ret;
 
+       amdgpu_atombios_encoder_set_backlight_level_to_reg(adev,
+                                                          adev->mode_info.bl_level);
+
        ret = dce_v8_0_hw_init(handle);
 
        /* turn on the BL */
index a066c5e..a430969 100644 (file)
@@ -4384,34 +4384,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev)
        case CHIP_KAVERI:
                adev->gfx.config.max_shader_engines = 1;
                adev->gfx.config.max_tile_pipes = 4;
-               if ((adev->pdev->device == 0x1304) ||
-                   (adev->pdev->device == 0x1305) ||
-                   (adev->pdev->device == 0x130C) ||
-                   (adev->pdev->device == 0x130F) ||
-                   (adev->pdev->device == 0x1310) ||
-                   (adev->pdev->device == 0x1311) ||
-                   (adev->pdev->device == 0x131C)) {
-                       adev->gfx.config.max_cu_per_sh = 8;
-                       adev->gfx.config.max_backends_per_se = 2;
-               } else if ((adev->pdev->device == 0x1309) ||
-                          (adev->pdev->device == 0x130A) ||
-                          (adev->pdev->device == 0x130D) ||
-                          (adev->pdev->device == 0x1313) ||
-                          (adev->pdev->device == 0x131D)) {
-                       adev->gfx.config.max_cu_per_sh = 6;
-                       adev->gfx.config.max_backends_per_se = 2;
-               } else if ((adev->pdev->device == 0x1306) ||
-                          (adev->pdev->device == 0x1307) ||
-                          (adev->pdev->device == 0x130B) ||
-                          (adev->pdev->device == 0x130E) ||
-                          (adev->pdev->device == 0x1315) ||
-                          (adev->pdev->device == 0x131B)) {
-                       adev->gfx.config.max_cu_per_sh = 4;
-                       adev->gfx.config.max_backends_per_se = 1;
-               } else {
-                       adev->gfx.config.max_cu_per_sh = 3;
-                       adev->gfx.config.max_backends_per_se = 1;
-               }
+               adev->gfx.config.max_cu_per_sh = 8;
+               adev->gfx.config.max_backends_per_se = 2;
                adev->gfx.config.max_sh_per_se = 1;
                adev->gfx.config.max_texture_channel_caches = 4;
                adev->gfx.config.max_gprs = 256;
index 2719937..3b7e7af 100644 (file)
@@ -634,7 +634,7 @@ static int gmc_v9_0_late_init(void *handle)
        for(i = 0; i < AMDGPU_MAX_VMHUBS; ++i)
                BUG_ON(vm_inv_eng[i] > 16);
 
-       if (adev->asic_type == CHIP_VEGA10) {
+       if (adev->asic_type == CHIP_VEGA10 && !amdgpu_sriov_vf(adev)) {
                r = gmc_v9_0_ecc_available(adev);
                if (r == 1) {
                        DRM_INFO("ECC is active.\n");
@@ -682,7 +682,10 @@ static int gmc_v9_0_mc_init(struct amdgpu_device *adev)
        adev->mc.vram_width = amdgpu_atomfirmware_get_vram_width(adev);
        if (!adev->mc.vram_width) {
                /* hbm memory channel size */
-               chansize = 128;
+               if (adev->flags & AMD_IS_APU)
+                       chansize = 64;
+               else
+                       chansize = 128;
 
                tmp = RREG32_SOC15(DF, 0, mmDF_CS_AON0_DramBaseAddress0);
                tmp &= DF_CS_AON0_DramBaseAddress0__IntLvNumChan_MASK;
index e92fb37..91cf95a 100644 (file)
@@ -238,31 +238,27 @@ static uint64_t sdma_v4_0_ring_get_rptr(struct amdgpu_ring *ring)
 static uint64_t sdma_v4_0_ring_get_wptr(struct amdgpu_ring *ring)
 {
        struct amdgpu_device *adev = ring->adev;
-       u64 *wptr = NULL;
-       uint64_t local_wptr = 0;
+       u64 wptr;
 
        if (ring->use_doorbell) {
                /* XXX check if swapping is necessary on BE */
-               wptr = ((u64 *)&adev->wb.wb[ring->wptr_offs]);
-               DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", *wptr);
-               *wptr = (*wptr) >> 2;
-               DRM_DEBUG("wptr/doorbell after shift == 0x%016llx\n", *wptr);
+               wptr = READ_ONCE(*((u64 *)&adev->wb.wb[ring->wptr_offs]));
+               DRM_DEBUG("wptr/doorbell before shift == 0x%016llx\n", wptr);
        } else {
                u32 lowbit, highbit;
                int me = (ring == &adev->sdma.instance[0].ring) ? 0 : 1;
 
-               wptr = &local_wptr;
                lowbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR)) >> 2;
                highbit = RREG32(sdma_v4_0_get_reg_offset(adev, me, mmSDMA0_GFX_RB_WPTR_HI)) >> 2;
 
                DRM_DEBUG("wptr [%i]high== 0x%08x low==0x%08x\n",
                                me, highbit, lowbit);
-               *wptr = highbit;
-               *wptr = (*wptr) << 32;
-               *wptr |= lowbit;
+               wptr = highbit;
+               wptr = wptr << 32;
+               wptr |= lowbit;
        }
 
-       return *wptr;
+       return wptr >> 2;
 }
 
 /**
index 543101d..2095173 100644 (file)
@@ -31,6 +31,7 @@
 #include "amdgpu_uvd.h"
 #include "amdgpu_vce.h"
 #include "atom.h"
+#include "amd_pcie.h"
 #include "amdgpu_powerplay.h"
 #include "sid.h"
 #include "si_ih.h"
@@ -1461,8 +1462,8 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 {
        struct pci_dev *root = adev->pdev->bus->self;
        int bridge_pos, gpu_pos;
-       u32 speed_cntl, mask, current_data_rate;
-       int ret, i;
+       u32 speed_cntl, current_data_rate;
+       int i;
        u16 tmp16;
 
        if (pci_is_root_bus(adev->pdev->bus))
@@ -1474,23 +1475,20 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
        if (adev->flags & AMD_IS_APU)
                return;
 
-       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-       if (ret != 0)
-               return;
-
-       if (!(mask & (DRM_PCIE_SPEED_50 | DRM_PCIE_SPEED_80)))
+       if (!(adev->pm.pcie_gen_mask & (CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2 |
+                                       CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)))
                return;
 
        speed_cntl = RREG32_PCIE_PORT(PCIE_LC_SPEED_CNTL);
        current_data_rate = (speed_cntl & LC_CURRENT_DATA_RATE_MASK) >>
                LC_CURRENT_DATA_RATE_SHIFT;
-       if (mask & DRM_PCIE_SPEED_80) {
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
                if (current_data_rate == 2) {
                        DRM_INFO("PCIE gen 3 link speeds already enabled\n");
                        return;
                }
                DRM_INFO("enabling PCIE gen 3 link speeds, disable with amdgpu.pcie_gen2=0\n");
-       } else if (mask & DRM_PCIE_SPEED_50) {
+       } else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) {
                if (current_data_rate == 1) {
                        DRM_INFO("PCIE gen 2 link speeds already enabled\n");
                        return;
@@ -1506,7 +1504,7 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
        if (!gpu_pos)
                return;
 
-       if (mask & DRM_PCIE_SPEED_80) {
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) {
                if (current_data_rate != 2) {
                        u16 bridge_cfg, gpu_cfg;
                        u16 bridge_cfg2, gpu_cfg2;
@@ -1589,9 +1587,9 @@ static void si_pcie_gen3_enable(struct amdgpu_device *adev)
 
        pci_read_config_word(adev->pdev, gpu_pos + PCI_EXP_LNKCTL2, &tmp16);
        tmp16 &= ~0xf;
-       if (mask & DRM_PCIE_SPEED_80)
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
                tmp16 |= 3;
-       else if (mask & DRM_PCIE_SPEED_50)
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
                tmp16 |= 2;
        else
                tmp16 |= 1;
index ce675a7..22f0b7f 100644 (file)
@@ -26,6 +26,7 @@
 #include "amdgpu_pm.h"
 #include "amdgpu_dpm.h"
 #include "amdgpu_atombios.h"
+#include "amd_pcie.h"
 #include "sid.h"
 #include "r600_dpm.h"
 #include "si_dpm.h"
@@ -3331,29 +3332,6 @@ static void btc_apply_voltage_delta_rules(struct amdgpu_device *adev,
        }
 }
 
-static enum amdgpu_pcie_gen r600_get_pcie_gen_support(struct amdgpu_device *adev,
-                                              u32 sys_mask,
-                                              enum amdgpu_pcie_gen asic_gen,
-                                              enum amdgpu_pcie_gen default_gen)
-{
-       switch (asic_gen) {
-       case AMDGPU_PCIE_GEN1:
-               return AMDGPU_PCIE_GEN1;
-       case AMDGPU_PCIE_GEN2:
-               return AMDGPU_PCIE_GEN2;
-       case AMDGPU_PCIE_GEN3:
-               return AMDGPU_PCIE_GEN3;
-       default:
-               if ((sys_mask & DRM_PCIE_SPEED_80) && (default_gen == AMDGPU_PCIE_GEN3))
-                       return AMDGPU_PCIE_GEN3;
-               else if ((sys_mask & DRM_PCIE_SPEED_50) && (default_gen == AMDGPU_PCIE_GEN2))
-                       return AMDGPU_PCIE_GEN2;
-               else
-                       return AMDGPU_PCIE_GEN1;
-       }
-       return AMDGPU_PCIE_GEN1;
-}
-
 static void r600_calculate_u_and_p(u32 i, u32 r_c, u32 p_b,
                            u32 *p, u32 *u)
 {
@@ -5028,10 +5006,11 @@ static int si_populate_smc_acpi_state(struct amdgpu_device *adev,
                                                              table->ACPIState.levels[0].vddc.index,
                                                              &table->ACPIState.levels[0].std_vddc);
                }
-               table->ACPIState.levels[0].gen2PCIE = (u8)r600_get_pcie_gen_support(adev,
-                                                                                   si_pi->sys_pcie_mask,
-                                                                                   si_pi->boot_pcie_gen,
-                                                                                   AMDGPU_PCIE_GEN1);
+               table->ACPIState.levels[0].gen2PCIE =
+                       (u8)amdgpu_get_pcie_gen_support(adev,
+                                                       si_pi->sys_pcie_mask,
+                                                       si_pi->boot_pcie_gen,
+                                                       AMDGPU_PCIE_GEN1);
 
                if (si_pi->vddc_phase_shed_control)
                        si_populate_phase_shedding_value(adev,
@@ -7168,10 +7147,10 @@ static void si_parse_pplib_clock_info(struct amdgpu_device *adev,
        pl->vddc = le16_to_cpu(clock_info->si.usVDDC);
        pl->vddci = le16_to_cpu(clock_info->si.usVDDCI);
        pl->flags = le32_to_cpu(clock_info->si.ulFlags);
-       pl->pcie_gen = r600_get_pcie_gen_support(adev,
-                                                si_pi->sys_pcie_mask,
-                                                si_pi->boot_pcie_gen,
-                                                clock_info->si.ucPCIEGen);
+       pl->pcie_gen = amdgpu_get_pcie_gen_support(adev,
+                                                  si_pi->sys_pcie_mask,
+                                                  si_pi->boot_pcie_gen,
+                                                  clock_info->si.ucPCIEGen);
 
        /* patch up vddc if necessary */
        ret = si_get_leakage_voltage_from_leakage_index(adev, pl->vddc,
@@ -7326,7 +7305,6 @@ static int si_dpm_init(struct amdgpu_device *adev)
        struct si_power_info *si_pi;
        struct atom_clock_dividers dividers;
        int ret;
-       u32 mask;
 
        si_pi = kzalloc(sizeof(struct si_power_info), GFP_KERNEL);
        if (si_pi == NULL)
@@ -7336,11 +7314,9 @@ static int si_dpm_init(struct amdgpu_device *adev)
        eg_pi = &ni_pi->eg;
        pi = &eg_pi->rv7xx;
 
-       ret = drm_pcie_get_speed_cap_mask(adev->ddev, &mask);
-       if (ret)
-               si_pi->sys_pcie_mask = 0;
-       else
-               si_pi->sys_pcie_mask = mask;
+       si_pi->sys_pcie_mask =
+               (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_MASK) >>
+               CAIL_PCIE_LINK_SPEED_SUPPORT_SHIFT;
        si_pi->force_pcie_gen = AMDGPU_PCIE_GEN_INVALID;
        si_pi->boot_pcie_gen = si_get_current_pcie_speed(adev);
 
index b2bfeda..9bab484 100644 (file)
@@ -1618,7 +1618,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_enc_ring_vm_funcs = {
        .set_wptr = uvd_v6_0_enc_ring_set_wptr,
        .emit_frame_size =
                4 + /* uvd_v6_0_enc_ring_emit_pipeline_sync */
-               6 + /* uvd_v6_0_enc_ring_emit_vm_flush */
+               5 + /* uvd_v6_0_enc_ring_emit_vm_flush */
                5 + 5 + /* uvd_v6_0_enc_ring_emit_fence x2 vm fence */
                1, /* uvd_v6_0_enc_ring_insert_end */
        .emit_ib_size = 5, /* uvd_v6_0_enc_ring_emit_ib */
index b21285a..1bd5f26 100644 (file)
@@ -821,13 +821,13 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
                pr_warn("Can't create new usermode queue because %d queues were already created\n",
                                dqm->total_queue_count);
                retval = -EPERM;
-               goto out;
+               goto out_unlock;
        }
 
        if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
                retval = allocate_sdma_queue(dqm, &q->sdma_id);
                if (retval)
-                       goto out;
+                       goto out_unlock;
                q->properties.sdma_queue_id =
                        q->sdma_id / CIK_SDMA_QUEUES_PER_ENGINE;
                q->properties.sdma_engine_id =
@@ -838,7 +838,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
 
        if (!mqd) {
                retval = -ENOMEM;
-               goto out;
+               goto out_deallocate_sdma_queue;
        }
 
        dqm->asic_ops.init_sdma_vm(dqm, q, qpd);
@@ -848,7 +848,7 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
        retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
                                &q->gart_mqd_addr, &q->properties);
        if (retval)
-               goto out;
+               goto out_deallocate_sdma_queue;
 
        list_add(&q->list, &qpd->queues_list);
        qpd->queue_count++;
@@ -869,7 +869,13 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
        pr_debug("Total of %d queues are accountable so far\n",
                        dqm->total_queue_count);
 
-out:
+       mutex_unlock(&dqm->lock);
+       return retval;
+
+out_deallocate_sdma_queue:
+       if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+               deallocate_sdma_queue(dqm, q->sdma_id);
+out_unlock:
        mutex_unlock(&dqm->lock);
        return retval;
 }
@@ -1188,8 +1194,10 @@ static int process_termination_cpsch(struct device_queue_manager *dqm,
 
        /* Clear all user mode queues */
        list_for_each_entry(q, &qpd->queues_list, list) {
-               if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+               if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
                        dqm->sdma_queue_count--;
+                       deallocate_sdma_queue(dqm, q->sdma_id);
+               }
 
                if (q->properties.is_active)
                        dqm->queue_count--;
index 0ecbd1f..0c3bc00 100644 (file)
@@ -188,8 +188,7 @@ static int pm_create_map_process(struct packet_manager *pm, uint32_t *buffer,
        packet->sh_mem_ape1_base = qpd->sh_mem_ape1_base;
        packet->sh_mem_ape1_limit = qpd->sh_mem_ape1_limit;
 
-       /* TODO: scratch support */
-       packet->sh_hidden_private_base_vmid = 0;
+       packet->sh_hidden_private_base_vmid = qpd->sh_hidden_private_base;
 
        packet->gds_addr_lo = lower_32_bits(qpd->gds_context_area);
        packet->gds_addr_hi = upper_32_bits(qpd->gds_context_area);
index 1ce4c98..63c6734 100644 (file)
@@ -629,11 +629,13 @@ static int dm_resume(void *handle)
 {
        struct amdgpu_device *adev = handle;
        struct amdgpu_display_manager *dm = &adev->dm;
+       int ret = 0;
 
        /* power on hardware */
        dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
 
-       return 0;
+       ret = amdgpu_dm_display_resume(adev);
+       return ret;
 }
 
 int amdgpu_dm_display_resume(struct amdgpu_device *adev)
@@ -1035,6 +1037,10 @@ static void handle_hpd_rx_irq(void *param)
                        !is_mst_root_connector) {
                /* Downstream Port status changed. */
                if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
+
+                       if (aconnector->fake_enable)
+                               aconnector->fake_enable = false;
+
                        amdgpu_dm_update_connector_after_detect(aconnector);
 
 
@@ -2010,30 +2016,32 @@ static void update_stream_scaling_settings(const struct drm_display_mode *mode,
        dst.width = stream->timing.h_addressable;
        dst.height = stream->timing.v_addressable;
 
-       rmx_type = dm_state->scaling;
-       if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) {
-               if (src.width * dst.height <
-                               src.height * dst.width) {
-                       /* height needs less upscaling/more downscaling */
-                       dst.width = src.width *
-                                       dst.height / src.height;
-               } else {
-                       /* width needs less upscaling/more downscaling */
-                       dst.height = src.height *
-                                       dst.width / src.width;
+       if (dm_state) {
+               rmx_type = dm_state->scaling;
+               if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) {
+                       if (src.width * dst.height <
+                                       src.height * dst.width) {
+                               /* height needs less upscaling/more downscaling */
+                               dst.width = src.width *
+                                               dst.height / src.height;
+                       } else {
+                               /* width needs less upscaling/more downscaling */
+                               dst.height = src.height *
+                                               dst.width / src.width;
+                       }
+               } else if (rmx_type == RMX_CENTER) {
+                       dst = src;
                }
-       } else if (rmx_type == RMX_CENTER) {
-               dst = src;
-       }
 
-       dst.x = (stream->timing.h_addressable - dst.width) / 2;
-       dst.y = (stream->timing.v_addressable - dst.height) / 2;
+               dst.x = (stream->timing.h_addressable - dst.width) / 2;
+               dst.y = (stream->timing.v_addressable - dst.height) / 2;
 
-       if (dm_state->underscan_enable) {
-               dst.x += dm_state->underscan_hborder / 2;
-               dst.y += dm_state->underscan_vborder / 2;
-               dst.width -= dm_state->underscan_hborder;
-               dst.height -= dm_state->underscan_vborder;
+               if (dm_state->underscan_enable) {
+                       dst.x += dm_state->underscan_hborder / 2;
+                       dst.y += dm_state->underscan_vborder / 2;
+                       dst.width -= dm_state->underscan_hborder;
+                       dst.height -= dm_state->underscan_vborder;
+               }
        }
 
        stream->src = src;
@@ -2358,12 +2366,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
 
        if (aconnector == NULL) {
                DRM_ERROR("aconnector is NULL!\n");
-               goto drm_connector_null;
-       }
-
-       if (dm_state == NULL) {
-               DRM_ERROR("dm_state is NULL!\n");
-               goto dm_state_null;
+               return stream;
        }
 
        drm_connector = &aconnector->base;
@@ -2375,18 +2378,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                 */
                if (aconnector->mst_port) {
                        dm_dp_mst_dc_sink_create(drm_connector);
-                       goto mst_dc_sink_create_done;
+                       return stream;
                }
 
                if (create_fake_sink(aconnector))
-                       goto stream_create_fail;
+                       return stream;
        }
 
        stream = dc_create_stream_for_sink(aconnector->dc_sink);
 
        if (stream == NULL) {
                DRM_ERROR("Failed to create stream for sink!\n");
-               goto stream_create_fail;
+               return stream;
        }
 
        list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
@@ -2412,9 +2415,12 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        } else {
                decide_crtc_timing_for_drm_display_mode(
                                &mode, preferred_mode,
-                               dm_state->scaling != RMX_OFF);
+                               dm_state ? (dm_state->scaling != RMX_OFF) : false);
        }
 
+       if (!dm_state)
+               drm_mode_set_crtcinfo(&mode, 0);
+
        fill_stream_properties_from_drm_display_mode(stream,
                        &mode, &aconnector->base);
        update_stream_scaling_settings(&mode, dm_state, stream);
@@ -2424,10 +2430,8 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                drm_connector,
                aconnector->dc_sink);
 
-stream_create_fail:
-dm_state_null:
-drm_connector_null:
-mst_dc_sink_create_done:
+       update_stream_signal(stream);
+
        return stream;
 }
 
@@ -2495,6 +2499,27 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
        return &state->base;
 }
 
+
+static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
+{
+       enum dc_irq_source irq_source;
+       struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+
+       irq_source = IRQ_TYPE_VBLANK + acrtc->otg_inst;
+       return dc_interrupt_set(adev->dm.dc, irq_source, enable) ? 0 : -EBUSY;
+}
+
+static int dm_enable_vblank(struct drm_crtc *crtc)
+{
+       return dm_set_vblank(crtc, true);
+}
+
+static void dm_disable_vblank(struct drm_crtc *crtc)
+{
+       dm_set_vblank(crtc, false);
+}
+
 /* Implemented only the options currently availible for the driver */
 static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
        .reset = dm_crtc_reset_state,
@@ -2504,6 +2529,8 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
        .page_flip = drm_atomic_helper_page_flip,
        .atomic_duplicate_state = dm_crtc_duplicate_state,
        .atomic_destroy_state = dm_crtc_destroy_state,
+       .enable_vblank = dm_enable_vblank,
+       .disable_vblank = dm_disable_vblank,
 };
 
 static enum drm_connector_status
@@ -2798,7 +2825,7 @@ int amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
                goto fail;
        }
 
-       stream = dc_create_stream_for_sink(dc_sink);
+       stream = create_stream_for_sink(aconnector, mode, NULL);
        if (stream == NULL) {
                DRM_ERROR("Failed to create stream for sink!\n");
                goto fail;
@@ -3058,6 +3085,9 @@ static int dm_plane_atomic_check(struct drm_plane *plane,
        if (!dm_plane_state->dc_state)
                return 0;
 
+       if (!fill_rects_from_plane_state(state, dm_plane_state->dc_state))
+               return -EINVAL;
+
        if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
                return 0;
 
@@ -3104,8 +3134,6 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
 
        switch (aplane->base.type) {
        case DRM_PLANE_TYPE_PRIMARY:
-               aplane->base.format_default = true;
-
                res = drm_universal_plane_init(
                                dm->adev->ddev,
                                &aplane->base,
@@ -4630,8 +4658,6 @@ static int dm_update_planes_state(struct dc *dc,
        bool pflip_needed  = !state->allow_modeset;
        int ret = 0;
 
-       if (pflip_needed)
-               return ret;
 
        /* Add new planes */
        for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
@@ -4646,6 +4672,8 @@ static int dm_update_planes_state(struct dc *dc,
 
                /* Remove any changed/removed planes */
                if (!enable) {
+                       if (pflip_needed)
+                               continue;
 
                        if (!old_plane_crtc)
                                continue;
@@ -4677,6 +4705,7 @@ static int dm_update_planes_state(struct dc *dc,
                        *lock_and_validation_needed = true;
 
                } else { /* Add new planes */
+                       struct dc_plane_state *dc_new_plane_state;
 
                        if (drm_atomic_plane_disabling(plane->state, new_plane_state))
                                continue;
@@ -4690,38 +4719,50 @@ static int dm_update_planes_state(struct dc *dc,
                        if (!dm_new_crtc_state->stream)
                                continue;
 
+                       if (pflip_needed)
+                               continue;
 
                        WARN_ON(dm_new_plane_state->dc_state);
 
-                       dm_new_plane_state->dc_state = dc_create_plane_state(dc);
-
-                       DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
-                                       plane->base.id, new_plane_crtc->base.id);
-
-                       if (!dm_new_plane_state->dc_state) {
+                       dc_new_plane_state = dc_create_plane_state(dc);
+                       if (!dc_new_plane_state) {
                                ret = -EINVAL;
                                return ret;
                        }
 
+                       DRM_DEBUG_DRIVER("Enabling DRM plane: %d on DRM crtc %d\n",
+                                       plane->base.id, new_plane_crtc->base.id);
+
                        ret = fill_plane_attributes(
                                new_plane_crtc->dev->dev_private,
-                               dm_new_plane_state->dc_state,
+                               dc_new_plane_state,
                                new_plane_state,
                                new_crtc_state);
-                       if (ret)
+                       if (ret) {
+                               dc_plane_state_release(dc_new_plane_state);
                                return ret;
+                       }
 
-
+                       /*
+                        * Any atomic check errors that occur after this will
+                        * not need a release. The plane state will be attached
+                        * to the stream, and therefore part of the atomic
+                        * state. It'll be released when the atomic state is
+                        * cleaned.
+                        */
                        if (!dc_add_plane_to_context(
                                        dc,
                                        dm_new_crtc_state->stream,
-                                       dm_new_plane_state->dc_state,
+                                       dc_new_plane_state,
                                        dm_state->context)) {
 
+                               dc_plane_state_release(dc_new_plane_state);
                                ret = -EINVAL;
                                return ret;
                        }
 
+                       dm_new_plane_state->dc_state = dc_new_plane_state;
+
                        /* Tell DC to do a full surface update every time there
                         * is a plane change. Inefficient, but works for now.
                         */
@@ -4735,6 +4776,33 @@ static int dm_update_planes_state(struct dc *dc,
        return ret;
 }
 
+static int dm_atomic_check_plane_state_fb(struct drm_atomic_state *state,
+                                         struct drm_crtc *crtc)
+{
+       struct drm_plane *plane;
+       struct drm_crtc_state *crtc_state;
+
+       WARN_ON(!drm_atomic_get_new_crtc_state(state, crtc));
+
+       drm_for_each_plane_mask(plane, state->dev, crtc->state->plane_mask) {
+               struct drm_plane_state *plane_state =
+                       drm_atomic_get_plane_state(state, plane);
+
+               if (IS_ERR(plane_state))
+                       return -EDEADLK;
+
+               crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc);
+               if (IS_ERR(crtc_state))
+                       return PTR_ERR(crtc_state);
+
+               if (crtc->primary == plane && crtc_state->active) {
+                       if (!plane_state->fb)
+                               return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static int amdgpu_dm_atomic_check(struct drm_device *dev,
                                  struct drm_atomic_state *state)
 {
@@ -4758,6 +4826,10 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
                goto fail;
 
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               ret = dm_atomic_check_plane_state_fb(state, crtc);
+               if (ret)
+                       goto fail;
+
                if (!drm_atomic_crtc_needs_modeset(new_crtc_state) &&
                    !new_crtc_state->color_mgmt_changed)
                        continue;
index 9bd142f..e1acc10 100644 (file)
@@ -109,7 +109,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
                struct cea_sad *sad = &sads[i];
 
                edid_caps->audio_modes[i].format_code = sad->format;
-               edid_caps->audio_modes[i].channel_count = sad->channels;
+               edid_caps->audio_modes[i].channel_count = sad->channels + 1;
                edid_caps->audio_modes[i].sample_rate = sad->freq;
                edid_caps->audio_modes[i].sample_size = sad->byte2;
        }
index 1874b6c..4220550 100644 (file)
@@ -683,10 +683,8 @@ static const struct amdgpu_irq_src_funcs dm_hpd_irq_funcs = {
 
 void amdgpu_dm_set_irq_funcs(struct amdgpu_device *adev)
 {
-       if (adev->mode_info.num_crtc > 0)
-               adev->crtc_irq.num_types = AMDGPU_CRTC_IRQ_VLINE1 + adev->mode_info.num_crtc;
-       else
-               adev->crtc_irq.num_types = 0;
+
+       adev->crtc_irq.num_types = adev->mode_info.num_crtc;
        adev->crtc_irq.funcs = &dm_crtc_irq_funcs;
 
        adev->pageflip_irq.num_types = adev->mode_info.num_crtc;
index f3d87f4..93421da 100644 (file)
@@ -189,6 +189,12 @@ void dm_dp_mst_dc_sink_create(struct drm_connector *connector)
                        .link = aconnector->dc_link,
                        .sink_signal = SIGNAL_TYPE_DISPLAY_PORT_MST };
 
+       /*
+        * TODO: Need to further figure out why ddc.algo is NULL while MST port exists
+        */
+       if (!aconnector->port || !aconnector->port->aux.ddc.algo)
+               return;
+
        edid = drm_dp_mst_get_edid(connector, &aconnector->mst_port->mst_mgr, aconnector->port);
 
        if (!edid) {
index 35e84ed..12868c7 100644 (file)
@@ -1358,13 +1358,13 @@ enum dc_irq_source dc_interrupt_to_irq_source(
        return dal_irq_service_to_irq_source(dc->res_pool->irqs, src_id, ext_id);
 }
 
-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)
+bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable)
 {
 
        if (dc == NULL)
-               return;
+               return false;
 
-       dal_irq_service_set(dc->res_pool->irqs, src, enable);
+       return dal_irq_service_set(dc->res_pool->irqs, src, enable);
 }
 
 void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src)
index a374282..be55461 100644 (file)
@@ -1749,8 +1749,7 @@ static void enable_link_hdmi(struct pipe_ctx *pipe_ctx)
                        link->link_enc,
                        pipe_ctx->clock_source->id,
                        display_color_depth,
-                       pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A,
-                       pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK,
+                       pipe_ctx->stream->signal,
                        stream->phy_pix_clk);
 
        if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
index 61e8c3e..639421a 100644 (file)
@@ -718,7 +718,7 @@ static enum link_training_result perform_channel_equalization_sequence(
        uint32_t retries_ch_eq;
        enum dc_lane_count lane_count = lt_settings->link_settings.lane_count;
        union lane_align_status_updated dpcd_lane_status_updated = {{0}};
-       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};;
+       union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};
 
        hw_tr_pattern = get_supported_tp(link);
 
@@ -1465,7 +1465,7 @@ void decide_link_settings(struct dc_stream_state *stream,
        /* MST doesn't perform link training for now
         * TODO: add MST specific link training routine
         */
-       if (is_mst_supported(link)) {
+       if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
                *link_setting = link->verified_link_cap;
                return;
        }
index 95b8dd0..4d07ffe 100644 (file)
@@ -1360,9 +1360,6 @@ bool dc_is_stream_scaling_unchanged(
        return true;
 }
 
-/* Maximum TMDS single link pixel clock 165MHz */
-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
-
 static void update_stream_engine_usage(
                struct resource_context *res_ctx,
                const struct resource_pool *pool,
index 261811e..cd58197 100644 (file)
@@ -33,8 +33,7 @@
 /*******************************************************************************
  * Private functions
  ******************************************************************************/
-#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST 297000
-static void update_stream_signal(struct dc_stream_state *stream)
+void update_stream_signal(struct dc_stream_state *stream)
 {
 
        struct dc_sink *dc_sink = stream->sink;
@@ -45,8 +44,9 @@ static void update_stream_signal(struct dc_stream_state *stream)
                stream->signal = dc_sink->sink_signal;
 
        if (dc_is_dvi_signal(stream->signal)) {
-               if (stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK_IN_KHZ_UPMOST &&
-                       stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
+               if (stream->ctx->dc->caps.dual_link_dvi &&
+                   stream->timing.pix_clk_khz > TMDS_MAX_PIXEL_CLOCK &&
+                   stream->sink->sink_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
                        stream->signal = SIGNAL_TYPE_DVI_DUAL_LINK;
                else
                        stream->signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
@@ -193,44 +193,20 @@ bool dc_stream_set_cursor_attributes(
 
        core_dc = stream->ctx->dc;
        res_ctx = &core_dc->current_state->res_ctx;
+       stream->cursor_attributes = *attributes;
 
        for (i = 0; i < MAX_PIPES; i++) {
                struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
 
-               if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp))
+               if (pipe_ctx->stream != stream || (!pipe_ctx->plane_res.xfm &&
+                   !pipe_ctx->plane_res.dpp) || !pipe_ctx->plane_res.ipp)
                        continue;
                if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
                        continue;
 
 
-               if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes != NULL)
-                       pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes(
-                                               pipe_ctx->plane_res.ipp, attributes);
-
-               if (pipe_ctx->plane_res.hubp != NULL &&
-                               pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes != NULL)
-                       pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
-                                       pipe_ctx->plane_res.hubp, attributes);
-
-               if (pipe_ctx->plane_res.mi != NULL &&
-                               pipe_ctx->plane_res.mi->funcs->set_cursor_attributes != NULL)
-                       pipe_ctx->plane_res.mi->funcs->set_cursor_attributes(
-                                       pipe_ctx->plane_res.mi, attributes);
-
-
-               if (pipe_ctx->plane_res.xfm != NULL &&
-                               pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes != NULL)
-                       pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes(
-                               pipe_ctx->plane_res.xfm, attributes);
-
-               if (pipe_ctx->plane_res.dpp != NULL &&
-                               pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes != NULL)
-                       pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
-                               pipe_ctx->plane_res.dpp, attributes->color_format);
+               core_dc->hwss.set_cursor_attribute(pipe_ctx);
        }
-
-       stream->cursor_attributes = *attributes;
-
        return true;
 }
 
@@ -254,55 +230,21 @@ bool dc_stream_set_cursor_position(
 
        core_dc = stream->ctx->dc;
        res_ctx = &core_dc->current_state->res_ctx;
+       stream->cursor_position = *position;
 
        for (i = 0; i < MAX_PIPES; i++) {
                struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[i];
-               struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
-               struct mem_input *mi = pipe_ctx->plane_res.mi;
-               struct hubp *hubp = pipe_ctx->plane_res.hubp;
-               struct dpp *dpp = pipe_ctx->plane_res.dpp;
-               struct dc_cursor_position pos_cpy = *position;
-               struct dc_cursor_mi_param param = {
-                       .pixel_clk_khz = stream->timing.pix_clk_khz,
-                       .ref_clk_khz = core_dc->res_pool->ref_clock_inKhz,
-                       .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x,
-                       .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width,
-                       .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz
-               };
 
                if (pipe_ctx->stream != stream ||
                                (!pipe_ctx->plane_res.mi  && !pipe_ctx->plane_res.hubp) ||
                                !pipe_ctx->plane_state ||
-                               (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp))
-                       continue;
-
-               if (pipe_ctx->plane_state->address.type
-                               == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
-                       pos_cpy.enable = false;
-
-               if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
-                       pos_cpy.enable = false;
-
-
-               if (ipp != NULL && ipp->funcs->ipp_cursor_set_position != NULL)
-                       ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
-
-               if (mi != NULL && mi->funcs->set_cursor_position != NULL)
-                       mi->funcs->set_cursor_position(mi, &pos_cpy, &param);
-
-               if (!hubp)
+                               (!pipe_ctx->plane_res.xfm && !pipe_ctx->plane_res.dpp) ||
+                               !pipe_ctx->plane_res.ipp)
                        continue;
 
-               if (hubp->funcs->set_cursor_position != NULL)
-                       hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
-
-               if (dpp != NULL && dpp->funcs->set_cursor_position != NULL)
-                       dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width);
-
+               core_dc->hwss.set_cursor_position(pipe_ctx);
        }
 
-       stream->cursor_position = *position;
-
        return true;
 }
 
index e2e3c9d..d6d5661 100644 (file)
@@ -62,6 +62,7 @@ struct dc_caps {
        bool dcc_const_color;
        bool dynamic_audio;
        bool is_apu;
+       bool dual_link_dvi;
 };
 
 struct dc_dcc_surface_param {
@@ -672,7 +673,7 @@ enum dc_irq_source dc_interrupt_to_irq_source(
                struct dc *dc,
                uint32_t src_id,
                uint32_t ext_id);
-void dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable);
+bool dc_interrupt_set(struct dc *dc, enum dc_irq_source src, bool enable);
 void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src);
 enum dc_irq_source dc_get_hpd_irq_source_at_index(
                struct dc *dc, uint32_t link_index);
index 01c60f1..456e4d2 100644 (file)
@@ -237,6 +237,8 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
  */
 struct dc_stream_state *dc_create_stream_for_sink(struct dc_sink *dc_sink);
 
+void update_stream_signal(struct dc_stream_state *stream);
+
 void dc_stream_retain(struct dc_stream_state *dc_stream);
 void dc_stream_release(struct dc_stream_state *dc_stream);
 
index b73db9e..f11f17f 100644 (file)
        SR(D2VGA_CONTROL), \
        SR(D3VGA_CONTROL), \
        SR(D4VGA_CONTROL), \
+       SR(VGA_TEST_CONTROL), \
        SR(DC_IP_REQUEST_CNTL), \
        BL_REG_LIST()
 
@@ -337,6 +338,7 @@ struct dce_hwseq_registers {
        uint32_t D2VGA_CONTROL;
        uint32_t D3VGA_CONTROL;
        uint32_t D4VGA_CONTROL;
+       uint32_t VGA_TEST_CONTROL;
        /* MMHUB registers. read only. temporary hack */
        uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32;
        uint32_t VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32;
@@ -493,6 +495,12 @@ struct dce_hwseq_registers {
        HWS_SF(, DOMAIN6_PG_STATUS, DOMAIN6_PGFSM_PWR_STATUS, mask_sh), \
        HWS_SF(, DOMAIN7_PG_STATUS, DOMAIN7_PGFSM_PWR_STATUS, mask_sh), \
        HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \
+       HWS_SF(, D1VGA_CONTROL, D1VGA_MODE_ENABLE, mask_sh),\
+       HWS_SF(, D2VGA_CONTROL, D2VGA_MODE_ENABLE, mask_sh),\
+       HWS_SF(, D3VGA_CONTROL, D3VGA_MODE_ENABLE, mask_sh),\
+       HWS_SF(, D4VGA_CONTROL, D4VGA_MODE_ENABLE, mask_sh),\
+       HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_ENABLE, mask_sh),\
+       HWS_SF(, VGA_TEST_CONTROL, VGA_TEST_RENDER_START, mask_sh),\
        HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
        HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
 
@@ -583,7 +591,13 @@ struct dce_hwseq_registers {
        type DCFCLK_GATE_DIS; \
        type DCHUBBUB_GLOBAL_TIMER_REFDIV; \
        type DENTIST_DPPCLK_WDIVIDER; \
-       type DENTIST_DISPCLK_WDIVIDER;
+       type DENTIST_DISPCLK_WDIVIDER; \
+       type VGA_TEST_ENABLE; \
+       type VGA_TEST_RENDER_START; \
+       type D1VGA_MODE_ENABLE; \
+       type D2VGA_MODE_ENABLE; \
+       type D3VGA_MODE_ENABLE; \
+       type D4VGA_MODE_ENABLE;
 
 struct dce_hwseq_shift {
        HWSEQ_REG_FIELD_LIST(uint8_t)
index a266e3f..e4741f1 100644 (file)
 #define DCE110_DIG_FE_SOURCE_SELECT_DIGF 0x20
 #define DCE110_DIG_FE_SOURCE_SELECT_DIGG 0x40
 
-/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
-#define TMDS_MIN_PIXEL_CLOCK 25000
-/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
-#define TMDS_MAX_PIXEL_CLOCK 165000
-/* For current ASICs pixel clock - 600MHz */
-#define MAX_ENCODER_CLOCK 600000
-
 enum {
        DP_MST_UPDATE_MAX_RETRY = 50
 };
@@ -683,6 +676,7 @@ void dce110_link_encoder_construct(
 {
        struct bp_encoder_cap_info bp_cap_info = {0};
        const struct dc_vbios_funcs *bp_funcs = init_data->ctx->dc_bios->funcs;
+       enum bp_result result = BP_RESULT_OK;
 
        enc110->base.funcs = &dce110_lnk_enc_funcs;
        enc110->base.ctx = init_data->ctx;
@@ -757,15 +751,24 @@ void dce110_link_encoder_construct(
                enc110->base.preferred_engine = ENGINE_ID_UNKNOWN;
        }
 
+       /* default to one to mirror Windows behavior */
+       enc110->base.features.flags.bits.HDMI_6GB_EN = 1;
+
+       result = bp_funcs->get_encoder_cap_info(enc110->base.ctx->dc_bios,
+                                               enc110->base.id, &bp_cap_info);
+
        /* Override features with DCE-specific values */
-       if (BP_RESULT_OK == bp_funcs->get_encoder_cap_info(
-                       enc110->base.ctx->dc_bios, enc110->base.id,
-                       &bp_cap_info)) {
+       if (BP_RESULT_OK == result) {
                enc110->base.features.flags.bits.IS_HBR2_CAPABLE =
                                bp_cap_info.DP_HBR2_EN;
                enc110->base.features.flags.bits.IS_HBR3_CAPABLE =
                                bp_cap_info.DP_HBR3_EN;
                enc110->base.features.flags.bits.HDMI_6GB_EN = bp_cap_info.HDMI_6GB_EN;
+       } else {
+               dm_logger_write(enc110->base.ctx->logger, LOG_WARNING,
+                               "%s: Failed to get encoder_cap_info from VBIOS with error code %d!\n",
+                               __func__,
+                               result);
        }
 }
 
@@ -904,8 +907,7 @@ void dce110_link_encoder_enable_tmds_output(
        struct link_encoder *enc,
        enum clock_source_id clock_source,
        enum dc_color_depth color_depth,
-       bool hdmi,
-       bool dual_link,
+       enum signal_type signal,
        uint32_t pixel_clock)
 {
        struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
@@ -919,16 +921,12 @@ void dce110_link_encoder_enable_tmds_output(
        cntl.engine_id = enc->preferred_engine;
        cntl.transmitter = enc110->base.transmitter;
        cntl.pll_id = clock_source;
-       if (hdmi) {
-               cntl.signal = SIGNAL_TYPE_HDMI_TYPE_A;
-               cntl.lanes_number = 4;
-       } else if (dual_link) {
-               cntl.signal = SIGNAL_TYPE_DVI_DUAL_LINK;
+       cntl.signal = signal;
+       if (cntl.signal == SIGNAL_TYPE_DVI_DUAL_LINK)
                cntl.lanes_number = 8;
-       } else {
-               cntl.signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+       else
                cntl.lanes_number = 4;
-       }
+
        cntl.hpd_sel = enc110->base.hpd_source;
 
        cntl.pixel_clock = pixel_clock;
index 8ca9afe..0ec3433 100644 (file)
@@ -210,8 +210,7 @@ void dce110_link_encoder_enable_tmds_output(
        struct link_encoder *enc,
        enum clock_source_id clock_source,
        enum dc_color_depth color_depth,
-       bool hdmi,
-       bool dual_link,
+       enum signal_type signal,
        uint32_t pixel_clock);
 
 /* enables DP PHY output */
index 3931412..8709389 100644 (file)
@@ -128,23 +128,22 @@ static void set_truncation(
                return;
        }
        /* on other format-to do */
-       if (params->flags.TRUNCATE_ENABLED == 0 ||
-                       params->flags.TRUNCATE_DEPTH == 2)
+       if (params->flags.TRUNCATE_ENABLED == 0)
                return;
        /*Set truncation depth and Enable truncation*/
        REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL,
                                FMT_TRUNCATE_EN, 1,
                                FMT_TRUNCATE_DEPTH,
-                               params->flags.TRUNCATE_MODE,
+                               params->flags.TRUNCATE_DEPTH,
                                FMT_TRUNCATE_MODE,
-                               params->flags.TRUNCATE_DEPTH);
+                               params->flags.TRUNCATE_MODE);
 }
 
 
 /**
  *     set_spatial_dither
  *     1) set spatial dithering mode: pattern of seed
- *     2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp
+ *     2) set spatial dithering depth: 0 for 18bpp or 1 for 24bpp
  *     3) set random seed
  *     4) set random mode
  *             lfsr is reset every frame or not reset
index 3ea43e2..442dd2d 100644 (file)
@@ -852,6 +852,7 @@ static bool construct(
        dc->caps.max_downscale_ratio = 200;
        dc->caps.i2c_speed_in_khz = 40;
        dc->caps.max_cursor_size = 128;
+       dc->caps.dual_link_dvi = true;
 
        for (i = 0; i < pool->base.pipe_count; i++) {
                pool->base.timing_generators[i] =
index 86cdd7b..6f382a3 100644 (file)
@@ -688,15 +688,22 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
        struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
        struct dc_link *link = pipe_ctx->stream->sink->link;
 
-       /* 1. update AVI info frame (HDMI, DP)
-        * we always need to update info frame
-       */
+
        uint32_t active_total_with_borders;
        uint32_t early_control = 0;
        struct timing_generator *tg = pipe_ctx->stream_res.tg;
 
-       /* TODOFPGA may change to hwss.update_info_frame */
+       /* For MST, there are multiply stream go to only one link.
+        * connect DIG back_end to front_end while enable_stream and
+        * disconnect them during disable_stream
+        * BY this, it is logic clean to separate stream and link */
+       link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
+                                                   pipe_ctx->stream_res.stream_enc->id, true);
+
+       /* update AVI info frame (HDMI, DP)*/
+       /* TODO: FPGA may change to hwss.update_info_frame */
        dce110_update_info_frame(pipe_ctx);
+
        /* enable early control to avoid corruption on DP monitor*/
        active_total_with_borders =
                        timing->h_addressable
@@ -717,12 +724,8 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
                        pipe_ctx->stream_res.stream_enc->funcs->dp_audio_enable(pipe_ctx->stream_res.stream_enc);
        }
 
-       /* For MST, there are multiply stream go to only one link.
-        * connect DIG back_end to front_end while enable_stream and
-        * disconnect them during disable_stream
-        * BY this, it is logic clean to separate stream and link */
-       link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
-                                                   pipe_ctx->stream_res.stream_enc->id, true);
+
+
 
 }
 
@@ -1690,9 +1693,13 @@ static void apply_min_clocks(
  *  Check if FBC can be enabled
  */
 static bool should_enable_fbc(struct dc *dc,
-                             struct dc_state *context)
+                             struct dc_state *context,
+                             uint32_t *pipe_idx)
 {
-       struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0];
+       uint32_t i;
+       struct pipe_ctx *pipe_ctx = NULL;
+       struct resource_context *res_ctx = &context->res_ctx;
+
 
        ASSERT(dc->fbc_compressor);
 
@@ -1704,6 +1711,14 @@ static bool should_enable_fbc(struct dc *dc,
        if (context->stream_count != 1)
                return false;
 
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               if (res_ctx->pipe_ctx[i].stream) {
+                       pipe_ctx = &res_ctx->pipe_ctx[i];
+                       *pipe_idx = i;
+                       break;
+               }
+       }
+
        /* Only supports eDP */
        if (pipe_ctx->stream->sink->link->connector_signal != SIGNAL_TYPE_EDP)
                return false;
@@ -1729,11 +1744,14 @@ static bool should_enable_fbc(struct dc *dc,
 static void enable_fbc(struct dc *dc,
                       struct dc_state *context)
 {
-       if (should_enable_fbc(dc, context)) {
+       uint32_t pipe_idx = 0;
+
+       if (should_enable_fbc(dc, context, &pipe_idx)) {
                /* Program GRPH COMPRESSED ADDRESS and PITCH */
                struct compr_addr_and_pitch_params params = {0, 0, 0};
                struct compressor *compr = dc->fbc_compressor;
-               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[0];
+               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[pipe_idx];
+
 
                params.source_view_width = pipe_ctx->stream->timing.h_addressable;
                params.source_view_height = pipe_ctx->stream->timing.v_addressable;
@@ -2915,6 +2933,49 @@ static void program_csc_matrix(struct pipe_ctx *pipe_ctx,
        }
 }
 
+void dce110_set_cursor_position(struct pipe_ctx *pipe_ctx)
+{
+       struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
+       struct input_pixel_processor *ipp = pipe_ctx->plane_res.ipp;
+       struct mem_input *mi = pipe_ctx->plane_res.mi;
+       struct dc_cursor_mi_param param = {
+               .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz,
+               .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz,
+               .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x,
+               .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width,
+               .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz
+       };
+
+       if (pipe_ctx->plane_state->address.type
+                       == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+               pos_cpy.enable = false;
+
+       if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
+               pos_cpy.enable = false;
+
+       if (ipp->funcs->ipp_cursor_set_position)
+               ipp->funcs->ipp_cursor_set_position(ipp, &pos_cpy, &param);
+       if (mi->funcs->set_cursor_position)
+               mi->funcs->set_cursor_position(mi, &pos_cpy, &param);
+}
+
+void dce110_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
+{
+       struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
+
+       if (pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes)
+               pipe_ctx->plane_res.ipp->funcs->ipp_cursor_set_attributes(
+                               pipe_ctx->plane_res.ipp, attributes);
+
+       if (pipe_ctx->plane_res.mi->funcs->set_cursor_attributes)
+               pipe_ctx->plane_res.mi->funcs->set_cursor_attributes(
+                               pipe_ctx->plane_res.mi, attributes);
+
+       if (pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes)
+               pipe_ctx->plane_res.xfm->funcs->set_cursor_attributes(
+                               pipe_ctx->plane_res.xfm, attributes);
+}
+
 static void ready_shared_resources(struct dc *dc, struct dc_state *context) {}
 
 static void optimize_shared_resources(struct dc *dc) {}
@@ -2957,6 +3018,8 @@ static const struct hw_sequencer_funcs dce110_funcs = {
        .edp_backlight_control = hwss_edp_backlight_control,
        .edp_power_control = hwss_edp_power_control,
        .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
+       .set_cursor_position = dce110_set_cursor_position,
+       .set_cursor_attribute = dce110_set_cursor_attribute
 };
 
 void dce110_hw_sequencer_construct(struct dc *dc)
index 7c47795..00f18c4 100644 (file)
@@ -846,6 +846,16 @@ static bool dce110_validate_bandwidth(
        return result;
 }
 
+enum dc_status dce110_validate_plane(const struct dc_plane_state *plane_state,
+                                    struct dc_caps *caps)
+{
+       if (((plane_state->dst_rect.width * 2) < plane_state->src_rect.width) ||
+           ((plane_state->dst_rect.height * 2) < plane_state->src_rect.height))
+               return DC_FAIL_SURFACE_VALIDATE;
+
+       return DC_OK;
+}
+
 static bool dce110_validate_surface_sets(
                struct dc_state *context)
 {
@@ -869,6 +879,13 @@ static bool dce110_validate_surface_sets(
                                        plane->src_rect.height > 1080))
                                        return false;
 
+                               /* we don't have the logic to support underlay
+                                * only yet so block the use case where we get
+                                * NV12 plane as top layer
+                                */
+                               if (j == 0)
+                                       return false;
+
                                /* irrespective of plane format,
                                 * stream should be RGB encoded
                                 */
@@ -1021,6 +1038,7 @@ static const struct resource_funcs dce110_res_pool_funcs = {
        .link_enc_create = dce110_link_encoder_create,
        .validate_guaranteed = dce110_validate_guaranteed,
        .validate_bandwidth = dce110_validate_bandwidth,
+       .validate_plane = dce110_validate_plane,
        .acquire_idle_pipe_for_layer = dce110_acquire_underlay,
        .add_stream_to_ctx = dce110_add_stream_to_ctx,
        .validate_global = dce110_validate_global
index 663e0a0..98d9cd0 100644 (file)
@@ -1103,6 +1103,8 @@ static bool construct(
        dc->caps.max_downscale_ratio = 200;
        dc->caps.i2c_speed_in_khz = 100;
        dc->caps.max_cursor_size = 128;
+       dc->caps.dual_link_dvi = true;
+
 
        /*************************************************
         *  Create resources                             *
index 57cd673..5aab01d 100644 (file)
@@ -835,6 +835,8 @@ static bool construct(
        dc->caps.max_downscale_ratio = 200;
        dc->caps.i2c_speed_in_khz = 100;
        dc->caps.max_cursor_size = 128;
+       dc->caps.dual_link_dvi = true;
+
        dc->debug = debug_defaults;
 
        /*************************************************
index 8f2bd56..25d7eb1 100644 (file)
@@ -793,6 +793,7 @@ static bool dce80_construct(
        dc->caps.max_downscale_ratio = 200;
        dc->caps.i2c_speed_in_khz = 40;
        dc->caps.max_cursor_size = 128;
+       dc->caps.dual_link_dvi = true;
 
        /*************************************************
         *  Create resources                             *
index 8257286..dc1e010 100644 (file)
@@ -238,10 +238,34 @@ static void enable_power_gating_plane(
 static void disable_vga(
        struct dce_hwseq *hws)
 {
+       unsigned int in_vga1_mode = 0;
+       unsigned int in_vga2_mode = 0;
+       unsigned int in_vga3_mode = 0;
+       unsigned int in_vga4_mode = 0;
+
+       REG_GET(D1VGA_CONTROL, D1VGA_MODE_ENABLE, &in_vga1_mode);
+       REG_GET(D2VGA_CONTROL, D2VGA_MODE_ENABLE, &in_vga2_mode);
+       REG_GET(D3VGA_CONTROL, D3VGA_MODE_ENABLE, &in_vga3_mode);
+       REG_GET(D4VGA_CONTROL, D4VGA_MODE_ENABLE, &in_vga4_mode);
+
+       if (in_vga1_mode == 0 && in_vga2_mode == 0 &&
+                       in_vga3_mode == 0 && in_vga4_mode == 0)
+               return;
+
        REG_WRITE(D1VGA_CONTROL, 0);
        REG_WRITE(D2VGA_CONTROL, 0);
        REG_WRITE(D3VGA_CONTROL, 0);
        REG_WRITE(D4VGA_CONTROL, 0);
+
+       /* HW Engineer's Notes:
+        *  During switch from vga->extended, if we set the VGA_TEST_ENABLE and
+        *  then hit the VGA_TEST_RENDER_START, then the DCHUBP timing gets updated correctly.
+        *
+        *  Then vBIOS will have it poll for the VGA_TEST_RENDER_DONE and unset
+        *  VGA_TEST_ENABLE, to leave it in the same state as before.
+        */
+       REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_ENABLE, 1);
+       REG_UPDATE(VGA_TEST_CONTROL, VGA_TEST_RENDER_START, 1);
 }
 
 static void dpp_pg_control(
@@ -1761,6 +1785,11 @@ static void update_dchubp_dpp(
                        &pipe_ctx->plane_res.scl_data.viewport_c);
        }
 
+       if (pipe_ctx->stream->cursor_attributes.address.quad_part != 0) {
+               dc->hwss.set_cursor_position(pipe_ctx);
+               dc->hwss.set_cursor_attribute(pipe_ctx);
+       }
+
        if (plane_state->update_flags.bits.full_update) {
                /*gamut remap*/
                program_gamut_remap(pipe_ctx);
@@ -2296,7 +2325,7 @@ static bool dcn10_dummy_display_power_gating(
        return true;
 }
 
-void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
+static void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
 {
        struct dc_plane_state *plane_state = pipe_ctx->plane_state;
        struct timing_generator *tg = pipe_ctx->stream_res.tg;
@@ -2316,12 +2345,46 @@ void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx)
        }
 }
 
-void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
+static void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data)
 {
        if (hws->ctx->dc->res_pool->hubbub != NULL)
                hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data);
 }
 
+static void dcn10_set_cursor_position(struct pipe_ctx *pipe_ctx)
+{
+       struct dc_cursor_position pos_cpy = pipe_ctx->stream->cursor_position;
+       struct hubp *hubp = pipe_ctx->plane_res.hubp;
+       struct dpp *dpp = pipe_ctx->plane_res.dpp;
+       struct dc_cursor_mi_param param = {
+               .pixel_clk_khz = pipe_ctx->stream->timing.pix_clk_khz,
+               .ref_clk_khz = pipe_ctx->stream->ctx->dc->res_pool->ref_clock_inKhz,
+               .viewport_x_start = pipe_ctx->plane_res.scl_data.viewport.x,
+               .viewport_width = pipe_ctx->plane_res.scl_data.viewport.width,
+               .h_scale_ratio = pipe_ctx->plane_res.scl_data.ratios.horz
+       };
+
+       if (pipe_ctx->plane_state->address.type
+                       == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+               pos_cpy.enable = false;
+
+       if (pipe_ctx->top_pipe && pipe_ctx->plane_state != pipe_ctx->top_pipe->plane_state)
+               pos_cpy.enable = false;
+
+       hubp->funcs->set_cursor_position(hubp, &pos_cpy, &param);
+       dpp->funcs->set_cursor_position(dpp, &pos_cpy, &param, hubp->curs_attr.width);
+}
+
+static void dcn10_set_cursor_attribute(struct pipe_ctx *pipe_ctx)
+{
+       struct dc_cursor_attributes *attributes = &pipe_ctx->stream->cursor_attributes;
+
+       pipe_ctx->plane_res.hubp->funcs->set_cursor_attributes(
+                       pipe_ctx->plane_res.hubp, attributes);
+       pipe_ctx->plane_res.dpp->funcs->set_cursor_attributes(
+               pipe_ctx->plane_res.dpp, attributes->color_format);
+}
+
 static const struct hw_sequencer_funcs dcn10_funcs = {
        .program_gamut_remap = program_gamut_remap,
        .program_csc_matrix = program_csc_matrix,
@@ -2362,6 +2425,8 @@ static const struct hw_sequencer_funcs dcn10_funcs = {
        .edp_backlight_control = hwss_edp_backlight_control,
        .edp_power_control = hwss_edp_power_control,
        .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready,
+       .set_cursor_position = dcn10_set_cursor_position,
+       .set_cursor_attribute = dcn10_set_cursor_attribute
 };
 
 
index 0fd329d..54d8a13 100644 (file)
@@ -123,8 +123,7 @@ struct link_encoder_funcs {
        void (*enable_tmds_output)(struct link_encoder *enc,
                enum clock_source_id clock_source,
                enum dc_color_depth color_depth,
-               bool hdmi,
-               bool dual_link,
+               enum signal_type signal,
                uint32_t pixel_clock);
        void (*enable_dp_output)(struct link_encoder *enc,
                const struct dc_link_settings *link_settings,
index 4c0aa56..379c6ec 100644 (file)
@@ -198,6 +198,9 @@ struct hw_sequencer_funcs {
                        bool enable);
        void (*edp_wait_for_hpd_ready)(struct dc_link *link, bool power_up);
 
+       void (*set_cursor_position)(struct pipe_ctx *pipe);
+       void (*set_cursor_attribute)(struct pipe_ctx *pipe);
+
 };
 
 void color_space_to_black_color(
index f7e40b2..d3e1923 100644 (file)
@@ -217,7 +217,7 @@ bool dce110_vblank_set(
                        core_dc->current_state->res_ctx.pipe_ctx[pipe_offset].stream_res.tg;
 
        if (enable) {
-               if (!tg->funcs->arm_vert_intr(tg, 2)) {
+               if (!tg || !tg->funcs->arm_vert_intr(tg, 2)) {
                        DC_ERROR("Failed to get VBLANK!\n");
                        return false;
                }
index 57a54a7..1c079ba 100644 (file)
@@ -42,8 +42,7 @@ static void virtual_link_encoder_enable_tmds_output(
        struct link_encoder *enc,
        enum clock_source_id clock_source,
        enum dc_color_depth color_depth,
-       bool hdmi,
-       bool dual_link,
+       enum signal_type signal,
        uint32_t pixel_clock) {}
 
 static void virtual_link_encoder_enable_dp_output(
index 7a9b43f..36bbad5 100644 (file)
@@ -419,11 +419,6 @@ struct bios_event_info {
        bool backlight_changed;
 };
 
-enum {
-       HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000,
-       TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000
-};
-
 /*
  * DFS-bypass flag
  */
index b5ebde6..199c5db 100644 (file)
 #ifndef __DC_SIGNAL_TYPES_H__
 #define __DC_SIGNAL_TYPES_H__
 
+/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
+#define TMDS_MIN_PIXEL_CLOCK 25000
+/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
+#define TMDS_MAX_PIXEL_CLOCK 165000
+
 enum signal_type {
        SIGNAL_TYPE_NONE                = 0L,           /* no signal */
        SIGNAL_TYPE_DVI_SINGLE_LINK     = (1 << 0),
index 4c3223a..adb6e7b 100644 (file)
@@ -162,7 +162,7 @@ static int pp_hw_init(void *handle)
                if(hwmgr->smumgr_funcs->start_smu(pp_handle->hwmgr)) {
                        pr_err("smc start failed\n");
                        hwmgr->smumgr_funcs->smu_fini(pp_handle->hwmgr);
-                       return -EINVAL;;
+                       return -EINVAL;
                }
                if (ret == PP_DPM_DISABLED)
                        goto exit;
index 41e42be..08e8a79 100644 (file)
@@ -2756,10 +2756,13 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
                                    PHM_PlatformCaps_DisableMclkSwitchingForFrameLock);
 
 
-       disable_mclk_switching = ((1 < info.display_count) ||
-                                 disable_mclk_switching_for_frame_lock ||
-                                 smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) ||
-                                 (mode_info.refresh_rate > 120));
+       if (info.display_count == 0)
+               disable_mclk_switching = false;
+       else
+               disable_mclk_switching = ((1 < info.display_count) ||
+                                         disable_mclk_switching_for_frame_lock ||
+                                         smu7_vblank_too_short(hwmgr, mode_info.vblank_time_us) ||
+                                         (mode_info.refresh_rate > 120));
 
        sclk = smu7_ps->performance_levels[0].engine_clock;
        mclk = smu7_ps->performance_levels[0].memory_clock;
@@ -4534,13 +4537,6 @@ static int smu7_set_power_profile_state(struct pp_hwmgr *hwmgr,
        int tmp_result, result = 0;
        uint32_t sclk_mask = 0, mclk_mask = 0;
 
-       if (hwmgr->chip_id == CHIP_FIJI) {
-               if (request->type == AMD_PP_GFX_PROFILE)
-                       smu7_enable_power_containment(hwmgr);
-               else if (request->type == AMD_PP_COMPUTE_PROFILE)
-                       smu7_disable_power_containment(hwmgr);
-       }
-
        if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_AUTO)
                return -EINVAL;
 
index 2d55dab..5f9c3ef 100644 (file)
@@ -3168,10 +3168,13 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr,
        disable_mclk_switching_for_vr = PP_CAP(PHM_PlatformCaps_DisableMclkSwitchForVR);
        force_mclk_high = PP_CAP(PHM_PlatformCaps_ForceMclkHigh);
 
-       disable_mclk_switching = (info.display_count > 1) ||
-                                   disable_mclk_switching_for_frame_lock ||
-                                   disable_mclk_switching_for_vr ||
-                                   force_mclk_high;
+       if (info.display_count == 0)
+               disable_mclk_switching = false;
+       else
+               disable_mclk_switching = (info.display_count > 1) ||
+                       disable_mclk_switching_for_frame_lock ||
+                       disable_mclk_switching_for_vr ||
+                       force_mclk_high;
 
        sclk = vega10_ps->performance_levels[0].gfx_clock;
        mclk = vega10_ps->performance_levels[0].mem_clock;
index 5f4c2e8..d665dd5 100644 (file)
@@ -97,7 +97,7 @@ static const struct ast_vbios_dclk_info dclk_table[] = {
        {0x67, 0x22, 0x00},                     /* 0E: VCLK157_5        */
        {0x6A, 0x22, 0x00},                     /* 0F: VCLK162          */
        {0x4d, 0x4c, 0x80},                     /* 10: VCLK154          */
-       {0xa7, 0x78, 0x80},                     /* 11: VCLK83.5         */
+       {0x68, 0x6f, 0x80},                     /* 11: VCLK83.5         */
        {0x28, 0x49, 0x80},                     /* 12: VCLK106.5        */
        {0x37, 0x49, 0x80},                     /* 13: VCLK146.25       */
        {0x1f, 0x45, 0x80},                     /* 14: VCLK148.5        */
@@ -127,7 +127,7 @@ static const struct ast_vbios_dclk_info dclk_table_ast2500[] = {
        {0x67, 0x22, 0x00},                     /* 0E: VCLK157_5        */
        {0x6A, 0x22, 0x00},                     /* 0F: VCLK162          */
        {0x4d, 0x4c, 0x80},                     /* 10: VCLK154          */
-       {0xa7, 0x78, 0x80},                     /* 11: VCLK83.5         */
+       {0x68, 0x6f, 0x80},                     /* 11: VCLK83.5         */
        {0x28, 0x49, 0x80},                     /* 12: VCLK106.5        */
        {0x37, 0x49, 0x80},                     /* 13: VCLK146.25       */
        {0x1f, 0x45, 0x80},                     /* 14: VCLK148.5        */
index cd23b1b..c91b9b0 100644 (file)
@@ -294,22 +294,7 @@ static void cirrus_crtc_prepare(struct drm_crtc *crtc)
 {
 }
 
-/*
- * This is called after a mode is programmed. It should reverse anything done
- * by the prepare function
- */
-static void cirrus_crtc_commit(struct drm_crtc *crtc)
-{
-}
-
-/*
- * The core can pass us a set of gamma values to program. We actually only
- * use this for 8-bit mode so can't perform smooth fades on deeper modes,
- * but it's a requirement that we provide the function
- */
-static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
-                                u16 *blue, uint32_t size,
-                                struct drm_modeset_acquire_ctx *ctx)
+static void cirrus_crtc_load_lut(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct cirrus_device *cdev = dev->dev_private;
@@ -317,7 +302,7 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
        int i;
 
        if (!crtc->enabled)
-               return 0;
+               return;
 
        r = crtc->gamma_store;
        g = r + crtc->gamma_size;
@@ -330,6 +315,27 @@ static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
                WREG8(PALETTE_DATA, *g++ >> 8);
                WREG8(PALETTE_DATA, *b++ >> 8);
        }
+}
+
+/*
+ * This is called after a mode is programmed. It should reverse anything done
+ * by the prepare function
+ */
+static void cirrus_crtc_commit(struct drm_crtc *crtc)
+{
+       cirrus_crtc_load_lut(crtc);
+}
+
+/*
+ * The core can pass us a set of gamma values to program. We actually only
+ * use this for 8-bit mode so can't perform smooth fades on deeper modes,
+ * but it's a requirement that we provide the function
+ */
+static int cirrus_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                u16 *blue, uint32_t size,
+                                struct drm_modeset_acquire_ctx *ctx)
+{
+       cirrus_crtc_load_lut(crtc);
 
        return 0;
 }
index ab40321..ae3cbfe 100644 (file)
@@ -1878,6 +1878,8 @@ int drm_atomic_helper_setup_commit(struct drm_atomic_state *state,
                new_crtc_state->event->base.completion = &commit->flip_done;
                new_crtc_state->event->base.completion_release = release_crtc_commit;
                drm_crtc_commit_get(commit);
+
+               commit->abort_completion = true;
        }
 
        for_each_oldnew_connector_in_state(state, conn, old_conn_state, new_conn_state, i) {
@@ -3421,8 +3423,21 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state);
 void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc_state *state)
 {
        if (state->commit) {
+               /*
+                * In the event that a non-blocking commit returns
+                * -ERESTARTSYS before the commit_tail work is queued, we will
+                * have an extra reference to the commit object. Release it, if
+                * the event has not been consumed by the worker.
+                *
+                * state->event may be freed, so we can't directly look at
+                * state->event->base.completion.
+                */
+               if (state->event && state->commit->abort_completion)
+                       drm_crtc_commit_put(state->commit);
+
                kfree(state->commit->event);
                state->commit->event = NULL;
+
                drm_crtc_commit_put(state->commit);
        }
 
index ddd5379..4f751a9 100644 (file)
@@ -113,6 +113,9 @@ static const struct edid_quirk {
        /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */
        { "AEO", 0, EDID_QUIRK_FORCE_6BPC },
 
+       /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */
+       { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC },
+
        /* Belinea 10 15 55 */
        { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 },
        { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 },
@@ -162,6 +165,24 @@ static const struct edid_quirk {
 
        /* HTC Vive VR Headset */
        { "HVR", 0xaa01, EDID_QUIRK_NON_DESKTOP },
+
+       /* Oculus Rift DK1, DK2, and CV1 VR Headsets */
+       { "OVR", 0x0001, EDID_QUIRK_NON_DESKTOP },
+       { "OVR", 0x0003, EDID_QUIRK_NON_DESKTOP },
+       { "OVR", 0x0004, EDID_QUIRK_NON_DESKTOP },
+
+       /* Windows Mixed Reality Headsets */
+       { "ACR", 0x7fce, EDID_QUIRK_NON_DESKTOP },
+       { "HPN", 0x3515, EDID_QUIRK_NON_DESKTOP },
+       { "LEN", 0x0408, EDID_QUIRK_NON_DESKTOP },
+       { "LEN", 0xb800, EDID_QUIRK_NON_DESKTOP },
+       { "FUJ", 0x1970, EDID_QUIRK_NON_DESKTOP },
+       { "DEL", 0x7fce, EDID_QUIRK_NON_DESKTOP },
+       { "SEC", 0x144a, EDID_QUIRK_NON_DESKTOP },
+       { "AUS", 0xc102, EDID_QUIRK_NON_DESKTOP },
+
+       /* Sony PlayStation VR Headset */
+       { "SNY", 0x0704, EDID_QUIRK_NON_DESKTOP },
 };
 
 /*
index 5a13ff2..2dc5e8b 100644 (file)
@@ -121,6 +121,10 @@ int drm_mode_addfb(struct drm_device *dev,
        r.pixel_format = drm_mode_legacy_fb_format(or->bpp, or->depth);
        r.handles[0] = or->handle;
 
+       if (r.pixel_format == DRM_FORMAT_XRGB2101010 &&
+           dev->driver->driver_features & DRIVER_PREFER_XBGR_30BPP)
+               r.pixel_format = DRM_FORMAT_XBGR2101010;
+
        ret = drm_mode_addfb2(dev, &r, file_priv);
        if (ret)
                return ret;
@@ -457,6 +461,12 @@ int drm_mode_getfb(struct drm_device *dev,
        if (!fb)
                return -ENOENT;
 
+       /* Multi-planar framebuffers need getfb2. */
+       if (fb->format->num_planes > 1) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        r->height = fb->height;
        r->width = fb->width;
        r->depth = fb->format->depth;
@@ -480,6 +490,7 @@ int drm_mode_getfb(struct drm_device *dev,
                ret = -ENODEV;
        }
 
+out:
        drm_framebuffer_put(fb);
 
        return ret;
index 186c4e9..89eef1b 100644 (file)
@@ -836,9 +836,24 @@ struct drm_mm_node *drm_mm_scan_color_evict(struct drm_mm_scan *scan)
        if (!mm->color_adjust)
                return NULL;
 
-       hole = list_first_entry(&mm->hole_stack, typeof(*hole), hole_stack);
-       hole_start = __drm_mm_hole_node_start(hole);
-       hole_end = hole_start + hole->hole_size;
+       /*
+        * The hole found during scanning should ideally be the first element
+        * in the hole_stack list, but due to side-effects in the driver it
+        * may not be.
+        */
+       list_for_each_entry(hole, &mm->hole_stack, hole_stack) {
+               hole_start = __drm_mm_hole_node_start(hole);
+               hole_end = hole_start + hole->hole_size;
+
+               if (hole_start <= scan->hit_start &&
+                   hole_end >= scan->hit_end)
+                       break;
+       }
+
+       /* We should only be called after we found the hole previously */
+       DRM_MM_BUG_ON(&hole->hole_stack == &mm->hole_stack);
+       if (unlikely(&hole->hole_stack == &mm->hole_stack))
+               return NULL;
 
        DRM_MM_BUG_ON(hole_start > scan->hit_start);
        DRM_MM_BUG_ON(hole_end < scan->hit_end);
index 555fbe5..00b8445 100644 (file)
@@ -654,6 +654,26 @@ out:
 }
 
 /**
+ * drm_kms_helper_is_poll_worker - is %current task an output poll worker?
+ *
+ * Determine if %current task is an output poll worker.  This can be used
+ * to select distinct code paths for output polling versus other contexts.
+ *
+ * One use case is to avoid a deadlock between the output poll worker and
+ * the autosuspend worker wherein the latter waits for polling to finish
+ * upon calling drm_kms_helper_poll_disable(), while the former waits for
+ * runtime suspend to finish upon calling pm_runtime_get_sync() in a
+ * connector ->detect hook.
+ */
+bool drm_kms_helper_is_poll_worker(void)
+{
+       struct work_struct *work = current_work();
+
+       return work && work->func == output_poll_execute;
+}
+EXPORT_SYMBOL(drm_kms_helper_is_poll_worker);
+
+/**
  * drm_kms_helper_poll_disable - disable output polling
  * @dev: drm_device
  *
index 2b8bf2d..f68ef1b 100644 (file)
@@ -286,7 +286,6 @@ static int g2d_init_cmdlist(struct g2d_data *g2d)
 
        node = kcalloc(G2D_CMDLIST_NUM, sizeof(*node), GFP_KERNEL);
        if (!node) {
-               dev_err(dev, "failed to allocate memory\n");
                ret = -ENOMEM;
                goto err;
        }
@@ -926,7 +925,7 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
        struct drm_device *drm_dev = g2d->subdrv.drm_dev;
        struct g2d_runqueue_node *runqueue_node = g2d->runqueue_node;
        struct drm_exynos_pending_g2d_event *e;
-       struct timeval now;
+       struct timespec64 now;
 
        if (list_empty(&runqueue_node->event_list))
                return;
@@ -934,9 +933,9 @@ static void g2d_finish_event(struct g2d_data *g2d, u32 cmdlist_no)
        e = list_first_entry(&runqueue_node->event_list,
                             struct drm_exynos_pending_g2d_event, base.link);
 
-       do_gettimeofday(&now);
+       ktime_get_ts64(&now);
        e->event.tv_sec = now.tv_sec;
-       e->event.tv_usec = now.tv_usec;
+       e->event.tv_usec = now.tv_nsec / NSEC_PER_USEC;
        e->event.cmdlist_no = cmdlist_no;
 
        drm_send_event(drm_dev, &e->base);
@@ -1358,10 +1357,9 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
                return -EFAULT;
 
        runqueue_node = kmem_cache_alloc(g2d->runqueue_slab, GFP_KERNEL);
-       if (!runqueue_node) {
-               dev_err(dev, "failed to allocate memory\n");
+       if (!runqueue_node)
                return -ENOMEM;
-       }
+
        run_cmdlist = &runqueue_node->run_cmdlist;
        event_list = &runqueue_node->event_list;
        INIT_LIST_HEAD(run_cmdlist);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.h b/drivers/gpu/drm/exynos/exynos_drm_rotator.h
deleted file mode 100644 (file)
index 71a0b4c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- *
- * Authors:
- *     YoungJun Cho <yj44.cho@samsung.com>
- *     Eunchul Kim <chulspro.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef        _EXYNOS_DRM_ROTATOR_H_
-#define        _EXYNOS_DRM_ROTATOR_H_
-
-/* TODO */
-
-#endif
index a4b75a4..abd84cb 100644 (file)
@@ -1068,10 +1068,13 @@ static void hdmi_audio_config(struct hdmi_context *hdata)
        /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
        hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_0, HDMI_I2S_SEL_SCLK(5)
                        | HDMI_I2S_SEL_LRCK(6));
-       hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(1)
-                       | HDMI_I2S_SEL_SDATA2(4));
+
+       hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_1, HDMI_I2S_SEL_SDATA1(3)
+                       | HDMI_I2S_SEL_SDATA0(4));
+
        hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_2, HDMI_I2S_SEL_SDATA3(1)
                        | HDMI_I2S_SEL_SDATA2(2));
+
        hdmi_reg_writeb(hdata, HDMI_I2S_PIN_SEL_3, HDMI_I2S_SEL_DSD(0));
 
        /* I2S_CON_1 & 2 */
index 3049613..d7cbe53 100644 (file)
 #define EXYNOS_CIIMGEFF_FIN_EMBOSSING          (4 << 26)
 #define EXYNOS_CIIMGEFF_FIN_SILHOUETTE         (5 << 26)
 #define EXYNOS_CIIMGEFF_FIN_MASK                       (7 << 26)
-#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK          ((0xff < 13) | (0xff < 0))
+#define EXYNOS_CIIMGEFF_PAT_CBCR_MASK          ((0xff << 13) | (0xff << 0))
 
 /* Real input DMA size register */
 #define EXYNOS_CIREAL_ISIZE_AUTOLOAD_ENABLE    (1 << 31)
index 04be0f7..4420c20 100644 (file)
 
 /* I2S_PIN_SEL_1 */
 #define HDMI_I2S_SEL_SDATA1(x)         (((x) & 0x7) << 4)
-#define HDMI_I2S_SEL_SDATA2(x)         ((x) & 0x7)
+#define HDMI_I2S_SEL_SDATA0(x)         ((x) & 0x7)
 
 /* I2S_PIN_SEL_2 */
 #define HDMI_I2S_SEL_SDATA3(x)         (((x) & 0x7) << 4)
index c8454ac..db6b94d 100644 (file)
@@ -471,6 +471,7 @@ struct parser_exec_state {
         * used when ret from 2nd level batch buffer
         */
        int saved_buf_addr_type;
+       bool is_ctx_wa;
 
        struct cmd_info *info;
 
@@ -1715,6 +1716,11 @@ static int perform_bb_shadow(struct parser_exec_state *s)
        bb->accessing = true;
        bb->bb_start_cmd_va = s->ip_va;
 
+       if ((s->buf_type == BATCH_BUFFER_INSTRUCTION) && (!s->is_ctx_wa))
+               bb->bb_offset = s->ip_va - s->rb_va;
+       else
+               bb->bb_offset = 0;
+
        /*
         * ip_va saves the virtual address of the shadow batch buffer, while
         * ip_gma saves the graphics address of the original batch buffer.
@@ -2571,6 +2577,7 @@ static int scan_workload(struct intel_vgpu_workload *workload)
        s.ring_tail = gma_tail;
        s.rb_va = workload->shadow_ring_buffer_va;
        s.workload = workload;
+       s.is_ctx_wa = false;
 
        if ((bypass_scan_mask & (1 << workload->ring_id)) ||
                gma_head == gma_tail)
@@ -2624,6 +2631,7 @@ static int scan_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx)
        s.ring_tail = gma_tail;
        s.rb_va = wa_ctx->indirect_ctx.shadow_va;
        s.workload = workload;
+       s.is_ctx_wa = true;
 
        if (!intel_gvt_ggtt_validate_range(s.vgpu, s.ring_start, s.ring_size)) {
                ret = -EINVAL;
index 909499b..021f722 100644 (file)
@@ -733,6 +733,25 @@ static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf,
        return ret == 0 ? count : ret;
 }
 
+static bool gtt_entry(struct mdev_device *mdev, loff_t *ppos)
+{
+       struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
+       unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
+       struct intel_gvt *gvt = vgpu->gvt;
+       int offset;
+
+       /* Only allow MMIO GGTT entry access */
+       if (index != PCI_BASE_ADDRESS_0)
+               return false;
+
+       offset = (u64)(*ppos & VFIO_PCI_OFFSET_MASK) -
+               intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0);
+
+       return (offset >= gvt->device_info.gtt_start_offset &&
+               offset < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) ?
+                       true : false;
+}
+
 static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf,
                        size_t count, loff_t *ppos)
 {
@@ -742,7 +761,21 @@ static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf,
        while (count) {
                size_t filled;
 
-               if (count >= 4 && !(*ppos % 4)) {
+               /* Only support GGTT entry 8 bytes read */
+               if (count >= 8 && !(*ppos % 8) &&
+                       gtt_entry(mdev, ppos)) {
+                       u64 val;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+                                       ppos, false);
+                       if (ret <= 0)
+                               goto read_err;
+
+                       if (copy_to_user(buf, &val, sizeof(val)))
+                               goto read_err;
+
+                       filled = 8;
+               } else if (count >= 4 && !(*ppos % 4)) {
                        u32 val;
 
                        ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
@@ -802,7 +835,21 @@ static ssize_t intel_vgpu_write(struct mdev_device *mdev,
        while (count) {
                size_t filled;
 
-               if (count >= 4 && !(*ppos % 4)) {
+               /* Only support GGTT entry 8 bytes write */
+               if (count >= 8 && !(*ppos % 8) &&
+                       gtt_entry(mdev, ppos)) {
+                       u64 val;
+
+                       if (copy_from_user(&val, buf, sizeof(val)))
+                               goto write_err;
+
+                       ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
+                                       ppos, true);
+                       if (ret <= 0)
+                               goto write_err;
+
+                       filled = 8;
+               } else if (count >= 4 && !(*ppos % 4)) {
                        u32 val;
 
                        if (copy_from_user(&val, buf, sizeof(val)))
index 73ad6e9..152df3d 100644 (file)
@@ -118,6 +118,7 @@ static struct engine_mmio gen9_engine_mmio_list[] __cacheline_aligned = {
        {RCS, HALF_SLICE_CHICKEN3, 0xffff, true}, /* 0xe184 */
        {RCS, GEN9_HALF_SLICE_CHICKEN5, 0xffff, true}, /* 0xe188 */
        {RCS, GEN9_HALF_SLICE_CHICKEN7, 0xffff, true}, /* 0xe194 */
+       {RCS, GEN8_ROW_CHICKEN, 0xffff, true}, /* 0xe4f0 */
        {RCS, TRVATTL3PTRDW(0), 0, false}, /* 0x4de0 */
        {RCS, TRVATTL3PTRDW(1), 0, false}, /* 0x4de4 */
        {RCS, TRNULLDETCT, 0, false}, /* 0x4de8 */
@@ -393,9 +394,11 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre,
         * performace for batch mmio read/write, so we need
         * handle forcewake mannually.
         */
+       intel_runtime_pm_get(dev_priv);
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
        switch_mmio(pre, next, ring_id);
        intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+       intel_runtime_pm_put(dev_priv);
 }
 
 /**
index b55b358..d74d6f0 100644 (file)
@@ -52,6 +52,54 @@ static void set_context_pdp_root_pointer(
                pdp_pair[i].val = pdp[7 - i];
 }
 
+/*
+ * when populating shadow ctx from guest, we should not overrride oa related
+ * registers, so that they will not be overlapped by guest oa configs. Thus
+ * made it possible to capture oa data from host for both host and guests.
+ */
+static void sr_oa_regs(struct intel_vgpu_workload *workload,
+               u32 *reg_state, bool save)
+{
+       struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv;
+       u32 ctx_oactxctrl = dev_priv->perf.oa.ctx_oactxctrl_offset;
+       u32 ctx_flexeu0 = dev_priv->perf.oa.ctx_flexeu0_offset;
+       int i = 0;
+       u32 flex_mmio[] = {
+               i915_mmio_reg_offset(EU_PERF_CNTL0),
+               i915_mmio_reg_offset(EU_PERF_CNTL1),
+               i915_mmio_reg_offset(EU_PERF_CNTL2),
+               i915_mmio_reg_offset(EU_PERF_CNTL3),
+               i915_mmio_reg_offset(EU_PERF_CNTL4),
+               i915_mmio_reg_offset(EU_PERF_CNTL5),
+               i915_mmio_reg_offset(EU_PERF_CNTL6),
+       };
+
+       if (!workload || !reg_state || workload->ring_id != RCS)
+               return;
+
+       if (save) {
+               workload->oactxctrl = reg_state[ctx_oactxctrl + 1];
+
+               for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
+                       u32 state_offset = ctx_flexeu0 + i * 2;
+
+                       workload->flex_mmio[i] = reg_state[state_offset + 1];
+               }
+       } else {
+               reg_state[ctx_oactxctrl] =
+                       i915_mmio_reg_offset(GEN8_OACTXCONTROL);
+               reg_state[ctx_oactxctrl + 1] = workload->oactxctrl;
+
+               for (i = 0; i < ARRAY_SIZE(workload->flex_mmio); i++) {
+                       u32 state_offset = ctx_flexeu0 + i * 2;
+                       u32 mmio = flex_mmio[i];
+
+                       reg_state[state_offset] = mmio;
+                       reg_state[state_offset + 1] = workload->flex_mmio[i];
+               }
+       }
+}
+
 static int populate_shadow_context(struct intel_vgpu_workload *workload)
 {
        struct intel_vgpu *vgpu = workload->vgpu;
@@ -98,6 +146,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
        page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN);
        shadow_ring_context = kmap(page);
 
+       sr_oa_regs(workload, (u32 *)shadow_ring_context, true);
 #define COPY_REG(name) \
        intel_gvt_hypervisor_read_gpa(vgpu, workload->ring_context_gpa \
                + RING_CTX_OFF(name.val), &shadow_ring_context->name.val, 4)
@@ -122,6 +171,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
                        sizeof(*shadow_ring_context),
                        I915_GTT_PAGE_SIZE - sizeof(*shadow_ring_context));
 
+       sr_oa_regs(workload, (u32 *)shadow_ring_context, false);
        kunmap(page);
        return 0;
 }
@@ -376,6 +426,17 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload)
                        goto err;
                }
 
+               /* For privilge batch buffer and not wa_ctx, the bb_start_cmd_va
+                * is only updated into ring_scan_buffer, not real ring address
+                * allocated in later copy_workload_to_ring_buffer. pls be noted
+                * shadow_ring_buffer_va is now pointed to real ring buffer va
+                * in copy_workload_to_ring_buffer.
+                */
+
+               if (bb->bb_offset)
+                       bb->bb_start_cmd_va = workload->shadow_ring_buffer_va
+                               + bb->bb_offset;
+
                /* relocate shadow batch buffer */
                bb->bb_start_cmd_va[1] = i915_ggtt_offset(bb->vma);
                if (gmadr_bytes == 8)
@@ -1044,10 +1105,12 @@ int intel_vgpu_setup_submission(struct intel_vgpu *vgpu)
 
        bitmap_zero(s->shadow_ctx_desc_updated, I915_NUM_ENGINES);
 
-       s->workloads = kmem_cache_create("gvt-g_vgpu_workload",
-                       sizeof(struct intel_vgpu_workload), 0,
-                       SLAB_HWCACHE_ALIGN,
-                       NULL);
+       s->workloads = kmem_cache_create_usercopy("gvt-g_vgpu_workload",
+                                                 sizeof(struct intel_vgpu_workload), 0,
+                                                 SLAB_HWCACHE_ALIGN,
+                                                 offsetof(struct intel_vgpu_workload, rb_tail),
+                                                 sizeof_field(struct intel_vgpu_workload, rb_tail),
+                                                 NULL);
 
        if (!s->workloads) {
                ret = -ENOMEM;
index ff175a9..a79a4f6 100644 (file)
@@ -110,6 +110,10 @@ struct intel_vgpu_workload {
        /* shadow batch buffer */
        struct list_head shadow_bb;
        struct intel_shadow_wa_ctx wa_ctx;
+
+       /* oa registers */
+       u32 oactxctrl;
+       u32 flex_mmio[7];
 };
 
 struct intel_vgpu_shadow_bb {
@@ -120,6 +124,7 @@ struct intel_vgpu_shadow_bb {
        u32 *bb_start_cmd_va;
        unsigned int clflush;
        bool accessing;
+       unsigned long bb_offset;
 };
 
 #define workload_q_head(vgpu, ring_id) \
index 7a25115..736bd2b 100644 (file)
@@ -333,7 +333,7 @@ TRACE_EVENT(render_mmio,
        TP_PROTO(int old_id, int new_id, char *action, unsigned int reg,
                 unsigned int old_val, unsigned int new_val),
 
-       TP_ARGS(old_id, new_id, action, reg, new_val, old_val),
+       TP_ARGS(old_id, new_id, action, reg, old_val, new_val),
 
        TP_STRUCT__entry(
                __field(int, old_id)
index 173d009..2f5209d 100644 (file)
@@ -1433,19 +1433,7 @@ void i915_driver_unload(struct drm_device *dev)
 
        intel_modeset_cleanup(dev);
 
-       /*
-        * free the memory space allocated for the child device
-        * config parsed from VBT
-        */
-       if (dev_priv->vbt.child_dev && dev_priv->vbt.child_dev_num) {
-               kfree(dev_priv->vbt.child_dev);
-               dev_priv->vbt.child_dev = NULL;
-               dev_priv->vbt.child_dev_num = 0;
-       }
-       kfree(dev_priv->vbt.sdvo_lvds_vbt_mode);
-       dev_priv->vbt.sdvo_lvds_vbt_mode = NULL;
-       kfree(dev_priv->vbt.lfp_lvds_vbt_mode);
-       dev_priv->vbt.lfp_lvds_vbt_mode = NULL;
+       intel_bios_cleanup(dev_priv);
 
        vga_switcheroo_unregister_client(pdev);
        vga_client_register(pdev, NULL, NULL, NULL);
index a42deeb..d307429 100644 (file)
@@ -1349,6 +1349,7 @@ struct intel_vbt_data {
                u32 size;
                u8 *data;
                const u8 *sequence[MIPI_SEQ_MAX];
+               u8 *deassert_seq; /* Used by fixup_mipi_sequences() */
        } dsi;
 
        int crt_ddc_pin;
@@ -3657,6 +3658,7 @@ extern void intel_i2c_reset(struct drm_i915_private *dev_priv);
 
 /* intel_bios.c */
 void intel_bios_init(struct drm_i915_private *dev_priv);
+void intel_bios_cleanup(struct drm_i915_private *dev_priv);
 bool intel_bios_is_valid_vbt(const void *buf, size_t size);
 bool intel_bios_is_tv_present(struct drm_i915_private *dev_priv);
 bool intel_bios_is_lvds_present(struct drm_i915_private *dev_priv, u8 *i2c_pin);
index dd89abd..6ff5d65 100644 (file)
@@ -434,20 +434,28 @@ i915_gem_object_wait_reservation(struct reservation_object *resv,
                        dma_fence_put(shared[i]);
                kfree(shared);
 
+               /*
+                * If both shared fences and an exclusive fence exist,
+                * then by construction the shared fences must be later
+                * than the exclusive fence. If we successfully wait for
+                * all the shared fences, we know that the exclusive fence
+                * must all be signaled. If all the shared fences are
+                * signaled, we can prune the array and recover the
+                * floating references on the fences/requests.
+                */
                prune_fences = count && timeout >= 0;
        } else {
                excl = reservation_object_get_excl_rcu(resv);
        }
 
-       if (excl && timeout >= 0) {
+       if (excl && timeout >= 0)
                timeout = i915_gem_object_wait_fence(excl, flags, timeout,
                                                     rps_client);
-               prune_fences = timeout >= 0;
-       }
 
        dma_fence_put(excl);
 
-       /* Oportunistically prune the fences iff we know they have *all* been
+       /*
+        * Opportunistically prune the fences iff we know they have *all* been
         * signaled and that the reservation object has not been changed (i.e.
         * no new fences have been added).
         */
@@ -3205,8 +3213,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
         * rolling the global seqno forward (since this would complete requests
         * for which we haven't set the fence error to EIO yet).
         */
-       for_each_engine(engine, i915, id)
+       for_each_engine(engine, i915, id) {
+               i915_gem_reset_prepare_engine(engine);
                engine->submit_request = nop_submit_request;
+       }
 
        /*
         * Make sure no one is running the old callback before we proceed with
@@ -3244,6 +3254,8 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
                intel_engine_init_global_seqno(engine,
                                               intel_engine_last_submit(engine));
                spin_unlock_irqrestore(&engine->timeline->lock, flags);
+
+               i915_gem_reset_finish_engine(engine);
        }
 
        set_bit(I915_WEDGED, &i915->gpu_error.flags);
index 648e753..0c963fc 100644 (file)
@@ -803,7 +803,7 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
 
        case I915_CONTEXT_PARAM_PRIORITY:
                {
-                       int priority = args->value;
+                       s64 priority = args->value;
 
                        if (args->size)
                                ret = -EINVAL;
index 4401068..3ab1ace 100644 (file)
@@ -505,6 +505,8 @@ eb_add_vma(struct i915_execbuffer *eb, unsigned int i, struct i915_vma *vma)
                list_add_tail(&vma->exec_link, &eb->unbound);
                if (drm_mm_node_allocated(&vma->node))
                        err = i915_vma_unbind(vma);
+               if (unlikely(err))
+                       vma->exec_flags = NULL;
        }
        return err;
 }
@@ -2410,7 +2412,7 @@ err_request:
        if (out_fence) {
                if (err == 0) {
                        fd_install(out_fence_fd, out_fence->file);
-                       args->rsvd2 &= GENMASK_ULL(0, 31); /* keep in-fence */
+                       args->rsvd2 &= GENMASK_ULL(31, 0); /* keep in-fence */
                        args->rsvd2 |= (u64)out_fence_fd << 32;
                        out_fence_fd = -1;
                } else {
index e09d18d..a3e93d4 100644 (file)
@@ -476,8 +476,6 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request)
        GEM_BUG_ON(!irqs_disabled());
        lockdep_assert_held(&engine->timeline->lock);
 
-       trace_i915_gem_request_execute(request);
-
        /* Transfer from per-context onto the global per-engine timeline */
        timeline = engine->timeline;
        GEM_BUG_ON(timeline == request->timeline);
@@ -501,6 +499,8 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request)
        list_move_tail(&request->link, &timeline->requests);
        spin_unlock(&request->timeline->lock);
 
+       trace_i915_gem_request_execute(request);
+
        wake_up_all(&request->execute);
 }
 
index 42ff06f..792facd 100644 (file)
@@ -84,9 +84,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf)
 void
 i915_perf_load_test_config_cflgt3(struct drm_i915_private *dev_priv)
 {
-       strncpy(dev_priv->perf.oa.test_config.uuid,
+       strlcpy(dev_priv->perf.oa.test_config.uuid,
                "577e8e2c-3fa0-4875-8743-3538d585e3b0",
-               UUID_STRING_LEN);
+               sizeof(dev_priv->perf.oa.test_config.uuid));
        dev_priv->perf.oa.test_config.id = 1;
 
        dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa;
index ff0ac36..ba9140c 100644 (file)
@@ -96,9 +96,9 @@ show_test_oa_id(struct device *kdev, struct device_attribute *attr, char *buf)
 void
 i915_perf_load_test_config_cnl(struct drm_i915_private *dev_priv)
 {
-       strncpy(dev_priv->perf.oa.test_config.uuid,
+       strlcpy(dev_priv->perf.oa.test_config.uuid,
                "db41edd4-d8e7-4730-ad11-b9a2d6833503",
-               UUID_STRING_LEN);
+               sizeof(dev_priv->perf.oa.test_config.uuid));
        dev_priv->perf.oa.test_config.id = 1;
 
        dev_priv->perf.oa.test_config.mux_regs = mux_config_test_oa;
index 0be50e4..f8fe5ff 100644 (file)
@@ -1303,9 +1303,8 @@ static void i915_oa_stream_destroy(struct i915_perf_stream *stream)
         */
        mutex_lock(&dev_priv->drm.struct_mutex);
        dev_priv->perf.oa.exclusive_stream = NULL;
-       mutex_unlock(&dev_priv->drm.struct_mutex);
-
        dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
 
        free_oa_buffer(dev_priv);
 
@@ -1756,22 +1755,13 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
  * Note: it's only the RCS/Render context that has any OA state.
  */
 static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
-                                      const struct i915_oa_config *oa_config,
-                                      bool interruptible)
+                                      const struct i915_oa_config *oa_config)
 {
        struct i915_gem_context *ctx;
        int ret;
        unsigned int wait_flags = I915_WAIT_LOCKED;
 
-       if (interruptible) {
-               ret = i915_mutex_lock_interruptible(&dev_priv->drm);
-               if (ret)
-                       return ret;
-
-               wait_flags |= I915_WAIT_INTERRUPTIBLE;
-       } else {
-               mutex_lock(&dev_priv->drm.struct_mutex);
-       }
+       lockdep_assert_held(&dev_priv->drm.struct_mutex);
 
        /* Switch away from any user context. */
        ret = gen8_switch_to_updated_kernel_context(dev_priv, oa_config);
@@ -1819,8 +1809,6 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
        }
 
  out:
-       mutex_unlock(&dev_priv->drm.struct_mutex);
-
        return ret;
 }
 
@@ -1863,7 +1851,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
         * to make sure all slices/subslices are ON before writing to NOA
         * registers.
         */
-       ret = gen8_configure_all_contexts(dev_priv, oa_config, true);
+       ret = gen8_configure_all_contexts(dev_priv, oa_config);
        if (ret)
                return ret;
 
@@ -1878,7 +1866,7 @@ static int gen8_enable_metric_set(struct drm_i915_private *dev_priv,
 static void gen8_disable_metric_set(struct drm_i915_private *dev_priv)
 {
        /* Reset all contexts' slices/subslices configurations. */
-       gen8_configure_all_contexts(dev_priv, NULL, false);
+       gen8_configure_all_contexts(dev_priv, NULL);
 
        I915_WRITE(GDT_CHICKEN_BITS, (I915_READ(GDT_CHICKEN_BITS) &
                                      ~GT_NOA_ENABLE));
@@ -1888,7 +1876,7 @@ static void gen8_disable_metric_set(struct drm_i915_private *dev_priv)
 static void gen10_disable_metric_set(struct drm_i915_private *dev_priv)
 {
        /* Reset all contexts' slices/subslices configurations. */
-       gen8_configure_all_contexts(dev_priv, NULL, false);
+       gen8_configure_all_contexts(dev_priv, NULL);
 
        /* Make sure we disable noa to save power. */
        I915_WRITE(RPM_CONFIG1,
@@ -2138,6 +2126,10 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
        if (ret)
                goto err_oa_buf_alloc;
 
+       ret = i915_mutex_lock_interruptible(&dev_priv->drm);
+       if (ret)
+               goto err_lock;
+
        ret = dev_priv->perf.oa.ops.enable_metric_set(dev_priv,
                                                      stream->oa_config);
        if (ret)
@@ -2145,23 +2137,17 @@ static int i915_oa_stream_init(struct i915_perf_stream *stream,
 
        stream->ops = &i915_oa_stream_ops;
 
-       /* Lock device for exclusive_stream access late because
-        * enable_metric_set() might lock as well on gen8+.
-        */
-       ret = i915_mutex_lock_interruptible(&dev_priv->drm);
-       if (ret)
-               goto err_lock;
-
        dev_priv->perf.oa.exclusive_stream = stream;
 
        mutex_unlock(&dev_priv->drm.struct_mutex);
 
        return 0;
 
-err_lock:
+err_enable:
        dev_priv->perf.oa.ops.disable_metric_set(dev_priv);
+       mutex_unlock(&dev_priv->drm.struct_mutex);
 
-err_enable:
+err_lock:
        free_oa_buffer(dev_priv);
 
 err_oa_buf_alloc:
index 55a8a1e..0e9b98c 100644 (file)
@@ -285,26 +285,41 @@ static u64 count_interrupts(struct drm_i915_private *i915)
        return sum;
 }
 
-static void i915_pmu_event_destroy(struct perf_event *event)
+static void engine_event_destroy(struct perf_event *event)
 {
-       WARN_ON(event->parent);
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
+       struct intel_engine_cs *engine;
+
+       engine = intel_engine_lookup_user(i915,
+                                         engine_event_class(event),
+                                         engine_event_instance(event));
+       if (WARN_ON_ONCE(!engine))
+               return;
+
+       if (engine_event_sample(event) == I915_SAMPLE_BUSY &&
+           intel_engine_supports_stats(engine))
+               intel_disable_engine_stats(engine);
 }
 
-static int engine_event_init(struct perf_event *event)
+static void i915_pmu_event_destroy(struct perf_event *event)
 {
-       struct drm_i915_private *i915 =
-               container_of(event->pmu, typeof(*i915), pmu.base);
+       WARN_ON(event->parent);
 
-       if (!intel_engine_lookup_user(i915, engine_event_class(event),
-                                     engine_event_instance(event)))
-               return -ENODEV;
+       if (is_engine_event(event))
+               engine_event_destroy(event);
+}
 
-       switch (engine_event_sample(event)) {
+static int
+engine_event_status(struct intel_engine_cs *engine,
+                   enum drm_i915_pmu_engine_sample sample)
+{
+       switch (sample) {
        case I915_SAMPLE_BUSY:
        case I915_SAMPLE_WAIT:
                break;
        case I915_SAMPLE_SEMA:
-               if (INTEL_GEN(i915) < 6)
+               if (INTEL_GEN(engine->i915) < 6)
                        return -ENODEV;
                break;
        default:
@@ -314,6 +329,30 @@ static int engine_event_init(struct perf_event *event)
        return 0;
 }
 
+static int engine_event_init(struct perf_event *event)
+{
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
+       struct intel_engine_cs *engine;
+       u8 sample;
+       int ret;
+
+       engine = intel_engine_lookup_user(i915, engine_event_class(event),
+                                         engine_event_instance(event));
+       if (!engine)
+               return -ENODEV;
+
+       sample = engine_event_sample(event);
+       ret = engine_event_status(engine, sample);
+       if (ret)
+               return ret;
+
+       if (sample == I915_SAMPLE_BUSY && intel_engine_supports_stats(engine))
+               ret = intel_enable_engine_stats(engine);
+
+       return ret;
+}
+
 static int i915_pmu_event_init(struct perf_event *event)
 {
        struct drm_i915_private *i915 =
@@ -370,7 +409,94 @@ static int i915_pmu_event_init(struct perf_event *event)
        return 0;
 }
 
-static u64 __i915_pmu_event_read(struct perf_event *event)
+static u64 __get_rc6(struct drm_i915_private *i915)
+{
+       u64 val;
+
+       val = intel_rc6_residency_ns(i915,
+                                    IS_VALLEYVIEW(i915) ?
+                                    VLV_GT_RENDER_RC6 :
+                                    GEN6_GT_GFX_RC6);
+
+       if (HAS_RC6p(i915))
+               val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6p);
+
+       if (HAS_RC6pp(i915))
+               val += intel_rc6_residency_ns(i915, GEN6_GT_GFX_RC6pp);
+
+       return val;
+}
+
+static u64 get_rc6(struct drm_i915_private *i915, bool locked)
+{
+#if IS_ENABLED(CONFIG_PM)
+       unsigned long flags;
+       u64 val;
+
+       if (intel_runtime_pm_get_if_in_use(i915)) {
+               val = __get_rc6(i915);
+               intel_runtime_pm_put(i915);
+
+               /*
+                * If we are coming back from being runtime suspended we must
+                * be careful not to report a larger value than returned
+                * previously.
+                */
+
+               if (!locked)
+                       spin_lock_irqsave(&i915->pmu.lock, flags);
+
+               if (val >= i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur) {
+                       i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = 0;
+                       i915->pmu.sample[__I915_SAMPLE_RC6].cur = val;
+               } else {
+                       val = i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur;
+               }
+
+               if (!locked)
+                       spin_unlock_irqrestore(&i915->pmu.lock, flags);
+       } else {
+               struct pci_dev *pdev = i915->drm.pdev;
+               struct device *kdev = &pdev->dev;
+               unsigned long flags2;
+
+               /*
+                * We are runtime suspended.
+                *
+                * Report the delta from when the device was suspended to now,
+                * on top of the last known real value, as the approximated RC6
+                * counter value.
+                */
+               if (!locked)
+                       spin_lock_irqsave(&i915->pmu.lock, flags);
+
+               spin_lock_irqsave(&kdev->power.lock, flags2);
+
+               if (!i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur)
+                       i915->pmu.suspended_jiffies_last =
+                                               kdev->power.suspended_jiffies;
+
+               val = kdev->power.suspended_jiffies -
+                     i915->pmu.suspended_jiffies_last;
+               val += jiffies - kdev->power.accounting_timestamp;
+
+               spin_unlock_irqrestore(&kdev->power.lock, flags2);
+
+               val = jiffies_to_nsecs(val);
+               val += i915->pmu.sample[__I915_SAMPLE_RC6].cur;
+               i915->pmu.sample[__I915_SAMPLE_RC6_ESTIMATED].cur = val;
+
+               if (!locked)
+                       spin_unlock_irqrestore(&i915->pmu.lock, flags);
+       }
+
+       return val;
+#else
+       return __get_rc6(i915);
+#endif
+}
+
+static u64 __i915_pmu_event_read(struct perf_event *event, bool locked)
 {
        struct drm_i915_private *i915 =
                container_of(event->pmu, typeof(*i915), pmu.base);
@@ -387,7 +513,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event)
                if (WARN_ON_ONCE(!engine)) {
                        /* Do nothing */
                } else if (sample == I915_SAMPLE_BUSY &&
-                          engine->pmu.busy_stats) {
+                          intel_engine_supports_stats(engine)) {
                        val = ktime_to_ns(intel_engine_get_busy_time(engine));
                } else {
                        val = engine->pmu.sample[sample].cur;
@@ -408,18 +534,7 @@ static u64 __i915_pmu_event_read(struct perf_event *event)
                        val = count_interrupts(i915);
                        break;
                case I915_PMU_RC6_RESIDENCY:
-                       intel_runtime_pm_get(i915);
-                       val = intel_rc6_residency_ns(i915,
-                                                    IS_VALLEYVIEW(i915) ?
-                                                    VLV_GT_RENDER_RC6 :
-                                                    GEN6_GT_GFX_RC6);
-                       if (HAS_RC6p(i915))
-                               val += intel_rc6_residency_ns(i915,
-                                                             GEN6_GT_GFX_RC6p);
-                       if (HAS_RC6pp(i915))
-                               val += intel_rc6_residency_ns(i915,
-                                                             GEN6_GT_GFX_RC6pp);
-                       intel_runtime_pm_put(i915);
+                       val = get_rc6(i915, locked);
                        break;
                }
        }
@@ -434,7 +549,7 @@ static void i915_pmu_event_read(struct perf_event *event)
 
 again:
        prev = local64_read(&hwc->prev_count);
-       new = __i915_pmu_event_read(event);
+       new = __i915_pmu_event_read(event, false);
 
        if (local64_cmpxchg(&hwc->prev_count, prev, new) != prev)
                goto again;
@@ -442,12 +557,6 @@ again:
        local64_add(new - prev, &event->count);
 }
 
-static bool engine_needs_busy_stats(struct intel_engine_cs *engine)
-{
-       return intel_engine_supports_stats(engine) &&
-              (engine->pmu.enable & BIT(I915_SAMPLE_BUSY));
-}
-
 static void i915_pmu_enable(struct perf_event *event)
 {
        struct drm_i915_private *i915 =
@@ -487,21 +596,7 @@ static void i915_pmu_enable(struct perf_event *event)
 
                GEM_BUG_ON(sample >= I915_PMU_SAMPLE_BITS);
                GEM_BUG_ON(engine->pmu.enable_count[sample] == ~0);
-               if (engine->pmu.enable_count[sample]++ == 0) {
-                       /*
-                        * Enable engine busy stats tracking if needed or
-                        * alternatively cancel the scheduled disable.
-                        *
-                        * If the delayed disable was pending, cancel it and
-                        * in this case do not enable since it already is.
-                        */
-                       if (engine_needs_busy_stats(engine) &&
-                           !engine->pmu.busy_stats) {
-                               engine->pmu.busy_stats = true;
-                               if (!cancel_delayed_work(&engine->pmu.disable_busy_stats))
-                                       intel_enable_engine_stats(engine);
-                       }
-               }
+               engine->pmu.enable_count[sample]++;
        }
 
        /*
@@ -509,19 +604,11 @@ static void i915_pmu_enable(struct perf_event *event)
         * for all listeners. Even when the event was already enabled and has
         * an existing non-zero value.
         */
-       local64_set(&event->hw.prev_count, __i915_pmu_event_read(event));
+       local64_set(&event->hw.prev_count, __i915_pmu_event_read(event, true));
 
        spin_unlock_irqrestore(&i915->pmu.lock, flags);
 }
 
-static void __disable_busy_stats(struct work_struct *work)
-{
-       struct intel_engine_cs *engine =
-              container_of(work, typeof(*engine), pmu.disable_busy_stats.work);
-
-       intel_disable_engine_stats(engine);
-}
-
 static void i915_pmu_disable(struct perf_event *event)
 {
        struct drm_i915_private *i915 =
@@ -545,26 +632,8 @@ static void i915_pmu_disable(struct perf_event *event)
                 * Decrement the reference count and clear the enabled
                 * bitmask when the last listener on an event goes away.
                 */
-               if (--engine->pmu.enable_count[sample] == 0) {
+               if (--engine->pmu.enable_count[sample] == 0)
                        engine->pmu.enable &= ~BIT(sample);
-                       if (!engine_needs_busy_stats(engine) &&
-                           engine->pmu.busy_stats) {
-                               engine->pmu.busy_stats = false;
-                               /*
-                                * We request a delayed disable to handle the
-                                * rapid on/off cycles on events, which can
-                                * happen when tools like perf stat start, in a
-                                * nicer way.
-                                *
-                                * In addition, this also helps with busy stats
-                                * accuracy with background CPU offline/online
-                                * migration events.
-                                */
-                               queue_delayed_work(system_wq,
-                                                  &engine->pmu.disable_busy_stats,
-                                                  round_jiffies_up_relative(HZ));
-                       }
-               }
        }
 
        GEM_BUG_ON(bit >= I915_PMU_MASK_BITS);
@@ -797,8 +866,6 @@ static void i915_pmu_unregister_cpuhp_state(struct drm_i915_private *i915)
 
 void i915_pmu_register(struct drm_i915_private *i915)
 {
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
        int ret;
 
        if (INTEL_GEN(i915) <= 2) {
@@ -820,10 +887,6 @@ void i915_pmu_register(struct drm_i915_private *i915)
        hrtimer_init(&i915->pmu.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        i915->pmu.timer.function = i915_sample;
 
-       for_each_engine(engine, i915, id)
-               INIT_DELAYED_WORK(&engine->pmu.disable_busy_stats,
-                                 __disable_busy_stats);
-
        ret = perf_pmu_register(&i915->pmu.base, "i915", -1);
        if (ret)
                goto err;
@@ -843,9 +906,6 @@ err:
 
 void i915_pmu_unregister(struct drm_i915_private *i915)
 {
-       struct intel_engine_cs *engine;
-       enum intel_engine_id id;
-
        if (!i915->pmu.base.event_init)
                return;
 
@@ -853,11 +913,6 @@ void i915_pmu_unregister(struct drm_i915_private *i915)
 
        hrtimer_cancel(&i915->pmu.timer);
 
-       for_each_engine(engine, i915, id) {
-               GEM_BUG_ON(engine->pmu.busy_stats);
-               flush_delayed_work(&engine->pmu.disable_busy_stats);
-       }
-
        i915_pmu_unregister_cpuhp_state(i915);
 
        perf_pmu_unregister(&i915->pmu.base);
index 40c154d..bb62df1 100644 (file)
@@ -27,6 +27,8 @@
 enum {
        __I915_SAMPLE_FREQ_ACT = 0,
        __I915_SAMPLE_FREQ_REQ,
+       __I915_SAMPLE_RC6,
+       __I915_SAMPLE_RC6_ESTIMATED,
        __I915_NUM_PMU_SAMPLERS
 };
 
@@ -94,6 +96,10 @@ struct i915_pmu {
         * struct intel_engine_cs.
         */
        struct i915_pmu_sample sample[__I915_NUM_PMU_SAMPLERS];
+       /**
+        * @suspended_jiffies_last: Cached suspend time from PM core.
+        */
+       unsigned long suspended_jiffies_last;
 };
 
 #ifdef CONFIG_PERF_EVENTS
index a2108e3..33eb0c5 100644 (file)
@@ -2027,7 +2027,7 @@ enum i915_power_well_id {
 #define _CNL_PORT_TX_DW5_LN0_AE                0x162454
 #define _CNL_PORT_TX_DW5_LN0_B         0x162654
 #define _CNL_PORT_TX_DW5_LN0_C         0x162C54
-#define _CNL_PORT_TX_DW5_LN0_D         0x162ED4
+#define _CNL_PORT_TX_DW5_LN0_D         0x162E54
 #define _CNL_PORT_TX_DW5_LN0_F         0x162854
 #define CNL_PORT_TX_DW5_GRP(port)      _MMIO_PORT6(port, \
                                                    _CNL_PORT_TX_DW5_GRP_AE, \
@@ -2058,7 +2058,7 @@ enum i915_power_well_id {
 #define _CNL_PORT_TX_DW7_LN0_AE                0x16245C
 #define _CNL_PORT_TX_DW7_LN0_B         0x16265C
 #define _CNL_PORT_TX_DW7_LN0_C         0x162C5C
-#define _CNL_PORT_TX_DW7_LN0_D         0x162EDC
+#define _CNL_PORT_TX_DW7_LN0_D         0x162E5C
 #define _CNL_PORT_TX_DW7_LN0_F         0x16285C
 #define CNL_PORT_TX_DW7_GRP(port)      _MMIO_PORT6(port, \
                                                    _CNL_PORT_TX_DW7_GRP_AE, \
index b33d215..e5e6f6b 100644 (file)
@@ -304,8 +304,9 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev,
 {
        struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
        struct intel_rps *rps = &dev_priv->gt_pm.rps;
-       u32 val;
+       bool boost = false;
        ssize_t ret;
+       u32 val;
 
        ret = kstrtou32(buf, 0, &val);
        if (ret)
@@ -317,8 +318,13 @@ static ssize_t gt_boost_freq_mhz_store(struct device *kdev,
                return -EINVAL;
 
        mutex_lock(&dev_priv->pcu_lock);
-       rps->boost_freq = val;
+       if (val != rps->boost_freq) {
+               rps->boost_freq = val;
+               boost = atomic_read(&rps->num_waiters);
+       }
        mutex_unlock(&dev_priv->pcu_lock);
+       if (boost)
+               schedule_work(&rps->work);
 
        return count;
 }
index 522d54f..4a01f62 100644 (file)
@@ -779,11 +779,11 @@ static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
 {
        struct intel_encoder *encoder;
 
-       if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map)))
-               return NULL;
-
        /* MST */
        if (pipe >= 0) {
+               if (WARN_ON(pipe >= ARRAY_SIZE(dev_priv->av_enc_map)))
+                       return NULL;
+
                encoder = dev_priv->av_enc_map[pipe];
                /*
                 * when bootup, audio driver may not know it is
index f7f7717..b49a2df 100644 (file)
@@ -947,6 +947,86 @@ static int goto_next_sequence_v3(const u8 *data, int index, int total)
        return 0;
 }
 
+/*
+ * Get len of pre-fixed deassert fragment from a v1 init OTP sequence,
+ * skip all delay + gpio operands and stop at the first DSI packet op.
+ */
+static int get_init_otp_deassert_fragment_len(struct drm_i915_private *dev_priv)
+{
+       const u8 *data = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
+       int index, len;
+
+       if (WARN_ON(!data || dev_priv->vbt.dsi.seq_version != 1))
+               return 0;
+
+       /* index = 1 to skip sequence byte */
+       for (index = 1; data[index] != MIPI_SEQ_ELEM_END; index += len) {
+               switch (data[index]) {
+               case MIPI_SEQ_ELEM_SEND_PKT:
+                       return index == 1 ? 0 : index;
+               case MIPI_SEQ_ELEM_DELAY:
+                       len = 5; /* 1 byte for operand + uint32 */
+                       break;
+               case MIPI_SEQ_ELEM_GPIO:
+                       len = 3; /* 1 byte for op, 1 for gpio_nr, 1 for value */
+                       break;
+               default:
+                       return 0;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Some v1 VBT MIPI sequences do the deassert in the init OTP sequence.
+ * The deassert must be done before calling intel_dsi_device_ready, so for
+ * these devices we split the init OTP sequence into a deassert sequence and
+ * the actual init OTP part.
+ */
+static void fixup_mipi_sequences(struct drm_i915_private *dev_priv)
+{
+       u8 *init_otp;
+       int len;
+
+       /* Limit this to VLV for now. */
+       if (!IS_VALLEYVIEW(dev_priv))
+               return;
+
+       /* Limit this to v1 vid-mode sequences */
+       if (dev_priv->vbt.dsi.config->is_cmd_mode ||
+           dev_priv->vbt.dsi.seq_version != 1)
+               return;
+
+       /* Only do this if there are otp and assert seqs and no deassert seq */
+       if (!dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] ||
+           !dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET] ||
+           dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET])
+               return;
+
+       /* The deassert-sequence ends at the first DSI packet */
+       len = get_init_otp_deassert_fragment_len(dev_priv);
+       if (!len)
+               return;
+
+       DRM_DEBUG_KMS("Using init OTP fragment to deassert reset\n");
+
+       /* Copy the fragment, update seq byte and terminate it */
+       init_otp = (u8 *)dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
+       dev_priv->vbt.dsi.deassert_seq = kmemdup(init_otp, len + 1, GFP_KERNEL);
+       if (!dev_priv->vbt.dsi.deassert_seq)
+               return;
+       dev_priv->vbt.dsi.deassert_seq[0] = MIPI_SEQ_DEASSERT_RESET;
+       dev_priv->vbt.dsi.deassert_seq[len] = MIPI_SEQ_ELEM_END;
+       /* Use the copy for deassert */
+       dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET] =
+               dev_priv->vbt.dsi.deassert_seq;
+       /* Replace the last byte of the fragment with init OTP seq byte */
+       init_otp[len - 1] = MIPI_SEQ_INIT_OTP;
+       /* And make MIPI_MIPI_SEQ_INIT_OTP point to it */
+       dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP] = init_otp + len - 1;
+}
+
 static void
 parse_mipi_sequence(struct drm_i915_private *dev_priv,
                    const struct bdb_header *bdb)
@@ -1016,6 +1096,8 @@ parse_mipi_sequence(struct drm_i915_private *dev_priv,
        dev_priv->vbt.dsi.size = seq_size;
        dev_priv->vbt.dsi.seq_version = sequence->version;
 
+       fixup_mipi_sequences(dev_priv);
+
        DRM_DEBUG_DRIVER("MIPI related VBT parsing complete\n");
        return;
 
@@ -1589,6 +1671,29 @@ out:
 }
 
 /**
+ * intel_bios_cleanup - Free any resources allocated by intel_bios_init()
+ * @dev_priv: i915 device instance
+ */
+void intel_bios_cleanup(struct drm_i915_private *dev_priv)
+{
+       kfree(dev_priv->vbt.child_dev);
+       dev_priv->vbt.child_dev = NULL;
+       dev_priv->vbt.child_dev_num = 0;
+       kfree(dev_priv->vbt.sdvo_lvds_vbt_mode);
+       dev_priv->vbt.sdvo_lvds_vbt_mode = NULL;
+       kfree(dev_priv->vbt.lfp_lvds_vbt_mode);
+       dev_priv->vbt.lfp_lvds_vbt_mode = NULL;
+       kfree(dev_priv->vbt.dsi.data);
+       dev_priv->vbt.dsi.data = NULL;
+       kfree(dev_priv->vbt.dsi.pps);
+       dev_priv->vbt.dsi.pps = NULL;
+       kfree(dev_priv->vbt.dsi.config);
+       dev_priv->vbt.dsi.config = NULL;
+       kfree(dev_priv->vbt.dsi.deassert_seq);
+       dev_priv->vbt.dsi.deassert_seq = NULL;
+}
+
+/**
  * intel_bios_is_tv_present - is integrated TV present in VBT
  * @dev_priv:  i915 device instance
  *
index bd40fea..f54ddda 100644 (file)
@@ -594,29 +594,16 @@ void intel_engine_remove_wait(struct intel_engine_cs *engine,
        spin_unlock_irq(&b->rb_lock);
 }
 
-static bool signal_valid(const struct drm_i915_gem_request *request)
-{
-       return intel_wait_check_request(&request->signaling.wait, request);
-}
-
 static bool signal_complete(const struct drm_i915_gem_request *request)
 {
        if (!request)
                return false;
 
-       /* If another process served as the bottom-half it may have already
-        * signalled that this wait is already completed.
-        */
-       if (intel_wait_complete(&request->signaling.wait))
-               return signal_valid(request);
-
-       /* Carefully check if the request is complete, giving time for the
+       /*
+        * Carefully check if the request is complete, giving time for the
         * seqno to be visible or if the GPU hung.
         */
-       if (__i915_request_irq_complete(request))
-               return true;
-
-       return false;
+       return __i915_request_irq_complete(request);
 }
 
 static struct drm_i915_gem_request *to_signaler(struct rb_node *rb)
@@ -659,9 +646,13 @@ static int intel_breadcrumbs_signaler(void *arg)
                        request = i915_gem_request_get_rcu(request);
                rcu_read_unlock();
                if (signal_complete(request)) {
-                       local_bh_disable();
-                       dma_fence_signal(&request->fence);
-                       local_bh_enable(); /* kick start the tasklets */
+                       if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT,
+                                     &request->fence.flags)) {
+                               local_bh_disable();
+                               dma_fence_signal(&request->fence);
+                               GEM_BUG_ON(!i915_gem_request_completed(request));
+                               local_bh_enable(); /* kick start the tasklets */
+                       }
 
                        spin_lock_irq(&b->rb_lock);
 
index 5dc118f..1704c88 100644 (file)
@@ -1952,6 +1952,14 @@ int intel_crtc_compute_min_cdclk(const struct intel_crtc_state *crtc_state)
        if (crtc_state->has_audio && INTEL_GEN(dev_priv) >= 9)
                min_cdclk = max(2 * 96000, min_cdclk);
 
+       /*
+        * On Valleyview some DSI panels lose (v|h)sync when the clock is lower
+        * than 320000KHz.
+        */
+       if (intel_crtc_has_type(crtc_state, INTEL_OUTPUT_DSI) &&
+           IS_VALLEYVIEW(dev_priv))
+               min_cdclk = max(320000, min_cdclk);
+
        if (min_cdclk > dev_priv->max_cdclk_freq) {
                DRM_DEBUG_KMS("required cdclk (%d kHz) exceeds max (%d kHz)\n",
                              min_cdclk, dev_priv->max_cdclk_freq);
index f51645a..6aff9d0 100644 (file)
@@ -2175,8 +2175,7 @@ static void intel_ddi_pre_enable_dp(struct intel_encoder *encoder,
                intel_prepare_dp_ddi_buffers(encoder, crtc_state);
 
        intel_ddi_init_dp_buf_reg(encoder);
-       if (!is_mst)
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
        if (port != PORT_A || INTEL_GEN(dev_priv) >= 9)
                intel_dp_stop_link_train(intel_dp);
@@ -2274,14 +2273,12 @@ static void intel_ddi_post_disable_dp(struct intel_encoder *encoder,
        struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
        struct intel_digital_port *dig_port = enc_to_dig_port(&encoder->base);
        struct intel_dp *intel_dp = &dig_port->dp;
-       bool is_mst = intel_crtc_has_type(old_crtc_state, INTEL_OUTPUT_DP_MST);
 
        /*
         * Power down sink before disabling the port, otherwise we end
         * up getting interrupts from the sink on detecting link loss.
         */
-       if (!is_mst)
-               intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+       intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 
        intel_disable_ddi_buf(encoder);
 
index 35c5299..a29868c 100644 (file)
@@ -620,19 +620,15 @@ static int
 bxt_power_sequencer_idx(struct intel_dp *intel_dp)
 {
        struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
+       int backlight_controller = dev_priv->vbt.backlight.controller;
 
        lockdep_assert_held(&dev_priv->pps_mutex);
 
        /* We should never land here with regular DP ports */
        WARN_ON(!intel_dp_is_edp(intel_dp));
 
-       /*
-        * TODO: BXT has 2 PPS instances. The correct port->PPS instance
-        * mapping needs to be retrieved from VBT, for now just hard-code to
-        * use instance #0 always.
-        */
        if (!intel_dp->pps_reset)
-               return 0;
+               return backlight_controller;
 
        intel_dp->pps_reset = false;
 
@@ -642,7 +638,7 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
         */
        intel_dp_init_panel_power_sequencer_registers(intel_dp, false);
 
-       return 0;
+       return backlight_controller;
 }
 
 typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
index d790bdc..fa960cf 100644 (file)
@@ -1458,7 +1458,9 @@ static bool ring_is_idle(struct intel_engine_cs *engine)
        struct drm_i915_private *dev_priv = engine->i915;
        bool idle = true;
 
-       intel_runtime_pm_get(dev_priv);
+       /* If the whole device is asleep, the engine must be idle */
+       if (!intel_runtime_pm_get_if_in_use(dev_priv))
+               return true;
 
        /* First check that no commands are left in the ring */
        if ((I915_READ_HEAD(engine) & HEAD_ADDR) !=
@@ -1943,16 +1945,22 @@ intel_engine_lookup_user(struct drm_i915_private *i915, u8 class, u8 instance)
  */
 int intel_enable_engine_stats(struct intel_engine_cs *engine)
 {
+       struct intel_engine_execlists *execlists = &engine->execlists;
        unsigned long flags;
+       int err = 0;
 
        if (!intel_engine_supports_stats(engine))
                return -ENODEV;
 
+       tasklet_disable(&execlists->tasklet);
        spin_lock_irqsave(&engine->stats.lock, flags);
-       if (engine->stats.enabled == ~0)
-               goto busy;
+
+       if (unlikely(engine->stats.enabled == ~0)) {
+               err = -EBUSY;
+               goto unlock;
+       }
+
        if (engine->stats.enabled++ == 0) {
-               struct intel_engine_execlists *execlists = &engine->execlists;
                const struct execlist_port *port = execlists->port;
                unsigned int num_ports = execlists_num_ports(execlists);
 
@@ -1967,14 +1975,12 @@ int intel_enable_engine_stats(struct intel_engine_cs *engine)
                if (engine->stats.active)
                        engine->stats.start = engine->stats.enabled_at;
        }
-       spin_unlock_irqrestore(&engine->stats.lock, flags);
-
-       return 0;
 
-busy:
+unlock:
        spin_unlock_irqrestore(&engine->stats.lock, flags);
+       tasklet_enable(&execlists->tasklet);
 
-       return -EBUSY;
+       return err;
 }
 
 static ktime_t __intel_engine_get_busy_time(struct intel_engine_cs *engine)
index 348a4f7..5374731 100644 (file)
@@ -246,7 +246,7 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd)
         */
        tmp = I915_READ_CTL(engine);
        if (tmp & RING_WAIT) {
-               i915_handle_error(dev_priv, 0,
+               i915_handle_error(dev_priv, BIT(engine->id),
                                  "Kicking stuck wait on %s",
                                  engine->name);
                I915_WRITE_CTL(engine, tmp);
@@ -258,7 +258,7 @@ engine_stuck(struct intel_engine_cs *engine, u64 acthd)
                default:
                        return ENGINE_DEAD;
                case 1:
-                       i915_handle_error(dev_priv, 0,
+                       i915_handle_error(dev_priv, ALL_ENGINES,
                                          "Kicking stuck semaphore on %s",
                                          engine->name);
                        I915_WRITE_CTL(engine, tmp);
index 7ece2f0..e0fca03 100644 (file)
@@ -719,6 +719,8 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
        struct rb_node *rb;
        unsigned long flags;
 
+       GEM_TRACE("%s\n", engine->name);
+
        spin_lock_irqsave(&engine->timeline->lock, flags);
 
        /* Cancel the requests on the HW and clear the ELSP tracker. */
@@ -765,6 +767,9 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
         */
        clear_bit(ENGINE_IRQ_EXECLIST, &engine->irq_posted);
 
+       /* Mark all CS interrupts as complete */
+       execlists->active = 0;
+
        spin_unlock_irqrestore(&engine->timeline->lock, flags);
 }
 
index c5ff203..a0e7a6c 100644 (file)
@@ -366,20 +366,6 @@ struct intel_engine_cs {
                 */
 #define I915_ENGINE_SAMPLE_MAX (I915_SAMPLE_SEMA + 1)
                struct i915_pmu_sample sample[I915_ENGINE_SAMPLE_MAX];
-               /**
-                * @busy_stats: Has enablement of engine stats tracking been
-                *              requested.
-                */
-               bool busy_stats;
-               /**
-                * @disable_busy_stats: Work item for busy stats disabling.
-                *
-                * Same as with @enable_busy_stats action, with the difference
-                * that we delay it in case there are rapid enable-disable
-                * actions, which can happen during tool startup (like perf
-                * stat).
-                */
-               struct delayed_work disable_busy_stats;
        } pmu;
 
        /*
index 9a99618..e83af0f 100644 (file)
@@ -225,7 +225,11 @@ static void ipu_crtc_atomic_begin(struct drm_crtc *crtc,
                                  struct drm_crtc_state *old_crtc_state)
 {
        drm_crtc_vblank_on(crtc);
+}
 
+static void ipu_crtc_atomic_flush(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *old_crtc_state)
+{
        spin_lock_irq(&crtc->dev->event_lock);
        if (crtc->state->event) {
                WARN_ON(drm_crtc_vblank_get(crtc));
@@ -293,6 +297,7 @@ static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
        .mode_set_nofb = ipu_crtc_mode_set_nofb,
        .atomic_check = ipu_crtc_atomic_check,
        .atomic_begin = ipu_crtc_atomic_begin,
+       .atomic_flush = ipu_crtc_atomic_flush,
        .atomic_disable = ipu_crtc_atomic_disable,
        .atomic_enable = ipu_crtc_atomic_enable,
 };
index 57ed56d..d9113fa 100644 (file)
@@ -22,6 +22,7 @@
 #include <drm/drm_plane_helper.h>
 
 #include "video/imx-ipu-v3.h"
+#include "imx-drm.h"
 #include "ipuv3-plane.h"
 
 struct ipu_plane_state {
@@ -272,7 +273,7 @@ static void ipu_plane_destroy(struct drm_plane *plane)
        kfree(ipu_plane);
 }
 
-void ipu_plane_state_reset(struct drm_plane *plane)
+static void ipu_plane_state_reset(struct drm_plane *plane)
 {
        struct ipu_plane_state *ipu_state;
 
@@ -292,7 +293,8 @@ void ipu_plane_state_reset(struct drm_plane *plane)
        plane->state = &ipu_state->base;
 }
 
-struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *
+ipu_plane_duplicate_state(struct drm_plane *plane)
 {
        struct ipu_plane_state *state;
 
@@ -306,8 +308,8 @@ struct drm_plane_state *ipu_plane_duplicate_state(struct drm_plane *plane)
        return &state->base;
 }
 
-void ipu_plane_destroy_state(struct drm_plane *plane,
-                            struct drm_plane_state *state)
+static void ipu_plane_destroy_state(struct drm_plane *plane,
+                                   struct drm_plane_state *state)
 {
        struct ipu_plane_state *ipu_state = to_ipu_plane_state(state);
 
index 5155f01..0552020 100644 (file)
@@ -36,6 +36,7 @@
 #include "meson_venc.h"
 #include "meson_vpp.h"
 #include "meson_viu.h"
+#include "meson_canvas.h"
 #include "meson_registers.h"
 
 /* CRTC definition */
@@ -192,6 +193,11 @@ void meson_crtc_irq(struct meson_drm *priv)
                } else
                        meson_vpp_disable_interlace_vscaler_osd1(priv);
 
+               meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
+                          priv->viu.osd1_addr, priv->viu.osd1_stride,
+                          priv->viu.osd1_height, MESON_CANVAS_WRAP_NONE,
+                          MESON_CANVAS_BLKMODE_LINEAR);
+
                /* Enable OSD1 */
                writel_bits_relaxed(VPP_OSD1_POSTBLEND, VPP_OSD1_POSTBLEND,
                                    priv->io_base + _REG(VPP_MISC));
index 5e8b392..8450d6a 100644 (file)
@@ -43,6 +43,9 @@ struct meson_drm {
                bool osd1_commit;
                uint32_t osd1_ctrl_stat;
                uint32_t osd1_blk0_cfg[5];
+               uint32_t osd1_addr;
+               uint32_t osd1_stride;
+               uint32_t osd1_height;
        } viu;
 
        struct {
index d0a6ac8..27bd350 100644 (file)
@@ -164,10 +164,9 @@ static void meson_plane_atomic_update(struct drm_plane *plane,
        /* Update Canvas with buffer address */
        gem = drm_fb_cma_get_gem_obj(fb, 0);
 
-       meson_canvas_setup(priv, MESON_CANVAS_ID_OSD1,
-                          gem->paddr, fb->pitches[0],
-                          fb->height, MESON_CANVAS_WRAP_NONE,
-                          MESON_CANVAS_BLKMODE_LINEAR);
+       priv->viu.osd1_addr = gem->paddr;
+       priv->viu.osd1_stride = fb->pitches[0];
+       priv->viu.osd1_height = fb->height;
 
        spin_unlock_irqrestore(&priv->drm->event_lock, flags);
 }
index 3e9bba4..6d8e3a9 100644 (file)
@@ -680,7 +680,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
        } else {
                dev_info(&pdev->dev,
                         "no iommu, fallback to phys contig buffers for scanout\n");
-               aspace = NULL;;
+               aspace = NULL;
        }
 
        pm_runtime_put_sync(&pdev->dev);
index 380f340..debbbf0 100644 (file)
@@ -134,7 +134,7 @@ nv50_get_intensity(struct backlight_device *bd)
        struct nouveau_encoder *nv_encoder = bl_get_data(bd);
        struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
        struct nvif_object *device = &drm->client.device.object;
-       int or = nv_encoder->or;
+       int or = ffs(nv_encoder->dcb->or) - 1;
        u32 div = 1025;
        u32 val;
 
@@ -149,7 +149,7 @@ nv50_set_intensity(struct backlight_device *bd)
        struct nouveau_encoder *nv_encoder = bl_get_data(bd);
        struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
        struct nvif_object *device = &drm->client.device.object;
-       int or = nv_encoder->or;
+       int or = ffs(nv_encoder->dcb->or) - 1;
        u32 div = 1025;
        u32 val = (bd->props.brightness * div) / 100;
 
@@ -170,7 +170,7 @@ nva3_get_intensity(struct backlight_device *bd)
        struct nouveau_encoder *nv_encoder = bl_get_data(bd);
        struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
        struct nvif_object *device = &drm->client.device.object;
-       int or = nv_encoder->or;
+       int or = ffs(nv_encoder->dcb->or) - 1;
        u32 div, val;
 
        div  = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or));
@@ -188,7 +188,7 @@ nva3_set_intensity(struct backlight_device *bd)
        struct nouveau_encoder *nv_encoder = bl_get_data(bd);
        struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev);
        struct nvif_object *device = &drm->client.device.object;
-       int or = nv_encoder->or;
+       int or = ffs(nv_encoder->dcb->or) - 1;
        u32 div, val;
 
        div = nvif_rd32(device, NV50_PDISP_SOR_PWM_DIV(or));
@@ -228,7 +228,7 @@ nv50_backlight_init(struct drm_connector *connector)
                        return -ENODEV;
        }
 
-       if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or)))
+       if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(ffs(nv_encoder->dcb->or) - 1)))
                return 0;
 
        if (drm->client.device.info.chipset <= 0xa0 ||
@@ -268,13 +268,13 @@ nouveau_backlight_init(struct drm_device *dev)
        struct nvif_device *device = &drm->client.device;
        struct drm_connector *connector;
 
+       INIT_LIST_HEAD(&drm->bl_connectors);
+
        if (apple_gmux_present()) {
                NV_INFO(drm, "Apple GMUX detected: not registering Nouveau backlight interface\n");
                return 0;
        }
 
-       INIT_LIST_HEAD(&drm->bl_connectors);
-
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
                    connector->connector_type != DRM_MODE_CONNECTOR_eDP)
index 69d6e61..6ed9cb0 100644 (file)
@@ -570,9 +570,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
                nv_connector->edid = NULL;
        }
 
-       ret = pm_runtime_get_sync(connector->dev->dev);
-       if (ret < 0 && ret != -EACCES)
-               return conn_status;
+       /* Outputs are only polled while runtime active, so acquiring a
+        * runtime PM ref here is unnecessary (and would deadlock upon
+        * runtime suspend because it waits for polling to finish).
+        */
+       if (!drm_kms_helper_is_poll_worker()) {
+               ret = pm_runtime_get_sync(connector->dev->dev);
+               if (ret < 0 && ret != -EACCES)
+                       return conn_status;
+       }
 
        nv_encoder = nouveau_connector_ddc_detect(connector);
        if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
@@ -647,8 +653,10 @@ detect_analog:
 
  out:
 
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return conn_status;
 }
index dd8d435..caddce8 100644 (file)
@@ -4477,6 +4477,7 @@ nv50_display_create(struct drm_device *dev)
        nouveau_display(dev)->fini = nv50_display_fini;
        disp->disp = &nouveau_display(dev)->disp;
        dev->mode_config.funcs = &nv50_disp_func;
+       dev->driver->driver_features |= DRIVER_PREFER_XBGR_30BPP;
        if (nouveau_atomic)
                dev->driver->driver_features |= DRIVER_ATOMIC;
 
index 93946dc..1c12e58 100644 (file)
@@ -1354,7 +1354,7 @@ nvkm_vmm_get_locked(struct nvkm_vmm *vmm, bool getref, bool mapref, bool sparse,
 
                tail = this->addr + this->size;
                if (vmm->func->page_block && next && next->page != p)
-                       tail = ALIGN_DOWN(addr, vmm->func->page_block);
+                       tail = ALIGN_DOWN(tail, vmm->func->page_block);
 
                if (addr <= tail && tail - addr >= size) {
                        rb_erase(&this->tree, &vmm->free);
index bf62303..3695cde 100644 (file)
@@ -301,7 +301,7 @@ nvkm_therm_attr_set(struct nvkm_therm *therm,
 void
 nvkm_therm_clkgate_enable(struct nvkm_therm *therm)
 {
-       if (!therm->func->clkgate_enable || !therm->clkgating_enabled)
+       if (!therm || !therm->func->clkgate_enable || !therm->clkgating_enabled)
                return;
 
        nvkm_debug(&therm->subdev,
@@ -312,7 +312,7 @@ nvkm_therm_clkgate_enable(struct nvkm_therm *therm)
 void
 nvkm_therm_clkgate_fini(struct nvkm_therm *therm, bool suspend)
 {
-       if (!therm->func->clkgate_fini || !therm->clkgating_enabled)
+       if (!therm || !therm->func->clkgate_fini || !therm->clkgating_enabled)
                return;
 
        nvkm_debug(&therm->subdev,
@@ -395,7 +395,7 @@ void
 nvkm_therm_clkgate_init(struct nvkm_therm *therm,
                        const struct nvkm_therm_clkgate_pack *p)
 {
-       if (!therm->func->clkgate_init || !therm->clkgating_enabled)
+       if (!therm || !therm->func->clkgate_init || !therm->clkgating_enabled)
                return;
 
        therm->func->clkgate_init(therm, p);
index d3045a3..7c73bc7 100644 (file)
@@ -3221,35 +3221,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
        case CHIP_KAVERI:
                rdev->config.cik.max_shader_engines = 1;
                rdev->config.cik.max_tile_pipes = 4;
-               if ((rdev->pdev->device == 0x1304) ||
-                   (rdev->pdev->device == 0x1305) ||
-                   (rdev->pdev->device == 0x130C) ||
-                   (rdev->pdev->device == 0x130F) ||
-                   (rdev->pdev->device == 0x1310) ||
-                   (rdev->pdev->device == 0x1311) ||
-                   (rdev->pdev->device == 0x131C)) {
-                       rdev->config.cik.max_cu_per_sh = 8;
-                       rdev->config.cik.max_backends_per_se = 2;
-               } else if ((rdev->pdev->device == 0x1309) ||
-                          (rdev->pdev->device == 0x130A) ||
-                          (rdev->pdev->device == 0x130D) ||
-                          (rdev->pdev->device == 0x1313) ||
-                          (rdev->pdev->device == 0x131D)) {
-                       rdev->config.cik.max_cu_per_sh = 6;
-                       rdev->config.cik.max_backends_per_se = 2;
-               } else if ((rdev->pdev->device == 0x1306) ||
-                          (rdev->pdev->device == 0x1307) ||
-                          (rdev->pdev->device == 0x130B) ||
-                          (rdev->pdev->device == 0x130E) ||
-                          (rdev->pdev->device == 0x1315) ||
-                          (rdev->pdev->device == 0x1318) ||
-                          (rdev->pdev->device == 0x131B)) {
-                       rdev->config.cik.max_cu_per_sh = 4;
-                       rdev->config.cik.max_backends_per_se = 1;
-               } else {
-                       rdev->config.cik.max_cu_per_sh = 3;
-                       rdev->config.cik.max_backends_per_se = 1;
-               }
+               rdev->config.cik.max_cu_per_sh = 8;
+               rdev->config.cik.max_backends_per_se = 2;
                rdev->config.cik.max_sh_per_se = 1;
                rdev->config.cik.max_texture_channel_caches = 4;
                rdev->config.cik.max_gprs = 256;
index 5012f5e..df9469a 100644 (file)
@@ -90,25 +90,18 @@ void radeon_connector_hotplug(struct drm_connector *connector)
                /* don't do anything if sink is not display port, i.e.,
                 * passive dp->(dvi|hdmi) adaptor
                 */
-               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-                       int saved_dpms = connector->dpms;
-                       /* Only turn off the display if it's physically disconnected */
-                       if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
-                       } else if (radeon_dp_needs_link_train(radeon_connector)) {
-                               /* Don't try to start link training before we
-                                * have the dpcd */
-                               if (!radeon_dp_getdpcd(radeon_connector))
-                                       return;
-
-                               /* set it to OFF so that drm_helper_connector_dpms()
-                                * won't return immediately since the current state
-                                * is ON at this point.
-                                */
-                               connector->dpms = DRM_MODE_DPMS_OFF;
-                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
-                       }
-                       connector->dpms = saved_dpms;
+               if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT &&
+                   radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) &&
+                   radeon_dp_needs_link_train(radeon_connector)) {
+                       /* Don't start link training before we have the DPCD */
+                       if (!radeon_dp_getdpcd(radeon_connector))
+                               return;
+
+                       /* Turn the connector off and back on immediately, which
+                        * will trigger link training
+                        */
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
                }
        }
 }
@@ -899,9 +892,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (encoder) {
                struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
@@ -924,8 +919,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force)
        /* check acpi lid status ??? */
 
        radeon_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
+
        return ret;
 }
 
@@ -1039,9 +1038,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        int r;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        encoder = radeon_best_single_encoder(connector);
        if (!encoder)
@@ -1108,8 +1109,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force)
        radeon_connector_update_scratch_regs(connector, ret);
 
 out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
@@ -1173,9 +1176,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
        if (!radeon_connector->dac_load_detect)
                return ret;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        encoder = radeon_best_single_encoder(connector);
        if (!encoder)
@@ -1187,8 +1192,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force)
        if (ret == connector_status_connected)
                ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false);
        radeon_connector_update_scratch_regs(connector, ret);
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
+
        return ret;
 }
 
@@ -1251,9 +1260,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
        enum drm_connector_status ret = connector_status_disconnected;
        bool dret = false, broken_edid = false;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (radeon_connector->detected_hpd_without_ddc) {
                force = true;
@@ -1436,8 +1447,10 @@ out:
        }
 
 exit:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
@@ -1688,9 +1701,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        if (radeon_dig_connector->is_mst)
                return connector_status_disconnected;
 
-       r = pm_runtime_get_sync(connector->dev->dev);
-       if (r < 0)
-               return connector_status_disconnected;
+       if (!drm_kms_helper_is_poll_worker()) {
+               r = pm_runtime_get_sync(connector->dev->dev);
+               if (r < 0)
+                       return connector_status_disconnected;
+       }
 
        if (!force && radeon_check_hpd_status_unchanged(connector)) {
                ret = connector->status;
@@ -1777,8 +1792,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
        }
 
 out:
-       pm_runtime_mark_last_busy(connector->dev->dev);
-       pm_runtime_put_autosuspend(connector->dev->dev);
+       if (!drm_kms_helper_is_poll_worker()) {
+               pm_runtime_mark_last_busy(connector->dev->dev);
+               pm_runtime_put_autosuspend(connector->dev->dev);
+       }
 
        return ret;
 }
index 8d3e3d2..7828a5e 100644 (file)
@@ -1365,6 +1365,10 @@ int radeon_device_init(struct radeon_device *rdev,
        if ((rdev->flags & RADEON_IS_PCI) &&
            (rdev->family <= CHIP_RS740))
                rdev->need_dma32 = true;
+#ifdef CONFIG_PPC64
+       if (rdev->family == CHIP_CEDAR)
+               rdev->need_dma32 = true;
+#endif
 
        dma_bits = rdev->need_dma32 ? 32 : 40;
        r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(dma_bits));
index a9962ff..27d8e7d 100644 (file)
@@ -34,8 +34,6 @@ void radeon_gem_object_free(struct drm_gem_object *gobj)
        struct radeon_bo *robj = gem_to_radeon_bo(gobj);
 
        if (robj) {
-               if (robj->gem_base.import_attach)
-                       drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg);
                radeon_mn_unregister(robj);
                radeon_bo_unref(&robj);
        }
index 15404af..31f5ad6 100644 (file)
@@ -82,6 +82,8 @@ static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
        mutex_unlock(&bo->rdev->gem.mutex);
        radeon_bo_clear_surface_reg(bo);
        WARN_ON_ONCE(!list_empty(&bo->va));
+       if (bo->gem_base.import_attach)
+               drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg);
        drm_gem_object_release(&bo->gem_base);
        kfree(bo);
 }
index 326ad06..4b65425 100644 (file)
@@ -47,7 +47,6 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev);
 static bool radeon_pm_debug_check_in_vbl(struct radeon_device *rdev, bool finish);
 static void radeon_pm_update_profile(struct radeon_device *rdev);
 static void radeon_pm_set_clocks(struct radeon_device *rdev);
-static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev);
 
 int radeon_pm_get_type_index(struct radeon_device *rdev,
                             enum radeon_pm_state_type ps_type,
@@ -80,8 +79,6 @@ void radeon_pm_acpi_event_handler(struct radeon_device *rdev)
                                radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power);
                }
                mutex_unlock(&rdev->pm.mutex);
-               /* allow new DPM state to be picked */
-               radeon_pm_compute_clocks_dpm(rdev);
        } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
                if (rdev->pm.profile == PM_PROFILE_AUTO) {
                        mutex_lock(&rdev->pm.mutex);
@@ -885,8 +882,7 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
                dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
        /* balanced states don't exist at the moment */
        if (dpm_state == POWER_STATE_TYPE_BALANCED)
-               dpm_state = rdev->pm.dpm.ac_power ?
-                       POWER_STATE_TYPE_PERFORMANCE : POWER_STATE_TYPE_BATTERY;
+               dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 
 restart_search:
        /* Pick the best power state based on current conditions */
index 2c18996..0d95888 100644 (file)
@@ -461,7 +461,7 @@ void drm_sched_hw_job_reset(struct drm_gpu_scheduler *sched, struct drm_sched_jo
 {
        struct drm_sched_job *s_job;
        struct drm_sched_entity *entity, *tmp;
-       int i;;
+       int i;
 
        spin_lock(&sched->job_list_lock);
        list_for_each_entry_reverse(s_job, &sched->ring_mirror_list, node) {
index 5decae0..78cbc31 100644 (file)
@@ -93,6 +93,8 @@ static void sun4i_crtc_atomic_disable(struct drm_crtc *crtc,
 
        DRM_DEBUG_DRIVER("Disabling the CRTC\n");
 
+       drm_crtc_vblank_off(crtc);
+
        sun4i_tcon_set_status(scrtc->tcon, encoder, false);
 
        if (crtc->state->event && !crtc->state->active) {
@@ -113,6 +115,8 @@ static void sun4i_crtc_atomic_enable(struct drm_crtc *crtc,
        DRM_DEBUG_DRIVER("Enabling the CRTC\n");
 
        sun4i_tcon_set_status(scrtc->tcon, encoder, true);
+
+       drm_crtc_vblank_on(crtc);
 }
 
 static void sun4i_crtc_mode_set_nofb(struct drm_crtc *crtc)
index 023f39b..e36004f 100644 (file)
@@ -132,10 +132,13 @@ static int sun4i_dclk_get_phase(struct clk_hw *hw)
 static int sun4i_dclk_set_phase(struct clk_hw *hw, int degrees)
 {
        struct sun4i_dclk *dclk = hw_to_dclk(hw);
+       u32 val = degrees / 120;
+
+       val <<= 28;
 
        regmap_update_bits(dclk->regmap, SUN4I_TCON0_IO_POL_REG,
                           GENMASK(29, 28),
-                          degrees / 120);
+                          val);
 
        return 0;
 }
index 4570da0..d9a71f3 100644 (file)
@@ -111,7 +111,7 @@ static int sun4i_drv_bind(struct device *dev)
        /* drm_vblank_init calls kcalloc, which can fail */
        ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
        if (ret)
-               goto free_mem_region;
+               goto cleanup_mode_config;
 
        drm->irq_enabled = true;
 
@@ -139,7 +139,6 @@ finish_poll:
        sun4i_framebuffer_free(drm);
 cleanup_mode_config:
        drm_mode_config_cleanup(drm);
-free_mem_region:
        of_reserved_mem_device_release(dev);
 free_drm:
        drm_dev_unref(drm);
index 500b6fb..fa4bcd0 100644 (file)
@@ -538,7 +538,8 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
                                             &sun4i_hdmi_regmap_config);
        if (IS_ERR(hdmi->regmap)) {
                dev_err(dev, "Couldn't create HDMI encoder regmap\n");
-               return PTR_ERR(hdmi->regmap);
+               ret = PTR_ERR(hdmi->regmap);
+               goto err_disable_mod_clk;
        }
 
        ret = sun4i_tmds_create(hdmi);
@@ -551,7 +552,8 @@ static int sun4i_hdmi_bind(struct device *dev, struct device *master,
                hdmi->ddc_parent_clk = devm_clk_get(dev, "ddc");
                if (IS_ERR(hdmi->ddc_parent_clk)) {
                        dev_err(dev, "Couldn't get the HDMI DDC clock\n");
-                       return PTR_ERR(hdmi->ddc_parent_clk);
+                       ret = PTR_ERR(hdmi->ddc_parent_clk);
+                       goto err_disable_mod_clk;
                }
        } else {
                hdmi->ddc_parent_clk = hdmi->tmds_clk;
index 832f8f9..b8da5a5 100644 (file)
@@ -92,6 +92,8 @@ static int sun4i_rgb_mode_valid(struct drm_connector *connector,
 
        DRM_DEBUG_DRIVER("Vertical parameters OK\n");
 
+       tcon->dclk_min_div = 6;
+       tcon->dclk_max_div = 127;
        rounded_rate = clk_round_rate(tcon->dclk, rate);
        if (rounded_rate < rate)
                return MODE_CLOCK_LOW;
index 3c15cf2..a818ca4 100644 (file)
@@ -101,10 +101,13 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
                return;
        }
 
-       if (enabled)
+       if (enabled) {
                clk_prepare_enable(clk);
-       else
+               clk_rate_exclusive_get(clk);
+       } else {
+               clk_rate_exclusive_put(clk);
                clk_disable_unprepare(clk);
+       }
 }
 
 static void sun4i_tcon_lvds_set_status(struct sun4i_tcon *tcon,
@@ -335,6 +338,9 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
        regmap_update_bits(tcon->regs, SUN4I_TCON_GCTL_REG,
                           SUN4I_TCON_GCTL_IOMAP_MASK,
                           SUN4I_TCON_GCTL_IOMAP_TCON0);
+
+       /* Enable the output on the pins */
+       regmap_write(tcon->regs, SUN4I_TCON0_IO_TRI_REG, 0xe0000000);
 }
 
 static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
@@ -870,52 +876,56 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                return ret;
        }
 
-       /*
-        * This can only be made optional since we've had DT nodes
-        * without the LVDS reset properties.
-        *
-        * If the property is missing, just disable LVDS, and print a
-        * warning.
-        */
-       tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
-       if (IS_ERR(tcon->lvds_rst)) {
-               dev_err(dev, "Couldn't get our reset line\n");
-               return PTR_ERR(tcon->lvds_rst);
-       } else if (tcon->lvds_rst) {
-               has_lvds_rst = true;
-               reset_control_reset(tcon->lvds_rst);
-       } else {
-               has_lvds_rst = false;
-       }
+       if (tcon->quirks->supports_lvds) {
+               /*
+                * This can only be made optional since we've had DT
+                * nodes without the LVDS reset properties.
+                *
+                * If the property is missing, just disable LVDS, and
+                * print a warning.
+                */
+               tcon->lvds_rst = devm_reset_control_get_optional(dev, "lvds");
+               if (IS_ERR(tcon->lvds_rst)) {
+                       dev_err(dev, "Couldn't get our reset line\n");
+                       return PTR_ERR(tcon->lvds_rst);
+               } else if (tcon->lvds_rst) {
+                       has_lvds_rst = true;
+                       reset_control_reset(tcon->lvds_rst);
+               } else {
+                       has_lvds_rst = false;
+               }
 
-       /*
-        * This can only be made optional since we've had DT nodes
-        * without the LVDS reset properties.
-        *
-        * If the property is missing, just disable LVDS, and print a
-        * warning.
-        */
-       if (tcon->quirks->has_lvds_alt) {
-               tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
-               if (IS_ERR(tcon->lvds_pll)) {
-                       if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
-                               has_lvds_alt = false;
+               /*
+                * This can only be made optional since we've had DT
+                * nodes without the LVDS reset properties.
+                *
+                * If the property is missing, just disable LVDS, and
+                * print a warning.
+                */
+               if (tcon->quirks->has_lvds_alt) {
+                       tcon->lvds_pll = devm_clk_get(dev, "lvds-alt");
+                       if (IS_ERR(tcon->lvds_pll)) {
+                               if (PTR_ERR(tcon->lvds_pll) == -ENOENT) {
+                                       has_lvds_alt = false;
+                               } else {
+                                       dev_err(dev, "Couldn't get the LVDS PLL\n");
+                                       return PTR_ERR(tcon->lvds_pll);
+                               }
                        } else {
-                               dev_err(dev, "Couldn't get the LVDS PLL\n");
-                               return PTR_ERR(tcon->lvds_pll);
+                               has_lvds_alt = true;
                        }
-               } else {
-                       has_lvds_alt = true;
                }
-       }
 
-       if (!has_lvds_rst || (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
-               dev_warn(dev,
-                        "Missing LVDS properties, Please upgrade your DT\n");
-               dev_warn(dev, "LVDS output disabled\n");
-               can_lvds = false;
+               if (!has_lvds_rst ||
+                   (tcon->quirks->has_lvds_alt && !has_lvds_alt)) {
+                       dev_warn(dev, "Missing LVDS properties, Please upgrade your DT\n");
+                       dev_warn(dev, "LVDS output disabled\n");
+                       can_lvds = false;
+               } else {
+                       can_lvds = true;
+               }
        } else {
-               can_lvds = true;
+               can_lvds = false;
        }
 
        ret = sun4i_tcon_init_clocks(dev, tcon);
@@ -1134,7 +1144,7 @@ static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
 };
 
 static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
-       /* nothing is supported */
+       .supports_lvds          = true,
 };
 
 static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
index b761c7b..278700c 100644 (file)
@@ -175,6 +175,7 @@ struct sun4i_tcon_quirks {
        bool    has_channel_1;  /* a33 does not have channel 1 */
        bool    has_lvds_alt;   /* Does the LVDS clock have a parent other than the TCON clock? */
        bool    needs_de_be_mux; /* sun6i needs mux to select backend */
+       bool    supports_lvds;   /* Does the TCON support an LVDS output? */
 
        /* callback to handle tcon muxing options */
        int     (*set_mux)(struct sun4i_tcon *, const struct drm_encoder *);
index b8403ed..90b25ce 100644 (file)
@@ -1903,8 +1903,12 @@ cleanup:
        if (!IS_ERR(primary))
                drm_plane_cleanup(primary);
 
-       if (group && tegra->domain) {
-               iommu_detach_group(tegra->domain, group);
+       if (group && dc->domain) {
+               if (group == tegra->group) {
+                       iommu_detach_group(dc->domain, group);
+                       tegra->group = NULL;
+               }
+
                dc->domain = NULL;
        }
 
@@ -1913,8 +1917,10 @@ cleanup:
 
 static int tegra_dc_exit(struct host1x_client *client)
 {
+       struct drm_device *drm = dev_get_drvdata(client->parent);
        struct iommu_group *group = iommu_group_get(client->dev);
        struct tegra_dc *dc = host1x_client_to_dc(client);
+       struct tegra_drm *tegra = drm->dev_private;
        int err;
 
        devm_free_irq(dc->dev, dc->irq, dc);
@@ -1926,7 +1932,11 @@ static int tegra_dc_exit(struct host1x_client *client)
        }
 
        if (group && dc->domain) {
-               iommu_detach_group(dc->domain, group);
+               if (group == tegra->group) {
+                       iommu_detach_group(dc->domain, group);
+                       tegra->group = NULL;
+               }
+
                dc->domain = NULL;
        }
 
@@ -1999,9 +2009,9 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
        .coupled_pm = false,
        .has_nvdisplay = false,
        .num_primary_formats = ARRAY_SIZE(tegra124_primary_formats),
-       .primary_formats = tegra114_primary_formats,
+       .primary_formats = tegra124_primary_formats,
        .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),
-       .overlay_formats = tegra114_overlay_formats,
+       .overlay_formats = tegra124_overlay_formats,
 };
 
 static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
@@ -2150,7 +2160,7 @@ static int tegra_dc_couple(struct tegra_dc *dc)
                struct device_link *link;
                struct device *partner;
 
-               partner = driver_find_device(dc->dev->driver, NULL, 0,
+               partner = driver_find_device(dc->dev->driver, NULL, NULL,
                                             tegra_dc_match_by_pipe);
                if (!partner)
                        return -EPROBE_DEFER;
index d50bddb..7fcf4a2 100644 (file)
@@ -250,6 +250,7 @@ static void tegra_drm_unload(struct drm_device *drm)
 
        drm_kms_helper_poll_fini(drm);
        tegra_drm_fb_exit(drm);
+       drm_atomic_helper_shutdown(drm);
        drm_mode_config_cleanup(drm);
 
        err = host1x_device_exit(device);
index 4d2ed96..87c5d89 100644 (file)
@@ -1072,7 +1072,6 @@ static int tegra_dsi_exit(struct host1x_client *client)
        struct tegra_dsi *dsi = host1x_client_to_dsi(client);
 
        tegra_output_exit(&dsi->output);
-       regulator_disable(dsi->vdd);
 
        return 0;
 }
index 36a06a9..94dac79 100644 (file)
@@ -297,6 +297,10 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
        case WIN_COLOR_DEPTH_B8G8R8X8:
                *alpha = WIN_COLOR_DEPTH_B8G8R8A8;
                return 0;
+
+       case WIN_COLOR_DEPTH_B5G6R5:
+               *alpha = opaque;
+               return 0;
        }
 
        return -EINVAL;
@@ -330,9 +334,6 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,
        unsigned int zpos[2];
        unsigned int i;
 
-       for (i = 0; i < 3; i++)
-               state->dependent[i] = false;
-
        for (i = 0; i < 2; i++)
                zpos[i] = 0;
 
@@ -346,6 +347,8 @@ void tegra_plane_check_dependent(struct tegra_plane *tegra,
 
                index = tegra_plane_get_overlap_index(tegra, p);
 
+               state->dependent[index] = false;
+
                /*
                 * If any of the other planes is on top of this plane and uses
                 * a format with an alpha component, mark this plane as being
index b5b335c..2ebdc6d 100644 (file)
@@ -159,10 +159,15 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        unsigned long start = vma->vm_start;
        unsigned long size = vma->vm_end - vma->vm_start;
-       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       unsigned long offset;
        unsigned long page, pos;
 
-       if (offset + size > info->fix.smem_len)
+       if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+               return -EINVAL;
+
+       offset = vma->vm_pgoff << PAGE_SHIFT;
+
+       if (offset > info->fix.smem_len || size > info->fix.smem_len - offset)
                return -EINVAL;
 
        pos = (unsigned long)info->fix.smem_start + offset;
index 5720a0d..677ac16 100644 (file)
@@ -197,6 +197,9 @@ static int virtio_gpu_getparam_ioctl(struct drm_device *dev, void *data,
        case VIRTGPU_PARAM_3D_FEATURES:
                value = vgdev->has_virgl_3d == true ? 1 : 0;
                break;
+       case VIRTGPU_PARAM_CAPSET_QUERY_FIX:
+               value = 1;
+               break;
        default:
                return -EINVAL;
        }
@@ -472,7 +475,7 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
 {
        struct virtio_gpu_device *vgdev = dev->dev_private;
        struct drm_virtgpu_get_caps *args = data;
-       int size;
+       unsigned size, host_caps_size;
        int i;
        int found_valid = -1;
        int ret;
@@ -481,6 +484,10 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
        if (vgdev->num_capsets == 0)
                return -ENOSYS;
 
+       /* don't allow userspace to pass 0 */
+       if (args->size == 0)
+               return -EINVAL;
+
        spin_lock(&vgdev->display_info_lock);
        for (i = 0; i < vgdev->num_capsets; i++) {
                if (vgdev->capsets[i].id == args->cap_set_id) {
@@ -496,11 +503,9 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
                return -EINVAL;
        }
 
-       size = vgdev->capsets[found_valid].max_size;
-       if (args->size > size) {
-               spin_unlock(&vgdev->display_info_lock);
-               return -EINVAL;
-       }
+       host_caps_size = vgdev->capsets[found_valid].max_size;
+       /* only copy to user the minimum of the host caps size or the guest caps size */
+       size = min(args->size, host_caps_size);
 
        list_for_each_entry(cache_ent, &vgdev->cap_cache, head) {
                if (cache_ent->id == args->cap_set_id &&
index 184340d..86d25f1 100644 (file)
@@ -1337,6 +1337,19 @@ static void __vmw_svga_disable(struct vmw_private *dev_priv)
  */
 void vmw_svga_disable(struct vmw_private *dev_priv)
 {
+       /*
+        * Disabling SVGA will turn off device modesetting capabilities, so
+        * notify KMS about that so that it doesn't cache atomic state that
+        * isn't valid anymore, for example crtcs turned on.
+        * Strictly we'd want to do this under the SVGA lock (or an SVGA mutex),
+        * but vmw_kms_lost_device() takes the reservation sem and thus we'll
+        * end up with lock order reversal. Thus, a master may actually perform
+        * a new modeset just after we call vmw_kms_lost_device() and race with
+        * vmw_svga_disable(), but that should at worst cause atomic KMS state
+        * to be inconsistent with the device, causing modesetting problems.
+        *
+        */
+       vmw_kms_lost_device(dev_priv->dev);
        ttm_write_lock(&dev_priv->reservation_sem, false);
        spin_lock(&dev_priv->svga_lock);
        if (dev_priv->bdev.man[TTM_PL_VRAM].use_type) {
index d08753e..9116fe8 100644 (file)
@@ -938,6 +938,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
 int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv);
 void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv);
+void vmw_kms_lost_device(struct drm_device *dev);
 
 int vmw_dumb_create(struct drm_file *file_priv,
                    struct drm_device *dev,
index ead6101..3c824fd 100644 (file)
@@ -31,7 +31,6 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_rect.h>
 
-
 /* Might need a hrtimer here? */
 #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
 
@@ -2517,9 +2516,12 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
  * Helper to be used if an error forces the caller to undo the actions of
  * vmw_kms_helper_resource_prepare.
  */
-void vmw_kms_helper_resource_revert(struct vmw_resource *res)
+void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx)
 {
-       vmw_kms_helper_buffer_revert(res->backup);
+       struct vmw_resource *res = ctx->res;
+
+       vmw_kms_helper_buffer_revert(ctx->buf);
+       vmw_dmabuf_unreference(&ctx->buf);
        vmw_resource_unreserve(res, false, NULL, 0);
        mutex_unlock(&res->dev_priv->cmdbuf_mutex);
 }
@@ -2536,10 +2538,14 @@ void vmw_kms_helper_resource_revert(struct vmw_resource *res)
  * interrupted by a signal.
  */
 int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
-                                   bool interruptible)
+                                   bool interruptible,
+                                   struct vmw_validation_ctx *ctx)
 {
        int ret = 0;
 
+       ctx->buf = NULL;
+       ctx->res = res;
+
        if (interruptible)
                ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex);
        else
@@ -2558,6 +2564,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
                                                    res->dev_priv->has_mob);
                if (ret)
                        goto out_unreserve;
+
+               ctx->buf = vmw_dmabuf_reference(res->backup);
        }
        ret = vmw_resource_validate(res);
        if (ret)
@@ -2565,7 +2573,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
        return 0;
 
 out_revert:
-       vmw_kms_helper_buffer_revert(res->backup);
+       vmw_kms_helper_buffer_revert(ctx->buf);
 out_unreserve:
        vmw_resource_unreserve(res, false, NULL, 0);
 out_unlock:
@@ -2581,11 +2589,13 @@ out_unlock:
  * @out_fence: Optional pointer to a fence pointer. If non-NULL, a
  * ref-counted fence pointer is returned here.
  */
-void vmw_kms_helper_resource_finish(struct vmw_resource *res,
-                            struct vmw_fence_obj **out_fence)
+void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
+                                   struct vmw_fence_obj **out_fence)
 {
-       if (res->backup || out_fence)
-               vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup,
+       struct vmw_resource *res = ctx->res;
+
+       if (ctx->buf || out_fence)
+               vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf,
                                             out_fence, NULL);
 
        vmw_resource_unreserve(res, false, NULL, 0);
@@ -2851,3 +2861,14 @@ int vmw_kms_set_config(struct drm_mode_set *set,
 
        return drm_atomic_helper_set_config(set, ctx);
 }
+
+
+/**
+ * vmw_kms_lost_device - Notify kms that modesetting capabilities will be lost
+ *
+ * @dev: Pointer to the drm device
+ */
+void vmw_kms_lost_device(struct drm_device *dev)
+{
+       drm_atomic_helper_shutdown(dev);
+}
index cd9da2d..3d2ca28 100644 (file)
@@ -240,6 +240,11 @@ struct vmw_display_unit {
        int set_gui_y;
 };
 
+struct vmw_validation_ctx {
+       struct vmw_resource *res;
+       struct vmw_dma_buffer *buf;
+};
+
 #define vmw_crtc_to_du(x) \
        container_of(x, struct vmw_display_unit, crtc)
 #define vmw_connector_to_du(x) \
@@ -296,9 +301,10 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv,
                                  struct drm_vmw_fence_rep __user *
                                  user_fence_rep);
 int vmw_kms_helper_resource_prepare(struct vmw_resource *res,
-                                   bool interruptible);
-void vmw_kms_helper_resource_revert(struct vmw_resource *res);
-void vmw_kms_helper_resource_finish(struct vmw_resource *res,
+                                   bool interruptible,
+                                   struct vmw_validation_ctx *ctx);
+void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx);
+void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx,
                                    struct vmw_fence_obj **out_fence);
 int vmw_kms_readback(struct vmw_private *dev_priv,
                     struct drm_file *file_priv,
@@ -439,5 +445,4 @@ int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
 
 int vmw_kms_set_config(struct drm_mode_set *set,
                       struct drm_modeset_acquire_ctx *ctx);
-
 #endif
index 63a4cd7..3ec9eae 100644 (file)
@@ -909,12 +909,13 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
        struct vmw_framebuffer_surface *vfbs =
                container_of(framebuffer, typeof(*vfbs), base);
        struct vmw_kms_sou_surface_dirty sdirty;
+       struct vmw_validation_ctx ctx;
        int ret;
 
        if (!srf)
                srf = &vfbs->surface->res;
 
-       ret = vmw_kms_helper_resource_prepare(srf, true);
+       ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
        if (ret)
                return ret;
 
@@ -933,7 +934,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv,
        ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
                                   dest_x, dest_y, num_clips, inc,
                                   &sdirty.base);
-       vmw_kms_helper_resource_finish(srf, out_fence);
+       vmw_kms_helper_resource_finish(&ctx, out_fence);
 
        return ret;
 }
index b68d748..6b969e5 100644 (file)
@@ -980,12 +980,13 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
        struct vmw_framebuffer_surface *vfbs =
                container_of(framebuffer, typeof(*vfbs), base);
        struct vmw_stdu_dirty sdirty;
+       struct vmw_validation_ctx ctx;
        int ret;
 
        if (!srf)
                srf = &vfbs->surface->res;
 
-       ret = vmw_kms_helper_resource_prepare(srf, true);
+       ret = vmw_kms_helper_resource_prepare(srf, true, &ctx);
        if (ret)
                return ret;
 
@@ -1008,7 +1009,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
                                   dest_x, dest_y, num_clips, inc,
                                   &sdirty.base);
 out_finish:
-       vmw_kms_helper_resource_finish(srf, out_fence);
+       vmw_kms_helper_resource_finish(&ctx, out_fence);
 
        return ret;
 }
index 658fa2d..48685cd 100644 (file)
@@ -1089,7 +1089,7 @@ static void ipu_irq_handler(struct irq_desc *desc)
 {
        struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
+       static const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14};
 
        chained_irq_enter(chip, desc);
 
@@ -1102,7 +1102,7 @@ static void ipu_err_irq_handler(struct irq_desc *desc)
 {
        struct ipu_soc *ipu = irq_desc_get_handler_data(desc);
        struct irq_chip *chip = irq_desc_get_chip(desc);
-       const int int_reg[] = { 4, 5, 8, 9};
+       static const int int_reg[] = { 4, 5, 8, 9};
 
        chained_irq_enter(chip, desc);
 
index bb9c087..9f2d9ec 100644 (file)
@@ -788,12 +788,14 @@ int ipu_cpmem_set_image(struct ipuv3_channel *ch, struct ipu_image *image)
        case V4L2_PIX_FMT_SGBRG8:
        case V4L2_PIX_FMT_SGRBG8:
        case V4L2_PIX_FMT_SRGGB8:
+       case V4L2_PIX_FMT_GREY:
                offset = image->rect.left + image->rect.top * pix->bytesperline;
                break;
        case V4L2_PIX_FMT_SBGGR16:
        case V4L2_PIX_FMT_SGBRG16:
        case V4L2_PIX_FMT_SGRBG16:
        case V4L2_PIX_FMT_SRGGB16:
+       case V4L2_PIX_FMT_Y16:
                offset = image->rect.left * 2 +
                         image->rect.top * pix->bytesperline;
                break;
index 24e12b8..caa05b0 100644 (file)
@@ -288,6 +288,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
        case MEDIA_BUS_FMT_SGBRG10_1X10:
        case MEDIA_BUS_FMT_SGRBG10_1X10:
        case MEDIA_BUS_FMT_SRGGB10_1X10:
+       case MEDIA_BUS_FMT_Y10_1X10:
                cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
                cfg->mipi_dt = MIPI_DT_RAW10;
                cfg->data_width = IPU_CSI_DATA_WIDTH_10;
@@ -296,6 +297,7 @@ static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
        case MEDIA_BUS_FMT_SGBRG12_1X12:
        case MEDIA_BUS_FMT_SGRBG12_1X12:
        case MEDIA_BUS_FMT_SRGGB12_1X12:
+       case MEDIA_BUS_FMT_Y12_1X12:
                cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
                cfg->mipi_dt = MIPI_DT_RAW12;
                cfg->data_width = IPU_CSI_DATA_WIDTH_12;
index f1cec3d..0f70e88 100644 (file)
@@ -129,11 +129,14 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
                if (pre_node == pre->dev->of_node) {
                        mutex_unlock(&ipu_pre_list_mutex);
                        device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE);
+                       of_node_put(pre_node);
                        return pre;
                }
        }
        mutex_unlock(&ipu_pre_list_mutex);
 
+       of_node_put(pre_node);
+
        return NULL;
 }
 
index 067365c..83f9dd9 100644 (file)
@@ -102,11 +102,14 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
                        mutex_unlock(&ipu_prg_list_mutex);
                        device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
                        prg->id = ipu_id;
+                       of_node_put(prg_node);
                        return prg;
                }
        }
        mutex_unlock(&ipu_prg_list_mutex);
 
+       of_node_put(prg_node);
+
        return NULL;
 }
 
@@ -247,10 +250,14 @@ void ipu_prg_channel_disable(struct ipuv3_channel *ipu_chan)
 {
        int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
        struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
-       struct ipu_prg_channel *chan = &prg->chan[prg_chan];
+       struct ipu_prg_channel *chan;
        u32 val;
 
-       if (!chan->enabled || prg_chan < 0)
+       if (prg_chan < 0)
+               return;
+
+       chan = &prg->chan[prg_chan];
+       if (!chan->enabled)
                return;
 
        pm_runtime_get_sync(prg->dev);
@@ -277,13 +284,15 @@ int ipu_prg_channel_configure(struct ipuv3_channel *ipu_chan,
 {
        int prg_chan = ipu_prg_ipu_to_prg_chan(ipu_chan->num);
        struct ipu_prg *prg = ipu_chan->ipu->prg_priv;
-       struct ipu_prg_channel *chan = &prg->chan[prg_chan];
+       struct ipu_prg_channel *chan;
        u32 val;
        int ret;
 
        if (prg_chan < 0)
                return prg_chan;
 
+       chan = &prg->chan[prg_chan];
+
        if (chan->enabled) {
                ipu_pre_update(prg->pres[chan->used_pre], *eba);
                return 0;
index 43ddcdf..9454ac1 100644 (file)
 #define USB_DEVICE_ID_LD_MICROCASSYTIME                0x1033
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035
 #define USB_DEVICE_ID_LD_MICROCASSYPH          0x1038
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY    0x1040
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY      0x1042
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY      0x1043
 #define USB_DEVICE_ID_LD_JWM           0x1080
 #define USB_DEVICE_ID_LD_DMMP          0x1081
 #define USB_DEVICE_ID_LD_UMIP          0x1090
index 5f6035a..e92b77f 100644 (file)
@@ -809,6 +809,9 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
index 50e0714..8699bb9 100644 (file)
@@ -417,13 +417,24 @@ __hv_pkt_iter_next(struct vmbus_channel *channel,
 }
 EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
 
+/* How many bytes were read in this iterator cycle */
+static u32 hv_pkt_iter_bytes_read(const struct hv_ring_buffer_info *rbi,
+                                       u32 start_read_index)
+{
+       if (rbi->priv_read_index >= start_read_index)
+               return rbi->priv_read_index - start_read_index;
+       else
+               return rbi->ring_datasize - start_read_index +
+                       rbi->priv_read_index;
+}
+
 /*
  * Update host ring buffer after iterating over packets.
  */
 void hv_pkt_iter_close(struct vmbus_channel *channel)
 {
        struct hv_ring_buffer_info *rbi = &channel->inbound;
-       u32 orig_write_sz = hv_get_bytes_to_write(rbi);
+       u32 curr_write_sz, pending_sz, bytes_read, start_read_index;
 
        /*
         * Make sure all reads are done before we update the read index since
@@ -431,8 +442,12 @@ void hv_pkt_iter_close(struct vmbus_channel *channel)
         * is updated.
         */
        virt_rmb();
+       start_read_index = rbi->ring_buffer->read_index;
        rbi->ring_buffer->read_index = rbi->priv_read_index;
 
+       if (!rbi->ring_buffer->feature_bits.feat_pending_send_sz)
+               return;
+
        /*
         * Issue a full memory barrier before making the signaling decision.
         * Here is the reason for having this barrier:
@@ -446,26 +461,29 @@ void hv_pkt_iter_close(struct vmbus_channel *channel)
         */
        virt_mb();
 
-       /* If host has disabled notifications then skip */
-       if (rbi->ring_buffer->interrupt_mask)
+       pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz);
+       if (!pending_sz)
                return;
 
-       if (rbi->ring_buffer->feature_bits.feat_pending_send_sz) {
-               u32 pending_sz = READ_ONCE(rbi->ring_buffer->pending_send_sz);
+       /*
+        * Ensure the read of write_index in hv_get_bytes_to_write()
+        * happens after the read of pending_send_sz.
+        */
+       virt_rmb();
+       curr_write_sz = hv_get_bytes_to_write(rbi);
+       bytes_read = hv_pkt_iter_bytes_read(rbi, start_read_index);
 
-               /*
-                * If there was space before we began iteration,
-                * then host was not blocked. Also handles case where
-                * pending_sz is zero then host has nothing pending
-                * and does not need to be signaled.
-                */
-               if (orig_write_sz > pending_sz)
-                       return;
+       /*
+        * If there was space before we began iteration,
+        * then host was not blocked.
+        */
 
-               /* If pending write will not fit, don't give false hope. */
-               if (hv_get_bytes_to_write(rbi) < pending_sz)
-                       return;
-       }
+       if (curr_write_sz - bytes_read > pending_sz)
+               return;
+
+       /* If pending write will not fit, don't give false hope. */
+       if (curr_write_sz <= pending_sz)
+               return;
 
        vmbus_setevent(channel);
 }
index 3030363..051a72e 100644 (file)
@@ -129,7 +129,10 @@ static ssize_t temp1_input_show(struct device *dev,
 
        data->read_tempreg(data->pdev, &regval);
        temp = (regval >> 21) * 125;
-       temp -= data->temp_offset;
+       if (temp > data->temp_offset)
+               temp -= data->temp_offset;
+       else
+               temp = 0;
 
        return sprintf(buf, "%u\n", temp);
 }
index a9805c7..e2954fb 100644 (file)
@@ -123,8 +123,10 @@ config I2C_I801
            Wildcat Point (PCH)
            Wildcat Point-LP (PCH)
            BayTrail (SOC)
+           Braswell (SOC)
            Sunrise Point-H (PCH)
            Sunrise Point-LP (PCH)
+           Kaby Lake-H (PCH)
            DNV (SOC)
            Broxton (SOC)
            Lewisburg (PCH)
index cd07a69..44deae7 100644 (file)
@@ -50,6 +50,9 @@
 #define BCM2835_I2C_S_CLKT     BIT(9)
 #define BCM2835_I2C_S_LEN      BIT(10) /* Fake bit for SW error reporting */
 
+#define BCM2835_I2C_FEDL_SHIFT 16
+#define BCM2835_I2C_REDL_SHIFT 0
+
 #define BCM2835_I2C_CDIV_MIN   0x0002
 #define BCM2835_I2C_CDIV_MAX   0xFFFE
 
@@ -81,7 +84,7 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg)
 
 static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
 {
-       u32 divider;
+       u32 divider, redl, fedl;
 
        divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk),
                               i2c_dev->bus_clk_rate);
@@ -100,6 +103,22 @@ static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev)
 
        bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider);
 
+       /*
+        * Number of core clocks to wait after falling edge before
+        * outputting the next data bit.  Note that both FEDL and REDL
+        * can't be greater than CDIV/2.
+        */
+       fedl = max(divider / 16, 1u);
+
+       /*
+        * Number of core clocks to wait after rising edge before
+        * sampling the next incoming data bit.
+        */
+       redl = max(divider / 4, 1u);
+
+       bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DEL,
+                          (fedl << BCM2835_I2C_FEDL_SHIFT) |
+                          (redl << BCM2835_I2C_REDL_SHIFT));
        return 0;
 }
 
index ae69188..0573253 100644 (file)
@@ -209,7 +209,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
        i2c_dw_disable_int(dev);
 
        /* Enable the adapter */
-       __i2c_dw_enable(dev, true);
+       __i2c_dw_enable_and_wait(dev, true);
 
        /* Clear and enable interrupts */
        dw_readl(dev, DW_IC_CLR_INTR);
@@ -644,7 +644,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
        gpio = devm_gpiod_get(dev->dev, "scl", GPIOD_OUT_HIGH);
        if (IS_ERR(gpio)) {
                r = PTR_ERR(gpio);
-               if (r == -ENOENT)
+               if (r == -ENOENT || r == -ENOSYS)
                        return 0;
                return r;
        }
index 8eac00e..692b341 100644 (file)
@@ -58,6 +58,7 @@
  * Wildcat Point (PCH)         0x8ca2  32      hard    yes     yes     yes
  * Wildcat Point-LP (PCH)      0x9ca2  32      hard    yes     yes     yes
  * BayTrail (SOC)              0x0f12  32      hard    yes     yes     yes
+ * Braswell (SOC)              0x2292  32      hard    yes     yes     yes
  * Sunrise Point-H (PCH)       0xa123  32      hard    yes     yes     yes
  * Sunrise Point-LP (PCH)      0x9d23  32      hard    yes     yes     yes
  * DNV (SOC)                   0x19df  32      hard    yes     yes     yes
index 1d87757..d960790 100644 (file)
@@ -233,6 +233,7 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read)
                return -EOPNOTSUPP;
 
        case STAT_TXDATA_NAK:
+       case STAT_BUS_ERROR:
                return -EIO;
        case STAT_TXADDR_NAK:
        case STAT_RXADDR_NAK:
index a7ef198..9bb9f64 100644 (file)
@@ -43,7 +43,7 @@
 #define TWSI_CTL_AAK           0x04    /* Assert ACK */
 
 /* Status values */
-#define STAT_ERROR             0x00
+#define STAT_BUS_ERROR         0x00
 #define STAT_START             0x08
 #define STAT_REP_START         0x10
 #define STAT_TXADDR_ACK                0x18
index 2fd8b6d..87197ec 100644 (file)
@@ -341,7 +341,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, adap);
        init_completion(&siic->done);
 
-       /* Controller Initalisation */
+       /* Controller initialisation */
 
        writel(SIRFSOC_I2C_RESET, siic->base + SIRFSOC_I2C_CTRL);
        while (readl(siic->base + SIRFSOC_I2C_CTRL) & SIRFSOC_I2C_RESET)
@@ -369,7 +369,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
         * but they start to affect the speed when clock is set to faster
         * frequencies.
         * Through the actual tests, use the different user_div value(which
-        * in the divider formular 'Fio / (Fi2c * user_div)') to adapt
+        * in the divider formula 'Fio / (Fi2c * user_div)') to adapt
         * the different ranges of i2c bus clock frequency, to make the SCL
         * more accurate.
         */
index b445b3b..f273e28 100644 (file)
@@ -888,6 +888,11 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
        }
 
        setup = of_device_get_match_data(&pdev->dev);
+       if (!setup) {
+               dev_err(&pdev->dev, "Can't get device data\n");
+               ret = -ENODEV;
+               goto clk_free;
+       }
        i2c_dev->setup = *setup;
 
        ret = device_property_read_u32(i2c_dev->dev, "i2c-scl-rising-time-ns",
index 17fd55a..caa20eb 100644 (file)
@@ -928,7 +928,7 @@ static int exact_lock(dev_t dev, void *data)
 {
        struct gendisk *p = data;
 
-       if (!get_disk(p))
+       if (!get_disk_and_module(p))
                return -1;
        return 0;
 }
index 6fe995c..3e6fd5a 100644 (file)
@@ -920,6 +920,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = {
 int st_accel_common_probe(struct iio_dev *indio_dev)
 {
        struct st_sensor_data *adata = iio_priv(indio_dev);
+       struct st_sensors_platform_data *pdata =
+               (struct st_sensors_platform_data *)adata->dev->platform_data;
        int irq = adata->get_irq_data_ready(indio_dev);
        int err;
 
@@ -946,7 +948,10 @@ int st_accel_common_probe(struct iio_dev *indio_dev)
                                        &adata->sensor_settings->fs.fs_avl[0];
        adata->odr = adata->sensor_settings->odr.odr_avl[0].hz;
 
-       err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data);
+       if (!pdata)
+               pdata = (struct st_sensors_platform_data *)&default_accel_pdata;
+
+       err = st_sensors_init_sensor(indio_dev, pdata);
        if (err < 0)
                goto st_accel_power_off;
 
index 327a49b..9515ca1 100644 (file)
@@ -243,7 +243,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
                                         ASPEED_ADC_INIT_POLLING_TIME,
                                         ASPEED_ADC_INIT_TIMEOUT);
                if (ret)
-                       goto scaler_error;
+                       goto poll_timeout_error;
        }
 
        /* Start all channels in normal mode. */
@@ -274,9 +274,10 @@ iio_register_error:
        writel(ASPEED_OPERATION_MODE_POWER_DOWN,
                data->base + ASPEED_REG_ENGINE_CONTROL);
        clk_disable_unprepare(data->clk_scaler->clk);
-reset_error:
-       reset_control_assert(data->rst);
 clk_enable_error:
+poll_timeout_error:
+       reset_control_assert(data->rst);
+reset_error:
        clk_hw_unregister_divider(data->clk_scaler);
 scaler_error:
        clk_hw_unregister_divider(data->clk_prescaler);
index 29fa773..ede955d 100644 (file)
@@ -462,8 +462,10 @@ static int meson_sar_adc_lock(struct iio_dev *indio_dev)
                        regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val);
                } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--);
 
-               if (timeout < 0)
+               if (timeout < 0) {
+                       mutex_unlock(&indio_dev->mlock);
                        return -ETIMEDOUT;
+               }
        }
 
        return 0;
index 7f5def4..9a2583c 100644 (file)
@@ -722,8 +722,6 @@ static int stm32h7_adc_enable(struct stm32_adc *adc)
        int ret;
        u32 val;
 
-       /* Clear ADRDY by writing one, then enable ADC */
-       stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY);
        stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN);
 
        /* Poll for ADRDY to be set (after adc startup time) */
@@ -731,8 +729,11 @@ static int stm32h7_adc_enable(struct stm32_adc *adc)
                                           val & STM32H7_ADRDY,
                                           100, STM32_ADC_TIMEOUT_US);
        if (ret) {
-               stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADEN);
+               stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADDIS);
                dev_err(&indio_dev->dev, "Failed to enable ADC\n");
+       } else {
+               /* Clear ADRDY by writing one */
+               stm32_adc_set_bits(adc, STM32H7_ADC_ISR, STM32H7_ADRDY);
        }
 
        return ret;
index daa026d..01422d1 100644 (file)
@@ -54,7 +54,6 @@ struct stm32_dfsdm_adc {
        struct stm32_dfsdm *dfsdm;
        const struct stm32_dfsdm_dev_data *dev_data;
        unsigned int fl_id;
-       unsigned int ch_id;
 
        /* ADC specific */
        unsigned int oversamp;
@@ -384,7 +383,7 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
        struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
-       struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id];
+       struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
        unsigned int sample_freq = adc->sample_freq;
        unsigned int spi_freq;
        int ret;
@@ -419,18 +418,20 @@ static ssize_t dfsdm_adc_audio_set_spiclk(struct iio_dev *indio_dev,
        return len;
 }
 
-static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc, bool dma)
+static int stm32_dfsdm_start_conv(struct stm32_dfsdm_adc *adc,
+                                 const struct iio_chan_spec *chan,
+                                 bool dma)
 {
        struct regmap *regmap = adc->dfsdm->regmap;
        int ret;
        unsigned int dma_en = 0, cont_en = 0;
 
-       ret = stm32_dfsdm_start_channel(adc->dfsdm, adc->ch_id);
+       ret = stm32_dfsdm_start_channel(adc->dfsdm, chan->channel);
        if (ret < 0)
                return ret;
 
        ret = stm32_dfsdm_filter_configure(adc->dfsdm, adc->fl_id,
-                                          adc->ch_id);
+                                          chan->channel);
        if (ret < 0)
                goto stop_channels;
 
@@ -464,12 +465,13 @@ stop_channels:
 
        regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
                           DFSDM_CR1_RCONT_MASK, 0);
-       stm32_dfsdm_stop_channel(adc->dfsdm, adc->fl_id);
+       stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
 
        return ret;
 }
 
-static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc)
+static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc,
+                                 const struct iio_chan_spec *chan)
 {
        struct regmap *regmap = adc->dfsdm->regmap;
 
@@ -482,7 +484,7 @@ static void stm32_dfsdm_stop_conv(struct stm32_dfsdm_adc *adc)
        regmap_update_bits(regmap, DFSDM_CR1(adc->fl_id),
                           DFSDM_CR1_RCONT_MASK, 0);
 
-       stm32_dfsdm_stop_channel(adc->dfsdm, adc->ch_id);
+       stm32_dfsdm_stop_channel(adc->dfsdm, chan->channel);
 }
 
 static int stm32_dfsdm_set_watermark(struct iio_dev *indio_dev,
@@ -609,6 +611,7 @@ static int stm32_dfsdm_adc_dma_start(struct iio_dev *indio_dev)
 static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+       const struct iio_chan_spec *chan = &indio_dev->channels[0];
        int ret;
 
        /* Reset adc buffer index */
@@ -618,7 +621,7 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
        if (ret < 0)
                return ret;
 
-       ret = stm32_dfsdm_start_conv(adc, true);
+       ret = stm32_dfsdm_start_conv(adc, chan, true);
        if (ret) {
                dev_err(&indio_dev->dev, "Can't start conversion\n");
                goto stop_dfsdm;
@@ -635,7 +638,7 @@ static int stm32_dfsdm_postenable(struct iio_dev *indio_dev)
        return 0;
 
 err_stop_conv:
-       stm32_dfsdm_stop_conv(adc);
+       stm32_dfsdm_stop_conv(adc, chan);
 stop_dfsdm:
        stm32_dfsdm_stop_dfsdm(adc->dfsdm);
 
@@ -645,11 +648,12 @@ stop_dfsdm:
 static int stm32_dfsdm_predisable(struct iio_dev *indio_dev)
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+       const struct iio_chan_spec *chan = &indio_dev->channels[0];
 
        if (adc->dma_chan)
                dmaengine_terminate_all(adc->dma_chan);
 
-       stm32_dfsdm_stop_conv(adc);
+       stm32_dfsdm_stop_conv(adc, chan);
 
        stm32_dfsdm_stop_dfsdm(adc->dfsdm);
 
@@ -730,7 +734,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
        if (ret < 0)
                goto stop_dfsdm;
 
-       ret = stm32_dfsdm_start_conv(adc, false);
+       ret = stm32_dfsdm_start_conv(adc, chan, false);
        if (ret < 0) {
                regmap_update_bits(adc->dfsdm->regmap, DFSDM_CR2(adc->fl_id),
                                   DFSDM_CR2_REOCIE_MASK, DFSDM_CR2_REOCIE(0));
@@ -751,7 +755,7 @@ static int stm32_dfsdm_single_conv(struct iio_dev *indio_dev,
        else
                ret = IIO_VAL_INT;
 
-       stm32_dfsdm_stop_conv(adc);
+       stm32_dfsdm_stop_conv(adc, chan);
 
 stop_dfsdm:
        stm32_dfsdm_stop_dfsdm(adc->dfsdm);
@@ -765,7 +769,7 @@ static int stm32_dfsdm_write_raw(struct iio_dev *indio_dev,
 {
        struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
        struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
-       struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[adc->ch_id];
+       struct stm32_dfsdm_channel *ch = &adc->dfsdm->ch_list[chan->channel];
        unsigned int spi_freq = adc->spi_freq;
        int ret = -EINVAL;
 
@@ -972,7 +976,6 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
        }
        ch->scan_type.realbits = 24;
        ch->scan_type.storagebits = 32;
-       adc->ch_id = ch->channel;
 
        return stm32_dfsdm_chan_configure(adc->dfsdm,
                                          &adc->dfsdm->ch_list[ch->channel]);
@@ -1001,7 +1004,7 @@ static int stm32_dfsdm_audio_init(struct iio_dev *indio_dev)
        }
        ch->info_mask_separate = BIT(IIO_CHAN_INFO_SAMP_FREQ);
 
-       d_ch = &adc->dfsdm->ch_list[adc->ch_id];
+       d_ch = &adc->dfsdm->ch_list[ch->channel];
        if (d_ch->src != DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL)
                adc->spi_freq = adc->dfsdm->spi_master_freq;
 
@@ -1042,8 +1045,8 @@ static int stm32_dfsdm_adc_init(struct iio_dev *indio_dev)
                return -ENOMEM;
 
        for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
-               ch->scan_index = chan_idx;
-               ret = stm32_dfsdm_adc_chan_init_one(indio_dev, ch);
+               ch[chan_idx].scan_index = chan_idx;
+               ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
                if (ret < 0) {
                        dev_err(&indio_dev->dev, "Channels init failed\n");
                        return ret;
index 6290332..e50efdc 100644 (file)
@@ -83,7 +83,7 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
 {
        struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm);
        struct device *dev = &priv->pdev->dev;
-       unsigned int clk_div = priv->spi_clk_out_div;
+       unsigned int clk_div = priv->spi_clk_out_div, clk_src;
        int ret;
 
        if (atomic_inc_return(&priv->n_active_ch) == 1) {
@@ -100,6 +100,14 @@ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
                        }
                }
 
+               /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */
+               clk_src = priv->aclk ? 1 : 0;
+               ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
+                                        DFSDM_CHCFGR1_CKOUTSRC_MASK,
+                                        DFSDM_CHCFGR1_CKOUTSRC(clk_src));
+               if (ret < 0)
+                       goto disable_aclk;
+
                /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */
                ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
                                         DFSDM_CHCFGR1_CKOUTDIV_MASK,
@@ -274,7 +282,7 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
 
        dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm",
                                                  dfsdm->base,
-                                                 &stm32h7_dfsdm_regmap_cfg);
+                                                 dev_data->regmap_cfg);
        if (IS_ERR(dfsdm->regmap)) {
                ret = PTR_ERR(dfsdm->regmap);
                dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n",
index fbe2431..1ea9f55 100644 (file)
@@ -133,6 +133,9 @@ static int ccs811_start_sensor_application(struct i2c_client *client)
        if (ret < 0)
                return ret;
 
+       if ((ret & CCS811_STATUS_FW_MODE_APPLICATION))
+               return 0;
+
        if ((ret & CCS811_STATUS_APP_VALID_MASK) !=
            CCS811_STATUS_APP_VALID_LOADED)
                return -EIO;
index 0dd5a38..457372f 100644 (file)
@@ -46,6 +46,10 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
        if (adis->trig == NULL)
                return -ENOMEM;
 
+       adis->trig->dev.parent = &adis->spi->dev;
+       adis->trig->ops = &adis_trigger_ops;
+       iio_trigger_set_drvdata(adis->trig, adis);
+
        ret = request_irq(adis->spi->irq,
                          &iio_trigger_generic_data_rdy_poll,
                          IRQF_TRIGGER_RISING,
@@ -54,9 +58,6 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
        if (ret)
                goto error_free_trig;
 
-       adis->trig->dev.parent = &adis->spi->dev;
-       adis->trig->ops = &adis_trigger_ops;
-       iio_trigger_set_drvdata(adis->trig, adis);
        ret = iio_trigger_register(adis->trig);
 
        indio_dev->trig = iio_trigger_get(adis->trig);
index 79abf70..cd5bfe3 100644 (file)
@@ -175,7 +175,7 @@ __poll_t iio_buffer_poll(struct file *filp,
        struct iio_dev *indio_dev = filp->private_data;
        struct iio_buffer *rb = indio_dev->buffer;
 
-       if (!indio_dev->info)
+       if (!indio_dev->info || rb == NULL)
                return 0;
 
        poll_wait(filp, &rb->pollq, wait);
index 349e5c7..4ddb6cf 100644 (file)
@@ -640,7 +640,7 @@ int st_press_common_probe(struct iio_dev *indio_dev)
                       press_data->sensor_settings->drdy_irq.int2.addr))
                pdata = (struct st_sensors_platform_data *)&default_press_pdata;
 
-       err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data);
+       err = st_sensors_init_sensor(indio_dev, pdata);
        if (err < 0)
                goto st_press_power_off;
 
index fcb1c4b..f726f94 100644 (file)
@@ -68,6 +68,8 @@ config SX9500
 
 config SRF08
        tristate "Devantech SRF02/SRF08/SRF10 ultrasonic ranger sensor"
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
        depends on I2C
        help
          Say Y here to build a driver for Devantech SRF02/SRF08/SRF10
index a5b4cf0..cb1d2ab 100644 (file)
@@ -207,6 +207,22 @@ int rdma_addr_size(struct sockaddr *addr)
 }
 EXPORT_SYMBOL(rdma_addr_size);
 
+int rdma_addr_size_in6(struct sockaddr_in6 *addr)
+{
+       int ret = rdma_addr_size((struct sockaddr *) addr);
+
+       return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_in6);
+
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr)
+{
+       int ret = rdma_addr_size((struct sockaddr *) addr);
+
+       return ret <= sizeof(*addr) ? ret : 0;
+}
+EXPORT_SYMBOL(rdma_addr_size_kss);
+
 static struct rdma_addr_client self;
 
 void rdma_addr_register_client(struct rdma_addr_client *client)
@@ -550,18 +566,13 @@ static int addr_resolve(struct sockaddr *src_in,
                dst_release(dst);
        }
 
-       if (ndev->flags & IFF_LOOPBACK) {
-               ret = rdma_translate_ip(dst_in, addr);
-               /*
-                * Put the loopback device and get the translated
-                * device instead.
-                */
+       if (ndev) {
+               if (ndev->flags & IFF_LOOPBACK)
+                       ret = rdma_translate_ip(dst_in, addr);
+               else
+                       addr->bound_dev_if = ndev->ifindex;
                dev_put(ndev);
-               ndev = dev_get_by_index(addr->net, addr->bound_dev_if);
-       } else {
-               addr->bound_dev_if = ndev->ifindex;
        }
-       dev_put(ndev);
 
        return ret;
 }
@@ -591,6 +602,15 @@ static void process_one_req(struct work_struct *_work)
        list_del(&req->list);
        mutex_unlock(&lock);
 
+       /*
+        * Although the work will normally have been canceled by the
+        * workqueue, it can still be requeued as long as it is on the
+        * req_list, so it could have been requeued before we grabbed &lock.
+        * We need to cancel it after it is removed from req_list to really be
+        * sure it is safe to free.
+        */
+       cancel_delayed_work(&req->work);
+
        req->callback(req->status, (struct sockaddr *)&req->src_addr,
                req->addr, req->context);
        put_client(req->client);
index e66963c..a5367c5 100644 (file)
@@ -3069,7 +3069,8 @@ static int cma_port_is_unique(struct rdma_bind_list *bind_list,
                        continue;
 
                /* different dest port -> unique */
-               if (!cma_any_port(cur_daddr) &&
+               if (!cma_any_port(daddr) &&
+                   !cma_any_port(cur_daddr) &&
                    (dport != cur_dport))
                        continue;
 
@@ -3080,7 +3081,8 @@ static int cma_port_is_unique(struct rdma_bind_list *bind_list,
                        continue;
 
                /* different dst address -> unique */
-               if (!cma_any_addr(cur_daddr) &&
+               if (!cma_any_addr(daddr) &&
+                   !cma_any_addr(cur_daddr) &&
                    cma_addr_cmp(daddr, cur_daddr))
                        continue;
 
@@ -3378,13 +3380,13 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
                }
 #endif
        }
+       daddr = cma_dst_addr(id_priv);
+       daddr->sa_family = addr->sa_family;
+
        ret = cma_get_port(id_priv);
        if (ret)
                goto err2;
 
-       daddr = cma_dst_addr(id_priv);
-       daddr->sa_family = addr->sa_family;
-
        return 0;
 err2:
        if (id_priv->cma_dev)
@@ -4173,6 +4175,9 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr,
        struct cma_multicast *mc;
        int ret;
 
+       if (!id->device)
+               return -EINVAL;
+
        id_priv = container_of(id, struct rdma_id_private, id);
        if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) &&
            !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED))
index c4560d8..25bb178 100644 (file)
@@ -305,16 +305,21 @@ void nldev_exit(void);
 static inline struct ib_qp *_ib_create_qp(struct ib_device *dev,
                                          struct ib_pd *pd,
                                          struct ib_qp_init_attr *attr,
-                                         struct ib_udata *udata)
+                                         struct ib_udata *udata,
+                                         struct ib_uobject *uobj)
 {
        struct ib_qp *qp;
 
+       if (!dev->create_qp)
+               return ERR_PTR(-EOPNOTSUPP);
+
        qp = dev->create_qp(pd, attr, udata);
        if (IS_ERR(qp))
                return qp;
 
        qp->device = dev;
        qp->pd = pd;
+       qp->uobject = uobj;
        /*
         * We don't track XRC QPs for now, because they don't have PD
         * and more importantly they are created internaly by driver,
index bc79ca8..af5ad6a 100644 (file)
@@ -17,6 +17,7 @@
 
 /* # of WCs to poll for with a single call to ib_poll_cq */
 #define IB_POLL_BATCH                  16
+#define IB_POLL_BATCH_DIRECT           8
 
 /* # of WCs to iterate over before yielding */
 #define IB_POLL_BUDGET_IRQ             256
 #define IB_POLL_FLAGS \
        (IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)
 
-static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc)
+static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *wcs,
+                          int batch)
 {
        int i, n, completed = 0;
-       struct ib_wc *wcs = poll_wc ? : cq->wc;
 
        /*
         * budget might be (-1) if the caller does not
         * want to bound this call, thus we need unsigned
         * minimum here.
         */
-       while ((n = ib_poll_cq(cq, min_t(u32, IB_POLL_BATCH,
-                       budget - completed), wcs)) > 0) {
+       while ((n = ib_poll_cq(cq, min_t(u32, batch,
+                                        budget - completed), wcs)) > 0) {
                for (i = 0; i < n; i++) {
                        struct ib_wc *wc = &wcs[i];
 
@@ -48,8 +49,7 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc)
 
                completed += n;
 
-               if (n != IB_POLL_BATCH ||
-                   (budget != -1 && completed >= budget))
+               if (n != batch || (budget != -1 && completed >= budget))
                        break;
        }
 
@@ -72,9 +72,9 @@ static int __ib_process_cq(struct ib_cq *cq, int budget, struct ib_wc *poll_wc)
  */
 int ib_process_cq_direct(struct ib_cq *cq, int budget)
 {
-       struct ib_wc wcs[IB_POLL_BATCH];
+       struct ib_wc wcs[IB_POLL_BATCH_DIRECT];
 
-       return __ib_process_cq(cq, budget, wcs);
+       return __ib_process_cq(cq, budget, wcs, IB_POLL_BATCH_DIRECT);
 }
 EXPORT_SYMBOL(ib_process_cq_direct);
 
@@ -88,7 +88,7 @@ static int ib_poll_handler(struct irq_poll *iop, int budget)
        struct ib_cq *cq = container_of(iop, struct ib_cq, iop);
        int completed;
 
-       completed = __ib_process_cq(cq, budget, NULL);
+       completed = __ib_process_cq(cq, budget, cq->wc, IB_POLL_BATCH);
        if (completed < budget) {
                irq_poll_complete(&cq->iop);
                if (ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0)
@@ -108,7 +108,8 @@ static void ib_cq_poll_work(struct work_struct *work)
        struct ib_cq *cq = container_of(work, struct ib_cq, work);
        int completed;
 
-       completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, NULL);
+       completed = __ib_process_cq(cq, IB_POLL_BUDGET_WORKQUEUE, cq->wc,
+                                   IB_POLL_BATCH);
        if (completed >= IB_POLL_BUDGET_WORKQUEUE ||
            ib_req_notify_cq(cq, IB_POLL_FLAGS) > 0)
                queue_work(ib_comp_wq, &cq->work);
index e8010e7..b7459cf 100644 (file)
@@ -290,6 +290,7 @@ void ib_dealloc_device(struct ib_device *device)
 {
        WARN_ON(device->reg_state != IB_DEV_UNREGISTERED &&
                device->reg_state != IB_DEV_UNINITIALIZED);
+       rdma_restrack_clean(&device->res);
        put_device(&device->dev);
 }
 EXPORT_SYMBOL(ib_dealloc_device);
@@ -536,14 +537,14 @@ int ib_register_device(struct ib_device *device,
        ret = device->query_device(device, &device->attrs, &uhw);
        if (ret) {
                pr_warn("Couldn't query the device attributes\n");
-               goto cache_cleanup;
+               goto cg_cleanup;
        }
 
        ret = ib_device_register_sysfs(device, port_callback);
        if (ret) {
                pr_warn("Couldn't register device %s with driver model\n",
                        device->name);
-               goto cache_cleanup;
+               goto cg_cleanup;
        }
 
        device->reg_state = IB_DEV_REGISTERED;
@@ -559,6 +560,8 @@ int ib_register_device(struct ib_device *device,
        mutex_unlock(&device_mutex);
        return 0;
 
+cg_cleanup:
+       ib_device_unregister_rdmacg(device);
 cache_cleanup:
        ib_cache_cleanup_one(device);
        ib_cache_release_one(device);
@@ -598,8 +601,6 @@ void ib_unregister_device(struct ib_device *device)
        }
        up_read(&lists_rwsem);
 
-       rdma_restrack_clean(&device->res);
-
        ib_device_unregister_rdmacg(device);
        ib_device_unregister_sysfs(device);
 
index 85b5ee4..d8eead5 100644 (file)
@@ -141,7 +141,12 @@ static struct ib_uobject *alloc_uobj(struct ib_ucontext *context,
         */
        uobj->context = context;
        uobj->type = type;
-       atomic_set(&uobj->usecnt, 0);
+       /*
+        * Allocated objects start out as write locked to deny any other
+        * syscalls from accessing them until they are committed. See
+        * rdma_alloc_commit_uobject
+        */
+       atomic_set(&uobj->usecnt, -1);
        kref_init(&uobj->ref);
 
        return uobj;
@@ -196,7 +201,15 @@ static struct ib_uobject *lookup_get_idr_uobject(const struct uverbs_obj_type *t
                goto free;
        }
 
-       uverbs_uobject_get(uobj);
+       /*
+        * The idr_find is guaranteed to return a pointer to something that
+        * isn't freed yet, or NULL, as the free after idr_remove goes through
+        * kfree_rcu(). However the object may still have been released and
+        * kfree() could be called at any time.
+        */
+       if (!kref_get_unless_zero(&uobj->ref))
+               uobj = ERR_PTR(-ENOENT);
+
 free:
        rcu_read_unlock();
        return uobj;
@@ -399,13 +412,13 @@ static int __must_check remove_commit_fd_uobject(struct ib_uobject *uobj,
        return ret;
 }
 
-static void lockdep_check(struct ib_uobject *uobj, bool exclusive)
+static void assert_uverbs_usecnt(struct ib_uobject *uobj, bool exclusive)
 {
 #ifdef CONFIG_LOCKDEP
        if (exclusive)
-               WARN_ON(atomic_read(&uobj->usecnt) > 0);
+               WARN_ON(atomic_read(&uobj->usecnt) != -1);
        else
-               WARN_ON(atomic_read(&uobj->usecnt) == -1);
+               WARN_ON(atomic_read(&uobj->usecnt) <= 0);
 #endif
 }
 
@@ -444,7 +457,7 @@ int __must_check rdma_remove_commit_uobject(struct ib_uobject *uobj)
                WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n");
                return 0;
        }
-       lockdep_check(uobj, true);
+       assert_uverbs_usecnt(uobj, true);
        ret = _rdma_remove_commit_uobject(uobj, RDMA_REMOVE_DESTROY);
 
        up_read(&ucontext->cleanup_rwsem);
@@ -474,16 +487,17 @@ int rdma_explicit_destroy(struct ib_uobject *uobject)
                WARN(true, "ib_uverbs: Cleanup is running while removing an uobject\n");
                return 0;
        }
-       lockdep_check(uobject, true);
+       assert_uverbs_usecnt(uobject, true);
        ret = uobject->type->type_class->remove_commit(uobject,
                                                       RDMA_REMOVE_DESTROY);
        if (ret)
-               return ret;
+               goto out;
 
        uobject->type = &null_obj_type;
 
+out:
        up_read(&ucontext->cleanup_rwsem);
-       return 0;
+       return ret;
 }
 
 static void alloc_commit_idr_uobject(struct ib_uobject *uobj)
@@ -527,6 +541,10 @@ int rdma_alloc_commit_uobject(struct ib_uobject *uobj)
                return ret;
        }
 
+       /* matches atomic_set(-1) in alloc_uobj */
+       assert_uverbs_usecnt(uobj, true);
+       atomic_set(&uobj->usecnt, 0);
+
        uobj->type->type_class->alloc_commit(uobj);
        up_read(&uobj->context->cleanup_rwsem);
 
@@ -561,7 +579,7 @@ static void lookup_put_fd_uobject(struct ib_uobject *uobj, bool exclusive)
 
 void rdma_lookup_put_uobject(struct ib_uobject *uobj, bool exclusive)
 {
-       lockdep_check(uobj, exclusive);
+       assert_uverbs_usecnt(uobj, exclusive);
        uobj->type->type_class->lookup_put(uobj, exclusive);
        /*
         * In order to unlock an object, either decrease its usecnt for
index 857637b..3dbc4e4 100644 (file)
@@ -7,7 +7,6 @@
 #include <rdma/restrack.h>
 #include <linux/mutex.h>
 #include <linux/sched/task.h>
-#include <linux/uaccess.h>
 #include <linux/pid_namespace.h>
 
 void rdma_restrack_init(struct rdma_restrack_root *res)
@@ -63,7 +62,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
 {
        enum rdma_restrack_type type = res->type;
        struct ib_device *dev;
-       struct ib_xrcd *xrcd;
        struct ib_pd *pd;
        struct ib_cq *cq;
        struct ib_qp *qp;
@@ -81,10 +79,6 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
                qp = container_of(res, struct ib_qp, res);
                dev = qp->device;
                break;
-       case RDMA_RESTRACK_XRCD:
-               xrcd = container_of(res, struct ib_xrcd, res);
-               dev = xrcd->device;
-               break;
        default:
                WARN_ONCE(true, "Wrong resource tracking type %u\n", type);
                return NULL;
@@ -93,6 +87,21 @@ static struct ib_device *res_to_dev(struct rdma_restrack_entry *res)
        return dev;
 }
 
+static bool res_is_user(struct rdma_restrack_entry *res)
+{
+       switch (res->type) {
+       case RDMA_RESTRACK_PD:
+               return container_of(res, struct ib_pd, res)->uobject;
+       case RDMA_RESTRACK_CQ:
+               return container_of(res, struct ib_cq, res)->uobject;
+       case RDMA_RESTRACK_QP:
+               return container_of(res, struct ib_qp, res)->uobject;
+       default:
+               WARN_ONCE(true, "Wrong resource tracking type %u\n", res->type);
+               return false;
+       }
+}
+
 void rdma_restrack_add(struct rdma_restrack_entry *res)
 {
        struct ib_device *dev = res_to_dev(res);
@@ -100,7 +109,7 @@ void rdma_restrack_add(struct rdma_restrack_entry *res)
        if (!dev)
                return;
 
-       if (!uaccess_kernel()) {
+       if (res_is_user(res)) {
                get_task_struct(current);
                res->task = current;
                res->kern_name = NULL;
index 8cf15d4..9f029a1 100644 (file)
@@ -1291,10 +1291,9 @@ int ib_init_ah_attr_from_path(struct ib_device *device, u8 port_num,
 
                resolved_dev = dev_get_by_index(dev_addr.net,
                                                dev_addr.bound_dev_if);
-               if (resolved_dev->flags & IFF_LOOPBACK) {
-                       dev_put(resolved_dev);
-                       resolved_dev = idev;
-                       dev_hold(resolved_dev);
+               if (!resolved_dev) {
+                       dev_put(idev);
+                       return -ENODEV;
                }
                ndev = ib_get_ndev_from_path(rec);
                rcu_read_lock();
index f015f1b..d933336 100644 (file)
@@ -132,7 +132,7 @@ static inline struct ucma_context *_ucma_find_context(int id,
        ctx = idr_find(&ctx_idr, id);
        if (!ctx)
                ctx = ERR_PTR(-ENOENT);
-       else if (ctx->file != file)
+       else if (ctx->file != file || !ctx->cm_id)
                ctx = ERR_PTR(-EINVAL);
        return ctx;
 }
@@ -456,6 +456,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
        struct rdma_ucm_create_id cmd;
        struct rdma_ucm_create_id_resp resp;
        struct ucma_context *ctx;
+       struct rdma_cm_id *cm_id;
        enum ib_qp_type qp_type;
        int ret;
 
@@ -476,10 +477,10 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
                return -ENOMEM;
 
        ctx->uid = cmd.uid;
-       ctx->cm_id = rdma_create_id(current->nsproxy->net_ns,
-                                   ucma_event_handler, ctx, cmd.ps, qp_type);
-       if (IS_ERR(ctx->cm_id)) {
-               ret = PTR_ERR(ctx->cm_id);
+       cm_id = rdma_create_id(current->nsproxy->net_ns,
+                              ucma_event_handler, ctx, cmd.ps, qp_type);
+       if (IS_ERR(cm_id)) {
+               ret = PTR_ERR(cm_id);
                goto err1;
        }
 
@@ -489,14 +490,19 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf,
                ret = -EFAULT;
                goto err2;
        }
+
+       ctx->cm_id = cm_id;
        return 0;
 
 err2:
-       rdma_destroy_id(ctx->cm_id);
+       rdma_destroy_id(cm_id);
 err1:
        mutex_lock(&mut);
        idr_remove(&ctx_idr, ctx->id);
        mutex_unlock(&mut);
+       mutex_lock(&file->mut);
+       list_del(&ctx->list);
+       mutex_unlock(&file->mut);
        kfree(ctx);
        return ret;
 }
@@ -626,6 +632,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       if (!rdma_addr_size_in6(&cmd.addr))
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
@@ -639,22 +648,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf,
                         int in_len, int out_len)
 {
        struct rdma_ucm_bind cmd;
-       struct sockaddr *addr;
        struct ucma_context *ctx;
        int ret;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       addr = (struct sockaddr *) &cmd.addr;
-       if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr)))
+       if (cmd.reserved || !cmd.addr_size ||
+           cmd.addr_size != rdma_addr_size_kss(&cmd.addr))
                return -EINVAL;
 
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_bind_addr(ctx->cm_id, addr);
+       ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr);
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -670,13 +678,16 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       if (!rdma_addr_size_in6(&cmd.src_addr) ||
+           !rdma_addr_size_in6(&cmd.dst_addr))
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
        ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
-                               (struct sockaddr *) &cmd.dst_addr,
-                               cmd.timeout_ms);
+                               (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -686,24 +697,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file,
                                 int in_len, int out_len)
 {
        struct rdma_ucm_resolve_addr cmd;
-       struct sockaddr *src, *dst;
        struct ucma_context *ctx;
        int ret;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
-       src = (struct sockaddr *) &cmd.src_addr;
-       dst = (struct sockaddr *) &cmd.dst_addr;
-       if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) ||
-           !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst)))
+       if (cmd.reserved ||
+           (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) ||
+           !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr)))
                return -EINVAL;
 
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms);
+       ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr,
+                               (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms);
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -1149,10 +1159,18 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       if (cmd.qp_state > IB_QPS_ERR)
+               return -EINVAL;
+
        ctx = ucma_get_ctx(file, cmd.id);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
+       if (!ctx->cm_id->device) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        resp.qp_attr_mask = 0;
        memset(&qp_attr, 0, sizeof qp_attr);
        qp_attr.qp_state = cmd.qp_state;
@@ -1294,6 +1312,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
+       if (unlikely(cmd.optlen > KMALLOC_MAX_SIZE))
+               return -EINVAL;
+
        optval = memdup_user((void __user *) (unsigned long) cmd.optval,
                             cmd.optlen);
        if (IS_ERR(optval)) {
@@ -1315,7 +1336,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
 {
        struct rdma_ucm_notify cmd;
        struct ucma_context *ctx;
-       int ret;
+       int ret = -EINVAL;
 
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
@@ -1324,7 +1345,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf,
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
 
-       ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event);
+       if (ctx->cm_id->device)
+               ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event);
+
        ucma_put_ctx(ctx);
        return ret;
 }
@@ -1343,7 +1366,7 @@ static ssize_t ucma_process_join(struct ucma_file *file,
                return -ENOSPC;
 
        addr = (struct sockaddr *) &cmd->addr;
-       if (!cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr)))
+       if (cmd->addr_size != rdma_addr_size(addr))
                return -EINVAL;
 
        if (cmd->join_flags == RDMA_MC_JOIN_FLAG_FULLMEMBER)
@@ -1410,7 +1433,10 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file,
        join_cmd.response = cmd.response;
        join_cmd.uid = cmd.uid;
        join_cmd.id = cmd.id;
-       join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr);
+       join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr);
+       if (!join_cmd.addr_size)
+               return -EINVAL;
+
        join_cmd.join_flags = RDMA_MC_JOIN_FLAG_FULLMEMBER;
        memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size);
 
@@ -1426,6 +1452,9 @@ static ssize_t ucma_join_multicast(struct ucma_file *file,
        if (copy_from_user(&cmd, inbuf, sizeof(cmd)))
                return -EFAULT;
 
+       if (!rdma_addr_size_kss(&cmd.addr))
+               return -EINVAL;
+
        return ucma_process_join(file, &cmd, out_len);
 }
 
index 256934d..a148de3 100644 (file)
@@ -562,9 +562,10 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file,
        if (f.file)
                fdput(f);
 
+       mutex_unlock(&file->device->xrcd_tree_mutex);
+
        uobj_alloc_commit(&obj->uobject);
 
-       mutex_unlock(&file->device->xrcd_tree_mutex);
        return in_len;
 
 err_copy:
@@ -603,10 +604,8 @@ ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file,
 
        uobj  = uobj_get_write(uobj_get_type(xrcd), cmd.xrcd_handle,
                               file->ucontext);
-       if (IS_ERR(uobj)) {
-               mutex_unlock(&file->device->xrcd_tree_mutex);
+       if (IS_ERR(uobj))
                return PTR_ERR(uobj);
-       }
 
        ret = uobj_remove_commit(uobj);
        return ret ?: in_len;
@@ -979,6 +978,9 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
        struct ib_uverbs_ex_create_cq_resp resp;
        struct ib_cq_init_attr attr = {};
 
+       if (!ib_dev->create_cq)
+               return ERR_PTR(-EOPNOTSUPP);
+
        if (cmd->comp_vector >= file->device->num_comp_vectors)
                return ERR_PTR(-EINVAL);
 
@@ -1030,14 +1032,14 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file,
        resp.response_length = offsetof(typeof(resp), response_length) +
                sizeof(resp.response_length);
 
+       cq->res.type = RDMA_RESTRACK_CQ;
+       rdma_restrack_add(&cq->res);
+
        ret = cb(file, obj, &resp, ucore, context);
        if (ret)
                goto err_cb;
 
        uobj_alloc_commit(&obj->uobject);
-       cq->res.type = RDMA_RESTRACK_CQ;
-       rdma_restrack_add(&cq->res);
-
        return obj;
 
 err_cb:
@@ -1518,7 +1520,8 @@ static int create_qp(struct ib_uverbs_file *file,
        if (cmd->qp_type == IB_QPT_XRC_TGT)
                qp = ib_create_qp(pd, &attr);
        else
-               qp = _ib_create_qp(device, pd, &attr, uhw);
+               qp = _ib_create_qp(device, pd, &attr, uhw,
+                                  &obj->uevent.uobject);
 
        if (IS_ERR(qp)) {
                ret = PTR_ERR(qp);
@@ -1550,8 +1553,10 @@ static int create_qp(struct ib_uverbs_file *file,
                        atomic_inc(&attr.srq->usecnt);
                if (ind_tbl)
                        atomic_inc(&ind_tbl->usecnt);
+       } else {
+               /* It is done in _ib_create_qp for other QP types */
+               qp->uobject = &obj->uevent.uobject;
        }
-       qp->uobject = &obj->uevent.uobject;
 
        obj->uevent.uobject.object = qp;
 
@@ -1971,8 +1976,15 @@ static int modify_qp(struct ib_uverbs_file *file,
                goto release_qp;
        }
 
+       if ((cmd->base.attr_mask & IB_QP_AV) &&
+           !rdma_is_port_valid(qp->device, cmd->base.dest.port_num)) {
+               ret = -EINVAL;
+               goto release_qp;
+       }
+
        if ((cmd->base.attr_mask & IB_QP_ALT_PATH) &&
-           !rdma_is_port_valid(qp->device, cmd->base.alt_port_num)) {
+           (!rdma_is_port_valid(qp->device, cmd->base.alt_port_num) ||
+           !rdma_is_port_valid(qp->device, cmd->base.alt_dest.port_num))) {
                ret = -EINVAL;
                goto release_qp;
        }
@@ -2941,6 +2953,11 @@ int ib_uverbs_ex_create_wq(struct ib_uverbs_file *file,
                wq_init_attr.create_flags = cmd.create_flags;
        obj->uevent.events_reported = 0;
        INIT_LIST_HEAD(&obj->uevent.event_list);
+
+       if (!pd->device->create_wq) {
+               err = -EOPNOTSUPP;
+               goto err_put_cq;
+       }
        wq = pd->device->create_wq(pd, &wq_init_attr, uhw);
        if (IS_ERR(wq)) {
                err = PTR_ERR(wq);
@@ -3084,7 +3101,12 @@ int ib_uverbs_ex_modify_wq(struct ib_uverbs_file *file,
                wq_attr.flags = cmd.flags;
                wq_attr.flags_mask = cmd.flags_mask;
        }
+       if (!wq->device->modify_wq) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
        ret = wq->device->modify_wq(wq, &wq_attr, cmd.attr_mask, uhw);
+out:
        uobj_put_obj_read(wq);
        return ret;
 }
@@ -3181,6 +3203,11 @@ int ib_uverbs_ex_create_rwq_ind_table(struct ib_uverbs_file *file,
 
        init_attr.log_ind_tbl_size = cmd.log_ind_tbl_size;
        init_attr.ind_tbl = wqs;
+
+       if (!ib_dev->create_rwq_ind_table) {
+               err = -EOPNOTSUPP;
+               goto err_uobj;
+       }
        rwq_ind_tbl = ib_dev->create_rwq_ind_table(ib_dev, &init_attr, uhw);
 
        if (IS_ERR(rwq_ind_tbl)) {
@@ -3770,6 +3797,9 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
        struct ib_device_attr attr = {0};
        int err;
 
+       if (!ib_dev->query_device)
+               return -EOPNOTSUPP;
+
        if (ucore->inlen < sizeof(cmd))
                return -EINVAL;
 
index d96dc1d..339b851 100644 (file)
@@ -59,6 +59,9 @@ static int uverbs_process_attr(struct ib_device *ibdev,
                        return 0;
        }
 
+       if (test_bit(attr_id, attr_bundle_h->valid_bitmap))
+               return -EINVAL;
+
        spec = &attr_spec_bucket->attrs[attr_id];
        e = &elements[attr_id];
        e->uattr = uattr_ptr;
index 062485f..62e1eb1 100644 (file)
@@ -114,6 +114,7 @@ static size_t get_elements_above_id(const void **iters,
        short min = SHRT_MAX;
        const void *elem;
        int i, j, last_stored = -1;
+       unsigned int equal_min = 0;
 
        for_each_element(elem, i, j, elements, num_elements, num_offset,
                         data_offset) {
@@ -136,6 +137,10 @@ static size_t get_elements_above_id(const void **iters,
                 */
                iters[last_stored == i ? num_iters - 1 : num_iters++] = elem;
                last_stored = i;
+               if (min == GET_ID(id))
+                       equal_min++;
+               else
+                       equal_min = 1;
                min = GET_ID(id);
        }
 
@@ -146,15 +151,10 @@ static size_t get_elements_above_id(const void **iters,
         * Therefore, we need to clean the beginning of the array to make sure
         * all ids of final elements are equal to min.
         */
-       for (i = num_iters - 1; i >= 0 &&
-            GET_ID(*(u16 *)(iters[i] + id_offset)) == min; i--)
-               ;
-
-       num_iters -= i + 1;
-       memmove(iters, iters + i + 1, sizeof(*iters) * num_iters);
+       memmove(iters, iters + num_iters - equal_min, sizeof(*iters) * equal_min);
 
        *min_id = min;
-       return num_iters;
+       return equal_min;
 }
 
 #define find_max_element_entry_id(num_elements, elements, num_objects_fld, \
@@ -322,7 +322,7 @@ static struct uverbs_method_spec *build_method_with_attrs(const struct uverbs_me
                hash = kzalloc(sizeof(*hash) +
                               ALIGN(sizeof(*hash->attrs) * (attr_max_bucket + 1),
                                     sizeof(long)) +
-                              BITS_TO_LONGS(attr_max_bucket) * sizeof(long),
+                              BITS_TO_LONGS(attr_max_bucket + 1) * sizeof(long),
                               GFP_KERNEL);
                if (!hash) {
                        res = -ENOMEM;
@@ -509,7 +509,7 @@ static struct uverbs_object_spec *build_object_with_methods(const struct uverbs_
                         * first handler which != NULL. This also defines the
                         * set of flags used for this handler.
                         */
-                       for (i = num_object_defs - 1;
+                       for (i = num_method_defs - 1;
                             i >= 0 && !method_defs[i]->handler; i--)
                                ;
                        hash->methods[min_id++] = method;
index 395a3b0..b1ca223 100644 (file)
@@ -650,12 +650,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command)
        return -1;
 }
 
+static bool verify_command_idx(u32 command, bool extended)
+{
+       if (extended)
+               return command < ARRAY_SIZE(uverbs_ex_cmd_table);
+
+       return command < ARRAY_SIZE(uverbs_cmd_table);
+}
+
 static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
                             size_t count, loff_t *pos)
 {
        struct ib_uverbs_file *file = filp->private_data;
        struct ib_device *ib_dev;
        struct ib_uverbs_cmd_hdr hdr;
+       bool extended_command;
        __u32 command;
        __u32 flags;
        int srcu_key;
@@ -688,6 +697,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
        }
 
        command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK;
+       flags = (hdr.command &
+                IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
+
+       extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED;
+       if (!verify_command_idx(command, extended_command)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
        if (verify_command_mask(ib_dev, command)) {
                ret = -EOPNOTSUPP;
                goto out;
@@ -699,12 +717,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
                goto out;
        }
 
-       flags = (hdr.command &
-                IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT;
-
        if (!flags) {
-               if (command >= ARRAY_SIZE(uverbs_cmd_table) ||
-                   !uverbs_cmd_table[command]) {
+               if (!uverbs_cmd_table[command]) {
                        ret = -EINVAL;
                        goto out;
                }
@@ -725,8 +739,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
                struct ib_udata uhw;
                size_t written_count = count;
 
-               if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) ||
-                   !uverbs_ex_cmd_table[command]) {
+               if (!uverbs_ex_cmd_table[command]) {
                        ret = -ENOSYS;
                        goto out;
                }
@@ -942,6 +955,7 @@ static const struct file_operations uverbs_fops = {
        .llseek  = no_llseek,
 #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS)
        .unlocked_ioctl = ib_uverbs_ioctl,
+       .compat_ioctl = ib_uverbs_ioctl,
 #endif
 };
 
@@ -954,6 +968,7 @@ static const struct file_operations uverbs_mmap_fops = {
        .llseek  = no_llseek,
 #if IS_ENABLED(CONFIG_INFINIBAND_EXP_USER_ACCESS)
        .unlocked_ioctl = ib_uverbs_ioctl,
+       .compat_ioctl = ib_uverbs_ioctl,
 #endif
 };
 
index cab0ac3..df1360e 100644 (file)
@@ -234,15 +234,18 @@ static void create_udata(struct uverbs_attr_bundle *ctx,
                uverbs_attr_get(ctx, UVERBS_UHW_OUT);
 
        if (!IS_ERR(uhw_in)) {
-               udata->inbuf = uhw_in->ptr_attr.ptr;
                udata->inlen = uhw_in->ptr_attr.len;
+               if (uverbs_attr_ptr_is_inline(uhw_in))
+                       udata->inbuf = &uhw_in->uattr->data;
+               else
+                       udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
        } else {
                udata->inbuf = NULL;
                udata->inlen = 0;
        }
 
        if (!IS_ERR(uhw_out)) {
-               udata->outbuf = uhw_out->ptr_attr.ptr;
+               udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
                udata->outlen = uhw_out->ptr_attr.len;
        } else {
                udata->outbuf = NULL;
@@ -323,7 +326,8 @@ static int uverbs_create_cq_handler(struct ib_device *ib_dev,
        cq->res.type = RDMA_RESTRACK_CQ;
        rdma_restrack_add(&cq->res);
 
-       ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe);
+       ret = uverbs_copy_to(attrs, CREATE_CQ_RESP_CQE, &cq->cqe,
+                            sizeof(cq->cqe));
        if (ret)
                goto err_cq;
 
@@ -375,7 +379,7 @@ static int uverbs_destroy_cq_handler(struct ib_device *ib_dev,
        resp.comp_events_reported  = obj->comp_events_reported;
        resp.async_events_reported = obj->async_events_reported;
 
-       return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp);
+       return uverbs_copy_to(attrs, DESTROY_CQ_RESP, &resp, sizeof(resp));
 }
 
 static DECLARE_UVERBS_METHOD(
index 16ebc63..93025d2 100644 (file)
@@ -887,7 +887,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        if (qp_init_attr->cap.max_rdma_ctxs)
                rdma_rw_init_qp(device, qp_init_attr);
 
-       qp = _ib_create_qp(device, pd, qp_init_attr, NULL);
+       qp = _ib_create_qp(device, pd, qp_init_attr, NULL, NULL);
        if (IS_ERR(qp))
                return qp;
 
@@ -898,7 +898,6 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
        }
 
        qp->real_qp    = qp;
-       qp->uobject    = NULL;
        qp->qp_type    = qp_init_attr->qp_type;
        qp->rwq_ind_tbl = qp_init_attr->rwq_ind_tbl;
 
index ca32057..96f7689 100644 (file)
@@ -57,8 +57,8 @@
 #define BNXT_RE_PAGE_SIZE_8M           BIT(BNXT_RE_PAGE_SHIFT_8M)
 #define BNXT_RE_PAGE_SIZE_1G           BIT(BNXT_RE_PAGE_SHIFT_1G)
 
-#define BNXT_RE_MAX_MR_SIZE_LOW                BIT(BNXT_RE_PAGE_SHIFT_1G)
-#define BNXT_RE_MAX_MR_SIZE_HIGH       BIT(39)
+#define BNXT_RE_MAX_MR_SIZE_LOW                BIT_ULL(BNXT_RE_PAGE_SHIFT_1G)
+#define BNXT_RE_MAX_MR_SIZE_HIGH       BIT_ULL(39)
 #define BNXT_RE_MAX_MR_SIZE            BNXT_RE_MAX_MR_SIZE_HIGH
 
 #define BNXT_RE_MAX_QPC_COUNT          (64 * 1024)
@@ -120,7 +120,6 @@ struct bnxt_re_dev {
 #define BNXT_RE_FLAG_HAVE_L2_REF               3
 #define BNXT_RE_FLAG_RCFW_CHANNEL_EN           4
 #define BNXT_RE_FLAG_QOS_WORK_REG              5
-#define BNXT_RE_FLAG_TASK_IN_PROG              6
 #define BNXT_RE_FLAG_ISSUE_ROCE_STATS          29
        struct net_device               *netdev;
        unsigned int                    version, major, minor;
@@ -158,6 +157,7 @@ struct bnxt_re_dev {
        atomic_t                        srq_count;
        atomic_t                        mr_count;
        atomic_t                        mw_count;
+       atomic_t                        sched_count;
        /* Max of 2 lossless traffic class supported per port */
        u16                             cosq[2];
 
index ae9e9ff..8301d7e 100644 (file)
@@ -174,10 +174,8 @@ int bnxt_re_query_device(struct ib_device *ibdev,
        ib_attr->max_pd = dev_attr->max_pd;
        ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom;
        ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
-       if (dev_attr->is_atomic) {
-               ib_attr->atomic_cap = IB_ATOMIC_HCA;
-               ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
-       }
+       ib_attr->atomic_cap = IB_ATOMIC_NONE;
+       ib_attr->masked_atomic_cap = IB_ATOMIC_NONE;
 
        ib_attr->max_ee_rd_atom = 0;
        ib_attr->max_res_rd_atom = 0;
@@ -787,20 +785,51 @@ int bnxt_re_query_ah(struct ib_ah *ib_ah, struct rdma_ah_attr *ah_attr)
        return 0;
 }
 
+unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp)
+       __acquires(&qp->scq->cq_lock) __acquires(&qp->rcq->cq_lock)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->scq->cq_lock, flags);
+       if (qp->rcq != qp->scq)
+               spin_lock(&qp->rcq->cq_lock);
+       else
+               __acquire(&qp->rcq->cq_lock);
+
+       return flags;
+}
+
+void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp,
+                       unsigned long flags)
+       __releases(&qp->scq->cq_lock) __releases(&qp->rcq->cq_lock)
+{
+       if (qp->rcq != qp->scq)
+               spin_unlock(&qp->rcq->cq_lock);
+       else
+               __release(&qp->rcq->cq_lock);
+       spin_unlock_irqrestore(&qp->scq->cq_lock, flags);
+}
+
 /* Queue Pairs */
 int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
 {
        struct bnxt_re_qp *qp = container_of(ib_qp, struct bnxt_re_qp, ib_qp);
        struct bnxt_re_dev *rdev = qp->rdev;
        int rc;
+       unsigned int flags;
 
        bnxt_qplib_flush_cqn_wq(&qp->qplib_qp);
-       bnxt_qplib_del_flush_qp(&qp->qplib_qp);
        rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
        if (rc) {
                dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
                return rc;
        }
+
+       flags = bnxt_re_lock_cqs(qp);
+       bnxt_qplib_clean_qp(&qp->qplib_qp);
+       bnxt_re_unlock_cqs(qp, flags);
+       bnxt_qplib_free_qp_res(&rdev->qplib_res, &qp->qplib_qp);
+
        if (ib_qp->qp_type == IB_QPT_GSI && rdev->qp1_sqp) {
                rc = bnxt_qplib_destroy_ah(&rdev->qplib_res,
                                           &rdev->sqp_ah->qplib_ah);
@@ -810,7 +839,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
                        return rc;
                }
 
-               bnxt_qplib_del_flush_qp(&qp->qplib_qp);
+               bnxt_qplib_clean_qp(&qp->qplib_qp);
                rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
                                           &rdev->qp1_sqp->qplib_qp);
                if (rc) {
@@ -1069,6 +1098,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
                        goto fail;
                }
                qp->qplib_qp.scq = &cq->qplib_cq;
+               qp->scq = cq;
        }
 
        if (qp_init_attr->recv_cq) {
@@ -1080,6 +1110,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
                        goto fail;
                }
                qp->qplib_qp.rcq = &cq->qplib_cq;
+               qp->rcq = cq;
        }
 
        if (qp_init_attr->srq) {
@@ -1185,7 +1216,7 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
                rc = bnxt_qplib_create_qp(&rdev->qplib_res, &qp->qplib_qp);
                if (rc) {
                        dev_err(rdev_to_dev(rdev), "Failed to create HW QP");
-                       goto fail;
+                       goto free_umem;
                }
        }
 
@@ -1213,6 +1244,13 @@ struct ib_qp *bnxt_re_create_qp(struct ib_pd *ib_pd,
        return &qp->ib_qp;
 qp_destroy:
        bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
+free_umem:
+       if (udata) {
+               if (qp->rumem)
+                       ib_umem_release(qp->rumem);
+               if (qp->sumem)
+                       ib_umem_release(qp->sumem);
+       }
 fail:
        kfree(qp);
        return ERR_PTR(rc);
@@ -1568,6 +1606,7 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
        int status;
        union ib_gid sgid;
        struct ib_gid_attr sgid_attr;
+       unsigned int flags;
        u8 nw_type;
 
        qp->qplib_qp.modify_flags = 0;
@@ -1596,14 +1635,18 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
                        dev_dbg(rdev_to_dev(rdev),
                                "Move QP = %p to flush list\n",
                                qp);
+                       flags = bnxt_re_lock_cqs(qp);
                        bnxt_qplib_add_flush_qp(&qp->qplib_qp);
+                       bnxt_re_unlock_cqs(qp, flags);
                }
                if (!qp->sumem &&
                    qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
                        dev_dbg(rdev_to_dev(rdev),
                                "Move QP = %p out of flush list\n",
                                qp);
-                       bnxt_qplib_del_flush_qp(&qp->qplib_qp);
+                       flags = bnxt_re_lock_cqs(qp);
+                       bnxt_qplib_clean_qp(&qp->qplib_qp);
+                       bnxt_re_unlock_cqs(qp, flags);
                }
        }
        if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
@@ -2189,10 +2232,13 @@ static int bnxt_re_build_inv_wqe(struct ib_send_wr *wr,
        wqe->type = BNXT_QPLIB_SWQE_TYPE_LOCAL_INV;
        wqe->local_inv.inv_l_key = wr->ex.invalidate_rkey;
 
+       /* Need unconditional fence for local invalidate
+        * opcode to work as expected.
+        */
+       wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
+
        if (wr->send_flags & IB_SEND_SIGNALED)
                wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP;
-       if (wr->send_flags & IB_SEND_FENCE)
-               wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
        if (wr->send_flags & IB_SEND_SOLICITED)
                wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SOLICIT_EVENT;
 
@@ -2213,8 +2259,12 @@ static int bnxt_re_build_reg_wqe(struct ib_reg_wr *wr,
        wqe->frmr.levels = qplib_frpl->hwq.level + 1;
        wqe->type = BNXT_QPLIB_SWQE_TYPE_REG_MR;
 
-       if (wr->wr.send_flags & IB_SEND_FENCE)
-               wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
+       /* Need unconditional fence for reg_mr
+        * opcode to function as expected.
+        */
+
+       wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_UC_FENCE;
+
        if (wr->wr.send_flags & IB_SEND_SIGNALED)
                wqe->flags |= BNXT_QPLIB_SWQE_FLAGS_SIGNAL_COMP;
 
@@ -3548,7 +3598,7 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length,
        int umem_pgs, page_shift, rc;
 
        if (length > BNXT_RE_MAX_MR_SIZE) {
-               dev_err(rdev_to_dev(rdev), "MR Size: %lld > Max supported:%ld\n",
+               dev_err(rdev_to_dev(rdev), "MR Size: %lld > Max supported:%lld\n",
                        length, BNXT_RE_MAX_MR_SIZE);
                return ERR_PTR(-ENOMEM);
        }
index 423ebe0..e62b7c2 100644 (file)
@@ -89,6 +89,8 @@ struct bnxt_re_qp {
        /* QP1 */
        u32                     send_psn;
        struct ib_ud_header     qp1_hdr;
+       struct bnxt_re_cq       *scq;
+       struct bnxt_re_cq       *rcq;
 };
 
 struct bnxt_re_cq {
@@ -220,4 +222,7 @@ struct ib_ucontext *bnxt_re_alloc_ucontext(struct ib_device *ibdev,
                                           struct ib_udata *udata);
 int bnxt_re_dealloc_ucontext(struct ib_ucontext *context);
 int bnxt_re_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+unsigned long bnxt_re_lock_cqs(struct bnxt_re_qp *qp);
+void bnxt_re_unlock_cqs(struct bnxt_re_qp *qp, unsigned long flags);
 #endif /* __BNXT_RE_IB_VERBS_H__ */
index 508d00a..f6e3617 100644 (file)
@@ -656,7 +656,6 @@ static void bnxt_re_dev_remove(struct bnxt_re_dev *rdev)
        mutex_unlock(&bnxt_re_dev_lock);
 
        synchronize_rcu();
-       flush_workqueue(bnxt_re_wq);
 
        ib_dealloc_device(&rdev->ibdev);
        /* rdev is gone */
@@ -731,6 +730,13 @@ static int bnxt_re_handle_qp_async_event(struct creq_qp_event *qp_event,
                                         struct bnxt_re_qp *qp)
 {
        struct ib_event event;
+       unsigned int flags;
+
+       if (qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
+               flags = bnxt_re_lock_cqs(qp);
+               bnxt_qplib_add_flush_qp(&qp->qplib_qp);
+               bnxt_re_unlock_cqs(qp, flags);
+       }
 
        memset(&event, 0, sizeof(event));
        if (qp->qplib_qp.srq) {
@@ -1417,9 +1423,12 @@ static void bnxt_re_task(struct work_struct *work)
        switch (re_work->event) {
        case NETDEV_REGISTER:
                rc = bnxt_re_ib_reg(rdev);
-               if (rc)
+               if (rc) {
                        dev_err(rdev_to_dev(rdev),
                                "Failed to register with IB: %#x", rc);
+                       bnxt_re_remove_one(rdev);
+                       bnxt_re_dev_unreg(rdev);
+               }
                break;
        case NETDEV_UP:
                bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1,
@@ -1441,7 +1450,7 @@ static void bnxt_re_task(struct work_struct *work)
                break;
        }
        smp_mb__before_atomic();
-       clear_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
+       atomic_dec(&rdev->sched_count);
        kfree(re_work);
 }
 
@@ -1503,7 +1512,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
                /* netdev notifier will call NETDEV_UNREGISTER again later since
                 * we are still holding the reference to the netdev
                 */
-               if (test_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags))
+               if (atomic_read(&rdev->sched_count) > 0)
                        goto exit;
                bnxt_re_ib_unreg(rdev, false);
                bnxt_re_remove_one(rdev);
@@ -1523,7 +1532,7 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
                        re_work->vlan_dev = (real_dev == netdev ?
                                             NULL : netdev);
                        INIT_WORK(&re_work->work, bnxt_re_task);
-                       set_bit(BNXT_RE_FLAG_TASK_IN_PROG, &rdev->flags);
+                       atomic_inc(&rdev->sched_count);
                        queue_work(bnxt_re_wq, &re_work->work);
                }
        }
@@ -1578,6 +1587,11 @@ static void __exit bnxt_re_mod_exit(void)
        */
        list_for_each_entry_safe_reverse(rdev, next, &to_be_deleted, list) {
                dev_info(rdev_to_dev(rdev), "Unregistering Device");
+               /*
+                * Flush out any scheduled tasks before destroying the
+                * resources
+                */
+               flush_workqueue(bnxt_re_wq);
                bnxt_re_dev_stop(rdev);
                bnxt_re_ib_unreg(rdev, true);
                bnxt_re_remove_one(rdev);
index 1b0e946..3a78fab 100644 (file)
@@ -88,75 +88,35 @@ static void __bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
        }
 }
 
-void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp,
-                                unsigned long *flags)
-       __acquires(&qp->scq->hwq.lock) __acquires(&qp->rcq->hwq.lock)
+static void bnxt_qplib_acquire_cq_flush_locks(struct bnxt_qplib_qp *qp,
+                                      unsigned long *flags)
+       __acquires(&qp->scq->flush_lock) __acquires(&qp->rcq->flush_lock)
 {
-       spin_lock_irqsave(&qp->scq->hwq.lock, *flags);
+       spin_lock_irqsave(&qp->scq->flush_lock, *flags);
        if (qp->scq == qp->rcq)
-               __acquire(&qp->rcq->hwq.lock);
+               __acquire(&qp->rcq->flush_lock);
        else
-               spin_lock(&qp->rcq->hwq.lock);
+               spin_lock(&qp->rcq->flush_lock);
 }
 
-void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp,
-                                unsigned long *flags)
-       __releases(&qp->scq->hwq.lock) __releases(&qp->rcq->hwq.lock)
+static void bnxt_qplib_release_cq_flush_locks(struct bnxt_qplib_qp *qp,
+                                      unsigned long *flags)
+       __releases(&qp->scq->flush_lock) __releases(&qp->rcq->flush_lock)
 {
        if (qp->scq == qp->rcq)
-               __release(&qp->rcq->hwq.lock);
+               __release(&qp->rcq->flush_lock);
        else
-               spin_unlock(&qp->rcq->hwq.lock);
-       spin_unlock_irqrestore(&qp->scq->hwq.lock, *flags);
-}
-
-static struct bnxt_qplib_cq *bnxt_qplib_find_buddy_cq(struct bnxt_qplib_qp *qp,
-                                                     struct bnxt_qplib_cq *cq)
-{
-       struct bnxt_qplib_cq *buddy_cq = NULL;
-
-       if (qp->scq == qp->rcq)
-               buddy_cq = NULL;
-       else if (qp->scq == cq)
-               buddy_cq = qp->rcq;
-       else
-               buddy_cq = qp->scq;
-       return buddy_cq;
-}
-
-static void bnxt_qplib_lock_buddy_cq(struct bnxt_qplib_qp *qp,
-                                    struct bnxt_qplib_cq *cq)
-       __acquires(&buddy_cq->hwq.lock)
-{
-       struct bnxt_qplib_cq *buddy_cq = NULL;
-
-       buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq);
-       if (!buddy_cq)
-               __acquire(&cq->hwq.lock);
-       else
-               spin_lock(&buddy_cq->hwq.lock);
-}
-
-static void bnxt_qplib_unlock_buddy_cq(struct bnxt_qplib_qp *qp,
-                                      struct bnxt_qplib_cq *cq)
-       __releases(&buddy_cq->hwq.lock)
-{
-       struct bnxt_qplib_cq *buddy_cq = NULL;
-
-       buddy_cq = bnxt_qplib_find_buddy_cq(qp, cq);
-       if (!buddy_cq)
-               __release(&cq->hwq.lock);
-       else
-               spin_unlock(&buddy_cq->hwq.lock);
+               spin_unlock(&qp->rcq->flush_lock);
+       spin_unlock_irqrestore(&qp->scq->flush_lock, *flags);
 }
 
 void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
 {
        unsigned long flags;
 
-       bnxt_qplib_acquire_cq_locks(qp, &flags);
+       bnxt_qplib_acquire_cq_flush_locks(qp, &flags);
        __bnxt_qplib_add_flush_qp(qp);
-       bnxt_qplib_release_cq_locks(qp, &flags);
+       bnxt_qplib_release_cq_flush_locks(qp, &flags);
 }
 
 static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
@@ -173,11 +133,11 @@ static void __bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
        }
 }
 
-void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
+void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp)
 {
        unsigned long flags;
 
-       bnxt_qplib_acquire_cq_locks(qp, &flags);
+       bnxt_qplib_acquire_cq_flush_locks(qp, &flags);
        __clean_cq(qp->scq, (u64)(unsigned long)qp);
        qp->sq.hwq.prod = 0;
        qp->sq.hwq.cons = 0;
@@ -186,7 +146,7 @@ void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
        qp->rq.hwq.cons = 0;
 
        __bnxt_qplib_del_flush_qp(qp);
-       bnxt_qplib_release_cq_locks(qp, &flags);
+       bnxt_qplib_release_cq_flush_locks(qp, &flags);
 }
 
 static void bnxt_qpn_cqn_sched_task(struct work_struct *work)
@@ -283,7 +243,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
        u32 sw_cons, raw_cons;
        u16 type;
        int budget = nq->budget;
-       u64 q_handle;
+       uintptr_t q_handle;
 
        /* Service the NQ until empty */
        raw_cons = hwq->cons;
@@ -566,7 +526,7 @@ int bnxt_qplib_create_srq(struct bnxt_qplib_res *res,
 
        /* Configure the request */
        req.dpi = cpu_to_le32(srq->dpi->dpi);
-       req.srq_handle = cpu_to_le64(srq);
+       req.srq_handle = cpu_to_le64((uintptr_t)srq);
 
        req.srq_size = cpu_to_le16((u16)srq->hwq.max_elements);
        pbl = &srq->hwq.pbl[PBL_LVL_0];
@@ -1419,7 +1379,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
        struct bnxt_qplib_rcfw *rcfw = res->rcfw;
        struct cmdq_destroy_qp req;
        struct creq_destroy_qp_resp resp;
-       unsigned long flags;
        u16 cmd_flags = 0;
        int rc;
 
@@ -1437,19 +1396,12 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
                return rc;
        }
 
-       /* Must walk the associated CQs to nullified the QP ptr */
-       spin_lock_irqsave(&qp->scq->hwq.lock, flags);
-
-       __clean_cq(qp->scq, (u64)(unsigned long)qp);
-
-       if (qp->rcq && qp->rcq != qp->scq) {
-               spin_lock(&qp->rcq->hwq.lock);
-               __clean_cq(qp->rcq, (u64)(unsigned long)qp);
-               spin_unlock(&qp->rcq->hwq.lock);
-       }
-
-       spin_unlock_irqrestore(&qp->scq->hwq.lock, flags);
+       return 0;
+}
 
+void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res,
+                           struct bnxt_qplib_qp *qp)
+{
        bnxt_qplib_free_qp_hdr_buf(res, qp);
        bnxt_qplib_free_hwq(res->pdev, &qp->sq.hwq);
        kfree(qp->sq.swq);
@@ -1462,7 +1414,6 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
        if (qp->orrq.max_elements)
                bnxt_qplib_free_hwq(res->pdev, &qp->orrq);
 
-       return 0;
 }
 
 void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp,
@@ -2116,9 +2067,6 @@ void bnxt_qplib_mark_qp_error(void *qp_handle)
        /* Must block new posting of SQ and RQ */
        qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
        bnxt_qplib_cancel_phantom_processing(qp);
-
-       /* Add qp to flush list of the CQ */
-       __bnxt_qplib_add_flush_qp(qp);
 }
 
 /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive)
@@ -2294,9 +2242,9 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
                                sw_sq_cons, cqe->wr_id, cqe->status);
                        cqe++;
                        (*budget)--;
-                       bnxt_qplib_lock_buddy_cq(qp, cq);
                        bnxt_qplib_mark_qp_error(qp);
-                       bnxt_qplib_unlock_buddy_cq(qp, cq);
+                       /* Add qp to flush list of the CQ */
+                       bnxt_qplib_add_flush_qp(qp);
                } else {
                        if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) {
                                /* Before we complete, do WA 9060 */
@@ -2412,9 +2360,7 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
                if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
                        qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
                        /* Add qp to flush list of the CQ */
-                       bnxt_qplib_lock_buddy_cq(qp, cq);
-                       __bnxt_qplib_add_flush_qp(qp);
-                       bnxt_qplib_unlock_buddy_cq(qp, cq);
+                       bnxt_qplib_add_flush_qp(qp);
                }
        }
 
@@ -2498,9 +2444,7 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
                if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
                        qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
                        /* Add qp to flush list of the CQ */
-                       bnxt_qplib_lock_buddy_cq(qp, cq);
-                       __bnxt_qplib_add_flush_qp(qp);
-                       bnxt_qplib_unlock_buddy_cq(qp, cq);
+                       bnxt_qplib_add_flush_qp(qp);
                }
        }
 done:
@@ -2510,11 +2454,9 @@ done:
 bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq)
 {
        struct cq_base *hw_cqe, **hw_cqe_ptr;
-       unsigned long flags;
        u32 sw_cons, raw_cons;
        bool rc = true;
 
-       spin_lock_irqsave(&cq->hwq.lock, flags);
        raw_cons = cq->hwq.cons;
        sw_cons = HWQ_CMP(raw_cons, &cq->hwq);
        hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr;
@@ -2522,7 +2464,6 @@ bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq)
 
         /* Check for Valid bit. If the CQE is valid, return false */
        rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements);
-       spin_unlock_irqrestore(&cq->hwq.lock, flags);
        return rc;
 }
 
@@ -2611,9 +2552,7 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
                if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
                        qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
                        /* Add qp to flush list of the CQ */
-                       bnxt_qplib_lock_buddy_cq(qp, cq);
-                       __bnxt_qplib_add_flush_qp(qp);
-                       bnxt_qplib_unlock_buddy_cq(qp, cq);
+                       bnxt_qplib_add_flush_qp(qp);
                }
        }
 
@@ -2728,9 +2667,7 @@ do_rq:
         */
 
        /* Add qp to flush list of the CQ */
-       bnxt_qplib_lock_buddy_cq(qp, cq);
-       __bnxt_qplib_add_flush_qp(qp);
-       bnxt_qplib_unlock_buddy_cq(qp, cq);
+       bnxt_qplib_add_flush_qp(qp);
 done:
        return rc;
 }
@@ -2759,7 +2696,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
        u32 budget = num_cqes;
        unsigned long flags;
 
-       spin_lock_irqsave(&cq->hwq.lock, flags);
+       spin_lock_irqsave(&cq->flush_lock, flags);
        list_for_each_entry(qp, &cq->sqf_head, sq_flush) {
                dev_dbg(&cq->hwq.pdev->dev,
                        "QPLIB: FP: Flushing SQ QP= %p",
@@ -2773,7 +2710,7 @@ int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
                        qp);
                __flush_rq(&qp->rq, qp, &cqe, &budget);
        }
-       spin_unlock_irqrestore(&cq->hwq.lock, flags);
+       spin_unlock_irqrestore(&cq->flush_lock, flags);
 
        return num_cqes - budget;
 }
@@ -2782,11 +2719,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
                       int num_cqes, struct bnxt_qplib_qp **lib_qp)
 {
        struct cq_base *hw_cqe, **hw_cqe_ptr;
-       unsigned long flags;
        u32 sw_cons, raw_cons;
        int budget, rc = 0;
 
-       spin_lock_irqsave(&cq->hwq.lock, flags);
        raw_cons = cq->hwq.cons;
        budget = num_cqes;
 
@@ -2862,20 +2797,15 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
                bnxt_qplib_arm_cq(cq, DBR_DBR_TYPE_CQ);
        }
 exit:
-       spin_unlock_irqrestore(&cq->hwq.lock, flags);
        return num_cqes - budget;
 }
 
 void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&cq->hwq.lock, flags);
        if (arm_type)
                bnxt_qplib_arm_cq(cq, arm_type);
        /* Using cq->arm_state variable to track whether to issue cq handler */
        atomic_set(&cq->arm_state, 1);
-       spin_unlock_irqrestore(&cq->hwq.lock, flags);
 }
 
 void bnxt_qplib_flush_cqn_wq(struct bnxt_qplib_qp *qp)
index 211b27a..ade9f13 100644 (file)
@@ -389,6 +389,18 @@ struct bnxt_qplib_cq {
        struct list_head                sqf_head, rqf_head;
        atomic_t                        arm_state;
        spinlock_t                      compl_lock; /* synch CQ handlers */
+/* Locking Notes:
+ * QP can move to error state from modify_qp, async error event or error
+ * CQE as part of poll_cq. When QP is moved to error state, it gets added
+ * to two flush lists, one each for SQ and RQ.
+ * Each flush list is protected by qplib_cq->flush_lock. Both scq and rcq
+ * flush_locks should be acquired when QP is moved to error. The control path
+ * operations(modify_qp and async error events) are synchronized with poll_cq
+ * using upper level CQ locks (bnxt_re_cq->cq_lock) of both SCQ and RCQ.
+ * The qplib_cq->flush_lock is required to synchronize two instances of poll_cq
+ * of the same QP while manipulating the flush list.
+ */
+       spinlock_t                      flush_lock; /* QP flush management */
 };
 
 #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE        sizeof(struct xrrq_irrq)
@@ -478,6 +490,9 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
 int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
 int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
 int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp);
+void bnxt_qplib_clean_qp(struct bnxt_qplib_qp *qp);
+void bnxt_qplib_free_qp_res(struct bnxt_qplib_res *res,
+                           struct bnxt_qplib_qp *qp);
 void *bnxt_qplib_get_qp1_sq_buf(struct bnxt_qplib_qp *qp,
                                struct bnxt_qplib_sge *sge);
 void *bnxt_qplib_get_qp1_rq_buf(struct bnxt_qplib_qp *qp,
@@ -500,7 +515,6 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
 void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
 int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
 void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp);
-void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp);
 void bnxt_qplib_acquire_cq_locks(struct bnxt_qplib_qp *qp,
                                 unsigned long *flags);
 void bnxt_qplib_release_cq_locks(struct bnxt_qplib_qp *qp,
index 8329ec6..80027a4 100644 (file)
@@ -305,9 +305,8 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
                        err_event->res_err_state_reason);
                if (!qp)
                        break;
-               bnxt_qplib_acquire_cq_locks(qp, &flags);
                bnxt_qplib_mark_qp_error(qp);
-               bnxt_qplib_release_cq_locks(qp, &flags);
+               rcfw->aeq_handler(rcfw, qp_event, qp);
                break;
        default:
                /* Command Response */
@@ -460,7 +459,11 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
        int rc;
 
        RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags);
-
+       /* Supply (log-base-2-of-host-page-size - base-page-shift)
+        * to bono to adjust the doorbell page sizes.
+        */
+       req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT -
+                                          RCFW_DBR_BASE_PAGE_SHIFT);
        /*
         * VFs need not setup the HW context area, PF
         * shall setup this area for VF. Skipping the
index 6bee6e3..c7cce2e 100644 (file)
@@ -49,6 +49,7 @@
 #define RCFW_COMM_SIZE                 0x104
 
 #define RCFW_DBR_PCI_BAR_REGION                2
+#define RCFW_DBR_BASE_PAGE_SHIFT       12
 
 #define RCFW_CMD_PREP(req, CMD, cmd_flags)                             \
        do {                                                            \
index c015c18..ee98e5e 100644 (file)
@@ -52,18 +52,6 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0,
 
 /* Device */
 
-static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw)
-{
-       int rc;
-       u16 pcie_ctl2;
-
-       rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2,
-                                      &pcie_ctl2);
-       if (rc)
-               return false;
-       return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ);
-}
-
 static void bnxt_qplib_query_version(struct bnxt_qplib_rcfw *rcfw,
                                     char *fw_ver)
 {
@@ -151,7 +139,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
        attr->max_pkey = le32_to_cpu(sb->max_pkeys);
 
        attr->max_inline_data = le32_to_cpu(sb->max_inline_data);
-       attr->l2_db_size = (sb->l2_db_space_size + 1) * PAGE_SIZE;
+       attr->l2_db_size = (sb->l2_db_space_size + 1) *
+                           (0x01 << RCFW_DBR_BASE_PAGE_SHIFT);
        attr->max_sgid = le32_to_cpu(sb->max_gid);
 
        bnxt_qplib_query_version(rcfw, attr->fw_ver);
@@ -165,7 +154,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
                attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc);
        }
 
-       attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw);
+       attr->is_atomic = 0;
 bail:
        bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf);
        return rc;
index 2d7ea09..3e5a4f7 100644 (file)
@@ -1761,7 +1761,30 @@ struct cmdq_initialize_fw {
        #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_2M               (0x3UL << 4)
        #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_8M               (0x4UL << 4)
        #define CMDQ_INITIALIZE_FW_TIM_PG_SIZE_PG_1G               (0x5UL << 4)
-       __le16 reserved16;
+       /* This value is (log-base-2-of-DBR-page-size - 12).
+        * 0 for 4KB. HW supported values are enumerated below.
+        */
+       __le16  log2_dbr_pg_size;
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_MASK        0xfUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_SFT         0
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4K       0x0UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8K       0x1UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16K      0x2UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32K      0x3UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64K      0x4UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128K     0x5UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_256K     0x6UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_512K     0x7UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_1M       0x8UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_2M       0x9UL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_4M       0xaUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_8M       0xbUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_16M      0xcUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_32M      0xdUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_64M      0xeUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M     0xfUL
+       #define CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_LAST                \
+                       CMDQ_INITIALIZE_FW_LOG2_DBR_PG_SIZE_PG_128M
        __le64 qpc_page_dir;
        __le64 mrw_page_dir;
        __le64 srq_page_dir;
index db2ff35..ec63877 100644 (file)
@@ -4383,7 +4383,7 @@ err_dma_alloc_buf:
        eq->l0_dma = 0;
 
        if (mhop_num == 1)
-               for (i -= i; i >= 0; i--)
+               for (i -= 1; i >= 0; i--)
                        dma_free_coherent(dev, buf_chk_sz, eq->buf[i],
                                          eq->buf_dma[i]);
        else if (mhop_num == 2) {
index 9a566ee..82adc0d 100644 (file)
@@ -601,6 +601,7 @@ static void use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct
        wc->dlid_path_bits = 0;
 
        if (is_eth) {
+               wc->slid = 0;
                wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid);
                memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4);
                memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2);
@@ -851,7 +852,6 @@ repoll:
                        }
                }
 
-               wc->slid           = be16_to_cpu(cqe->rlid);
                g_mlpath_rqpn      = be32_to_cpu(cqe->g_mlpath_rqpn);
                wc->src_qp         = g_mlpath_rqpn & 0xffffff;
                wc->dlid_path_bits = (g_mlpath_rqpn >> 24) & 0x7f;
@@ -860,6 +860,7 @@ repoll:
                wc->wc_flags      |= mlx4_ib_ipoib_csum_ok(cqe->status,
                                        cqe->checksum) ? IB_WC_IP_CSUM_OK : 0;
                if (is_eth) {
+                       wc->slid = 0;
                        wc->sl  = be16_to_cpu(cqe->sl_vid) >> 13;
                        if (be32_to_cpu(cqe->vlan_my_qpn) &
                                        MLX4_CQE_CVLAN_PRESENT_MASK) {
@@ -871,6 +872,7 @@ repoll:
                        memcpy(wc->smac, cqe->smac, ETH_ALEN);
                        wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC);
                } else {
+                       wc->slid = be16_to_cpu(cqe->rlid);
                        wc->sl  = be16_to_cpu(cqe->sl_vid) >> 12;
                        wc->vlan_id = 0xffff;
                }
index 8d2ee93..5a0e4fc 100644 (file)
@@ -219,8 +219,6 @@ static int mlx4_ib_update_gids_v1_v2(struct gid_entry *gids,
                        gid_tbl[i].version = 2;
                        if (!ipv6_addr_v4mapped((struct in6_addr *)&gids[i].gid))
                                gid_tbl[i].type = 1;
-                       else
-                               memset(&gid_tbl[i].gid, 0, 12);
                }
        }
 
@@ -366,8 +364,13 @@ static int mlx4_ib_del_gid(struct ib_device *device,
                if (!gids) {
                        ret = -ENOMEM;
                } else {
-                       for (i = 0; i < MLX4_MAX_PORT_GIDS; i++)
-                               memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid));
+                       for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) {
+                               memcpy(&gids[i].gid,
+                                      &port_gid_table->gids[i].gid,
+                                      sizeof(union ib_gid));
+                               gids[i].gid_type =
+                                   port_gid_table->gids[i].gid_type;
+                       }
                }
        }
        spin_unlock_bh(&iboe->lock);
index 5b974fb..15457c9 100644 (file)
@@ -226,7 +226,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
                wc->ex.invalidate_rkey = be32_to_cpu(cqe->imm_inval_pkey);
                break;
        }
-       wc->slid           = be16_to_cpu(cqe->slid);
        wc->src_qp         = be32_to_cpu(cqe->flags_rqpn) & 0xffffff;
        wc->dlid_path_bits = cqe->ml_path;
        g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
@@ -241,10 +240,12 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe,
        }
 
        if (ll != IB_LINK_LAYER_ETHERNET) {
+               wc->slid = be16_to_cpu(cqe->slid);
                wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf;
                return;
        }
 
+       wc->slid = 0;
        vlan_present = cqe->l4_l3_hdr_type & 0x1;
        roce_packet_type   = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3;
        if (vlan_present) {
@@ -1177,7 +1178,12 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq,
        if (ucmd.reserved0 || ucmd.reserved1)
                return -EINVAL;
 
-       umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size,
+       /* check multiplication overflow */
+       if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1)
+               return -EINVAL;
+
+       umem = ib_umem_get(context, ucmd.buf_addr,
+                          (size_t)ucmd.cqe_size * entries,
                           IB_ACCESS_LOCAL_WRITE, 1);
        if (IS_ERR(umem)) {
                err = PTR_ERR(umem);
index 4236c80..7f8bda3 100644 (file)
@@ -245,12 +245,16 @@ struct mlx5_core_dev *mlx5_ib_get_native_port_mdev(struct mlx5_ib_dev *ibdev,
        struct mlx5_ib_multiport_info *mpi;
        struct mlx5_ib_port *port;
 
+       if (!mlx5_core_mp_enabled(ibdev->mdev) ||
+           ll != IB_LINK_LAYER_ETHERNET) {
+               if (native_port_num)
+                       *native_port_num = ib_port_num;
+               return ibdev->mdev;
+       }
+
        if (native_port_num)
                *native_port_num = 1;
 
-       if (!mlx5_core_mp_enabled(ibdev->mdev) || ll != IB_LINK_LAYER_ETHERNET)
-               return ibdev->mdev;
-
        port = &ibdev->port[ib_port_num - 1];
        if (!port)
                return NULL;
@@ -3263,7 +3267,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work)
        struct mlx5_ib_dev *ibdev;
        struct ib_event ibev;
        bool fatal = false;
-       u8 port = 0;
+       u8 port = (u8)work->param;
 
        if (mlx5_core_is_mp_slave(work->dev)) {
                ibdev = mlx5_ib_get_ibdev_from_mpi(work->context);
@@ -3283,8 +3287,6 @@ static void mlx5_ib_handle_event(struct work_struct *_work)
        case MLX5_DEV_EVENT_PORT_UP:
        case MLX5_DEV_EVENT_PORT_DOWN:
        case MLX5_DEV_EVENT_PORT_INITIALIZED:
-               port = (u8)work->param;
-
                /* In RoCE, port up/down events are handled in
                 * mlx5_netdev_event().
                 */
@@ -3298,24 +3300,19 @@ static void mlx5_ib_handle_event(struct work_struct *_work)
 
        case MLX5_DEV_EVENT_LID_CHANGE:
                ibev.event = IB_EVENT_LID_CHANGE;
-               port = (u8)work->param;
                break;
 
        case MLX5_DEV_EVENT_PKEY_CHANGE:
                ibev.event = IB_EVENT_PKEY_CHANGE;
-               port = (u8)work->param;
-
                schedule_work(&ibdev->devr.ports[port - 1].pkey_change_work);
                break;
 
        case MLX5_DEV_EVENT_GUID_CHANGE:
                ibev.event = IB_EVENT_GID_CHANGE;
-               port = (u8)work->param;
                break;
 
        case MLX5_DEV_EVENT_CLIENT_REREG:
                ibev.event = IB_EVENT_CLIENT_REREGISTER;
-               port = (u8)work->param;
                break;
        case MLX5_DEV_EVENT_DELAY_DROP_TIMEOUT:
                schedule_work(&ibdev->delay_drop.delay_drop_work);
@@ -3327,7 +3324,7 @@ static void mlx5_ib_handle_event(struct work_struct *_work)
        ibev.device           = &ibdev->ib_dev;
        ibev.element.port_num = port;
 
-       if (port < 1 || port > ibdev->num_ports) {
+       if (!rdma_is_port_valid(&ibdev->ib_dev, port)) {
                mlx5_ib_warn(ibdev, "warning: event on port %d\n", port);
                goto out;
        }
@@ -3451,9 +3448,12 @@ static void destroy_umrc_res(struct mlx5_ib_dev *dev)
        if (err)
                mlx5_ib_warn(dev, "mr cache cleanup failed\n");
 
-       mlx5_ib_destroy_qp(dev->umrc.qp);
-       ib_free_cq(dev->umrc.cq);
-       ib_dealloc_pd(dev->umrc.pd);
+       if (dev->umrc.qp)
+               mlx5_ib_destroy_qp(dev->umrc.qp);
+       if (dev->umrc.cq)
+               ib_free_cq(dev->umrc.cq);
+       if (dev->umrc.pd)
+               ib_dealloc_pd(dev->umrc.pd);
 }
 
 enum {
@@ -3555,12 +3555,15 @@ static int create_umr_res(struct mlx5_ib_dev *dev)
 
 error_4:
        mlx5_ib_destroy_qp(qp);
+       dev->umrc.qp = NULL;
 
 error_3:
        ib_free_cq(cq);
+       dev->umrc.cq = NULL;
 
 error_2:
        ib_dealloc_pd(pd);
+       dev->umrc.pd = NULL;
 
 error_0:
        kfree(attr);
@@ -4863,19 +4866,19 @@ static int mlx5_ib_stage_ib_reg_init(struct mlx5_ib_dev *dev)
        return ib_register_device(&dev->ib_dev, NULL);
 }
 
-static void mlx5_ib_stage_ib_reg_cleanup(struct mlx5_ib_dev *dev)
+static void mlx5_ib_stage_pre_ib_reg_umr_cleanup(struct mlx5_ib_dev *dev)
 {
-       ib_unregister_device(&dev->ib_dev);
+       destroy_umrc_res(dev);
 }
 
-static int mlx5_ib_stage_umr_res_init(struct mlx5_ib_dev *dev)
+static void mlx5_ib_stage_ib_reg_cleanup(struct mlx5_ib_dev *dev)
 {
-       return create_umr_res(dev);
+       ib_unregister_device(&dev->ib_dev);
 }
 
-static void mlx5_ib_stage_umr_res_cleanup(struct mlx5_ib_dev *dev)
+static int mlx5_ib_stage_post_ib_reg_umr_init(struct mlx5_ib_dev *dev)
 {
-       destroy_umrc_res(dev);
+       return create_umr_res(dev);
 }
 
 static int mlx5_ib_stage_delay_drop_init(struct mlx5_ib_dev *dev)
@@ -4985,12 +4988,15 @@ static const struct mlx5_ib_profile pf_profile = {
        STAGE_CREATE(MLX5_IB_STAGE_BFREG,
                     mlx5_ib_stage_bfrag_init,
                     mlx5_ib_stage_bfrag_cleanup),
+       STAGE_CREATE(MLX5_IB_STAGE_PRE_IB_REG_UMR,
+                    NULL,
+                    mlx5_ib_stage_pre_ib_reg_umr_cleanup),
        STAGE_CREATE(MLX5_IB_STAGE_IB_REG,
                     mlx5_ib_stage_ib_reg_init,
                     mlx5_ib_stage_ib_reg_cleanup),
-       STAGE_CREATE(MLX5_IB_STAGE_UMR_RESOURCES,
-                    mlx5_ib_stage_umr_res_init,
-                    mlx5_ib_stage_umr_res_cleanup),
+       STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR,
+                    mlx5_ib_stage_post_ib_reg_umr_init,
+                    NULL),
        STAGE_CREATE(MLX5_IB_STAGE_DELAY_DROP,
                     mlx5_ib_stage_delay_drop_init,
                     mlx5_ib_stage_delay_drop_cleanup),
index 1393851..a527249 100644 (file)
@@ -739,8 +739,9 @@ enum mlx5_ib_stages {
        MLX5_IB_STAGE_CONG_DEBUGFS,
        MLX5_IB_STAGE_UAR,
        MLX5_IB_STAGE_BFREG,
+       MLX5_IB_STAGE_PRE_IB_REG_UMR,
        MLX5_IB_STAGE_IB_REG,
-       MLX5_IB_STAGE_UMR_RESOURCES,
+       MLX5_IB_STAGE_POST_IB_REG_UMR,
        MLX5_IB_STAGE_DELAY_DROP,
        MLX5_IB_STAGE_CLASS_ATTR,
        MLX5_IB_STAGE_MAX,
index 556e015..3e0b3f0 100644 (file)
@@ -739,6 +739,9 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev)
 {
        int i;
 
+       if (!dev->cache.wq)
+               return 0;
+
        dev->cache.stopped = 1;
        flush_workqueue(dev->cache.wq);
 
@@ -838,7 +841,8 @@ static int mr_umem_get(struct ib_pd *pd, u64 start, u64 length,
        *umem = ib_umem_get(pd->uobject->context, start, length,
                            access_flags, 0);
        err = PTR_ERR_OR_ZERO(*umem);
-       if (err < 0) {
+       if (err) {
+               *umem = NULL;
                mlx5_ib_err(dev, "umem get failed (%d)\n", err);
                return err;
        }
@@ -1415,6 +1419,7 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start,
                if (err) {
                        mlx5_ib_warn(dev, "Failed to rereg UMR\n");
                        ib_umem_release(mr->umem);
+                       mr->umem = NULL;
                        clean_mr(dev, mr);
                        return err;
                }
@@ -1498,14 +1503,11 @@ static int clean_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
                u32 key = mr->mmkey.key;
 
                err = destroy_mkey(dev, mr);
-               kfree(mr);
                if (err) {
                        mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n",
                                     key, err);
                        return err;
                }
-       } else {
-               mlx5_mr_cache_free(dev, mr);
        }
 
        return 0;
@@ -1548,6 +1550,11 @@ static int dereg_mr(struct mlx5_ib_dev *dev, struct mlx5_ib_mr *mr)
                atomic_sub(npages, &dev->mdev->priv.reg_pages);
        }
 
+       if (!mr->allocated_from_cache)
+               kfree(mr);
+       else
+               mlx5_mr_cache_free(dev, mr);
+
        return 0;
 }
 
@@ -1816,7 +1823,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
 
        mr->ibmr.iova = sg_dma_address(sg) + sg_offset;
        mr->ibmr.length = 0;
-       mr->ndescs = sg_nents;
 
        for_each_sg(sgl, sg, sg_nents, i) {
                if (unlikely(i >= mr->max_descs))
@@ -1828,6 +1834,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr,
 
                sg_offset = 0;
        }
+       mr->ndescs = i;
 
        if (sg_offset_p)
                *sg_offset_p = sg_offset;
index 39d24bf..a2e1aa8 100644 (file)
@@ -1161,7 +1161,7 @@ static void destroy_raw_packet_qp_sq(struct mlx5_ib_dev *dev,
        ib_umem_release(sq->ubuffer.umem);
 }
 
-static int get_rq_pas_size(void *qpc)
+static size_t get_rq_pas_size(void *qpc)
 {
        u32 log_page_size = MLX5_GET(qpc, qpc, log_page_size) + 12;
        u32 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride);
@@ -1177,7 +1177,8 @@ static int get_rq_pas_size(void *qpc)
 }
 
 static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
-                                  struct mlx5_ib_rq *rq, void *qpin)
+                                  struct mlx5_ib_rq *rq, void *qpin,
+                                  size_t qpinlen)
 {
        struct mlx5_ib_qp *mqp = rq->base.container_mibqp;
        __be64 *pas;
@@ -1186,9 +1187,12 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev,
        void *rqc;
        void *wq;
        void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc);
-       int inlen;
+       size_t rq_pas_size = get_rq_pas_size(qpc);
+       size_t inlen;
        int err;
-       u32 rq_pas_size = get_rq_pas_size(qpc);
+
+       if (qpinlen < rq_pas_size + MLX5_BYTE_OFF(create_qp_in, pas))
+               return -EINVAL;
 
        inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size;
        in = kvzalloc(inlen, GFP_KERNEL);
@@ -1277,7 +1281,7 @@ static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev,
 }
 
 static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
-                               u32 *in,
+                               u32 *in, size_t inlen,
                                struct ib_pd *pd)
 {
        struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp;
@@ -1309,7 +1313,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp,
                        rq->flags |= MLX5_IB_RQ_CVLAN_STRIPPING;
                if (qp->flags & MLX5_IB_QP_PCI_WRITE_END_PADDING)
                        rq->flags |= MLX5_IB_RQ_PCI_WRITE_END_PADDING;
-               err = create_raw_packet_qp_rq(dev, rq, in);
+               err = create_raw_packet_qp_rq(dev, rq, in, inlen);
                if (err)
                        goto err_destroy_sq;
 
@@ -1584,6 +1588,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        u32 uidx = MLX5_IB_DEFAULT_UIDX;
        struct mlx5_ib_create_qp ucmd;
        struct mlx5_ib_qp_base *base;
+       int mlx5_st;
        void *qpc;
        u32 *in;
        int err;
@@ -1592,6 +1597,10 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
        spin_lock_init(&qp->sq.lock);
        spin_lock_init(&qp->rq.lock);
 
+       mlx5_st = to_mlx5_st(init_attr->qp_type);
+       if (mlx5_st < 0)
+               return -EINVAL;
+
        if (init_attr->rwq_ind_tbl) {
                if (!udata)
                        return -ENOSYS;
@@ -1753,7 +1762,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
 
        qpc = MLX5_ADDR_OF(create_qp_in, in, qpc);
 
-       MLX5_SET(qpc, qpc, st, to_mlx5_st(init_attr->qp_type));
+       MLX5_SET(qpc, qpc, st, mlx5_st);
        MLX5_SET(qpc, qpc, pm_state, MLX5_QP_PM_MIGRATED);
 
        if (init_attr->qp_type != MLX5_IB_QPT_REG_UMR)
@@ -1867,11 +1876,16 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd,
                }
        }
 
+       if (inlen < 0) {
+               err = -EINVAL;
+               goto err;
+       }
+
        if (init_attr->qp_type == IB_QPT_RAW_PACKET ||
            qp->flags & MLX5_IB_QP_UNDERLAY) {
                qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr;
                raw_packet_qp_copy_info(qp, &qp->raw_packet_qp);
-               err = create_raw_packet_qp(dev, qp, in, pd);
+               err = create_raw_packet_qp(dev, qp, in, inlen, pd);
        } else {
                err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen);
        }
@@ -3095,8 +3109,10 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp,
                goto out;
 
        if (mlx5_cur >= MLX5_QP_NUM_STATE || mlx5_new >= MLX5_QP_NUM_STATE ||
-           !optab[mlx5_cur][mlx5_new])
+           !optab[mlx5_cur][mlx5_new]) {
+               err = -EINVAL;
                goto out;
+       }
 
        op = optab[mlx5_cur][mlx5_new];
        optpar = ib_mask_to_mlx5_opt(attr_mask);
index 6d5fada..3c7522d 100644 (file)
@@ -241,8 +241,8 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 {
        struct mlx5_ib_dev *dev = to_mdev(pd->device);
        struct mlx5_ib_srq *srq;
-       int desc_size;
-       int buf_size;
+       size_t desc_size;
+       size_t buf_size;
        int err;
        struct mlx5_srq_attr in = {0};
        __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz);
@@ -266,15 +266,18 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd,
 
        desc_size = sizeof(struct mlx5_wqe_srq_next_seg) +
                    srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg);
+       if (desc_size == 0 || srq->msrq.max_gs > desc_size)
+               return ERR_PTR(-EINVAL);
        desc_size = roundup_pow_of_two(desc_size);
-       desc_size = max_t(int, 32, desc_size);
+       desc_size = max_t(size_t, 32, desc_size);
+       if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg))
+               return ERR_PTR(-EINVAL);
        srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) /
                sizeof(struct mlx5_wqe_data_seg);
        srq->msrq.wqe_shift = ilog2(desc_size);
        buf_size = srq->msrq.max * desc_size;
-       mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n",
-                   desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs,
-                   srq->msrq.max_avail_gather);
+       if (buf_size < desc_size)
+               return ERR_PTR(-EINVAL);
        in.type = init_attr->srq_type;
 
        if (pd->uobject)
index db4bf97..0ffb9b9 100644 (file)
@@ -833,7 +833,8 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev,
 
        dev->num_cnq = dev->ops->rdma_get_min_cnq_msix(cdev);
        if (!dev->num_cnq) {
-               DP_ERR(dev, "not enough CNQ resources.\n");
+               DP_ERR(dev, "Failed. At least one CNQ is required.\n");
+               rc = -ENOMEM;
                goto init_err;
        }
 
index 478b731..26dc374 100644 (file)
@@ -458,8 +458,7 @@ qedr_addr6_resolve(struct qedr_dev *dev,
                }
                return -EINVAL;
        }
-       neigh = dst_neigh_lookup(dst, &dst_in);
-
+       neigh = dst_neigh_lookup(dst, &fl6.daddr);
        if (neigh) {
                rcu_read_lock();
                if (neigh->nud_state & NUD_VALID) {
@@ -494,10 +493,14 @@ int qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
 
        qp = idr_find(&dev->qpidr, conn_param->qpn);
 
-       laddr = (struct sockaddr_in *)&cm_id->local_addr;
-       raddr = (struct sockaddr_in *)&cm_id->remote_addr;
-       laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr;
-       raddr6 = (struct sockaddr_in6 *)&cm_id->remote_addr;
+       laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
+       raddr = (struct sockaddr_in *)&cm_id->m_remote_addr;
+       laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
+       raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr;
+
+       DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n",
+                ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port),
+                ntohs(raddr->sin_port));
 
        DP_DEBUG(dev, QEDR_MSG_IWARP,
                 "Connect source address: %pISpc, remote address: %pISpc\n",
@@ -599,8 +602,8 @@ int qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog)
        int rc;
        int i;
 
-       laddr = (struct sockaddr_in *)&cm_id->local_addr;
-       laddr6 = (struct sockaddr_in6 *)&cm_id->local_addr;
+       laddr = (struct sockaddr_in *)&cm_id->m_local_addr;
+       laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr;
 
        DP_DEBUG(dev, QEDR_MSG_IWARP,
                 "Create Listener address: %pISpc\n", &cm_id->local_addr);
index 53f00db..419a158 100644 (file)
@@ -1841,14 +1841,15 @@ static void qedr_reset_qp_hwq_info(struct qedr_qp_hwq_info *qph)
 
 static int qedr_update_qp_state(struct qedr_dev *dev,
                                struct qedr_qp *qp,
+                               enum qed_roce_qp_state cur_state,
                                enum qed_roce_qp_state new_state)
 {
        int status = 0;
 
-       if (new_state == qp->state)
+       if (new_state == cur_state)
                return 0;
 
-       switch (qp->state) {
+       switch (cur_state) {
        case QED_ROCE_QP_STATE_RESET:
                switch (new_state) {
                case QED_ROCE_QP_STATE_INIT:
@@ -1955,6 +1956,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
        struct qedr_dev *dev = get_qedr_dev(&qp->dev->ibdev);
        const struct ib_global_route *grh = rdma_ah_read_grh(&attr->ah_attr);
        enum ib_qp_state old_qp_state, new_qp_state;
+       enum qed_roce_qp_state cur_state;
        int rc = 0;
 
        DP_DEBUG(dev, QEDR_MSG_QP,
@@ -2086,18 +2088,23 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                SET_FIELD(qp_params.modify_flags,
                          QED_ROCE_MODIFY_QP_VALID_ACK_TIMEOUT, 1);
 
-               qp_params.ack_timeout = attr->timeout;
-               if (attr->timeout) {
-                       u32 temp;
-
-                       temp = 4096 * (1UL << attr->timeout) / 1000 / 1000;
-                       /* FW requires [msec] */
-                       qp_params.ack_timeout = temp;
-               } else {
-                       /* Infinite */
+               /* The received timeout value is an exponent used like this:
+                *    "12.7.34 LOCAL ACK TIMEOUT
+                *    Value representing the transport (ACK) timeout for use by
+                *    the remote, expressed as: 4.096 * 2^timeout [usec]"
+                * The FW expects timeout in msec so we need to divide the usec
+                * result by 1000. We'll approximate 1000~2^10, and 4.096 ~ 2^2,
+                * so we get: 2^2 * 2^timeout / 2^10 = 2^(timeout - 8).
+                * The value of zero means infinite so we use a 'max_t' to make
+                * sure that sub 1 msec values will be configured as 1 msec.
+                */
+               if (attr->timeout)
+                       qp_params.ack_timeout =
+                                       1 << max_t(int, attr->timeout - 8, 0);
+               else
                        qp_params.ack_timeout = 0;
-               }
        }
+
        if (attr_mask & IB_QP_RETRY_CNT) {
                SET_FIELD(qp_params.modify_flags,
                          QED_ROCE_MODIFY_QP_VALID_RETRY_CNT, 1);
@@ -2170,13 +2177,25 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
                qp->dest_qp_num = attr->dest_qp_num;
        }
 
+       cur_state = qp->state;
+
+       /* Update the QP state before the actual ramrod to prevent a race with
+        * fast path. Modifying the QP state to error will cause the device to
+        * flush the CQEs and while polling the flushed CQEs will considered as
+        * a potential issue if the QP isn't in error state.
+        */
+       if ((attr_mask & IB_QP_STATE) && qp->qp_type != IB_QPT_GSI &&
+           !udata && qp_params.new_state == QED_ROCE_QP_STATE_ERR)
+               qp->state = QED_ROCE_QP_STATE_ERR;
+
        if (qp->qp_type != IB_QPT_GSI)
                rc = dev->ops->rdma_modify_qp(dev->rdma_ctx,
                                              qp->qed_qp, &qp_params);
 
        if (attr_mask & IB_QP_STATE) {
                if ((qp->qp_type != IB_QPT_GSI) && (!udata))
-                       rc = qedr_update_qp_state(dev, qp, qp_params.new_state);
+                       rc = qedr_update_qp_state(dev, qp, cur_state,
+                                                 qp_params.new_state);
                qp->state = qp_params.new_state;
        }
 
@@ -3034,6 +3053,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 
        switch (wr->opcode) {
        case IB_WR_SEND_WITH_IMM:
+               if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) {
+                       rc = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
                wqe->req_type = RDMA_SQ_REQ_TYPE_SEND_WITH_IMM;
                swqe = (struct rdma_sq_send_wqe_1st *)wqe;
                swqe->wqe_size = 2;
@@ -3075,6 +3099,11 @@ static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
                break;
 
        case IB_WR_RDMA_WRITE_WITH_IMM:
+               if (unlikely(rdma_protocol_iwarp(&dev->ibdev, 1))) {
+                       rc = -EINVAL;
+                       *bad_wr = wr;
+                       break;
+               }
                wqe->req_type = RDMA_SQ_REQ_TYPE_RDMA_WR_WITH_IMM;
                rwqe = (struct rdma_sq_rdma_wqe_1st *)wqe;
 
@@ -3724,7 +3753,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
 {
        struct qedr_dev *dev = get_qedr_dev(ibcq->device);
        struct qedr_cq *cq = get_qedr_cq(ibcq);
-       union rdma_cqe *cqe = cq->latest_cqe;
+       union rdma_cqe *cqe;
        u32 old_cons, new_cons;
        unsigned long flags;
        int update = 0;
@@ -3741,6 +3770,7 @@ int qedr_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
                return qedr_gsi_poll_cq(ibcq, num_entries, wc);
 
        spin_lock_irqsave(&cq->cq_lock, flags);
+       cqe = cq->latest_cqe;
        old_cons = qed_chain_get_cons_idx_u32(&cq->pbl);
        while (num_entries && is_valid_cqe(cq, cqe)) {
                struct qedr_qp *qp;
index faa9478..f95b976 100644 (file)
@@ -114,6 +114,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
        union pvrdma_cmd_resp rsp;
        struct pvrdma_cmd_create_cq *cmd = &req.create_cq;
        struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp;
+       struct pvrdma_create_cq_resp cq_resp = {0};
        struct pvrdma_create_cq ucmd;
 
        BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64);
@@ -197,6 +198,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
 
        cq->ibcq.cqe = resp->cqe;
        cq->cq_handle = resp->cq_handle;
+       cq_resp.cqn = resp->cq_handle;
        spin_lock_irqsave(&dev->cq_tbl_lock, flags);
        dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq;
        spin_unlock_irqrestore(&dev->cq_tbl_lock, flags);
@@ -205,7 +207,7 @@ struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev,
                cq->uar = &(to_vucontext(context)->uar);
 
                /* Copy udata back. */
-               if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) {
+               if (ib_copy_to_udata(udata, &cq_resp, sizeof(cq_resp))) {
                        dev_warn(&dev->pdev->dev,
                                 "failed to copy back udata\n");
                        pvrdma_destroy_cq(&cq->ibcq);
index 5acebb1..af23596 100644 (file)
@@ -113,6 +113,7 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd,
        union pvrdma_cmd_resp rsp;
        struct pvrdma_cmd_create_srq *cmd = &req.create_srq;
        struct pvrdma_cmd_create_srq_resp *resp = &rsp.create_srq_resp;
+       struct pvrdma_create_srq_resp srq_resp = {0};
        struct pvrdma_create_srq ucmd;
        unsigned long flags;
        int ret;
@@ -204,12 +205,13 @@ struct ib_srq *pvrdma_create_srq(struct ib_pd *pd,
        }
 
        srq->srq_handle = resp->srqn;
+       srq_resp.srqn = resp->srqn;
        spin_lock_irqsave(&dev->srq_tbl_lock, flags);
        dev->srq_tbl[srq->srq_handle % dev->dsr->caps.max_srq] = srq;
        spin_unlock_irqrestore(&dev->srq_tbl_lock, flags);
 
        /* Copy udata back. */
-       if (ib_copy_to_udata(udata, &srq->srq_handle, sizeof(__u32))) {
+       if (ib_copy_to_udata(udata, &srq_resp, sizeof(srq_resp))) {
                dev_warn(&dev->pdev->dev, "failed to copy back udata\n");
                pvrdma_destroy_srq(&srq->ibsrq);
                return ERR_PTR(-EINVAL);
index 16b9661..a51463c 100644 (file)
@@ -447,6 +447,7 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev,
        union pvrdma_cmd_resp rsp;
        struct pvrdma_cmd_create_pd *cmd = &req.create_pd;
        struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp;
+       struct pvrdma_alloc_pd_resp pd_resp = {0};
        int ret;
        void *ptr;
 
@@ -475,9 +476,10 @@ struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev,
        pd->privileged = !context;
        pd->pd_handle = resp->pd_handle;
        pd->pdn = resp->pd_handle;
+       pd_resp.pdn = resp->pd_handle;
 
        if (context) {
-               if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) {
+               if (ib_copy_to_udata(udata, &pd_resp, sizeof(pd_resp))) {
                        dev_warn(&dev->pdev->dev,
                                 "failed to copy back protection domain\n");
                        pvrdma_dealloc_pd(&pd->ibpd);
index 1b2e536..cc429b5 100644 (file)
@@ -489,11 +489,13 @@ static int rvt_check_refs(struct rvt_mregion *mr, const char *t)
        unsigned long timeout;
        struct rvt_dev_info *rdi = ib_to_rvt(mr->pd->device);
 
-       if (percpu_ref_is_zero(&mr->refcount))
-               return 0;
-       /* avoid dma mr */
-       if (mr->lkey)
+       if (mr->lkey) {
+               /* avoid dma mr */
                rvt_dereg_clean_qps(mr);
+               /* @mr was indexed on rcu protected @lkey_table */
+               synchronize_rcu();
+       }
+
        timeout = wait_for_completion_timeout(&mr->comp, 5 * HZ);
        if (!timeout) {
                rvt_pr_err(rdi,
index 11f74cb..ea302b0 100644 (file)
@@ -281,8 +281,6 @@ void ipoib_delete_debug_files(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = ipoib_priv(dev);
 
-       WARN_ONCE(!priv->mcg_dentry, "null mcg debug file\n");
-       WARN_ONCE(!priv->path_dentry, "null path debug file\n");
        debugfs_remove(priv->mcg_dentry);
        debugfs_remove(priv->path_dentry);
        priv->mcg_dentry = priv->path_dentry = NULL;
index 1f316d6..41614c1 100644 (file)
@@ -218,8 +218,10 @@ static void matrix_keypad_stop(struct input_dev *dev)
 {
        struct matrix_keypad *keypad = input_get_drvdata(dev);
 
+       spin_lock_irq(&keypad->lock);
        keypad->stopped = true;
-       mb();
+       spin_unlock_irq(&keypad->lock);
+
        flush_work(&keypad->work.work);
        /*
         * matrix_keypad_scan() will leave IRQs enabled;
index 3d2e23a..a246fc6 100644 (file)
@@ -173,7 +173,6 @@ static const char * const smbus_pnp_ids[] = {
        "LEN0046", /* X250 */
        "LEN004a", /* W541 */
        "LEN200f", /* T450s */
-       "LEN2018", /* T460p */
        NULL
 };
 
index db4f6bb..a5ab774 100644 (file)
@@ -1,11 +1,8 @@
-/*
- * Copyright (C) 2012 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
+// SPDX-License-Identifier: GPL-2.0
+// Melfas MMS114/MMS152 touchscreen device driver
+//
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+// Author: Joonyoung Shim <jy0922.shim@samsung.com>
 
 #include <linux/module.h>
 #include <linux/delay.h>
@@ -624,4 +621,4 @@ module_i2c_driver(mms114_driver);
 /* Module information */
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
 MODULE_DESCRIPTION("MELFAS mms114 Touchscreen driver");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
index 35a408d..99bc9bd 100644 (file)
@@ -205,7 +205,7 @@ static void intel_flush_svm_range_dev (struct intel_svm *svm, struct intel_svm_d
                         * for example, an "address" value of 0x12345f000 will
                         * flush from 0x123440000 to 0x12347ffff (256KiB). */
                        unsigned long last = address + ((unsigned long)(pages - 1) << VTD_PAGE_SHIFT);
-                       unsigned long mask = __rounddown_pow_of_two(address ^ last);;
+                       unsigned long mask = __rounddown_pow_of_two(address ^ last);
 
                        desc.high = QI_DEV_EIOTLB_ADDR((address & ~mask) | (mask - 1)) | QI_DEV_EIOTLB_SIZE;
                } else {
index 55cfb98..faf734f 100644 (file)
@@ -339,9 +339,6 @@ int __init bcm7038_l1_of_init(struct device_node *dn,
                goto out_unmap;
        }
 
-       pr_info("registered BCM7038 L1 intc (mem: 0x%p, IRQs: %d)\n",
-               intc->cpus[0]->map_base, IRQS_PER_WORD * intc->n_words);
-
        return 0;
 
 out_unmap:
index 983640e..8968e5e 100644 (file)
@@ -318,9 +318,6 @@ static int __init bcm7120_l2_intc_probe(struct device_node *dn,
                }
        }
 
-       pr_info("registered %s intc (mem: 0x%p, parent IRQ(s): %d)\n",
-                       intc_name, data->map_base[0], data->num_parent_irqs);
-
        return 0;
 
 out_free_domain:
index 691d20e..0e65f60 100644 (file)
@@ -262,9 +262,6 @@ static int __init brcmstb_l2_intc_of_init(struct device_node *np,
                ct->chip.irq_set_wake = irq_gc_set_wake;
        }
 
-       pr_info("registered L2 intc (mem: 0x%p, parent irq: %d)\n",
-                       base, parent_irq);
-
        return 0;
 
 out_free_domain:
index 993a842..1ff38af 100644 (file)
@@ -94,7 +94,7 @@ static struct irq_chip gicv2m_msi_irq_chip = {
 
 static struct msi_domain_info gicv2m_msi_domain_info = {
        .flags  = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-                  MSI_FLAG_PCI_MSIX),
+                  MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
        .chip   = &gicv2m_msi_irq_chip,
 };
 
@@ -155,18 +155,12 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
        return 0;
 }
 
-static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq)
+static void gicv2m_unalloc_msi(struct v2m_data *v2m, unsigned int hwirq,
+                              int nr_irqs)
 {
-       int pos;
-
-       pos = hwirq - v2m->spi_start;
-       if (pos < 0 || pos >= v2m->nr_spis) {
-               pr_err("Failed to teardown msi. Invalid hwirq %d\n", hwirq);
-               return;
-       }
-
        spin_lock(&v2m_lock);
-       __clear_bit(pos, v2m->bm);
+       bitmap_release_region(v2m->bm, hwirq - v2m->spi_start,
+                             get_count_order(nr_irqs));
        spin_unlock(&v2m_lock);
 }
 
@@ -174,13 +168,13 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
                                   unsigned int nr_irqs, void *args)
 {
        struct v2m_data *v2m = NULL, *tmp;
-       int hwirq, offset, err = 0;
+       int hwirq, offset, i, err = 0;
 
        spin_lock(&v2m_lock);
        list_for_each_entry(tmp, &v2m_nodes, entry) {
-               offset = find_first_zero_bit(tmp->bm, tmp->nr_spis);
-               if (offset < tmp->nr_spis) {
-                       __set_bit(offset, tmp->bm);
+               offset = bitmap_find_free_region(tmp->bm, tmp->nr_spis,
+                                                get_count_order(nr_irqs));
+               if (offset >= 0) {
                        v2m = tmp;
                        break;
                }
@@ -192,16 +186,21 @@ static int gicv2m_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
 
        hwirq = v2m->spi_start + offset;
 
-       err = gicv2m_irq_gic_domain_alloc(domain, virq, hwirq);
-       if (err) {
-               gicv2m_unalloc_msi(v2m, hwirq);
-               return err;
-       }
+       for (i = 0; i < nr_irqs; i++) {
+               err = gicv2m_irq_gic_domain_alloc(domain, virq + i, hwirq + i);
+               if (err)
+                       goto fail;
 
-       irq_domain_set_hwirq_and_chip(domain, virq, hwirq,
-                                     &gicv2m_irq_chip, v2m);
+               irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+                                             &gicv2m_irq_chip, v2m);
+       }
 
        return 0;
+
+fail:
+       irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+       gicv2m_unalloc_msi(v2m, hwirq, get_count_order(nr_irqs));
+       return err;
 }
 
 static void gicv2m_irq_domain_free(struct irq_domain *domain,
@@ -210,8 +209,7 @@ static void gicv2m_irq_domain_free(struct irq_domain *domain,
        struct irq_data *d = irq_domain_get_irq_data(domain, virq);
        struct v2m_data *v2m = irq_data_get_irq_chip_data(d);
 
-       BUG_ON(nr_irqs != 1);
-       gicv2m_unalloc_msi(v2m, d->hwirq);
+       gicv2m_unalloc_msi(v2m, d->hwirq, nr_irqs);
        irq_domain_free_irqs_parent(domain, virq, nr_irqs);
 }
 
index 14a8c0a..25a98de 100644 (file)
@@ -132,6 +132,8 @@ static int __init its_pci_of_msi_init(void)
 
        for (np = of_find_matching_node(NULL, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
+               if (!of_device_is_available(np))
+                       continue;
                if (!of_property_read_bool(np, "msi-controller"))
                        continue;
 
index 833a90f..8881a05 100644 (file)
@@ -154,6 +154,8 @@ static void __init its_pmsi_of_init(void)
 
        for (np = of_find_matching_node(NULL, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
+               if (!of_device_is_available(np))
+                       continue;
                if (!of_property_read_bool(np, "msi-controller"))
                        continue;
 
index 06f025f..2cbb19c 100644 (file)
@@ -1412,7 +1412,7 @@ static struct irq_chip its_irq_chip = {
  * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations.
  */
 #define IRQS_PER_CHUNK_SHIFT   5
-#define IRQS_PER_CHUNK         (1 << IRQS_PER_CHUNK_SHIFT)
+#define IRQS_PER_CHUNK         (1UL << IRQS_PER_CHUNK_SHIFT)
 #define ITS_MAX_LPI_NRBITS     16 /* 64K LPIs */
 
 static unsigned long *lpi_bitmap;
@@ -2119,11 +2119,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
        /*
-        * At least one bit of EventID is being used, hence a minimum
-        * of two entries. No, the architecture doesn't let you
-        * express an ITT with a single entry.
+        * We allocate at least one chunk worth of LPIs bet device,
+        * and thus that many ITEs. The device may require less though.
         */
-       nr_ites = max(2UL, roundup_pow_of_two(nvecs));
+       nr_ites = max(IRQS_PER_CHUNK, roundup_pow_of_two(nvecs));
        sz = nr_ites * its->ite_size;
        sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
        itt = kzalloc(sz, GFP_KERNEL);
@@ -2495,7 +2494,7 @@ static int its_vpe_set_affinity(struct irq_data *d,
 
 static void its_vpe_schedule(struct its_vpe *vpe)
 {
-       void * __iomem vlpi_base = gic_data_rdist_vlpi_base();
+       void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
        u64 val;
 
        /* Schedule the VPE */
@@ -2527,7 +2526,7 @@ static void its_vpe_schedule(struct its_vpe *vpe)
 
 static void its_vpe_deschedule(struct its_vpe *vpe)
 {
-       void * __iomem vlpi_base = gic_data_rdist_vlpi_base();
+       void __iomem *vlpi_base = gic_data_rdist_vlpi_base();
        u32 count = 1000000;    /* 1s! */
        bool clean;
        u64 val;
@@ -3314,6 +3313,8 @@ static int __init its_of_probe(struct device_node *node)
 
        for (np = of_find_matching_node(node, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
+               if (!of_device_is_available(np))
+                       continue;
                if (!of_property_read_bool(np, "msi-controller")) {
                        pr_warn("%pOF: no msi-controller property, ITS ignored\n",
                                np);
index a57c0fb..d99cc07 100644 (file)
@@ -673,7 +673,7 @@ static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
               MPIDR_TO_SGI_RS(cluster_id)              |
               tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
 
-       pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
+       pr_devel("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
        gic_write_sgi1r(val);
 }
 
@@ -688,7 +688,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
         * Ensure that stores to Normal memory are visible to the
         * other CPUs before issuing the IPI.
         */
-       smp_wmb();
+       wmb();
 
        for_each_cpu(cpu, mask) {
                u64 cluster_id = MPIDR_TO_SGI_CLUSTER_ID(cpu_logical_map(cpu));
index 675eda5..4760307 100644 (file)
@@ -28,20 +28,6 @@ struct gpcv2_irqchip_data {
 
 static struct gpcv2_irqchip_data *imx_gpcv2_instance;
 
-/*
- * Interface for the low level wakeup code.
- */
-u32 imx_gpcv2_get_wakeup_source(u32 **sources)
-{
-       if (!imx_gpcv2_instance)
-               return 0;
-
-       if (sources)
-               *sources = imx_gpcv2_instance->wakeup_sources;
-
-       return IMR_NUM;
-}
-
 static int gpcv2_wakeup_source_save(void)
 {
        struct gpcv2_irqchip_data *cd;
index ef92a4d..d32268c 100644 (file)
@@ -424,8 +424,6 @@ static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
        spin_lock_irqsave(&gic_lock, flags);
        write_gic_map_pin(intr, GIC_MAP_PIN_MAP_TO_PIN | gic_cpu_pin);
        write_gic_map_vp(intr, BIT(mips_cm_vp_id(cpu)));
-       gic_clear_pcpu_masks(intr);
-       set_bit(intr, per_cpu_ptr(pcpu_masks, cpu));
        irq_data_update_effective_affinity(data, cpumask_of(cpu));
        spin_unlock_irqrestore(&gic_lock, flags);
 
index 62f541f..0707482 100644 (file)
@@ -375,6 +375,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
        dev->ofdev.dev.of_node = np;
        dev->ofdev.archdata.dma_mask = 0xffffffffUL;
        dev->ofdev.dev.dma_mask = &dev->ofdev.archdata.dma_mask;
+       dev->ofdev.dev.coherent_dma_mask = dev->ofdev.archdata.dma_mask;
        dev->ofdev.dev.parent = parent;
        dev->ofdev.dev.bus = &macio_bus_type;
        dev->ofdev.dev.release = macio_release_dev;
index 1a46b41..6422846 100644 (file)
@@ -659,11 +659,11 @@ static void do_bio_hook(struct search *s, struct bio *orig_bio)
 static void search_free(struct closure *cl)
 {
        struct search *s = container_of(cl, struct search, cl);
-       bio_complete(s);
 
        if (s->iop.bio)
                bio_put(s->iop.bio);
 
+       bio_complete(s);
        closure_debug_destroy(cl);
        mempool_free(s, s->d->c->search);
 }
index 3128957..f227314 100644 (file)
@@ -963,6 +963,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
        uint32_t rtime = cpu_to_le32(get_seconds());
        struct uuid_entry *u;
        char buf[BDEVNAME_SIZE];
+       struct cached_dev *exist_dc, *t;
 
        bdevname(dc->bdev, buf);
 
@@ -987,6 +988,16 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c,
                return -EINVAL;
        }
 
+       /* Check whether already attached */
+       list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) {
+               if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) {
+                       pr_err("Tried to attach %s but duplicate UUID already attached",
+                               buf);
+
+                       return -EINVAL;
+               }
+       }
+
        u = uuid_find(c, dc->sb.uuid);
 
        if (u &&
@@ -1204,7 +1215,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page,
 
        return;
 err:
-       pr_notice("error opening %s: %s", bdevname(bdev, name), err);
+       pr_notice("error %s: %s", bdevname(bdev, name), err);
        bcache_device_stop(&dc->disk);
 }
 
@@ -1274,7 +1285,7 @@ static int flash_devs_run(struct cache_set *c)
        struct uuid_entry *u;
 
        for (u = c->uuids;
-            u < c->uuids + c->devices_max_used && !ret;
+            u < c->uuids + c->nr_uuids && !ret;
             u++)
                if (UUID_FLASH_ONLY(u))
                        ret = flash_dev_run(c, u);
@@ -1883,6 +1894,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
        const char *err = NULL; /* must be set for any error case */
        int ret = 0;
 
+       bdevname(bdev, name);
+
        memcpy(&ca->sb, sb, sizeof(struct cache_sb));
        ca->bdev = bdev;
        ca->bdev->bd_holder = ca;
@@ -1891,11 +1904,12 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
        bio_first_bvec_all(&ca->sb_bio)->bv_page = sb_page;
        get_page(sb_page);
 
-       if (blk_queue_discard(bdev_get_queue(ca->bdev)))
+       if (blk_queue_discard(bdev_get_queue(bdev)))
                ca->discard = CACHE_DISCARD(&ca->sb);
 
        ret = cache_alloc(ca);
        if (ret != 0) {
+               blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
                if (ret == -ENOMEM)
                        err = "cache_alloc(): -ENOMEM";
                else
@@ -1918,14 +1932,14 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page,
                goto out;
        }
 
-       pr_info("registered cache device %s", bdevname(bdev, name));
+       pr_info("registered cache device %s", name);
 
 out:
        kobject_put(&ca->kobj);
 
 err:
        if (err)
-               pr_notice("error opening %s: %s", bdevname(bdev, name), err);
+               pr_notice("error %s: %s", name, err);
 
        return ret;
 }
@@ -2014,6 +2028,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
        if (err)
                goto err_close;
 
+       err = "failed to register device";
        if (SB_IS_BDEV(sb)) {
                struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL);
                if (!dc)
@@ -2028,7 +2043,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
                        goto err_close;
 
                if (register_cache(sb, sb_page, bdev, ca) != 0)
-                       goto err_close;
+                       goto err;
        }
 out:
        if (sb_page)
@@ -2041,7 +2056,7 @@ out:
 err_close:
        blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL);
 err:
-       pr_info("error opening %s: %s", path, err);
+       pr_info("error %s: %s", path, err);
        ret = -EINVAL;
        goto out;
 }
index 414c9af..aa2032f 100644 (file)
@@ -386,9 +386,6 @@ static void __cache_size_refresh(void)
 static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
                               enum data_mode *data_mode)
 {
-       unsigned noio_flag;
-       void *ptr;
-
        if (c->block_size <= DM_BUFIO_BLOCK_SIZE_SLAB_LIMIT) {
                *data_mode = DATA_MODE_SLAB;
                return kmem_cache_alloc(DM_BUFIO_CACHE(c), gfp_mask);
@@ -412,16 +409,15 @@ static void *alloc_buffer_data(struct dm_bufio_client *c, gfp_t gfp_mask,
         * all allocations done by this process (including pagetables) are done
         * as if GFP_NOIO was specified.
         */
+       if (gfp_mask & __GFP_NORETRY) {
+               unsigned noio_flag = memalloc_noio_save();
+               void *ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
 
-       if (gfp_mask & __GFP_NORETRY)
-               noio_flag = memalloc_noio_save();
-
-       ptr = __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
-
-       if (gfp_mask & __GFP_NORETRY)
                memalloc_noio_restore(noio_flag);
+               return ptr;
+       }
 
-       return ptr;
+       return __vmalloc(c->block_size, gfp_mask, PAGE_KERNEL);
 }
 
 /*
index 7d3e572..a6b7baf 100644 (file)
@@ -211,29 +211,27 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m)
                else
                        m->queue_mode = DM_TYPE_REQUEST_BASED;
 
-       } else if (m->queue_mode == DM_TYPE_BIO_BASED ||
-                  m->queue_mode == DM_TYPE_NVME_BIO_BASED) {
+       } else if (m->queue_mode == DM_TYPE_BIO_BASED) {
                INIT_WORK(&m->process_queued_bios, process_queued_bios);
-
-               if (m->queue_mode == DM_TYPE_BIO_BASED) {
-                       /*
-                        * bio-based doesn't support any direct scsi_dh management;
-                        * it just discovers if a scsi_dh is attached.
-                        */
-                       set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags);
-               }
-       }
-
-       if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) {
-               set_bit(MPATHF_QUEUE_IO, &m->flags);
-               atomic_set(&m->pg_init_in_progress, 0);
-               atomic_set(&m->pg_init_count, 0);
-               m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
-               init_waitqueue_head(&m->pg_init_wait);
+               /*
+                * bio-based doesn't support any direct scsi_dh management;
+                * it just discovers if a scsi_dh is attached.
+                */
+               set_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags);
        }
 
        dm_table_set_type(ti->table, m->queue_mode);
 
+       /*
+        * Init fields that are only used when a scsi_dh is attached
+        * - must do this unconditionally (really doesn't hurt non-SCSI uses)
+        */
+       set_bit(MPATHF_QUEUE_IO, &m->flags);
+       atomic_set(&m->pg_init_in_progress, 0);
+       atomic_set(&m->pg_init_count, 0);
+       m->pg_init_delay_msecs = DM_PG_INIT_DELAY_DEFAULT;
+       init_waitqueue_head(&m->pg_init_wait);
+
        return 0;
 }
 
@@ -337,9 +335,6 @@ static void __switch_pg(struct multipath *m, struct priority_group *pg)
 {
        m->current_pg = pg;
 
-       if (m->queue_mode == DM_TYPE_NVME_BIO_BASED)
-               return;
-
        /* Must we initialise the PG first, and queue I/O till it's ready? */
        if (m->hw_handler_name) {
                set_bit(MPATHF_PG_INIT_REQUIRED, &m->flags);
@@ -385,8 +380,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes)
        unsigned bypassed = 1;
 
        if (!atomic_read(&m->nr_valid_paths)) {
-               if (m->queue_mode != DM_TYPE_NVME_BIO_BASED)
-                       clear_bit(MPATHF_QUEUE_IO, &m->flags);
+               clear_bit(MPATHF_QUEUE_IO, &m->flags);
                goto failed;
        }
 
@@ -599,7 +593,7 @@ static struct pgpath *__map_bio(struct multipath *m, struct bio *bio)
        return pgpath;
 }
 
-static struct pgpath *__map_bio_nvme(struct multipath *m, struct bio *bio)
+static struct pgpath *__map_bio_fast(struct multipath *m, struct bio *bio)
 {
        struct pgpath *pgpath;
        unsigned long flags;
@@ -634,8 +628,8 @@ static int __multipath_map_bio(struct multipath *m, struct bio *bio,
 {
        struct pgpath *pgpath;
 
-       if (m->queue_mode == DM_TYPE_NVME_BIO_BASED)
-               pgpath = __map_bio_nvme(m, bio);
+       if (!m->hw_handler_name)
+               pgpath = __map_bio_fast(m, bio);
        else
                pgpath = __map_bio(m, bio);
 
@@ -675,8 +669,7 @@ static void process_queued_io_list(struct multipath *m)
 {
        if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED)
                dm_mq_kick_requeue_list(dm_table_get_md(m->ti->table));
-       else if (m->queue_mode == DM_TYPE_BIO_BASED ||
-                m->queue_mode == DM_TYPE_NVME_BIO_BASED)
+       else if (m->queue_mode == DM_TYPE_BIO_BASED)
                queue_work(kmultipathd, &m->process_queued_bios);
 }
 
@@ -811,15 +804,14 @@ static int parse_path_selector(struct dm_arg_set *as, struct priority_group *pg,
        return 0;
 }
 
-static int setup_scsi_dh(struct block_device *bdev, struct multipath *m, char **error)
+static int setup_scsi_dh(struct block_device *bdev, struct multipath *m,
+                        const char *attached_handler_name, char **error)
 {
        struct request_queue *q = bdev_get_queue(bdev);
-       const char *attached_handler_name;
        int r;
 
        if (test_bit(MPATHF_RETAIN_ATTACHED_HW_HANDLER, &m->flags)) {
 retain:
-               attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
                if (attached_handler_name) {
                        /*
                         * Clear any hw_handler_params associated with a
@@ -873,6 +865,8 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
        int r;
        struct pgpath *p;
        struct multipath *m = ti->private;
+       struct request_queue *q;
+       const char *attached_handler_name;
 
        /* we need at least a path arg */
        if (as->argc < 1) {
@@ -891,9 +885,11 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps
                goto bad;
        }
 
-       if (m->queue_mode != DM_TYPE_NVME_BIO_BASED) {
+       q = bdev_get_queue(p->path.dev->bdev);
+       attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL);
+       if (attached_handler_name || m->hw_handler_name) {
                INIT_DELAYED_WORK(&p->activate_path, activate_path_work);
-               r = setup_scsi_dh(p->path.dev->bdev, m, &ti->error);
+               r = setup_scsi_dh(p->path.dev->bdev, m, attached_handler_name, &ti->error);
                if (r) {
                        dm_put_device(ti, p->path.dev);
                        goto bad;
@@ -1001,8 +997,7 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m)
        if (!hw_argc)
                return 0;
 
-       if (m->queue_mode == DM_TYPE_BIO_BASED ||
-           m->queue_mode == DM_TYPE_NVME_BIO_BASED) {
+       if (m->queue_mode == DM_TYPE_BIO_BASED) {
                dm_consume_args(as, hw_argc);
                DMERR("bio-based multipath doesn't allow hardware handler args");
                return 0;
@@ -1091,8 +1086,6 @@ static int parse_features(struct dm_arg_set *as, struct multipath *m)
 
                        if (!strcasecmp(queue_mode_name, "bio"))
                                m->queue_mode = DM_TYPE_BIO_BASED;
-                       else if (!strcasecmp(queue_mode_name, "nvme"))
-                               m->queue_mode = DM_TYPE_NVME_BIO_BASED;
                        else if (!strcasecmp(queue_mode_name, "rq"))
                                m->queue_mode = DM_TYPE_REQUEST_BASED;
                        else if (!strcasecmp(queue_mode_name, "mq"))
@@ -1193,7 +1186,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv)
        ti->num_discard_bios = 1;
        ti->num_write_same_bios = 1;
        ti->num_write_zeroes_bios = 1;
-       if (m->queue_mode == DM_TYPE_BIO_BASED || m->queue_mode == DM_TYPE_NVME_BIO_BASED)
+       if (m->queue_mode == DM_TYPE_BIO_BASED)
                ti->per_io_data_size = multipath_per_bio_data_size();
        else
                ti->per_io_data_size = sizeof(struct dm_mpath_io);
@@ -1730,9 +1723,6 @@ static void multipath_status(struct dm_target *ti, status_type_t type,
                        case DM_TYPE_BIO_BASED:
                                DMEMIT("queue_mode bio ");
                                break;
-                       case DM_TYPE_NVME_BIO_BASED:
-                               DMEMIT("queue_mode nvme ");
-                               break;
                        case DM_TYPE_MQ_REQUEST_BASED:
                                DMEMIT("queue_mode mq ");
                                break;
@@ -2030,8 +2020,9 @@ static int multipath_busy(struct dm_target *ti)
  *---------------------------------------------------------------*/
 static struct target_type multipath_target = {
        .name = "multipath",
-       .version = {1, 12, 0},
-       .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE,
+       .version = {1, 13, 0},
+       .features = DM_TARGET_SINGLETON | DM_TARGET_IMMUTABLE |
+                   DM_TARGET_PASSES_INTEGRITY,
        .module = THIS_MODULE,
        .ctr = multipath_ctr,
        .dtr = multipath_dtr,
index 7ef469e..c1d1034 100644 (file)
@@ -3408,9 +3408,10 @@ static sector_t rs_get_progress(struct raid_set *rs, unsigned long recovery,
                set_bit(RT_FLAG_RS_IN_SYNC, &rs->runtime_flags);
 
        } else {
-               if (test_bit(MD_RECOVERY_NEEDED, &recovery) ||
-                   test_bit(MD_RECOVERY_RESHAPE, &recovery) ||
-                   test_bit(MD_RECOVERY_RUNNING, &recovery))
+               if (!test_bit(MD_RECOVERY_INTR, &recovery) &&
+                   (test_bit(MD_RECOVERY_NEEDED, &recovery) ||
+                    test_bit(MD_RECOVERY_RESHAPE, &recovery) ||
+                    test_bit(MD_RECOVERY_RUNNING, &recovery)))
                        r = mddev->curr_resync_completed;
                else
                        r = mddev->recovery_cp;
index 5fe7ec3..7eb3e2a 100644 (file)
@@ -942,17 +942,12 @@ static int dm_table_determine_type(struct dm_table *t)
 
        if (t->type != DM_TYPE_NONE) {
                /* target already set the table's type */
-               if (t->type == DM_TYPE_BIO_BASED)
-                       return 0;
-               else if (t->type == DM_TYPE_NVME_BIO_BASED) {
-                       if (!dm_table_does_not_support_partial_completion(t)) {
-                               DMERR("nvme bio-based is only possible with devices"
-                                     " that don't support partial completion");
-                               return -EINVAL;
-                       }
-                       /* Fallthru, also verify all devices are blk-mq */
+               if (t->type == DM_TYPE_BIO_BASED) {
+                       /* possibly upgrade to a variant of bio-based */
+                       goto verify_bio_based;
                }
                BUG_ON(t->type == DM_TYPE_DAX_BIO_BASED);
+               BUG_ON(t->type == DM_TYPE_NVME_BIO_BASED);
                goto verify_rq_based;
        }
 
@@ -985,6 +980,7 @@ static int dm_table_determine_type(struct dm_table *t)
        }
 
        if (bio_based) {
+verify_bio_based:
                /* We must use this table as bio-based */
                t->type = DM_TYPE_BIO_BASED;
                if (dm_table_supports_dax(t) ||
@@ -1755,7 +1751,7 @@ static int device_no_partial_completion(struct dm_target *ti, struct dm_dev *dev
        char b[BDEVNAME_SIZE];
 
        /* For now, NVMe devices are the only devices of this class */
-       return (strncmp(bdevname(dev->bdev, b), "nvme", 3) == 0);
+       return (strncmp(bdevname(dev->bdev, b), "nvme", 4) == 0);
 }
 
 static bool dm_table_does_not_support_partial_completion(struct dm_table *t)
index d6de00f..353ea0e 100644 (file)
@@ -458,13 +458,15 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return dm_get_geometry(md, geo);
 }
 
-static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
-                                 struct block_device **bdev,
-                                 fmode_t *mode)
+static char *_dm_claim_ptr = "I belong to device-mapper";
+
+static int dm_get_bdev_for_ioctl(struct mapped_device *md,
+                                struct block_device **bdev,
+                                fmode_t *mode)
 {
        struct dm_target *tgt;
        struct dm_table *map;
-       int srcu_idx, r;
+       int srcu_idx, r, r2;
 
 retry:
        r = -ENOTTY;
@@ -490,6 +492,12 @@ retry:
                goto out;
 
        bdgrab(*bdev);
+       r2 = blkdev_get(*bdev, *mode, _dm_claim_ptr);
+       if (r2 < 0) {
+               r = r2;
+               goto out;
+       }
+
        dm_put_live_table(md, srcu_idx);
        return r;
 
@@ -508,7 +516,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
        struct mapped_device *md = bdev->bd_disk->private_data;
        int r;
 
-       r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
        if (r < 0)
                return r;
 
@@ -528,7 +536,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
 
        r =  __blkdev_driver_ioctl(bdev, mode, cmd, arg);
 out:
-       bdput(bdev);
+       blkdev_put(bdev, mode);
        return r;
 }
 
@@ -708,14 +716,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
 static int open_table_device(struct table_device *td, dev_t dev,
                             struct mapped_device *md)
 {
-       static char *_claim_ptr = "I belong to device-mapper";
        struct block_device *bdev;
 
        int r;
 
        BUG_ON(td->dm_dev.bdev);
 
-       bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr);
+       bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr);
        if (IS_ERR(bdev))
                return PTR_ERR(bdev);
 
@@ -903,7 +910,8 @@ static void dec_pending(struct dm_io *io, blk_status_t error)
                        queue_io(md, bio);
                } else {
                        /* done with normal IO or empty flush */
-                       bio->bi_status = io_error;
+                       if (io_error)
+                               bio->bi_status = io_error;
                        bio_endio(bio);
                }
        }
@@ -3010,7 +3018,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
        fmode_t mode;
        int r;
 
-       r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
        if (r < 0)
                return r;
 
@@ -3020,7 +3028,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
        else
                r = -EOPNOTSUPP;
 
-       bdput(bdev);
+       blkdev_put(bdev, mode);
        return r;
 }
 
@@ -3031,7 +3039,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
        fmode_t mode;
        int r;
 
-       r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
        if (r < 0)
                return r;
 
@@ -3041,7 +3049,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
        else
                r = -EOPNOTSUPP;
 
-       bdput(bdev);
+       blkdev_put(bdev, mode);
        return r;
 }
 
@@ -3053,7 +3061,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
        fmode_t mode;
        int r;
 
-       r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
        if (r < 0)
                return r;
 
@@ -3063,7 +3071,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
        else
                r = -EOPNOTSUPP;
 
-       bdput(bdev);
+       blkdev_put(bdev, mode);
        return r;
 }
 
@@ -3074,7 +3082,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
        fmode_t mode;
        int r;
 
-       r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
        if (r < 0)
                return r;
 
@@ -3084,7 +3092,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
        else
                r = -EOPNOTSUPP;
 
-       bdput(bdev);
+       blkdev_put(bdev, mode);
        return r;
 }
 
index e40065b..0a7e99d 100644 (file)
@@ -157,7 +157,7 @@ static void multipath_status(struct seq_file *seq, struct mddev *mddev)
                seq_printf (seq, "%s", rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
        }
        rcu_read_unlock();
-       seq_printf (seq, "]");
+       seq_putc(seq, ']');
 }
 
 static int multipath_congested(struct mddev *mddev, int bits)
index bc67ab6..254e44e 100644 (file)
@@ -801,6 +801,9 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
        struct bio *bio;
        int ff = 0;
 
+       if (!page)
+               return;
+
        if (test_bit(Faulty, &rdev->flags))
                return;
 
@@ -5452,6 +5455,7 @@ int md_run(struct mddev *mddev)
         * the only valid external interface is through the md
         * device.
         */
+       mddev->has_superblocks = false;
        rdev_for_each(rdev, mddev) {
                if (test_bit(Faulty, &rdev->flags))
                        continue;
@@ -5465,6 +5469,9 @@ int md_run(struct mddev *mddev)
                                set_disk_ro(mddev->gendisk, 1);
                }
 
+               if (rdev->sb_page)
+                       mddev->has_superblocks = true;
+
                /* perform some consistency tests on the device.
                 * We don't want the data to overlap the metadata,
                 * Internal Bitmap issues have been handled elsewhere.
@@ -5497,8 +5504,10 @@ int md_run(struct mddev *mddev)
        }
        if (mddev->sync_set == NULL) {
                mddev->sync_set = bioset_create(BIO_POOL_SIZE, 0, BIOSET_NEED_BVECS);
-               if (!mddev->sync_set)
-                       return -ENOMEM;
+               if (!mddev->sync_set) {
+                       err = -ENOMEM;
+                       goto abort;
+               }
        }
 
        spin_lock(&pers_lock);
@@ -5511,7 +5520,8 @@ int md_run(struct mddev *mddev)
                else
                        pr_warn("md: personality for level %s is not loaded!\n",
                                mddev->clevel);
-               return -EINVAL;
+               err = -EINVAL;
+               goto abort;
        }
        spin_unlock(&pers_lock);
        if (mddev->level != pers->level) {
@@ -5524,7 +5534,8 @@ int md_run(struct mddev *mddev)
            pers->start_reshape == NULL) {
                /* This personality cannot handle reshaping... */
                module_put(pers->owner);
-               return -EINVAL;
+               err = -EINVAL;
+               goto abort;
        }
 
        if (pers->sync_request) {
@@ -5593,7 +5604,7 @@ int md_run(struct mddev *mddev)
                mddev->private = NULL;
                module_put(pers->owner);
                bitmap_destroy(mddev);
-               return err;
+               goto abort;
        }
        if (mddev->queue) {
                bool nonrot = true;
@@ -5655,6 +5666,18 @@ int md_run(struct mddev *mddev)
        sysfs_notify_dirent_safe(mddev->sysfs_action);
        sysfs_notify(&mddev->kobj, NULL, "degraded");
        return 0;
+
+abort:
+       if (mddev->bio_set) {
+               bioset_free(mddev->bio_set);
+               mddev->bio_set = NULL;
+       }
+       if (mddev->sync_set) {
+               bioset_free(mddev->sync_set);
+               mddev->sync_set = NULL;
+       }
+
+       return err;
 }
 EXPORT_SYMBOL_GPL(md_run);
 
@@ -8049,6 +8072,7 @@ EXPORT_SYMBOL(md_done_sync);
 bool md_write_start(struct mddev *mddev, struct bio *bi)
 {
        int did_change = 0;
+
        if (bio_data_dir(bi) != WRITE)
                return true;
 
@@ -8081,6 +8105,8 @@ bool md_write_start(struct mddev *mddev, struct bio *bi)
        rcu_read_unlock();
        if (did_change)
                sysfs_notify_dirent_safe(mddev->sysfs_state);
+       if (!mddev->has_superblocks)
+               return true;
        wait_event(mddev->sb_wait,
                   !test_bit(MD_SB_CHANGE_PENDING, &mddev->sb_flags) ||
                   mddev->suspended);
@@ -8543,6 +8569,19 @@ void md_do_sync(struct md_thread *thread)
        set_mask_bits(&mddev->sb_flags, 0,
                      BIT(MD_SB_CHANGE_PENDING) | BIT(MD_SB_CHANGE_DEVS));
 
+       if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
+                       !test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+                       mddev->delta_disks > 0 &&
+                       mddev->pers->finish_reshape &&
+                       mddev->pers->size &&
+                       mddev->queue) {
+               mddev_lock_nointr(mddev);
+               md_set_array_sectors(mddev, mddev->pers->size(mddev, 0, 0));
+               mddev_unlock(mddev);
+               set_capacity(mddev->gendisk, mddev->array_sectors);
+               revalidate_disk(mddev->gendisk);
+       }
+
        spin_lock(&mddev->lock);
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
                /* We completed so min/max setting can be forgotten if used. */
@@ -8569,6 +8608,10 @@ static int remove_and_add_spares(struct mddev *mddev,
        int removed = 0;
        bool remove_some = false;
 
+       if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+               /* Mustn't remove devices when resync thread is running */
+               return 0;
+
        rdev_for_each(rdev, mddev) {
                if ((this == NULL || rdev == this) &&
                    rdev->raid_disk >= 0 &&
index 58cd20a..fbc925c 100644 (file)
@@ -468,6 +468,8 @@ struct mddev {
        void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
        struct md_cluster_info          *cluster_info;
        unsigned int                    good_device_nr; /* good device num within cluster raid */
+
+       bool    has_superblocks:1;
 };
 
 enum recovery_flags {
index b2eae33..fe872dc 100644 (file)
@@ -1108,7 +1108,7 @@ static void alloc_behind_master_bio(struct r1bio *r1_bio,
 
        bio_copy_data(behind_bio, bio);
 skip_copy:
-       r1_bio->behind_master_bio = behind_bio;;
+       r1_bio->behind_master_bio = behind_bio;
        set_bit(R1BIO_BehindIO, &r1_bio->state);
 
        return;
@@ -1809,6 +1809,17 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev)
                        struct md_rdev *repl =
                                conf->mirrors[conf->raid_disks + number].rdev;
                        freeze_array(conf, 0);
+                       if (atomic_read(&repl->nr_pending)) {
+                               /* It means that some queued IO of retry_list
+                                * hold repl. Thus, we cannot set replacement
+                                * as NULL, avoiding rdev NULL pointer
+                                * dereference in sync_request_write and
+                                * handle_write_finished.
+                                */
+                               err = -EBUSY;
+                               unfreeze_array(conf);
+                               goto abort;
+                       }
                        clear_bit(Replacement, &repl->flags);
                        p->rdev = repl;
                        conf->mirrors[conf->raid_disks + number].rdev = NULL;
index c7294e7..eb84bc6 100644 (file)
 #define BARRIER_BUCKETS_NR_BITS                (PAGE_SHIFT - ilog2(sizeof(atomic_t)))
 #define BARRIER_BUCKETS_NR             (1<<BARRIER_BUCKETS_NR_BITS)
 
+/* Note: raid1_info.rdev can be set to NULL asynchronously by raid1_remove_disk.
+ * There are three safe ways to access raid1_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery is known to be happening - i.e. in code that is
+ *    called as part of performing resync/recovery.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the
+ *    RCU lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if it has
+ * been incremented, the pointer is put back in .rdev.
+ */
+
 struct raid1_info {
        struct md_rdev  *rdev;
        sector_t        head_position;
index 99c9207..c5e6c60 100644 (file)
@@ -141,7 +141,7 @@ static void r10bio_pool_free(void *r10_bio, void *data)
 #define RESYNC_WINDOW (1024*1024)
 /* maximum number of concurrent requests, memory permitting */
 #define RESYNC_DEPTH (32*1024*1024/RESYNC_BLOCK_SIZE)
-#define CLUSTER_RESYNC_WINDOW (16 * RESYNC_WINDOW)
+#define CLUSTER_RESYNC_WINDOW (32 * RESYNC_WINDOW)
 #define CLUSTER_RESYNC_WINDOW_SECTORS (CLUSTER_RESYNC_WINDOW >> 9)
 
 /*
@@ -2655,7 +2655,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                for (m = 0; m < conf->copies; m++) {
                        int dev = r10_bio->devs[m].devnum;
                        rdev = conf->mirrors[dev].rdev;
-                       if (r10_bio->devs[m].bio == NULL)
+                       if (r10_bio->devs[m].bio == NULL ||
+                               r10_bio->devs[m].bio->bi_end_io == NULL)
                                continue;
                        if (!r10_bio->devs[m].bio->bi_status) {
                                rdev_clear_badblocks(
@@ -2670,7 +2671,8 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
                                        md_error(conf->mddev, rdev);
                        }
                        rdev = conf->mirrors[dev].replacement;
-                       if (r10_bio->devs[m].repl_bio == NULL)
+                       if (r10_bio->devs[m].repl_bio == NULL ||
+                               r10_bio->devs[m].repl_bio->bi_end_io == NULL)
                                continue;
 
                        if (!r10_bio->devs[m].repl_bio->bi_status) {
@@ -3782,7 +3784,7 @@ static int raid10_run(struct mddev *mddev)
                if (fc > 1 || fo > 0) {
                        pr_err("only near layout is supported by clustered"
                                " raid10\n");
-                       goto out;
+                       goto out_free_conf;
                }
        }
 
@@ -4830,17 +4832,11 @@ static void raid10_finish_reshape(struct mddev *mddev)
                return;
 
        if (mddev->delta_disks > 0) {
-               sector_t size = raid10_size(mddev, 0, 0);
-               md_set_array_sectors(mddev, size);
                if (mddev->recovery_cp > mddev->resync_max_sectors) {
                        mddev->recovery_cp = mddev->resync_max_sectors;
                        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                }
-               mddev->resync_max_sectors = size;
-               if (mddev->queue) {
-                       set_capacity(mddev->gendisk, mddev->array_sectors);
-                       revalidate_disk(mddev->gendisk);
-               }
+               mddev->resync_max_sectors = mddev->array_sectors;
        } else {
                int d;
                rcu_read_lock();
index db2ac22..e2e8840 100644 (file)
@@ -2,6 +2,19 @@
 #ifndef _RAID10_H
 #define _RAID10_H
 
+/* Note: raid10_info.rdev can be set to NULL asynchronously by
+ * raid10_remove_disk.
+ * There are three safe ways to access raid10_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code
+ *    that is called as part of performing resync/recovery/reshape.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the
+ *    RCU lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if it has
+ * been incremented, the pointer is put back in .rdev.
+ */
+
 struct raid10_info {
        struct md_rdev  *rdev, *replacement;
        sector_t        head_position;
index 0c76bce..a001808 100644 (file)
@@ -44,6 +44,7 @@ extern void ppl_write_stripe_run(struct r5conf *conf);
 extern void ppl_stripe_write_finished(struct stripe_head *sh);
 extern int ppl_modify_log(struct r5conf *conf, struct md_rdev *rdev, bool add);
 extern void ppl_quiesce(struct r5conf *conf, int quiesce);
+extern int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio);
 
 static inline bool raid5_has_ppl(struct r5conf *conf)
 {
@@ -104,7 +105,7 @@ static inline int log_handle_flush_request(struct r5conf *conf, struct bio *bio)
        if (conf->log)
                ret = r5l_handle_flush_request(conf->log, bio);
        else if (raid5_has_ppl(conf))
-               ret = 0;
+               ret = ppl_handle_flush_request(conf->log, bio);
 
        return ret;
 }
index 2764c22..42890a0 100644 (file)
@@ -693,6 +693,16 @@ void ppl_quiesce(struct r5conf *conf, int quiesce)
        }
 }
 
+int ppl_handle_flush_request(struct r5l_log *log, struct bio *bio)
+{
+       if (bio->bi_iter.bi_size == 0) {
+               bio_endio(bio);
+               return 0;
+       }
+       bio->bi_opf &= ~REQ_PREFLUSH;
+       return -EAGAIN;
+}
+
 void ppl_stripe_write_finished(struct stripe_head *sh)
 {
        struct ppl_io_unit *io;
index 50d0114..b5d2601 100644 (file)
@@ -2196,15 +2196,16 @@ static int grow_one_stripe(struct r5conf *conf, gfp_t gfp)
 static int grow_stripes(struct r5conf *conf, int num)
 {
        struct kmem_cache *sc;
+       size_t namelen = sizeof(conf->cache_name[0]);
        int devs = max(conf->raid_disks, conf->previous_raid_disks);
 
        if (conf->mddev->gendisk)
-               sprintf(conf->cache_name[0],
+               snprintf(conf->cache_name[0], namelen,
                        "raid%d-%s", conf->level, mdname(conf->mddev));
        else
-               sprintf(conf->cache_name[0],
+               snprintf(conf->cache_name[0], namelen,
                        "raid%d-%p", conf->level, conf->mddev);
-       sprintf(conf->cache_name[1], "%s-alt", conf->cache_name[0]);
+       snprintf(conf->cache_name[1], namelen, "%.27s-alt", conf->cache_name[0]);
 
        conf->active_name = 0;
        sc = kmem_cache_create(conf->cache_name[conf->active_name],
@@ -6764,9 +6765,7 @@ static void free_conf(struct r5conf *conf)
 
        log_exit(conf);
 
-       if (conf->shrinker.nr_deferred)
-               unregister_shrinker(&conf->shrinker);
-
+       unregister_shrinker(&conf->shrinker);
        free_thread_groups(conf);
        shrink_stripes(conf);
        raid5_free_percpu(conf);
@@ -8001,13 +8000,7 @@ static void raid5_finish_reshape(struct mddev *mddev)
 
        if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
 
-               if (mddev->delta_disks > 0) {
-                       md_set_array_sectors(mddev, raid5_size(mddev, 0, 0));
-                       if (mddev->queue) {
-                               set_capacity(mddev->gendisk, mddev->array_sectors);
-                               revalidate_disk(mddev->gendisk);
-                       }
-               } else {
+               if (mddev->delta_disks <= 0) {
                        int d;
                        spin_lock_irq(&conf->device_lock);
                        mddev->degraded = raid5_calc_degraded(conf);
index 2e61238..3f8da26 100644 (file)
@@ -450,6 +450,18 @@ enum {
  * HANDLE gets cleared if stripe_handle leaves nothing locked.
  */
 
+/* Note: disk_info.rdev can be set to NULL asynchronously by raid5_remove_disk.
+ * There are three safe ways to access disk_info.rdev.
+ * 1/ when holding mddev->reconfig_mutex
+ * 2/ when resync/recovery/reshape is known to be happening - i.e. in code that
+ *    is called as part of performing resync/recovery/reshape.
+ * 3/ while holding rcu_read_lock(), use rcu_dereference to get the pointer
+ *    and if it is non-NULL, increment rdev->nr_pending before dropping the RCU
+ *    lock.
+ * When .rdev is set to NULL, the nr_pending count checked again and if
+ * it has been incremented, the pointer is put back in .rdev.
+ */
+
 struct disk_info {
        struct md_rdev  *rdev, *replacement;
        struct page     *extra_page; /* extra page to use in prexor */
index 145e12b..86c1a19 100644 (file)
@@ -147,9 +147,11 @@ config DVB_CORE
 config DVB_MMAP
        bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
        depends on DVB_CORE
+       depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
+       select VIDEOBUF2_VMALLOC
        default n
        help
-         This option enables DVB experimental memory-mapped API, with
+         This option enables DVB experimental memory-mapped API, which
          reduces the number of context switches to read DVB buffers, as
          the buffers can use mmap() syscalls.
 
index 5df0525..17c32ea 100644 (file)
@@ -3,6 +3,9 @@ config VIDEOBUF2_CORE
        select DMA_SHARED_BUFFER
        tristate
 
+config VIDEOBUF2_V4L2
+       tristate
+
 config VIDEOBUF2_MEMOPS
        tristate
        select FRAME_VECTOR
index 19de5cc..77bebe8 100644 (file)
@@ -1,5 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+videobuf2-common-objs := videobuf2-core.o
 
-obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-core.o videobuf2-v4l2.o
+ifeq ($(CONFIG_TRACEPOINTS),y)
+  videobuf2-common-objs += vb2-trace.o
+endif
+
+obj-$(CONFIG_VIDEOBUF2_CORE) += videobuf2-common.o
+obj-$(CONFIG_VIDEOBUF2_V4L2) += videobuf2-v4l2.o
 obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o
 obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
 obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
index 3a105d8..62b028d 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
-dvb-vb2-$(CONFIG_DVB_MMSP) := dvb_vb2.o
+dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
 
 dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o                 \
                 dvb_ca_en50221.o dvb_frontend.o                \
index 6d53af0..61a750f 100644 (file)
@@ -128,11 +128,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        struct dmx_frontend *front;
-#ifndef DVB_MMAP
        bool need_ringbuffer = false;
-#else
-       const bool need_ringbuffer = true;
-#endif
 
        dprintk("%s\n", __func__);
 
@@ -144,17 +140,31 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
                return -ENODEV;
        }
 
-#ifndef DVB_MMAP
+       dmxdev->may_do_mmap = 0;
+
+       /*
+        * The logic here is a little tricky due to the ifdef.
+        *
+        * The ringbuffer is used for both read and mmap.
+        *
+        * It is not needed, however, on two situations:
+        *      - Write devices (access with O_WRONLY);
+        *      - For duplex device nodes, opened with O_RDWR.
+        */
+
        if ((file->f_flags & O_ACCMODE) == O_RDONLY)
                need_ringbuffer = true;
-#else
-       if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+       else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
                if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+#ifdef CONFIG_DVB_MMAP
+                       dmxdev->may_do_mmap = 1;
+                       need_ringbuffer = true;
+#else
                        mutex_unlock(&dmxdev->mutex);
                        return -EOPNOTSUPP;
+#endif
                }
        }
-#endif
 
        if (need_ringbuffer) {
                void *mem;
@@ -169,8 +179,9 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
                        return -ENOMEM;
                }
                dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
-               dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
-                            file->f_flags & O_NONBLOCK);
+               if (dmxdev->may_do_mmap)
+                       dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
+                                    file->f_flags & O_NONBLOCK);
                dvbdev->readers--;
        }
 
@@ -200,11 +211,6 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
-#ifndef DVB_MMAP
-       bool need_ringbuffer = false;
-#else
-       const bool need_ringbuffer = true;
-#endif
 
        mutex_lock(&dmxdev->mutex);
 
@@ -213,15 +219,14 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
                dmxdev->demux->connect_frontend(dmxdev->demux,
                                                dmxdev->dvr_orig_fe);
        }
-#ifndef DVB_MMAP
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-               need_ringbuffer = true;
-#endif
 
-       if (need_ringbuffer) {
-               if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
-                       dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
-               dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
+       if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
+           dmxdev->may_do_mmap) {
+               if (dmxdev->may_do_mmap) {
+                       if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
+                               dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
+                       dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
+               }
                dvbdev->readers++;
                if (dmxdev->dvr_buffer.data) {
                        void *mem = dmxdev->dvr_buffer.data;
@@ -380,7 +385,8 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
 
 static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
                                       const u8 *buffer2, size_t buffer2_len,
-                                      struct dmx_section_filter *filter)
+                                      struct dmx_section_filter *filter,
+                                      u32 *buffer_flags)
 {
        struct dmxdev_filter *dmxdevfilter = filter->priv;
        int ret;
@@ -399,10 +405,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
        dprintk("section callback %*ph\n", 6, buffer1);
        if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
                ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
-                                         buffer1, buffer1_len);
+                                         buffer1, buffer1_len,
+                                         buffer_flags);
                if (ret == buffer1_len)
                        ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
-                                                 buffer2, buffer2_len);
+                                                 buffer2, buffer2_len,
+                                                 buffer_flags);
        } else {
                ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
                                              buffer1, buffer1_len);
@@ -422,11 +430,12 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
 
 static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
                                  const u8 *buffer2, size_t buffer2_len,
-                                 struct dmx_ts_feed *feed)
+                                 struct dmx_ts_feed *feed,
+                                 u32 *buffer_flags)
 {
        struct dmxdev_filter *dmxdevfilter = feed->priv;
        struct dvb_ringbuffer *buffer;
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
        struct dvb_vb2_ctx *ctx;
 #endif
        int ret;
@@ -440,20 +449,22 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
        if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
            dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
                buffer = &dmxdevfilter->buffer;
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
                ctx = &dmxdevfilter->vb2_ctx;
 #endif
        } else {
                buffer = &dmxdevfilter->dev->dvr_buffer;
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
                ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
 #endif
        }
 
        if (dvb_vb2_is_streaming(ctx)) {
-               ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len);
+               ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
+                                         buffer_flags);
                if (ret == buffer1_len)
-                       ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len);
+                       ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
+                                                 buffer_flags);
        } else {
                if (buffer->error) {
                        spin_unlock(&dmxdevfilter->dev->lock);
@@ -802,6 +813,12 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
        mutex_init(&dmxdevfilter->mutex);
        file->private_data = dmxdevfilter;
 
+#ifdef CONFIG_DVB_MMAP
+       dmxdev->may_do_mmap = 1;
+#else
+       dmxdev->may_do_mmap = 0;
+#endif
+
        dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
        dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
                     file->f_flags & O_NONBLOCK);
@@ -1111,7 +1128,7 @@ static int dvb_demux_do_ioctl(struct file *file,
                mutex_unlock(&dmxdevfilter->mutex);
                break;
 
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
        case DMX_REQBUFS:
                if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
                        mutex_unlock(&dmxdev->mutex);
@@ -1160,7 +1177,7 @@ static int dvb_demux_do_ioctl(struct file *file,
                break;
 #endif
        default:
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
        mutex_unlock(&dmxdev->mutex);
@@ -1199,13 +1216,16 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
        return mask;
 }
 
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
 static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct dmxdev_filter *dmxdevfilter = file->private_data;
        struct dmxdev *dmxdev = dmxdevfilter->dev;
        int ret;
 
+       if (!dmxdev->may_do_mmap)
+               return -ENOTTY;
+
        if (mutex_lock_interruptible(&dmxdev->mutex))
                return -ERESTARTSYS;
 
@@ -1249,7 +1269,7 @@ static const struct file_operations dvb_demux_fops = {
        .release = dvb_demux_release,
        .poll = dvb_demux_poll,
        .llseek = default_llseek,
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
        .mmap = dvb_demux_mmap,
 #endif
 };
@@ -1280,7 +1300,7 @@ static int dvb_dvr_do_ioctl(struct file *file,
                ret = dvb_dvr_set_buffer_size(dmxdev, arg);
                break;
 
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
        case DMX_REQBUFS:
                ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
                break;
@@ -1304,7 +1324,7 @@ static int dvb_dvr_do_ioctl(struct file *file,
                break;
 #endif
        default:
-               ret = -EINVAL;
+               ret = -ENOTTY;
                break;
        }
        mutex_unlock(&dmxdev->mutex);
@@ -1322,11 +1342,6 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        __poll_t mask = 0;
-#ifndef DVB_MMAP
-       bool need_ringbuffer = false;
-#else
-       const bool need_ringbuffer = true;
-#endif
 
        dprintk("%s\n", __func__);
 
@@ -1337,11 +1352,8 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
 
-#ifndef DVB_MMAP
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY)
-               need_ringbuffer = true;
-#endif
-       if (need_ringbuffer) {
+       if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
+           dmxdev->may_do_mmap) {
                if (dmxdev->dvr_buffer.error)
                        mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
 
@@ -1353,13 +1365,16 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
        return mask;
 }
 
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
 static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dmxdev *dmxdev = dvbdev->priv;
        int ret;
 
+       if (!dmxdev->may_do_mmap)
+               return -ENOTTY;
+
        if (dmxdev->exit)
                return -ENODEV;
 
@@ -1381,7 +1396,7 @@ static const struct file_operations dvb_dvr_fops = {
        .release = dvb_dvr_release,
        .poll = dvb_dvr_poll,
        .llseek = default_llseek,
-#ifdef DVB_MMAP
+#ifdef CONFIG_DVB_MMAP
        .mmap = dvb_dvr_mmap,
 #endif
 };
index 210eed0..f450912 100644 (file)
@@ -55,6 +55,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
                dprintk(x);                             \
 } while (0)
 
+#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
+#  define dprintk_sect_loss(x...) dprintk(x)
+#else
+#  define dprintk_sect_loss(x...)
+#endif
+
+#define set_buf_flags(__feed, __flag)                  \
+       do {                                            \
+               (__feed)->buffer_flags |= (__flag);     \
+       } while (0)
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -104,31 +115,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
 {
        int count = payload(buf);
        int p;
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
        int ccok;
        u8 cc;
-#endif
 
        if (count == 0)
                return -1;
 
        p = 188 - count;
 
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
        cc = buf[3] & 0x0f;
        ccok = ((feed->cc + 1) & 0x0f) == cc;
        feed->cc = cc;
-       if (!ccok)
-               dprintk("missed packet: %d instead of %d!\n",
-                       cc, (feed->cc + 1) & 0x0f);
-#endif
+       if (!ccok) {
+               set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+               dprintk_sect_loss("missed packet: %d instead of %d!\n",
+                                 cc, (feed->cc + 1) & 0x0f);
+       }
 
        if (buf[1] & 0x40)      // PUSI ?
                feed->peslen = 0xfffa;
 
        feed->peslen += count;
 
-       return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts);
+       return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
+                          &feed->buffer_flags);
 }
 
 static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@@ -150,7 +160,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
                return 0;
 
        return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
-                           NULL, 0, &f->filter);
+                           NULL, 0, &f->filter, &feed->buffer_flags);
 }
 
 static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@@ -169,8 +179,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
        if (sec->check_crc) {
                section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
                if (section_syntax_indicator &&
-                   demux->check_crc32(feed, sec->secbuf, sec->seclen))
+                   demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
+                       set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
                        return -1;
+               }
        }
 
        do {
@@ -187,7 +199,6 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
 {
        struct dmx_section_feed *sec = &feed->feed.sec;
 
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
        if (sec->secbufp < sec->tsfeedp) {
                int n = sec->tsfeedp - sec->secbufp;
 
@@ -197,12 +208,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
                 * but just first and last.
                 */
                if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
-                       dprintk("section ts padding loss: %d/%d\n",
-                              n, sec->tsfeedp);
-                       dprintk("pad data: %*ph\n", n, sec->secbuf);
+                       set_buf_flags(feed,
+                                     DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+                       dprintk_sect_loss("section ts padding loss: %d/%d\n",
+                                         n, sec->tsfeedp);
+                       dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
                }
        }
-#endif
 
        sec->tsfeedp = sec->secbufp = sec->seclen = 0;
        sec->secbuf = sec->secbuf_base;
@@ -237,11 +249,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
                return 0;
 
        if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
-               dprintk("section buffer full loss: %d/%d\n",
-                       sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
-                       DMX_MAX_SECFEED_SIZE);
-#endif
+               set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+               dprintk_sect_loss("section buffer full loss: %d/%d\n",
+                                 sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
+                                 DMX_MAX_SECFEED_SIZE);
                len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
        }
 
@@ -269,12 +280,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
                sec->seclen = seclen;
                sec->crc_val = ~0;
                /* dump [secbuf .. secbuf+seclen) */
-               if (feed->pusi_seen)
+               if (feed->pusi_seen) {
                        dvb_dmx_swfilter_section_feed(feed);
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
-               else
-                       dprintk("pusi not seen, discarding section data\n");
-#endif
+               } else {
+                       set_buf_flags(feed,
+                                     DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+                       dprintk_sect_loss("pusi not seen, discarding section data\n");
+               }
                sec->secbufp += seclen; /* secbufp and secbuf moving together is */
                sec->secbuf += seclen;  /* redundant but saves pointer arithmetic */
        }
@@ -307,18 +319,22 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
        }
 
        if (!ccok || dc_i) {
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
-               if (dc_i)
-                       dprintk("%d frame with disconnect indicator\n",
+               if (dc_i) {
+                       set_buf_flags(feed,
+                                     DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
+                       dprintk_sect_loss("%d frame with disconnect indicator\n",
                                cc);
-               else
-                       dprintk("discontinuity: %d instead of %d. %d bytes lost\n",
+               } else {
+                       set_buf_flags(feed,
+                                     DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+                       dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
                                cc, (feed->cc + 1) & 0x0f, count + 4);
+               }
                /*
-                * those bytes under sume circumstances will again be reported
+                * those bytes under some circumstances will again be reported
                 * in the following dvb_dmx_swfilter_section_new
                 */
-#endif
+
                /*
                 * Discontinuity detected. Reset pusi_seen to
                 * stop feeding of suspicious data until next PUSI=1 arrives
@@ -326,6 +342,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
                 * FIXME: does it make sense if the MPEG-TS is the one
                 *      reporting discontinuity?
                 */
+
                feed->pusi_seen = false;
                dvb_dmx_swfilter_section_new(feed);
        }
@@ -345,11 +362,11 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
                        dvb_dmx_swfilter_section_new(feed);
                        dvb_dmx_swfilter_section_copy_dump(feed, after,
                                                           after_len);
+               } else if (count > 0) {
+                       set_buf_flags(feed,
+                                     DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
+                       dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
                }
-#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
-               else if (count > 0)
-                       dprintk("PUSI=1 but %d bytes lost\n", count);
-#endif
        } else {
                /* PUSI=0 (is not set), no section boundary */
                dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
@@ -369,7 +386,8 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
                        if (feed->ts_type & TS_PAYLOAD_ONLY)
                                dvb_dmx_swfilter_payload(feed, buf);
                        else
-                               feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
+                               feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
+                                           &feed->buffer_flags);
                }
                /* Used only on full-featured devices */
                if (feed->ts_type & TS_DECODER)
@@ -430,6 +448,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
        }
 
        if (buf[1] & 0x80) {
+               list_for_each_entry(feed, &demux->feed_list, list_head) {
+                       if ((feed->pid != pid) && (feed->pid != 0x2000))
+                               continue;
+                       set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
+               }
                dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
                                pid, buf[1]);
                /* data in this packet can't be trusted - drop it unless
@@ -445,6 +468,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
                                                (demux->cnt_storage[pid] + 1) & 0xf;
 
                                if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
+                                       list_for_each_entry(feed, &demux->feed_list, list_head) {
+                                               if ((feed->pid != pid) && (feed->pid != 0x2000))
+                                                       continue;
+                                               set_buf_flags(feed,
+                                                             DMX_BUFFER_PKT_COUNTER_MISMATCH);
+                                       }
+
                                        dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
                                                        pid, demux->cnt_storage[pid],
                                                        buf[3] & 0xf);
@@ -466,7 +496,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
                if (feed->pid == pid)
                        dvb_dmx_swfilter_packet_type(feed, buf);
                else if (feed->pid == 0x2000)
-                       feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
+                       feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
+                                   &feed->buffer_flags);
        }
 }
 
@@ -585,7 +616,8 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
 
        spin_lock_irqsave(&demux->lock, flags);
 
-       demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts);
+       demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
+                          &demux->feed->buffer_flags);
 
        spin_unlock_irqrestore(&demux->lock, flags);
 }
@@ -785,6 +817,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
        feed->demux = demux;
        feed->pid = 0xffff;
        feed->peslen = 0xfffa;
+       feed->buffer_flags = 0;
 
        (*ts_feed) = &feed->feed.ts;
        (*ts_feed)->parent = dmx;
@@ -1042,6 +1075,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
        dvbdmxfeed->cb.sec = callback;
        dvbdmxfeed->demux = dvbdmx;
        dvbdmxfeed->pid = 0xffff;
+       dvbdmxfeed->buffer_flags = 0;
        dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
        dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
        dvbdmxfeed->feed.sec.tsfeedp = 0;
index b6c7eec..ba39f99 100644 (file)
@@ -883,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
 
 static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
                               const u8 *buffer2, size_t buffer2_len,
-                              struct dmx_ts_feed *feed)
+                              struct dmx_ts_feed *feed,
+                              u32 *buffer_flags)
 {
        struct net_device *dev = feed->priv;
 
@@ -992,7 +993,7 @@ static void dvb_net_sec(struct net_device *dev,
 
 static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
                 const u8 *buffer2, size_t buffer2_len,
-                struct dmx_section_filter *filter)
+                struct dmx_section_filter *filter, u32 *buffer_flags)
 {
        struct net_device *dev = filter->priv;
 
index 763145d..b811adf 100644 (file)
@@ -256,7 +256,8 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx)
 }
 
 int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
-                       const unsigned char *src, int len)
+                       const unsigned char *src, int len,
+                       enum dmx_buffer_flags *buffer_flags)
 {
        unsigned long flags = 0;
        void *vbuf = NULL;
@@ -264,15 +265,17 @@ int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
        unsigned char *psrc = (unsigned char *)src;
        int ll = 0;
 
-       dprintk(3, "[%s] %d bytes are rcvd\n", ctx->name, len);
-       if (!src) {
-               dprintk(3, "[%s]:NULL pointer src\n", ctx->name);
-               /**normal case: This func is called twice from demux driver
-                * once with valid src pointer, second time with NULL pointer
-                */
+       /*
+        * normal case: This func is called twice from demux driver
+        * one with valid src pointer, second time with NULL pointer
+        */
+       if (!src || !len)
                return 0;
-       }
        spin_lock_irqsave(&ctx->slock, flags);
+       if (buffer_flags && *buffer_flags) {
+               ctx->flags |= *buffer_flags;
+               *buffer_flags = 0;
+       }
        while (todo) {
                if (!ctx->buf) {
                        if (list_empty(&ctx->dvb_q)) {
@@ -395,6 +398,7 @@ int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
 
 int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
 {
+       unsigned long flags;
        int ret;
 
        ret = vb2_core_dqbuf(&ctx->vb_q, &b->index, b, ctx->nonblocking);
@@ -402,7 +406,16 @@ int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
                dprintk(1, "[%s] errno=%d\n", ctx->name, ret);
                return ret;
        }
-       dprintk(5, "[%s] index=%d\n", ctx->name, b->index);
+
+       spin_lock_irqsave(&ctx->slock, flags);
+       b->count = ctx->count++;
+       b->flags = ctx->flags;
+       ctx->flags = 0;
+       spin_unlock_irqrestore(&ctx->slock, flags);
+
+       dprintk(5, "[%s] index=%d, count=%d, flags=%d\n",
+               ctx->name, b->index, ctx->count, b->flags);
+
 
        return 0;
 }
index 50bce68..65d157f 100644 (file)
@@ -1262,11 +1262,12 @@ static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan)
  * New users must use I2C client binding directly!
  */
 struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
-               struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter)
+                                     struct i2c_adapter *i2c,
+                                     struct i2c_adapter **tuner_i2c_adapter)
 {
        struct i2c_client *client;
        struct i2c_board_info board_info;
-       struct m88ds3103_platform_data pdata;
+       struct m88ds3103_platform_data pdata = {};
 
        pdata.clk = cfg->clock;
        pdata.i2c_wr_max = cfg->i2c_wr_max;
@@ -1409,6 +1410,8 @@ static int m88ds3103_probe(struct i2c_client *client,
        case M88DS3103_CHIP_ID:
                break;
        default:
+               ret = -ENODEV;
+               dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id);
                goto err_kfree;
        }
 
index 3c18519..2476d81 100644 (file)
@@ -505,80 +505,77 @@ static struct i2c_vbi_ram_value vbi_ram_default[] =
        /* FIXME: Current api doesn't handle all VBI types, those not
           yet supported are placed under #if 0 */
 #if 0
-       {0x010, /* Teletext, SECAM, WST System A */
+       [0] = {0x010, /* Teletext, SECAM, WST System A */
                {V4L2_SLICED_TELETEXT_SECAM,6,23,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26,
                  0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
 #endif
-       {0x030, /* Teletext, PAL, WST System B */
+       [1] = {0x030, /* Teletext, PAL, WST System B */
                {V4L2_SLICED_TELETEXT_B,6,22,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b,
                  0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
 #if 0
-       {0x050, /* Teletext, PAL, WST System C */
+       [2] = {0x050, /* Teletext, PAL, WST System C */
                {V4L2_SLICED_TELETEXT_PAL_C,6,22,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
                  0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x070, /* Teletext, NTSC, WST System B */
+       [3] = {0x070, /* Teletext, NTSC, WST System B */
                {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23,
                  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x090, /* Tetetext, NTSC NABTS System C */
+       [4] = {0x090, /* Tetetext, NTSC NABTS System C */
                {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22,
                  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 }
        },
-       {0x0b0, /* Teletext, NTSC-J, NABTS System D */
+       [5] = {0x0b0, /* Teletext, NTSC-J, NABTS System D */
                {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1},
                { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23,
                  0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 }
        },
-       {0x0d0, /* Closed Caption, PAL/SECAM */
+       [6] = {0x0d0, /* Closed Caption, PAL/SECAM */
                {V4L2_SLICED_CAPTION_625,22,22,1},
                { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
                  0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
        },
 #endif
-       {0x0f0, /* Closed Caption, NTSC */
+       [7] = {0x0f0, /* Closed Caption, NTSC */
                {V4L2_SLICED_CAPTION_525,21,21,1},
                { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02,
                  0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 }
        },
-       {0x110, /* Wide Screen Signal, PAL/SECAM */
+       [8] = {0x110, /* Wide Screen Signal, PAL/SECAM */
                {V4L2_SLICED_WSS_625,23,23,1},
                { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42,
                  0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 }
        },
 #if 0
-       {0x130, /* Wide Screen Signal, NTSC C */
+       [9] = {0x130, /* Wide Screen Signal, NTSC C */
                {V4L2_SLICED_WSS_525,20,20,1},
                { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43,
                  0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 }
        },
-       {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
+       [10] = {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */
                {V4l2_SLICED_VITC_625,6,22,0},
                { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
                  0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
        },
-       {0x170, /* Vertical Interval Timecode (VITC), NTSC */
+       [11] = {0x170, /* Vertical Interval Timecode (VITC), NTSC */
                {V4l2_SLICED_VITC_525,10,20,0},
                { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49,
                  0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 }
        },
 #endif
-       {0x190, /* Video Program System (VPS), PAL */
+       [12] = {0x190, /* Video Program System (VPS), PAL */
                {V4L2_SLICED_VPS,16,16,0},
                { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d,
                  0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 }
        },
        /* 0x1d0 User programmable */
-
-       /* End of struct */
-       { (u16)-1 }
 };
 
 static int tvp5150_write_inittab(struct v4l2_subdev *sd,
@@ -591,10 +588,10 @@ static int tvp5150_write_inittab(struct v4l2_subdev *sd,
        return 0;
 }
 
-static int tvp5150_vdp_init(struct v4l2_subdev *sd,
-                               const struct i2c_vbi_ram_value *regs)
+static int tvp5150_vdp_init(struct v4l2_subdev *sd)
 {
        unsigned int i;
+       int j;
 
        /* Disable Full Field */
        tvp5150_write(sd, TVP5150_FULL_FIELD_ENA, 0);
@@ -604,14 +601,17 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd,
                tvp5150_write(sd, i, 0xff);
 
        /* Load Ram Table */
-       while (regs->reg != (u16)-1) {
+       for (j = 0; j < ARRAY_SIZE(vbi_ram_default); j++) {
+               const struct i2c_vbi_ram_value *regs = &vbi_ram_default[j];
+
+               if (!regs->type.vbi_type)
+                       continue;
+
                tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_HIGH, regs->reg >> 8);
                tvp5150_write(sd, TVP5150_CONF_RAM_ADDR_LOW, regs->reg);
 
                for (i = 0; i < 16; i++)
                        tvp5150_write(sd, TVP5150_VDP_CONF_RAM_DATA, regs->values[i]);
-
-               regs++;
        }
        return 0;
 }
@@ -620,19 +620,23 @@ static int tvp5150_vdp_init(struct v4l2_subdev *sd,
 static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
                                struct v4l2_sliced_vbi_cap *cap)
 {
-       const struct i2c_vbi_ram_value *regs = vbi_ram_default;
-       int line;
+       int line, i;
 
        dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n");
        memset(cap, 0, sizeof *cap);
 
-       while (regs->reg != (u16)-1 ) {
-               for (line=regs->type.ini_line;line<=regs->type.end_line;line++) {
+       for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
+               const struct i2c_vbi_ram_value *regs = &vbi_ram_default[i];
+
+               if (!regs->type.vbi_type)
+                       continue;
+
+               for (line = regs->type.ini_line;
+                    line <= regs->type.end_line;
+                    line++) {
                        cap->service_lines[0][line] |= regs->type.vbi_type;
                }
                cap->service_set |= regs->type.vbi_type;
-
-               regs++;
        }
        return 0;
 }
@@ -651,14 +655,13 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd,
  *     MSB = field2
  */
 static int tvp5150_set_vbi(struct v4l2_subdev *sd,
-                       const struct i2c_vbi_ram_value *regs,
                        unsigned int type,u8 flags, int line,
                        const int fields)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
        v4l2_std_id std = decoder->norm;
        u8 reg;
-       int pos = 0;
+       int i, pos = 0;
 
        if (std == V4L2_STD_ALL) {
                dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n");
@@ -671,19 +674,19 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd,
        if (line < 6 || line > 27)
                return 0;
 
-       while (regs->reg != (u16)-1) {
+       for (i = 0; i < ARRAY_SIZE(vbi_ram_default); i++) {
+               const struct i2c_vbi_ram_value *regs =  &vbi_ram_default[i];
+
+               if (!regs->type.vbi_type)
+                       continue;
+
                if ((type & regs->type.vbi_type) &&
                    (line >= regs->type.ini_line) &&
                    (line <= regs->type.end_line))
                        break;
-
-               regs++;
                pos++;
        }
 
-       if (regs->reg == (u16)-1)
-               return 0;
-
        type = pos | (flags & 0xf0);
        reg = ((line - 6) << 1) + TVP5150_LINE_MODE_INI;
 
@@ -696,8 +699,7 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd,
        return type;
 }
 
-static int tvp5150_get_vbi(struct v4l2_subdev *sd,
-                       const struct i2c_vbi_ram_value *regs, int line)
+static int tvp5150_get_vbi(struct v4l2_subdev *sd, int line)
 {
        struct tvp5150 *decoder = to_tvp5150(sd);
        v4l2_std_id std = decoder->norm;
@@ -726,8 +728,8 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd,
                        return 0;
                }
                pos = ret & 0x0f;
-               if (pos < 0x0f)
-                       type |= regs[pos].type.vbi_type;
+               if (pos < ARRAY_SIZE(vbi_ram_default))
+                       type |= vbi_ram_default[pos].type.vbi_type;
        }
 
        return type;
@@ -788,7 +790,7 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
        tvp5150_write_inittab(sd, tvp5150_init_default);
 
        /* Initializes VDP registers */
-       tvp5150_vdp_init(sd, vbi_ram_default);
+       tvp5150_vdp_init(sd);
 
        /* Selects decoder input */
        tvp5150_selmux(sd);
@@ -1121,8 +1123,8 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
                for (i = 0; i <= 23; i++) {
                        svbi->service_lines[1][i] = 0;
                        svbi->service_lines[0][i] =
-                               tvp5150_set_vbi(sd, vbi_ram_default,
-                                      svbi->service_lines[0][i], 0xf0, i, 3);
+                               tvp5150_set_vbi(sd, svbi->service_lines[0][i],
+                                               0xf0, i, 3);
                }
                /* Enables FIFO */
                tvp5150_write(sd, TVP5150_FIFO_OUT_CTRL, 1);
@@ -1148,7 +1150,7 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
 
        for (i = 0; i <= 23; i++) {
                svbi->service_lines[0][i] =
-                       tvp5150_get_vbi(sd, vbi_ram_default, i);
+                       tvp5150_get_vbi(sd, i);
                mask |= svbi->service_lines[0][i];
        }
        svbi->service_set = mask;
index dc8e577..d6816ef 100644 (file)
@@ -324,14 +324,15 @@ static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len,
                }
                return dvbdmxfilter->feed->cb.sec(buffer1, buffer1_len,
                                                  buffer2, buffer2_len,
-                                                 &dvbdmxfilter->filter);
+                                                 &dvbdmxfilter->filter, NULL);
        case DMX_TYPE_TS:
                if (!(dvbdmxfilter->feed->ts_type & TS_PACKET))
                        return 0;
                if (dvbdmxfilter->feed->ts_type & TS_PAYLOAD_ONLY)
                        return dvbdmxfilter->feed->cb.ts(buffer1, buffer1_len,
                                                         buffer2, buffer2_len,
-                                                        &dvbdmxfilter->feed->feed.ts);
+                                                        &dvbdmxfilter->feed->feed.ts,
+                                                        NULL);
                else
                        av7110_p2t_write(buffer1, buffer1_len,
                                         dvbdmxfilter->feed->pid,
index 4daba76..ef1bc17 100644 (file)
@@ -99,7 +99,7 @@ int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
                buf[4] = buf[5] = 0;
        if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
                return dvbdmxfeed->cb.ts(buf, len, NULL, 0,
-                                        &dvbdmxfeed->feed.ts);
+                                        &dvbdmxfeed->feed.ts, NULL);
        else
                return dvb_filter_pes2ts(p2t, buf, len, 1);
 }
@@ -109,7 +109,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
        struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;
 
        dvbdmxfeed->cb.ts(data, 188, NULL, 0,
-                         &dvbdmxfeed->feed.ts);
+                         &dvbdmxfeed->feed.ts, NULL);
        return 0;
 }
 
@@ -814,7 +814,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
                        memcpy(obuf + l, buf + c, TS_SIZE - l);
                        c = length;
                }
-               feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts);
+               feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, NULL);
                pes_start = 0;
        }
 }
index 92f93a8..aba488c 100644 (file)
@@ -172,16 +172,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)
                }
        }
 
-       if (status & (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN |
-                     TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED |
-                     TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED |
-                     TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED)) {
+       if (status & TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED) {
                cec_write(cec, TEGRA_CEC_INT_STAT,
-                         (TEGRA_CEC_INT_STAT_RX_REGISTER_OVERRUN |
-                          TEGRA_CEC_INT_STAT_RX_BUS_ANOMALY_DETECTED |
-                          TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED |
-                          TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED));
-       } else if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
+                         TEGRA_CEC_INT_STAT_RX_START_BIT_DETECTED);
+               cec->rx_done = false;
+               cec->rx_buf_cnt = 0;
+       }
+       if (status & TEGRA_CEC_INT_STAT_RX_REGISTER_FULL) {
                u32 v;
 
                cec_write(cec, TEGRA_CEC_INT_STAT,
@@ -255,7 +252,7 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)
                  TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |
                  TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED |
                  TEGRA_CEC_INT_MASK_RX_REGISTER_FULL |
-                 TEGRA_CEC_INT_MASK_RX_REGISTER_OVERRUN);
+                 TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED);
 
        cec_write(cec, TEGRA_CEC_HW_CONTROL, TEGRA_CEC_HWCTRL_TX_RX_MODE);
        return 0;
index 70521e0..bfaa806 100644 (file)
@@ -1,7 +1,7 @@
 
 config VIDEO_AU0828
        tristate "Auvitek AU0828 support"
-       depends on I2C && INPUT && DVB_CORE && USB
+       depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2
        select I2C_ALGOBIT
        select VIDEO_TVEEPROM
        select VIDEOBUF2_VMALLOC
index a8900f5..44ca66c 100644 (file)
@@ -428,7 +428,7 @@ static int ttusb_dec_audio_pes2ts_cb(void *priv, unsigned char *data)
        struct ttusb_dec *dec = priv;
 
        dec->audio_filter->feed->cb.ts(data, 188, NULL, 0,
-                                      &dec->audio_filter->feed->feed.ts);
+                                      &dec->audio_filter->feed->feed.ts, NULL);
 
        return 0;
 }
@@ -438,7 +438,7 @@ static int ttusb_dec_video_pes2ts_cb(void *priv, unsigned char *data)
        struct ttusb_dec *dec = priv;
 
        dec->video_filter->feed->cb.ts(data, 188, NULL, 0,
-                                      &dec->video_filter->feed->feed.ts);
+                                      &dec->video_filter->feed->feed.ts, NULL);
 
        return 0;
 }
@@ -490,7 +490,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
 
                if (output_pva) {
                        dec->video_filter->feed->cb.ts(pva, length, NULL, 0,
-                               &dec->video_filter->feed->feed.ts);
+                               &dec->video_filter->feed->feed.ts, NULL);
                        return;
                }
 
@@ -551,7 +551,7 @@ static void ttusb_dec_process_pva(struct ttusb_dec *dec, u8 *pva, int length)
        case 0x02:              /* MainAudioStream */
                if (output_pva) {
                        dec->audio_filter->feed->cb.ts(pva, length, NULL, 0,
-                               &dec->audio_filter->feed->feed.ts);
+                               &dec->audio_filter->feed->feed.ts, NULL);
                        return;
                }
 
@@ -589,7 +589,7 @@ static void ttusb_dec_process_filter(struct ttusb_dec *dec, u8 *packet,
 
        if (filter)
                filter->feed->cb.sec(&packet[2], length - 2, NULL, 0,
-                                    &filter->filter);
+                                    &filter->filter, NULL);
 }
 
 static void ttusb_dec_process_packet(struct ttusb_dec *dec)
index bf52fbd..8e37e7c 100644 (file)
@@ -7,6 +7,7 @@ config VIDEO_V4L2
        tristate
        depends on (I2C || I2C=n) && VIDEO_DEV
        select RATIONAL
+       select VIDEOBUF2_V4L2 if VIDEOBUF2_CORE
        default (I2C || I2C=n) && VIDEO_DEV
 
 config VIDEO_ADV_DEBUG
index 80de2cb..7df5458 100644 (file)
@@ -13,7 +13,7 @@ ifeq ($(CONFIG_COMPAT),y)
 endif
 obj-$(CONFIG_V4L2_FWNODE) += v4l2-fwnode.o
 ifeq ($(CONFIG_TRACEPOINTS),y)
-  videodev-objs += vb2-trace.o v4l2-trace.o
+  videodev-objs += v4l2-trace.o
 endif
 videodev-$(CONFIG_MEDIA_CONTROLLER) += v4l2-mc.o
 
@@ -35,4 +35,3 @@ obj-$(CONFIG_VIDEOBUF_DVB) += videobuf-dvb.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
 ccflags-y += -I$(srctree)/drivers/media/tuners
-
index 0a7bdbe..e9c1485 100644 (file)
 #define REG_TO_DCPU_MBOX       0x10
 #define REG_TO_HOST_MBOX       0x14
 
+/* Macros to process offsets returned by the DCPU */
+#define DRAM_MSG_ADDR_OFFSET   0x0
+#define DRAM_MSG_TYPE_OFFSET   0x1c
+#define DRAM_MSG_ADDR_MASK     ((1UL << DRAM_MSG_TYPE_OFFSET) - 1)
+#define DRAM_MSG_TYPE_MASK     ((1UL << \
+                                (BITS_PER_LONG - DRAM_MSG_TYPE_OFFSET)) - 1)
+
 /* Message RAM */
-#define DCPU_MSG_RAM(x)                (0x100 + (x) * sizeof(u32))
+#define DCPU_MSG_RAM_START     0x100
+#define DCPU_MSG_RAM(x)                (DCPU_MSG_RAM_START + (x) * sizeof(u32))
 
 /* DRAM Info Offsets & Masks */
 #define DRAM_INFO_INTERVAL     0x0
@@ -255,6 +263,40 @@ static unsigned int get_msg_chksum(const u32 msg[])
        return sum;
 }
 
+static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
+                                char *buf, ssize_t *size)
+{
+       unsigned int msg_type;
+       unsigned int offset;
+       void __iomem *ptr = NULL;
+
+       msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK;
+       offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;
+
+       /*
+        * msg_type == 1: the offset is relative to the message RAM
+        * msg_type == 0: the offset is relative to the data RAM (this is the
+        *                previous way of passing data)
+        * msg_type is anything else: there's critical hardware problem
+        */
+       switch (msg_type) {
+       case 1:
+               ptr = priv->regs + DCPU_MSG_RAM_START + offset;
+               break;
+       case 0:
+               ptr = priv->dmem + offset;
+               break;
+       default:
+               dev_emerg(priv->dev, "invalid message reply from DCPU: %#x\n",
+                       response);
+               if (buf && size)
+                       *size = sprintf(buf,
+                               "FATAL: communication error with DCPU\n");
+       }
+
+       return ptr;
+}
+
 static int __send_command(struct private_data *priv, unsigned int cmd,
                          u32 result[])
 {
@@ -507,7 +549,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
 {
        u32 response[MSG_FIELD_MAX];
        unsigned int info;
-       int ret;
+       ssize_t ret;
 
        ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf);
        if (ret)
@@ -528,18 +570,19 @@ static ssize_t show_refresh(struct device *dev,
        u32 response[MSG_FIELD_MAX];
        void __iomem *info;
        struct private_data *priv;
-       unsigned int offset;
        u8 refresh, sr_abort, ppre, thermal_offs, tuf;
        u32 mr4;
-       int ret;
+       ssize_t ret;
 
        ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf);
        if (ret)
                return ret;
 
        priv = dev_get_drvdata(dev);
-       offset = response[MSG_ARG0];
-       info = priv->dmem + offset;
+
+       info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
+       if (!info)
+               return ret;
 
        mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK;
 
@@ -561,7 +604,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
        u32 response[MSG_FIELD_MAX];
        struct private_data *priv;
        void __iomem *info;
-       unsigned int offset;
        unsigned long val;
        int ret;
 
@@ -574,8 +616,10 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
        if (ret)
                return ret;
 
-       offset = response[MSG_ARG0];
-       info = priv->dmem + offset;
+       info = get_msg_ptr(priv, response[MSG_ARG0], NULL, NULL);
+       if (!info)
+               return -EIO;
+
        writel_relaxed(val, info + DRAM_INFO_INTERVAL);
 
        return count;
@@ -587,23 +631,25 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
        u32 response[MSG_FIELD_MAX];
        struct private_data *priv;
        void __iomem *info;
-       unsigned int offset;
-       int ret;
+       ssize_t ret;
 
        ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf);
        if (ret)
                return ret;
 
-       offset = response[MSG_ARG0];
        priv = dev_get_drvdata(dev);
-       info = priv->dmem + offset;
+
+       info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
+       if (!info)
+               return ret;
 
        return sprintf(buf, "%#x %#x %#x %#x %#x\n",
                       readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK,
                       readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK,
                       readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK,
                       readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK,
-                      readl_relaxed(info + DRAM_VENDOR_ERROR));
+                      readl_relaxed(info + DRAM_VENDOR_ERROR) &
+                                    DRAM_VENDOR_MASK);
 }
 
 static int brcmstb_dpfe_resume(struct platform_device *pdev)
index 8d12017..4470630 100644 (file)
@@ -2687,6 +2687,8 @@ mptctl_hp_targetinfo(unsigned long arg)
                                __FILE__, __LINE__, iocnum);
                return -ENODEV;
        }
+       if (karg.hdr.id >= MPT_MAX_FC_DEVICES)
+               return -EINVAL;
        dctlprintk(ioc, printk(MYIOC_s_DEBUG_FMT "mptctl_hp_targetinfo called.\n",
            ioc->name));
 
index 3e5eabd..772d029 100644 (file)
@@ -548,12 +548,6 @@ int mei_cldev_disable(struct mei_cl_device *cldev)
                goto out;
        }
 
-       if (bus->dev_state == MEI_DEV_POWER_DOWN) {
-               dev_dbg(bus->dev, "Device is powering down, don't bother with disconnection\n");
-               err = 0;
-               goto out;
-       }
-
        err = mei_cl_disconnect(cl);
        if (err < 0)
                dev_err(bus->dev, "Could not disconnect from the ME client\n");
index be64969..7e60c18 100644 (file)
@@ -945,6 +945,12 @@ int mei_cl_disconnect(struct mei_cl *cl)
                return 0;
        }
 
+       if (dev->dev_state == MEI_DEV_POWER_DOWN) {
+               cl_dbg(dev, cl, "Device is powering down, don't bother with disconnection\n");
+               mei_cl_set_disconnected(cl);
+               return 0;
+       }
+
        rets = pm_runtime_get(dev->dev);
        if (rets < 0 && rets != -EINPROGRESS) {
                pm_runtime_put_noidle(dev->dev);
index 0ccccba..e4b10b2 100644 (file)
 #define MEI_DEV_ID_KBP        0xA2BA  /* Kaby Point */
 #define MEI_DEV_ID_KBP_2      0xA2BB  /* Kaby Point 2 */
 
+#define MEI_DEV_ID_CNP_LP     0x9DE0  /* Cannon Point LP */
+#define MEI_DEV_ID_CNP_LP_4   0x9DE4  /* Cannon Point LP 4 (iTouch) */
+#define MEI_DEV_ID_CNP_H      0xA360  /* Cannon Point H */
+#define MEI_DEV_ID_CNP_H_4    0xA364  /* Cannon Point H 4 (iTouch) */
+
 /*
  * MEI HW Section
  */
index 4a0ccda..ea4e152 100644 (file)
@@ -98,6 +98,11 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
        {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)},
        {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)},
 
+       {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP, MEI_ME_PCH8_CFG)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP_4, MEI_ME_PCH8_CFG)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H, MEI_ME_PCH8_CFG)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H_4, MEI_ME_PCH8_CFG)},
+
        /* required last entry */
        {0, }
 };
index 2dd2db9..038509e 100644 (file)
@@ -102,10 +102,32 @@ static long afu_ioctl_attach(struct ocxl_context *ctx,
        return rc;
 }
 
+static long afu_ioctl_get_metadata(struct ocxl_context *ctx,
+               struct ocxl_ioctl_metadata __user *uarg)
+{
+       struct ocxl_ioctl_metadata arg;
+
+       memset(&arg, 0, sizeof(arg));
+
+       arg.version = 0;
+
+       arg.afu_version_major = ctx->afu->config.version_major;
+       arg.afu_version_minor = ctx->afu->config.version_minor;
+       arg.pasid = ctx->pasid;
+       arg.pp_mmio_size = ctx->afu->config.pp_mmio_stride;
+       arg.global_mmio_size = ctx->afu->config.global_mmio_size;
+
+       if (copy_to_user(uarg, &arg, sizeof(arg)))
+               return -EFAULT;
+
+       return 0;
+}
+
 #define CMD_STR(x) (x == OCXL_IOCTL_ATTACH ? "ATTACH" :                        \
                        x == OCXL_IOCTL_IRQ_ALLOC ? "IRQ_ALLOC" :       \
                        x == OCXL_IOCTL_IRQ_FREE ? "IRQ_FREE" :         \
                        x == OCXL_IOCTL_IRQ_SET_FD ? "IRQ_SET_FD" :     \
+                       x == OCXL_IOCTL_GET_METADATA ? "GET_METADATA" : \
                        "UNKNOWN")
 
 static long afu_ioctl(struct file *file, unsigned int cmd,
@@ -133,8 +155,10 @@ static long afu_ioctl(struct file *file, unsigned int cmd,
                if (!rc) {
                        rc = copy_to_user((u64 __user *) args, &irq_offset,
                                        sizeof(irq_offset));
-                       if (rc)
+                       if (rc) {
                                ocxl_afu_irq_free(ctx, irq_offset);
+                               return -EFAULT;
+                       }
                }
                break;
 
@@ -157,6 +181,11 @@ static long afu_ioctl(struct file *file, unsigned int cmd,
                                        irq_fd.eventfd);
                break;
 
+       case OCXL_IOCTL_GET_METADATA:
+               rc = afu_ioctl_get_metadata(ctx,
+                               (struct ocxl_ioctl_metadata __user *) args);
+               break;
+
        default:
                rc = -EINVAL;
        }
@@ -329,7 +358,7 @@ static ssize_t afu_read(struct file *file, char __user *buf, size_t count,
 
        used += sizeof(header);
 
-       rc = (ssize_t) used;
+       rc = used;
        return rc;
 }
 
index 20135a5..2cfb963 100644 (file)
@@ -72,6 +72,7 @@ MODULE_ALIAS("mmc:block");
 #define MMC_BLK_TIMEOUT_MS  (10 * 1000)
 #define MMC_SANITIZE_REQ_TIMEOUT 240000
 #define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
+#define MMC_EXTRACT_VALUE_FROM_ARG(x) ((x & 0x0000FF00) >> 8)
 
 #define mmc_req_rel_wr(req)    ((req->cmd_flags & REQ_FUA) && \
                                  (rq_data_dir(req) == WRITE))
@@ -587,6 +588,24 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
        }
 
        /*
+        * Make sure the cache of the PARTITION_CONFIG register and
+        * PARTITION_ACCESS bits is updated in case the ioctl ext_csd write
+        * changed it successfully.
+        */
+       if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_PART_CONFIG) &&
+           (cmd.opcode == MMC_SWITCH)) {
+               struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
+               u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg);
+
+               /*
+                * Update cache so the next mmc_blk_part_switch call operates
+                * on up-to-date data.
+                */
+               card->ext_csd.part_config = value;
+               main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
+       }
+
+       /*
         * According to the SD specs, some commands require a delay after
         * issuing the command.
         */
index 79a5b98..9c821ee 100644 (file)
@@ -82,6 +82,7 @@ struct mmc_fixup {
 #define CID_MANFID_APACER       0x27
 #define CID_MANFID_KINGSTON     0x70
 #define CID_MANFID_HYNIX       0x90
+#define CID_MANFID_NUMONYX     0xFE
 
 #define END_FIXUP { NULL }
 
index 908e4db..42d6aa8 100644 (file)
@@ -848,7 +848,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
                return 1;
        }
 
-       mmc_claim_host(card->host);
        err = mmc_send_status(card, &status);
        if (err) {
                pr_err("%s: Get card status fail\n", mmc_hostname(card->host));
@@ -890,7 +889,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
        } while (!err);
 
 out:
-       mmc_release_host(card->host);
        return err;
 }
 
@@ -932,9 +930,7 @@ static int mmc_read_bkops_status(struct mmc_card *card)
        int err;
        u8 *ext_csd;
 
-       mmc_claim_host(card->host);
        err = mmc_get_ext_csd(card, &ext_csd);
-       mmc_release_host(card->host);
        if (err)
                return err;
 
index 75d3176..5153577 100644 (file)
@@ -109,6 +109,12 @@ static const struct mmc_fixup mmc_ext_csd_fixups[] = {
         */
        MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
                              0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),
+       /*
+        * Certain Micron (Numonyx) eMMC 4.5 cards might get broken when HPI
+        * feature is used so disable the HPI feature for such buggy cards.
+        */
+       MMC_FIXUP_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_NUMONYX,
+                             0x014e, add_quirk, MMC_QUIRK_BROKEN_HPI, 6),
 
        END_FIXUP
 };
index 229dc18..768972a 100644 (file)
@@ -1265,7 +1265,8 @@ static int bcm2835_add_host(struct bcm2835_host *host)
        char pio_limit_string[20];
        int ret;
 
-       mmc->f_max = host->max_clk;
+       if (!mmc->f_max || mmc->f_max > host->max_clk)
+               mmc->f_max = host->max_clk;
        mmc->f_min = host->max_clk / SDCDIV_MAX_CDIV;
 
        mmc->max_busy_timeout = ~0 / (mmc->f_max / 1000);
index 3502679..a84aa3f 100644 (file)
@@ -165,9 +165,15 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
 static int dw_mci_exynos_runtime_resume(struct device *dev)
 {
        struct dw_mci *host = dev_get_drvdata(dev);
+       int ret;
+
+       ret = dw_mci_runtime_resume(dev);
+       if (ret)
+               return ret;
 
        dw_mci_exynos_config_smu(host);
-       return dw_mci_runtime_resume(dev);
+
+       return ret;
 }
 
 /**
@@ -487,6 +493,7 @@ static unsigned long exynos_dwmmc_caps[4] = {
 
 static const struct dw_mci_drv_data exynos_drv_data = {
        .caps                   = exynos_dwmmc_caps,
+       .num_caps               = ARRAY_SIZE(exynos_dwmmc_caps),
        .init                   = dw_mci_exynos_priv_init,
        .set_ios                = dw_mci_exynos_set_ios,
        .parse_dt               = dw_mci_exynos_parse_dt,
index 73fd75c..89cdb3d 100644 (file)
@@ -135,6 +135,9 @@ static int dw_mci_hi6220_parse_dt(struct dw_mci *host)
        if (priv->ctrl_id < 0)
                priv->ctrl_id = 0;
 
+       if (priv->ctrl_id >= TIMING_MODE)
+               return -EINVAL;
+
        host->priv = priv;
        return 0;
 }
@@ -207,6 +210,7 @@ static int dw_mci_hi6220_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
 
 static const struct dw_mci_drv_data hi6220_data = {
        .caps                   = dw_mci_hi6220_caps,
+       .num_caps               = ARRAY_SIZE(dw_mci_hi6220_caps),
        .switch_voltage         = dw_mci_hi6220_switch_voltage,
        .set_ios                = dw_mci_hi6220_set_ios,
        .parse_dt               = dw_mci_hi6220_parse_dt,
index a3f1c2b..3392952 100644 (file)
@@ -319,6 +319,7 @@ static const struct dw_mci_drv_data rk2928_drv_data = {
 
 static const struct dw_mci_drv_data rk3288_drv_data = {
        .caps                   = dw_mci_rk3288_dwmmc_caps,
+       .num_caps               = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),
        .set_ios                = dw_mci_rk3288_set_ios,
        .execute_tuning         = dw_mci_rk3288_execute_tuning,
        .parse_dt               = dw_mci_rk3288_parse_dt,
index d38e94a..c06b539 100644 (file)
@@ -195,6 +195,7 @@ static unsigned long zx_dwmmc_caps[3] = {
 
 static const struct dw_mci_drv_data zx_drv_data = {
        .caps                   = zx_dwmmc_caps,
+       .num_caps               = ARRAY_SIZE(zx_dwmmc_caps),
        .execute_tuning         = dw_mci_zx_execute_tuning,
        .prepare_hs400_tuning   = dw_mci_zx_prepare_hs400_tuning,
        .parse_dt               = dw_mci_zx_parse_dt,
index 0aa3997..06d4741 100644 (file)
@@ -165,6 +165,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v)
 {
        struct dw_mci *host = s->private;
 
+       pm_runtime_get_sync(host->dev);
+
        seq_printf(s, "STATUS:\t0x%08x\n", mci_readl(host, STATUS));
        seq_printf(s, "RINTSTS:\t0x%08x\n", mci_readl(host, RINTSTS));
        seq_printf(s, "CMD:\t0x%08x\n", mci_readl(host, CMD));
@@ -172,6 +174,8 @@ static int dw_mci_regs_show(struct seq_file *s, void *v)
        seq_printf(s, "INTMASK:\t0x%08x\n", mci_readl(host, INTMASK));
        seq_printf(s, "CLKENA:\t0x%08x\n", mci_readl(host, CLKENA));
 
+       pm_runtime_put_autosuspend(host->dev);
+
        return 0;
 }
 
@@ -409,7 +413,9 @@ static inline void dw_mci_set_cto(struct dw_mci *host)
        cto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
        if (cto_div == 0)
                cto_div = 1;
-       cto_ms = DIV_ROUND_UP(MSEC_PER_SEC * cto_clks * cto_div, host->bus_hz);
+
+       cto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * cto_clks * cto_div,
+                                 host->bus_hz);
 
        /* add a bit spare time */
        cto_ms += 10;
@@ -558,6 +564,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
                                        (sizeof(struct idmac_desc_64addr) *
                                                        (i + 1))) >> 32;
                        /* Initialize reserved and buffer size fields to "0" */
+                       p->des0 = 0;
                        p->des1 = 0;
                        p->des2 = 0;
                        p->des3 = 0;
@@ -580,6 +587,7 @@ static int dw_mci_idmac_init(struct dw_mci *host)
                     i++, p++) {
                        p->des3 = cpu_to_le32(host->sg_dma +
                                        (sizeof(struct idmac_desc) * (i + 1)));
+                       p->des0 = 0;
                        p->des1 = 0;
                }
 
@@ -1795,8 +1803,8 @@ static bool dw_mci_reset(struct dw_mci *host)
        }
 
        if (host->use_dma == TRANS_MODE_IDMAC)
-               /* It is also recommended that we reset and reprogram idmac */
-               dw_mci_idmac_reset(host);
+               /* It is also required that we reinit idmac */
+               dw_mci_idmac_init(host);
 
        ret = true;
 
@@ -1944,8 +1952,9 @@ static void dw_mci_set_drto(struct dw_mci *host)
        drto_div = (mci_readl(host, CLKDIV) & 0xff) * 2;
        if (drto_div == 0)
                drto_div = 1;
-       drto_ms = DIV_ROUND_UP(MSEC_PER_SEC * drto_clks * drto_div,
-                              host->bus_hz);
+
+       drto_ms = DIV_ROUND_UP_ULL((u64)MSEC_PER_SEC * drto_clks * drto_div,
+                                  host->bus_hz);
 
        /* add a bit spare time */
        drto_ms += 10;
@@ -2778,12 +2787,57 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static int dw_mci_init_slot_caps(struct dw_mci_slot *slot)
+{
+       struct dw_mci *host = slot->host;
+       const struct dw_mci_drv_data *drv_data = host->drv_data;
+       struct mmc_host *mmc = slot->mmc;
+       int ctrl_id;
+
+       if (host->pdata->caps)
+               mmc->caps = host->pdata->caps;
+
+       /*
+        * Support MMC_CAP_ERASE by default.
+        * It needs to use trim/discard/erase commands.
+        */
+       mmc->caps |= MMC_CAP_ERASE;
+
+       if (host->pdata->pm_caps)
+               mmc->pm_caps = host->pdata->pm_caps;
+
+       if (host->dev->of_node) {
+               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
+               if (ctrl_id < 0)
+                       ctrl_id = 0;
+       } else {
+               ctrl_id = to_platform_device(host->dev)->id;
+       }
+
+       if (drv_data && drv_data->caps) {
+               if (ctrl_id >= drv_data->num_caps) {
+                       dev_err(host->dev, "invalid controller id %d\n",
+                               ctrl_id);
+                       return -EINVAL;
+               }
+               mmc->caps |= drv_data->caps[ctrl_id];
+       }
+
+       if (host->pdata->caps2)
+               mmc->caps2 = host->pdata->caps2;
+
+       /* Process SDIO IRQs through the sdio_irq_work. */
+       if (mmc->caps & MMC_CAP_SDIO_IRQ)
+               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
+       return 0;
+}
+
 static int dw_mci_init_slot(struct dw_mci *host)
 {
        struct mmc_host *mmc;
        struct dw_mci_slot *slot;
-       const struct dw_mci_drv_data *drv_data = host->drv_data;
-       int ctrl_id, ret;
+       int ret;
        u32 freq[2];
 
        mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
@@ -2817,38 +2871,13 @@ static int dw_mci_init_slot(struct dw_mci *host)
        if (!mmc->ocr_avail)
                mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
 
-       if (host->pdata->caps)
-               mmc->caps = host->pdata->caps;
-
-       /*
-        * Support MMC_CAP_ERASE by default.
-        * It needs to use trim/discard/erase commands.
-        */
-       mmc->caps |= MMC_CAP_ERASE;
-
-       if (host->pdata->pm_caps)
-               mmc->pm_caps = host->pdata->pm_caps;
-
-       if (host->dev->of_node) {
-               ctrl_id = of_alias_get_id(host->dev->of_node, "mshc");
-               if (ctrl_id < 0)
-                       ctrl_id = 0;
-       } else {
-               ctrl_id = to_platform_device(host->dev)->id;
-       }
-       if (drv_data && drv_data->caps)
-               mmc->caps |= drv_data->caps[ctrl_id];
-
-       if (host->pdata->caps2)
-               mmc->caps2 = host->pdata->caps2;
-
        ret = mmc_of_parse(mmc);
        if (ret)
                goto err_host_allocated;
 
-       /* Process SDIO IRQs through the sdio_irq_work. */
-       if (mmc->caps & MMC_CAP_SDIO_IRQ)
-               mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+       ret = dw_mci_init_slot_caps(slot);
+       if (ret)
+               goto err_host_allocated;
 
        /* Useful defaults if platform data is unset. */
        if (host->use_dma == TRANS_MODE_IDMAC) {
index e3124f0..1424bd4 100644 (file)
@@ -543,6 +543,7 @@ struct dw_mci_slot {
 /**
  * dw_mci driver data - dw-mshc implementation specific driver data.
  * @caps: mmc subsystem specified capabilities of the controller(s).
+ * @num_caps: number of capabilities specified by @caps.
  * @init: early implementation specific initialization.
  * @set_ios: handle bus specific extensions.
  * @parse_dt: parse implementation specific device tree properties.
@@ -554,6 +555,7 @@ struct dw_mci_slot {
  */
 struct dw_mci_drv_data {
        unsigned long   *caps;
+       u32             num_caps;
        int             (*init)(struct dw_mci *host);
        void            (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
        int             (*parse_dt)(struct dw_mci *host);
index 22438eb..4f972b8 100644 (file)
@@ -717,22 +717,6 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode,
 static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
        struct meson_host *host = mmc_priv(mmc);
-       int ret;
-
-       /*
-        * If this is the initial tuning, try to get a sane Rx starting
-        * phase before doing the actual tuning.
-        */
-       if (!mmc->doing_retune) {
-               ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);
-
-               if (ret)
-                       return ret;
-       }
-
-       ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk);
-       if (ret)
-               return ret;
 
        return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);
 }
@@ -763,9 +747,8 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if (!IS_ERR(mmc->supply.vmmc))
                        mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
 
-               /* Reset phases */
+               /* Reset rx phase */
                clk_set_phase(host->rx_clk, 0);
-               clk_set_phase(host->tx_clk, 270);
 
                break;
 
index 4065da5..32321bd 100644 (file)
@@ -680,7 +680,7 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
        host->hw_name   = "ACPI";
        host->ops       = &sdhci_acpi_ops_dflt;
        host->irq       = platform_get_irq(pdev, 0);
-       if (host->irq <= 0) {
+       if (host->irq < 0) {
                err = -EINVAL;
                goto err_free;
        }
index 6d1a983..82c4f05 100644 (file)
@@ -654,9 +654,36 @@ static void byt_read_dsm(struct sdhci_pci_slot *slot)
        slot->chip->rpm_retune = intel_host->d3_retune;
 }
 
-static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+       int err = sdhci_execute_tuning(mmc, opcode);
+       struct sdhci_host *host = mmc_priv(mmc);
+
+       if (err)
+               return err;
+
+       /*
+        * Tuning can leave the IP in an active state (Buffer Read Enable bit
+        * set) which prevents the entry to low power states (i.e. S0i3). Data
+        * reset will clear it.
+        */
+       sdhci_reset(host, SDHCI_RESET_DATA);
+
+       return 0;
+}
+
+static void byt_probe_slot(struct sdhci_pci_slot *slot)
 {
+       struct mmc_host_ops *ops = &slot->host->mmc_host_ops;
+
        byt_read_dsm(slot);
+
+       ops->execute_tuning = intel_execute_tuning;
+}
+
+static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
                                 MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
                                 MMC_CAP_CMD_DURING_TFR |
@@ -779,7 +806,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
        int err;
 
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
 
        err = ni_set_max_freq(slot);
        if (err)
@@ -792,7 +819,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 
 static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 {
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
                                 MMC_CAP_WAIT_WHILE_BUSY;
        return 0;
@@ -800,7 +827,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
 
 static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
 {
-       byt_read_dsm(slot);
+       byt_probe_slot(slot);
        slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY |
                                 MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE;
        slot->cd_idx = 0;
index 7c0b27d..b479bd8 100644 (file)
@@ -1889,6 +1889,8 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base,
        do {
                uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi);
                mask = (1 << (cfi->device_type * 8)) - 1;
+               if (ofs >= map->size)
+                       return 0;
                result = map_read(map, base + ofs);
                bank++;
        } while ((result.x[0] & mask) == CFI_MFR_CONTINUATION);
index de8c902..7d80a8b 100644 (file)
@@ -479,7 +479,7 @@ static int shrink_ecclayout(struct mtd_info *mtd,
        for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) {
                u32 eccpos;
 
-               ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
+               ret = mtd_ooblayout_ecc(mtd, section++, &oobregion);
                if (ret < 0) {
                        if (ret != -ERANGE)
                                return ret;
@@ -526,7 +526,7 @@ static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to)
        for (i = 0; i < ARRAY_SIZE(to->eccpos);) {
                u32 eccpos;
 
-               ret = mtd_ooblayout_ecc(mtd, section, &oobregion);
+               ret = mtd_ooblayout_ecc(mtd, section++, &oobregion);
                if (ret < 0) {
                        if (ret != -ERANGE)
                                return ret;
index e6b8c59..736ac88 100644 (file)
@@ -328,7 +328,7 @@ config MTD_NAND_MARVELL
        tristate "NAND controller support on Marvell boards"
        depends on PXA3xx || ARCH_MMP || PLAT_ORION || ARCH_MVEBU || \
                   COMPILE_TEST
-       depends on HAS_IOMEM
+       depends on HAS_IOMEM && HAS_DMA
        help
          This enables the NAND flash controller driver for Marvell boards,
          including:
index fcbe4fd..ca0a703 100644 (file)
@@ -426,7 +426,7 @@ static int get_strength(struct atmel_pmecc_user *user)
 
 static int get_sectorsize(struct atmel_pmecc_user *user)
 {
-       return user->cache.cfg & PMECC_LOOKUP_TABLE_SIZE_1024 ? 1024 : 512;
+       return user->cache.cfg & PMECC_CFG_SECTOR1024 ? 1024 : 512;
 }
 
 static void atmel_pmecc_gen_syndrome(struct atmel_pmecc_user *user, int sector)
index 4872a7b..5a9c2f0 100644 (file)
@@ -173,14 +173,9 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob)
 
 /* returns nonzero if entire page is blank */
 static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl,
-                         u32 *eccstat, unsigned int bufnum)
+                         u32 eccstat, unsigned int bufnum)
 {
-       u32 reg = eccstat[bufnum / 4];
-       int errors;
-
-       errors = (reg >> ((3 - bufnum % 4) * 8)) & 15;
-
-       return errors;
+       return  (eccstat >> ((3 - bufnum % 4) * 8)) & 15;
 }
 
 /*
@@ -193,7 +188,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl;
        struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
-       u32 eccstat[4];
+       u32 eccstat;
        int i;
 
        /* set the chip select for NAND Transaction */
@@ -228,19 +223,17 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
        if (nctrl->eccread) {
                int errors;
                int bufnum = nctrl->page & priv->bufnum_mask;
-               int sector = bufnum * chip->ecc.steps;
-               int sector_end = sector + chip->ecc.steps - 1;
+               int sector_start = bufnum * chip->ecc.steps;
+               int sector_end = sector_start + chip->ecc.steps - 1;
                __be32 *eccstat_regs;
 
-               if (ctrl->version >= FSL_IFC_VERSION_2_0_0)
-                       eccstat_regs = ifc->ifc_nand.v2_nand_eccstat;
-               else
-                       eccstat_regs = ifc->ifc_nand.v1_nand_eccstat;
+               eccstat_regs = ifc->ifc_nand.nand_eccstat;
+               eccstat = ifc_in32(&eccstat_regs[sector_start / 4]);
 
-               for (i = sector / 4; i <= sector_end / 4; i++)
-                       eccstat[i] = ifc_in32(&eccstat_regs[i]);
+               for (i = sector_start; i <= sector_end; i++) {
+                       if (i != sector_start && !(i % 4))
+                               eccstat = ifc_in32(&eccstat_regs[i / 4]);
 
-               for (i = sector; i <= sector_end; i++) {
                        errors = check_read_ecc(mtd, ctrl, eccstat, i);
 
                        if (errors == 15) {
@@ -626,6 +619,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        struct fsl_ifc_ctrl *ctrl = priv->ctrl;
        struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs;
        u32 nand_fsr;
+       int status;
 
        /* Use READ_STATUS command, but wait for the device to be ready */
        ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) |
@@ -640,12 +634,12 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip)
        fsl_ifc_run_command(mtd);
 
        nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr);
-
+       status = nand_fsr >> 24;
        /*
         * The chip always seems to report that it is
         * write-protected, even when it is not.
         */
-       return nand_fsr | NAND_STATUS_WP;
+       return status | NAND_STATUS_WP;
 }
 
 /*
index 80d31a5..f367144 100644 (file)
@@ -752,10 +752,8 @@ static int vf610_nfc_probe(struct platform_device *pdev)
                if (mtd->oobsize > 64)
                        mtd->oobsize = 64;
 
-               /*
-                * mtd->ecclayout is not specified here because we're using the
-                * default large page ECC layout defined in NAND core.
-                */
+               /* Use default large page ECC layout defined in NAND core */
+               mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
                if (chip->ecc.strength == 32) {
                        nfc->ecc_mode = ECC_60_BYTE;
                        chip->ecc.bytes = 60;
index c669554..b7b1130 100644 (file)
@@ -1528,39 +1528,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
                        goto err_close;
        }
 
-       /* If the mode uses primary, then the following is handled by
-        * bond_change_active_slave().
-        */
-       if (!bond_uses_primary(bond)) {
-               /* set promiscuity level to new slave */
-               if (bond_dev->flags & IFF_PROMISC) {
-                       res = dev_set_promiscuity(slave_dev, 1);
-                       if (res)
-                               goto err_close;
-               }
-
-               /* set allmulti level to new slave */
-               if (bond_dev->flags & IFF_ALLMULTI) {
-                       res = dev_set_allmulti(slave_dev, 1);
-                       if (res)
-                               goto err_close;
-               }
-
-               netif_addr_lock_bh(bond_dev);
-
-               dev_mc_sync_multiple(slave_dev, bond_dev);
-               dev_uc_sync_multiple(slave_dev, bond_dev);
-
-               netif_addr_unlock_bh(bond_dev);
-       }
-
-       if (BOND_MODE(bond) == BOND_MODE_8023AD) {
-               /* add lacpdu mc addr to mc list */
-               u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
-
-               dev_mc_add(slave_dev, lacpdu_multicast);
-       }
-
        res = vlan_vids_add_by_dev(slave_dev, bond_dev);
        if (res) {
                netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n",
@@ -1725,6 +1692,40 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
                goto err_upper_unlink;
        }
 
+       /* If the mode uses primary, then the following is handled by
+        * bond_change_active_slave().
+        */
+       if (!bond_uses_primary(bond)) {
+               /* set promiscuity level to new slave */
+               if (bond_dev->flags & IFF_PROMISC) {
+                       res = dev_set_promiscuity(slave_dev, 1);
+                       if (res)
+                               goto err_sysfs_del;
+               }
+
+               /* set allmulti level to new slave */
+               if (bond_dev->flags & IFF_ALLMULTI) {
+                       res = dev_set_allmulti(slave_dev, 1);
+                       if (res) {
+                               if (bond_dev->flags & IFF_PROMISC)
+                                       dev_set_promiscuity(slave_dev, -1);
+                               goto err_sysfs_del;
+                       }
+               }
+
+               netif_addr_lock_bh(bond_dev);
+               dev_mc_sync_multiple(slave_dev, bond_dev);
+               dev_uc_sync_multiple(slave_dev, bond_dev);
+               netif_addr_unlock_bh(bond_dev);
+
+               if (BOND_MODE(bond) == BOND_MODE_8023AD) {
+                       /* add lacpdu mc addr to mc list */
+                       u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR;
+
+                       dev_mc_add(slave_dev, lacpdu_multicast);
+               }
+       }
+
        bond->slave_cnt++;
        bond_compute_features(bond);
        bond_set_carrier(bond);
@@ -1748,6 +1749,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
        return 0;
 
 /* Undo stages on error */
+err_sysfs_del:
+       bond_sysfs_slave_del(new_slave);
+
 err_upper_unlink:
        bond_upper_dev_unlink(bond, new_slave);
 
@@ -1755,9 +1759,6 @@ err_unregister:
        netdev_rx_handler_unregister(slave_dev);
 
 err_detach:
-       if (!bond_uses_primary(bond))
-               bond_hw_addr_flush(bond_dev, slave_dev);
-
        vlan_vids_del_by_dev(slave_dev, bond_dev);
        if (rcu_access_pointer(bond->primary_slave) == new_slave)
                RCU_INIT_POINTER(bond->primary_slave, NULL);
index 1e37313..6da69af 100644 (file)
@@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev,
        return 0;
 }
 
-static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void cc770_tx(struct net_device *dev, int mo)
 {
        struct cc770_priv *priv = netdev_priv(dev);
-       struct net_device_stats *stats = &dev->stats;
-       struct can_frame *cf = (struct can_frame *)skb->data;
-       unsigned int mo = obj2msgobj(CC770_OBJ_TX);
+       struct can_frame *cf = (struct can_frame *)priv->tx_skb->data;
        u8 dlc, rtr;
        u32 id;
        int i;
 
-       if (can_dropped_invalid_skb(dev, skb))
-               return NETDEV_TX_OK;
-
-       if ((cc770_read_reg(priv,
-                           msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
-               netdev_err(dev, "TX register is still occupied!\n");
-               return NETDEV_TX_BUSY;
-       }
-
-       netif_stop_queue(dev);
-
        dlc = cf->can_dlc;
        id = cf->can_id;
-       if (cf->can_id & CAN_RTR_FLAG)
-               rtr = 0;
-       else
-               rtr = MSGCFG_DIR;
+       rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR;
+
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
        cc770_write_reg(priv, msgobj[mo].ctrl1,
                        RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES);
-       cc770_write_reg(priv, msgobj[mo].ctrl0,
-                       MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES);
+
        if (id & CAN_EFF_FLAG) {
                id &= CAN_EFF_MASK;
                cc770_write_reg(priv, msgobj[mo].config,
@@ -439,22 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
        for (i = 0; i < dlc; i++)
                cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]);
 
-       /* Store echo skb before starting the transfer */
-       can_put_echo_skb(skb, dev, 0);
-
        cc770_write_reg(priv, msgobj[mo].ctrl1,
-                       RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
+                       RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC);
+       cc770_write_reg(priv, msgobj[mo].ctrl0,
+                       MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC);
+}
 
-       stats->tx_bytes += dlc;
+static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct cc770_priv *priv = netdev_priv(dev);
+       unsigned int mo = obj2msgobj(CC770_OBJ_TX);
 
+       if (can_dropped_invalid_skb(dev, skb))
+               return NETDEV_TX_OK;
 
-       /*
-        * HM: We had some cases of repeated IRQs so make sure the
-        * INT is acknowledged I know it's already further up, but
-        * doing again fixed the issue
-        */
-       cc770_write_reg(priv, msgobj[mo].ctrl0,
-                       MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+       netif_stop_queue(dev);
+
+       if ((cc770_read_reg(priv,
+                           msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) {
+               netdev_err(dev, "TX register is still occupied!\n");
+               return NETDEV_TX_BUSY;
+       }
+
+       priv->tx_skb = skb;
+       cc770_tx(dev, mo);
 
        return NETDEV_TX_OK;
 }
@@ -680,19 +674,46 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o)
        struct cc770_priv *priv = netdev_priv(dev);
        struct net_device_stats *stats = &dev->stats;
        unsigned int mo = obj2msgobj(o);
+       struct can_frame *cf;
+       u8 ctrl1;
+
+       ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1);
 
-       /* Nothing more to send, switch off interrupts */
        cc770_write_reg(priv, msgobj[mo].ctrl0,
                        MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES);
-       /*
-        * We had some cases of repeated IRQ so make sure the
-        * INT is acknowledged
+       cc770_write_reg(priv, msgobj[mo].ctrl1,
+                       RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES);
+
+       if (unlikely(!priv->tx_skb)) {
+               netdev_err(dev, "missing tx skb in tx interrupt\n");
+               return;
+       }
+
+       if (unlikely(ctrl1 & MSGLST_SET)) {
+               stats->rx_over_errors++;
+               stats->rx_errors++;
+       }
+
+       /* When the CC770 is sending an RTR message and it receives a regular
+        * message that matches the id of the RTR message, it will overwrite the
+        * outgoing message in the TX register. When this happens we must
+        * process the received message and try to transmit the outgoing skb
+        * again.
         */
-       cc770_write_reg(priv, msgobj[mo].ctrl0,
-                       MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES);
+       if (unlikely(ctrl1 & NEWDAT_SET)) {
+               cc770_rx(dev, mo, ctrl1);
+               cc770_tx(dev, mo);
+               return;
+       }
 
+       cf = (struct can_frame *)priv->tx_skb->data;
+       stats->tx_bytes += cf->can_dlc;
        stats->tx_packets++;
+
+       can_put_echo_skb(priv->tx_skb, dev, 0);
        can_get_echo_skb(dev, 0);
+       priv->tx_skb = NULL;
+
        netif_wake_queue(dev);
 }
 
@@ -804,6 +825,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv)
        priv->can.do_set_bittiming = cc770_set_bittiming;
        priv->can.do_set_mode = cc770_set_mode;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+       priv->tx_skb = NULL;
 
        memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags));
 
index a1739db..95752e1 100644 (file)
@@ -193,6 +193,8 @@ struct cc770_priv {
        u8 cpu_interface;       /* CPU interface register */
        u8 clkout;              /* Clock out register */
        u8 bus_config;          /* Bus conffiguration register */
+
+       struct sk_buff *tx_skb;
 };
 
 struct net_device *alloc_cc770dev(int sizeof_priv);
index 2772d05..fedd927 100644 (file)
@@ -30,6 +30,7 @@
 #define IFI_CANFD_STCMD_ERROR_ACTIVE           BIT(2)
 #define IFI_CANFD_STCMD_ERROR_PASSIVE          BIT(3)
 #define IFI_CANFD_STCMD_BUSOFF                 BIT(4)
+#define IFI_CANFD_STCMD_ERROR_WARNING          BIT(5)
 #define IFI_CANFD_STCMD_BUSMONITOR             BIT(16)
 #define IFI_CANFD_STCMD_LOOPBACK               BIT(18)
 #define IFI_CANFD_STCMD_DISABLE_CANFD          BIT(24)
 #define IFI_CANFD_TXSTCMD_OVERFLOW             BIT(13)
 
 #define IFI_CANFD_INTERRUPT                    0xc
+#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF       BIT(0)
 #define IFI_CANFD_INTERRUPT_ERROR_WARNING      BIT(1)
+#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG    BIT(2)
+#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC  BIT(3)
 #define IFI_CANFD_INTERRUPT_ERROR_COUNTER      BIT(10)
 #define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY       BIT(16)
 #define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE      BIT(22)
 #define IFI_CANFD_INTERRUPT_SET_IRQ            ((u32)BIT(31))
 
 #define IFI_CANFD_IRQMASK                      0x10
+#define IFI_CANFD_IRQMASK_ERROR_BUSOFF         BIT(0)
+#define IFI_CANFD_IRQMASK_ERROR_WARNING                BIT(1)
+#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG      BIT(2)
+#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC    BIT(3)
 #define IFI_CANFD_IRQMASK_SET_ERR              BIT(7)
 #define IFI_CANFD_IRQMASK_SET_TS               BIT(15)
 #define IFI_CANFD_IRQMASK_TXFIFO_EMPTY         BIT(16)
 #define IFI_CANFD_SYSCLOCK                     0x50
 
 #define IFI_CANFD_VER                          0x54
+#define IFI_CANFD_VER_REV_MASK                 0xff
+#define IFI_CANFD_VER_REV_MIN_SUPPORTED                0x15
 
 #define IFI_CANFD_IP_ID                                0x58
 #define IFI_CANFD_IP_ID_VALUE                  0xD073CAFD
@@ -220,7 +230,10 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable)
 
        if (enable) {
                enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY |
-                       IFI_CANFD_IRQMASK_RXFIFO_NEMPTY;
+                       IFI_CANFD_IRQMASK_RXFIFO_NEMPTY |
+                       IFI_CANFD_IRQMASK_ERROR_STATE_CHG |
+                       IFI_CANFD_IRQMASK_ERROR_WARNING |
+                       IFI_CANFD_IRQMASK_ERROR_BUSOFF;
                if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
                        enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER;
        }
@@ -361,12 +374,13 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev)
        return 1;
 }
 
-static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr)
+static int ifi_canfd_handle_lec_err(struct net_device *ndev)
 {
        struct ifi_canfd_priv *priv = netdev_priv(ndev);
        struct net_device_stats *stats = &ndev->stats;
        struct can_frame *cf;
        struct sk_buff *skb;
+       u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
        const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST |
                            IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST |
                            IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST |
@@ -449,6 +463,11 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
 
        switch (new_state) {
        case CAN_STATE_ERROR_ACTIVE:
+               /* error active state */
+               priv->can.can_stats.error_warning++;
+               priv->can.state = CAN_STATE_ERROR_ACTIVE;
+               break;
+       case CAN_STATE_ERROR_WARNING:
                /* error warning state */
                priv->can.can_stats.error_warning++;
                priv->can.state = CAN_STATE_ERROR_WARNING;
@@ -477,7 +496,7 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
        ifi_canfd_get_berr_counter(ndev, &bec);
 
        switch (new_state) {
-       case CAN_STATE_ERROR_ACTIVE:
+       case CAN_STATE_ERROR_WARNING:
                /* error warning state */
                cf->can_id |= CAN_ERR_CRTL;
                cf->data[1] = (bec.txerr > bec.rxerr) ?
@@ -510,22 +529,21 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev,
        return 1;
 }
 
-static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd)
+static int ifi_canfd_handle_state_errors(struct net_device *ndev)
 {
        struct ifi_canfd_priv *priv = netdev_priv(ndev);
+       u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
        int work_done = 0;
-       u32 isr;
 
-       /*
-        * The ErrWarn condition is a little special, since the bit is
-        * located in the INTERRUPT register instead of STCMD register.
-        */
-       isr = readl(priv->base + IFI_CANFD_INTERRUPT);
-       if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) &&
+       if ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) &&
+           (priv->can.state != CAN_STATE_ERROR_ACTIVE)) {
+               netdev_dbg(ndev, "Error, entered active state\n");
+               work_done += ifi_canfd_handle_state_change(ndev,
+                                               CAN_STATE_ERROR_ACTIVE);
+       }
+
+       if ((stcmd & IFI_CANFD_STCMD_ERROR_WARNING) &&
            (priv->can.state != CAN_STATE_ERROR_WARNING)) {
-               /* Clear the interrupt */
-               writel(IFI_CANFD_INTERRUPT_ERROR_WARNING,
-                      priv->base + IFI_CANFD_INTERRUPT);
                netdev_dbg(ndev, "Error, entered warning state\n");
                work_done += ifi_canfd_handle_state_change(ndev,
                                                CAN_STATE_ERROR_WARNING);
@@ -552,18 +570,11 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
 {
        struct net_device *ndev = napi->dev;
        struct ifi_canfd_priv *priv = netdev_priv(ndev);
-       const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE |
-                                    IFI_CANFD_STCMD_BUSOFF;
-       int work_done = 0;
-
-       u32 stcmd = readl(priv->base + IFI_CANFD_STCMD);
        u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD);
-       u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR);
+       int work_done = 0;
 
        /* Handle bus state changes */
-       if ((stcmd & stcmd_state_mask) ||
-           ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0))
-               work_done += ifi_canfd_handle_state_errors(ndev, stcmd);
+       work_done += ifi_canfd_handle_state_errors(ndev);
 
        /* Handle lost messages on RX */
        if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW)
@@ -571,7 +582,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota)
 
        /* Handle lec errors on the bus */
        if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
-               work_done += ifi_canfd_handle_lec_err(ndev, errctr);
+               work_done += ifi_canfd_handle_lec_err(ndev);
 
        /* Handle normal messages on RX */
        if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY))
@@ -592,12 +603,13 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id)
        struct net_device_stats *stats = &ndev->stats;
        const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY |
                                IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER |
+                               IFI_CANFD_INTERRUPT_ERROR_COUNTER |
+                               IFI_CANFD_INTERRUPT_ERROR_STATE_CHG |
                                IFI_CANFD_INTERRUPT_ERROR_WARNING |
-                               IFI_CANFD_INTERRUPT_ERROR_COUNTER;
+                               IFI_CANFD_INTERRUPT_ERROR_BUSOFF;
        const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY |
                                IFI_CANFD_INTERRUPT_TXFIFO_REMOVE;
-       const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ |
-                                        IFI_CANFD_INTERRUPT_ERROR_WARNING));
+       const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ);
        u32 isr;
 
        isr = readl(priv->base + IFI_CANFD_INTERRUPT);
@@ -933,7 +945,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
        struct resource *res;
        void __iomem *addr;
        int irq, ret;
-       u32 id;
+       u32 id, rev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        addr = devm_ioremap_resource(dev, res);
@@ -947,6 +959,13 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
+       rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK;
+       if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) {
+               dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n",
+                       rev, IFI_CANFD_VER_REV_MIN_SUPPORTED);
+               return -EINVAL;
+       }
+
        ndev = alloc_candev(sizeof(*priv), 1);
        if (!ndev)
                return -ENOMEM;
index 2594f77..b397a33 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/iopoll.h>
 #include <linux/can/dev.h>
+#include <linux/pinctrl/consumer.h>
 
 /* napi related */
 #define M_CAN_NAPI_WEIGHT      64
@@ -253,7 +254,7 @@ enum m_can_mram_cfg {
 
 /* Rx FIFO 0/1 Configuration (RXF0C/RXF1C) */
 #define RXFC_FWM_SHIFT 24
-#define RXFC_FWM_MASK  (0x7f < RXFC_FWM_SHIFT)
+#define RXFC_FWM_MASK  (0x7f << RXFC_FWM_SHIFT)
 #define RXFC_FS_SHIFT  16
 #define RXFC_FS_MASK   (0x7f << RXFC_FS_SHIFT)
 
@@ -1700,6 +1701,8 @@ static __maybe_unused int m_can_suspend(struct device *dev)
                m_can_clk_stop(priv);
        }
 
+       pinctrl_pm_select_sleep_state(dev);
+
        priv->can.state = CAN_STATE_SLEEPING;
 
        return 0;
@@ -1710,6 +1713,8 @@ static __maybe_unused int m_can_resume(struct device *dev)
        struct net_device *ndev = dev_get_drvdata(dev);
        struct m_can_priv *priv = netdev_priv(ndev);
 
+       pinctrl_pm_select_default_state(dev);
+
        m_can_init_ram(priv);
 
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
index 5551341..ed8561d 100644 (file)
@@ -262,7 +262,6 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
 
                spin_lock_irqsave(&priv->echo_lock, flags);
                can_get_echo_skb(priv->ndev, msg->client);
-               spin_unlock_irqrestore(&priv->echo_lock, flags);
 
                /* count bytes of the echo instead of skb */
                stats->tx_bytes += cf_len;
@@ -271,6 +270,7 @@ static int pucan_handle_can_rx(struct peak_canfd_priv *priv,
                /* restart tx queue (a slot is free) */
                netif_wake_queue(priv->ndev);
 
+               spin_unlock_irqrestore(&priv->echo_lock, flags);
                return 0;
        }
 
@@ -333,7 +333,6 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
 
        /* this STATUS is the CNF of the RX_BARRIER: Tx path can be setup */
        if (pucan_status_is_rx_barrier(msg)) {
-               unsigned long flags;
 
                if (priv->enable_tx_path) {
                        int err = priv->enable_tx_path(priv);
@@ -342,16 +341,8 @@ static int pucan_handle_status(struct peak_canfd_priv *priv,
                                return err;
                }
 
-               /* restart network queue only if echo skb array is free */
-               spin_lock_irqsave(&priv->echo_lock, flags);
-
-               if (!priv->can.echo_skb[priv->echo_idx]) {
-                       spin_unlock_irqrestore(&priv->echo_lock, flags);
-
-                       netif_wake_queue(ndev);
-               } else {
-                       spin_unlock_irqrestore(&priv->echo_lock, flags);
-               }
+               /* start network queue (echo_skb array is empty) */
+               netif_start_queue(ndev);
 
                return 0;
        }
@@ -726,11 +717,6 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
         */
        should_stop_tx_queue = !!(priv->can.echo_skb[priv->echo_idx]);
 
-       spin_unlock_irqrestore(&priv->echo_lock, flags);
-
-       /* write the skb on the interface */
-       priv->write_tx_msg(priv, msg);
-
        /* stop network tx queue if not enough room to save one more msg too */
        if (priv->can.ctrlmode & CAN_CTRLMODE_FD)
                should_stop_tx_queue |= (room_left <
@@ -742,6 +728,11 @@ static netdev_tx_t peak_canfd_start_xmit(struct sk_buff *skb,
        if (should_stop_tx_queue)
                netif_stop_queue(ndev);
 
+       spin_unlock_irqrestore(&priv->echo_lock, flags);
+
+       /* write the skb on the interface */
+       priv->write_tx_msg(priv, msg);
+
        return NETDEV_TX_OK;
 }
 
index 788c346..3c51a88 100644 (file)
@@ -349,8 +349,12 @@ static irqreturn_t pciefd_irq_handler(int irq, void *arg)
                priv->tx_pages_free++;
                spin_unlock_irqrestore(&priv->tx_lock, flags);
 
-               /* wake producer up */
-               netif_wake_queue(priv->ucan.ndev);
+               /* wake producer up (only if enough room in echo_skb array) */
+               spin_lock_irqsave(&priv->ucan.echo_lock, flags);
+               if (!priv->ucan.can.echo_skb[priv->ucan.echo_idx])
+                       netif_wake_queue(priv->ucan.ndev);
+
+               spin_unlock_irqrestore(&priv->ucan.echo_lock, flags);
        }
 
        /* re-enable Rx DMA transfer for this CAN */
index d040aeb..15c2a83 100644 (file)
@@ -1,7 +1,10 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_NET_DSA_BCM_SF2)  += bcm-sf2.o
 bcm-sf2-objs                   := bcm_sf2.o bcm_sf2_cfp.o
-obj-$(CONFIG_NET_DSA_LOOP)     += dsa_loop.o dsa_loop_bdinfo.o
+obj-$(CONFIG_NET_DSA_LOOP)     += dsa_loop.o
+ifdef CONFIG_NET_DSA_LOOP
+obj-$(CONFIG_FIXED_PHY)                += dsa_loop_bdinfo.o
+endif
 obj-$(CONFIG_NET_DSA_MT7530)   += mt7530.o
 obj-$(CONFIG_NET_DSA_MV88E6060) += mv88e6060.o
 obj-$(CONFIG_NET_DSA_QCA8K)    += qca8k.o
index db830a1..63e02a5 100644 (file)
@@ -814,8 +814,8 @@ void b53_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
        unsigned int i;
 
        for (i = 0; i < mib_size; i++)
-               memcpy(data + i * ETH_GSTRING_LEN,
-                      mibs[i].name, ETH_GSTRING_LEN);
+               strlcpy(data + i * ETH_GSTRING_LEN,
+                       mibs[i].name, ETH_GSTRING_LEN);
 }
 EXPORT_SYMBOL(b53_get_strings);
 
index 8a0bb00..4e53c5c 100644 (file)
@@ -1409,6 +1409,7 @@ static const struct of_device_id mt7530_of_match[] = {
        { .compatible = "mediatek,mt7530" },
        { /* sentinel */ },
 };
+MODULE_DEVICE_TABLE(of, mt7530_of_match);
 
 static struct mdio_driver mt7530_mdio_driver = {
        .probe  = mt7530_probe,
@@ -1424,4 +1425,3 @@ mdio_module_driver(mt7530_mdio_driver);
 MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
 MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:mediatek-mt7530");
index 29c3075..fdc6734 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 config NET_VENDOR_8390
-       bool "National Semi-conductor 8390 devices"
+       bool "National Semiconductor 8390 devices"
        default y
        depends on NET_VENDOR_NATSEMI
        ---help---
index 3e5833c..eb23f9b 100644 (file)
@@ -426,6 +426,8 @@ static int xgbe_pci_resume(struct pci_dev *pdev)
        struct net_device *netdev = pdata->netdev;
        int ret = 0;
 
+       XP_IOWRITE(pdata, XP_INT_EN, 0x1fffff);
+
        pdata->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
        XMDIO_WRITE(pdata, MDIO_MMD_PCS, MDIO_CTRL1, pdata->lpm_ctrl);
 
index 0b49f1a..fc73831 100644 (file)
@@ -36,6 +36,8 @@
 #define AQ_CFG_TX_FRAME_MAX  (16U * 1024U)
 #define AQ_CFG_RX_FRAME_MAX  (4U * 1024U)
 
+#define AQ_CFG_TX_CLEAN_BUDGET 256U
+
 /* LRO */
 #define AQ_CFG_IS_LRO_DEF           1U
 
index ebbaf63..c96a921 100644 (file)
@@ -247,6 +247,8 @@ void aq_nic_ndev_init(struct aq_nic_s *self)
        self->ndev->hw_features |= aq_hw_caps->hw_features;
        self->ndev->features = aq_hw_caps->hw_features;
        self->ndev->priv_flags = aq_hw_caps->hw_priv_flags;
+       self->ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
+
        self->ndev->mtu = aq_nic_cfg->mtu - ETH_HLEN;
        self->ndev->max_mtu = aq_hw_caps->mtu - ETH_FCS_LEN - ETH_HLEN;
 
@@ -937,3 +939,23 @@ err_exit:
 out:
        return err;
 }
+
+void aq_nic_shutdown(struct aq_nic_s *self)
+{
+       int err = 0;
+
+       if (!self->ndev)
+               return;
+
+       rtnl_lock();
+
+       netif_device_detach(self->ndev);
+
+       err = aq_nic_stop(self);
+       if (err < 0)
+               goto err_exit;
+       aq_nic_deinit(self);
+
+err_exit:
+       rtnl_unlock();
+}
\ No newline at end of file
index d16b0f1..219b550 100644 (file)
@@ -118,5 +118,6 @@ struct aq_nic_cfg_s *aq_nic_get_cfg(struct aq_nic_s *self);
 u32 aq_nic_get_fw_version(struct aq_nic_s *self);
 int aq_nic_change_pm_state(struct aq_nic_s *self, pm_message_t *pm_msg);
 int aq_nic_update_interrupt_moderation_settings(struct aq_nic_s *self);
+void aq_nic_shutdown(struct aq_nic_s *self);
 
 #endif /* AQ_NIC_H */
index 22889fc..ecc6306 100644 (file)
@@ -226,6 +226,10 @@ static int aq_pci_probe(struct pci_dev *pdev,
                goto err_ioremap;
 
        self->aq_hw = kzalloc(sizeof(*self->aq_hw), GFP_KERNEL);
+       if (!self->aq_hw) {
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
        self->aq_hw->aq_nic_cfg = aq_nic_get_cfg(self);
 
        for (bar = 0; bar < 4; ++bar) {
@@ -235,19 +239,19 @@ static int aq_pci_probe(struct pci_dev *pdev,
                        mmio_pa = pci_resource_start(pdev, bar);
                        if (mmio_pa == 0U) {
                                err = -EIO;
-                               goto err_ioremap;
+                               goto err_free_aq_hw;
                        }
 
                        reg_sz = pci_resource_len(pdev, bar);
                        if ((reg_sz <= 24 /*ATL_REGS_SIZE*/)) {
                                err = -EIO;
-                               goto err_ioremap;
+                               goto err_free_aq_hw;
                        }
 
                        self->aq_hw->mmio = ioremap_nocache(mmio_pa, reg_sz);
                        if (!self->aq_hw->mmio) {
                                err = -EIO;
-                               goto err_ioremap;
+                               goto err_free_aq_hw;
                        }
                        break;
                }
@@ -255,7 +259,7 @@ static int aq_pci_probe(struct pci_dev *pdev,
 
        if (bar == 4) {
                err = -EIO;
-               goto err_ioremap;
+               goto err_free_aq_hw;
        }
 
        numvecs = min((u8)AQ_CFG_VECS_DEF,
@@ -290,6 +294,8 @@ err_register:
        aq_pci_free_irq_vectors(self);
 err_hwinit:
        iounmap(self->aq_hw->mmio);
+err_free_aq_hw:
+       kfree(self->aq_hw);
 err_ioremap:
        free_netdev(ndev);
 err_pci_func:
@@ -317,6 +323,20 @@ static void aq_pci_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
+static void aq_pci_shutdown(struct pci_dev *pdev)
+{
+       struct aq_nic_s *self = pci_get_drvdata(pdev);
+
+       aq_nic_shutdown(self);
+
+       pci_disable_device(pdev);
+
+       if (system_state == SYSTEM_POWER_OFF) {
+               pci_wake_from_d3(pdev, false);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
+}
+
 static int aq_pci_suspend(struct pci_dev *pdev, pm_message_t pm_msg)
 {
        struct aq_nic_s *self = pci_get_drvdata(pdev);
@@ -339,6 +359,7 @@ static struct pci_driver aq_pci_ops = {
        .remove = aq_pci_remove,
        .suspend = aq_pci_suspend,
        .resume = aq_pci_resume,
+       .shutdown = aq_pci_shutdown,
 };
 
 module_pci_driver(aq_pci_ops);
index 0be6a11..b5f1f62 100644 (file)
@@ -136,11 +136,12 @@ void aq_ring_queue_stop(struct aq_ring_s *ring)
                netif_stop_subqueue(ndev, ring->idx);
 }
 
-void aq_ring_tx_clean(struct aq_ring_s *self)
+bool aq_ring_tx_clean(struct aq_ring_s *self)
 {
        struct device *dev = aq_nic_get_dev(self->aq_nic);
+       unsigned int budget = AQ_CFG_TX_CLEAN_BUDGET;
 
-       for (; self->sw_head != self->hw_head;
+       for (; self->sw_head != self->hw_head && budget--;
                self->sw_head = aq_ring_next_dx(self, self->sw_head)) {
                struct aq_ring_buff_s *buff = &self->buff_ring[self->sw_head];
 
@@ -167,6 +168,8 @@ void aq_ring_tx_clean(struct aq_ring_s *self)
                buff->pa = 0U;
                buff->eop_index = 0xffffU;
        }
+
+       return !!budget;
 }
 
 #define AQ_SKB_ALIGN SKB_DATA_ALIGN(sizeof(struct skb_shared_info))
index 965fae0..ac1329f 100644 (file)
@@ -153,7 +153,7 @@ void aq_ring_free(struct aq_ring_s *self);
 void aq_ring_update_queue_state(struct aq_ring_s *ring);
 void aq_ring_queue_wake(struct aq_ring_s *ring);
 void aq_ring_queue_stop(struct aq_ring_s *ring);
-void aq_ring_tx_clean(struct aq_ring_s *self);
+bool aq_ring_tx_clean(struct aq_ring_s *self);
 int aq_ring_rx_clean(struct aq_ring_s *self,
                     struct napi_struct *napi,
                     int *work_done,
index f890b8a..d335c33 100644 (file)
@@ -35,12 +35,12 @@ struct aq_vec_s {
 static int aq_vec_poll(struct napi_struct *napi, int budget)
 {
        struct aq_vec_s *self = container_of(napi, struct aq_vec_s, napi);
+       unsigned int sw_tail_old = 0U;
        struct aq_ring_s *ring = NULL;
+       bool was_tx_cleaned = true;
+       unsigned int i = 0U;
        int work_done = 0;
        int err = 0;
-       unsigned int i = 0U;
-       unsigned int sw_tail_old = 0U;
-       bool was_tx_cleaned = false;
 
        if (!self) {
                err = -EINVAL;
@@ -57,9 +57,8 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
 
                        if (ring[AQ_VEC_TX_ID].sw_head !=
                            ring[AQ_VEC_TX_ID].hw_head) {
-                               aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
+                               was_tx_cleaned = aq_ring_tx_clean(&ring[AQ_VEC_TX_ID]);
                                aq_ring_update_queue_state(&ring[AQ_VEC_TX_ID]);
-                               was_tx_cleaned = true;
                        }
 
                        err = self->aq_hw_ops->hw_ring_rx_receive(self->aq_hw,
@@ -90,7 +89,7 @@ static int aq_vec_poll(struct napi_struct *napi, int budget)
                        }
                }
 
-               if (was_tx_cleaned)
+               if (!was_tx_cleaned)
                        work_done = budget;
 
                if (work_done < budget) {
index 967f0fd..d3b847e 100644 (file)
 
 #define HW_ATL_UCP_0X370_REG    0x0370U
 
+#define HW_ATL_MIF_CMD          0x0200U
+#define HW_ATL_MIF_ADDR         0x0208U
+#define HW_ATL_MIF_VAL          0x020CU
+
 #define HW_ATL_FW_SM_RAM        0x2U
 #define HW_ATL_MPI_FW_VERSION  0x18
 #define HW_ATL_MPI_CONTROL_ADR  0x0368U
@@ -79,16 +83,15 @@ int hw_atl_utils_initfw(struct aq_hw_s *self, const struct aq_fw_ops **fw_ops)
 
 static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
 {
+       u32 gsr, val;
        int k = 0;
-       u32 gsr;
 
        aq_hw_write_reg(self, 0x404, 0x40e1);
        AQ_HW_SLEEP(50);
 
        /* Cleanup SPI */
-       aq_hw_write_reg(self, 0x534, 0xA0);
-       aq_hw_write_reg(self, 0x100, 0x9F);
-       aq_hw_write_reg(self, 0x100, 0x809F);
+       val = aq_hw_read_reg(self, 0x53C);
+       aq_hw_write_reg(self, 0x53C, val | 0x10);
 
        gsr = aq_hw_read_reg(self, HW_ATL_GLB_SOFT_RES_ADR);
        aq_hw_write_reg(self, HW_ATL_GLB_SOFT_RES_ADR, (gsr & 0xBFFF) | 0x8000);
@@ -97,7 +100,14 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
        aq_hw_write_reg(self, 0x404, 0x80e0);
        aq_hw_write_reg(self, 0x32a8, 0x0);
        aq_hw_write_reg(self, 0x520, 0x1);
+
+       /* Reset SPI again because of possible interrupted SPI burst */
+       val = aq_hw_read_reg(self, 0x53C);
+       aq_hw_write_reg(self, 0x53C, val | 0x10);
        AQ_HW_SLEEP(10);
+       /* Clear SPI reset state */
+       aq_hw_write_reg(self, 0x53C, val & ~0x10);
+
        aq_hw_write_reg(self, 0x404, 0x180e0);
 
        for (k = 0; k < 1000; k++) {
@@ -141,13 +151,15 @@ static int hw_atl_utils_soft_reset_flb(struct aq_hw_s *self)
                aq_pr_err("FW kickstart failed\n");
                return -EIO;
        }
+       /* Old FW requires fixed delay after init */
+       AQ_HW_SLEEP(15);
 
        return 0;
 }
 
 static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
 {
-       u32 gsr, rbl_status;
+       u32 gsr, val, rbl_status;
        int k;
 
        aq_hw_write_reg(self, 0x404, 0x40e1);
@@ -157,6 +169,10 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
        /* Alter RBL status */
        aq_hw_write_reg(self, 0x388, 0xDEAD);
 
+       /* Cleanup SPI */
+       val = aq_hw_read_reg(self, 0x53C);
+       aq_hw_write_reg(self, 0x53C, val | 0x10);
+
        /* Global software reset*/
        hw_atl_rx_rx_reg_res_dis_set(self, 0U);
        hw_atl_tx_tx_reg_res_dis_set(self, 0U);
@@ -204,6 +220,8 @@ static int hw_atl_utils_soft_reset_rbl(struct aq_hw_s *self)
                aq_pr_err("FW kickstart failed\n");
                return -EIO;
        }
+       /* Old FW requires fixed delay after init */
+       AQ_HW_SLEEP(15);
 
        return 0;
 }
@@ -255,18 +273,22 @@ int hw_atl_utils_fw_downld_dwords(struct aq_hw_s *self, u32 a,
                }
        }
 
-       aq_hw_write_reg(self, 0x00000208U, a);
-
-       for (++cnt; --cnt;) {
-               u32 i = 0U;
+       aq_hw_write_reg(self, HW_ATL_MIF_ADDR, a);
 
-               aq_hw_write_reg(self, 0x00000200U, 0x00008000U);
+       for (++cnt; --cnt && !err;) {
+               aq_hw_write_reg(self, HW_ATL_MIF_CMD, 0x00008000U);
 
-               for (i = 1024U;
-                       (0x100U & aq_hw_read_reg(self, 0x00000200U)) && --i;) {
-               }
+               if (IS_CHIP_FEATURE(REVISION_B1))
+                       AQ_HW_WAIT_FOR(a != aq_hw_read_reg(self,
+                                                          HW_ATL_MIF_ADDR),
+                                      1, 1000U);
+               else
+                       AQ_HW_WAIT_FOR(!(0x100 & aq_hw_read_reg(self,
+                                                          HW_ATL_MIF_CMD)),
+                                      1, 1000U);
 
-               *(p++) = aq_hw_read_reg(self, 0x0000020CU);
+               *(p++) = aq_hw_read_reg(self, HW_ATL_MIF_VAL);
+               a += 4;
        }
 
        hw_atl_reg_glb_cpu_sem_set(self, 1U, HW_ATL_FW_SM_RAM);
@@ -662,14 +684,18 @@ void hw_atl_utils_hw_chip_features_init(struct aq_hw_s *self, u32 *p)
        u32 val = hw_atl_reg_glb_mif_id_get(self);
        u32 mif_rev = val & 0xFFU;
 
-       if ((3U & mif_rev) == 1U) {
-               chip_features |=
-                       HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
+       if ((0xFU & mif_rev) == 1U) {
+               chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_A0 |
                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
                        HAL_ATLANTIC_UTILS_CHIP_MIPS;
-       } else if ((3U & mif_rev) == 2U) {
-               chip_features |=
-                       HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
+       } else if ((0xFU & mif_rev) == 2U) {
+               chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B0 |
+                       HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
+                       HAL_ATLANTIC_UTILS_CHIP_MIPS |
+                       HAL_ATLANTIC_UTILS_CHIP_TPO2 |
+                       HAL_ATLANTIC_UTILS_CHIP_RPF2;
+       } else if ((0xFU & mif_rev) == 0xAU) {
+               chip_features |= HAL_ATLANTIC_UTILS_CHIP_REVISION_B1 |
                        HAL_ATLANTIC_UTILS_CHIP_MPI_AQ |
                        HAL_ATLANTIC_UTILS_CHIP_MIPS |
                        HAL_ATLANTIC_UTILS_CHIP_TPO2 |
index 2c69094..cd8f18f 100644 (file)
@@ -161,6 +161,7 @@ struct __packed hw_aq_atl_utils_mbox {
 #define HAL_ATLANTIC_UTILS_CHIP_MPI_AQ       0x00000010U
 #define HAL_ATLANTIC_UTILS_CHIP_REVISION_A0  0x01000000U
 #define HAL_ATLANTIC_UTILS_CHIP_REVISION_B0  0x02000000U
+#define HAL_ATLANTIC_UTILS_CHIP_REVISION_B1  0x04000000U
 
 #define IS_CHIP_FEATURE(_F_) (HAL_ATLANTIC_UTILS_CHIP_##_F_ & \
        self->chip_features)
index 5265b93..a445de6 100644 (file)
@@ -13,7 +13,7 @@
 #define NIC_MAJOR_DRIVER_VERSION           2
 #define NIC_MINOR_DRIVER_VERSION           0
 #define NIC_BUILD_DRIVER_VERSION           2
-#define NIC_REVISION_DRIVER_VERSION        0
+#define NIC_REVISION_DRIVER_VERSION        1
 
 #define AQ_CFG_DRV_VERSION_SUFFIX "-kern"
 
index 16f9bee..0f65768 100644 (file)
@@ -169,8 +169,10 @@ static int emac_rockchip_probe(struct platform_device *pdev)
        /* Optional regulator for PHY */
        priv->regulator = devm_regulator_get_optional(dev, "phy");
        if (IS_ERR(priv->regulator)) {
-               if (PTR_ERR(priv->regulator) == -EPROBE_DEFER)
-                       return -EPROBE_DEFER;
+               if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) {
+                       err = -EPROBE_DEFER;
+                       goto out_clk_disable;
+               }
                dev_err(dev, "no regulator found\n");
                priv->regulator = NULL;
        }
index f15a8fc..3fc549b 100644 (file)
@@ -855,10 +855,12 @@ static void bcm_sysport_tx_reclaim_one(struct bcm_sysport_tx_ring *ring,
 static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
                                             struct bcm_sysport_tx_ring *ring)
 {
-       unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs;
        unsigned int pkts_compl = 0, bytes_compl = 0;
        struct net_device *ndev = priv->netdev;
+       unsigned int txbds_processed = 0;
        struct bcm_sysport_cb *cb;
+       unsigned int txbds_ready;
+       unsigned int c_index;
        u32 hw_ind;
 
        /* Clear status before servicing to reduce spurious interrupts */
@@ -871,29 +873,23 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv,
        /* Compute how many descriptors have been processed since last call */
        hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index));
        c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK;
-       ring->p_index = (hw_ind & RING_PROD_INDEX_MASK);
-
-       last_c_index = ring->c_index;
-       num_tx_cbs = ring->size;
-
-       c_index &= (num_tx_cbs - 1);
-
-       if (c_index >= last_c_index)
-               last_tx_cn = c_index - last_c_index;
-       else
-               last_tx_cn = num_tx_cbs - last_c_index + c_index;
+       txbds_ready = (c_index - ring->c_index) & RING_CONS_INDEX_MASK;
 
        netif_dbg(priv, tx_done, ndev,
-                 "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n",
-                 ring->index, c_index, last_tx_cn, last_c_index);
+                 "ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n",
+                 ring->index, ring->c_index, c_index, txbds_ready);
 
-       while (last_tx_cn-- > 0) {
-               cb = ring->cbs + last_c_index;
+       while (txbds_processed < txbds_ready) {
+               cb = &ring->cbs[ring->clean_index];
                bcm_sysport_tx_reclaim_one(ring, cb, &bytes_compl, &pkts_compl);
 
                ring->desc_count++;
-               last_c_index++;
-               last_c_index &= (num_tx_cbs - 1);
+               txbds_processed++;
+
+               if (likely(ring->clean_index < ring->size - 1))
+                       ring->clean_index++;
+               else
+                       ring->clean_index = 0;
        }
 
        u64_stats_update_begin(&priv->syncp);
@@ -1394,6 +1390,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv,
        netif_tx_napi_add(priv->netdev, &ring->napi, bcm_sysport_tx_poll, 64);
        ring->index = index;
        ring->size = size;
+       ring->clean_index = 0;
        ring->alloc_size = ring->size;
        ring->desc_cpu = p;
        ring->desc_count = ring->size;
index f5a984c..19c91c7 100644 (file)
@@ -706,7 +706,7 @@ struct bcm_sysport_tx_ring {
        unsigned int    desc_count;     /* Number of descriptors */
        unsigned int    curr_desc;      /* Current descriptor */
        unsigned int    c_index;        /* Last consumer index */
-       unsigned int    p_index;        /* Current producer index */
+       unsigned int    clean_index;    /* Current clean index */
        struct bcm_sysport_cb *cbs;     /* Transmit control blocks */
        struct dma_desc *desc_cpu;      /* CPU view of the descriptor */
        struct bcm_sysport_priv *priv;  /* private context backpointer */
index 74fc9af..b8388e9 100644 (file)
@@ -13913,7 +13913,7 @@ static void bnx2x_register_phc(struct bnx2x *bp)
        bp->ptp_clock = ptp_clock_register(&bp->ptp_clock_info, &bp->pdev->dev);
        if (IS_ERR(bp->ptp_clock)) {
                bp->ptp_clock = NULL;
-               BNX2X_ERR("PTP clock registeration failed\n");
+               BNX2X_ERR("PTP clock registration failed\n");
        }
 }
 
index 1500243..c7e5e6f 100644 (file)
@@ -1439,7 +1439,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp,
            (skb->dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
                u16 vlan_proto = tpa_info->metadata >>
                        RX_CMP_FLAGS2_METADATA_TPID_SFT;
-               u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_VID_MASK;
+               u16 vtag = tpa_info->metadata & RX_CMP_FLAGS2_METADATA_TCI_MASK;
 
                __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vtag);
        }
@@ -1623,7 +1623,7 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
             cpu_to_le32(RX_CMP_FLAGS2_META_FORMAT_VLAN)) &&
            (skb->dev->features & NETIF_F_HW_VLAN_CTAG_RX)) {
                u32 meta_data = le32_to_cpu(rxcmp1->rx_cmp_meta_data);
-               u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_VID_MASK;
+               u16 vtag = meta_data & RX_CMP_FLAGS2_METADATA_TCI_MASK;
                u16 vlan_proto = meta_data >> RX_CMP_FLAGS2_METADATA_TPID_SFT;
 
                __vlan_hwaccel_put_tag(skb, htons(vlan_proto), vtag);
@@ -3847,6 +3847,9 @@ static int bnxt_hwrm_vnic_set_tpa(struct bnxt *bp, u16 vnic_id, u32 tpa_flags)
        struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id];
        struct hwrm_vnic_tpa_cfg_input req = {0};
 
+       if (vnic->fw_vnic_id == INVALID_HW_RING_ID)
+               return 0;
+
        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_TPA_CFG, -1, -1);
 
        if (tpa_flags) {
@@ -4558,18 +4561,17 @@ int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings)
        return rc;
 }
 
-static int
-bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
-                          int ring_grps, int cp_rings, int vnics)
+static void
+__bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, struct hwrm_func_cfg_input *req,
+                            int tx_rings, int rx_rings, int ring_grps,
+                            int cp_rings, int vnics)
 {
-       struct hwrm_func_cfg_input req = {0};
        u32 enables = 0;
-       int rc;
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
-       req.fid = cpu_to_le16(0xffff);
+       bnxt_hwrm_cmd_hdr_init(bp, req, HWRM_FUNC_CFG, -1, -1);
+       req->fid = cpu_to_le16(0xffff);
        enables |= tx_rings ? FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
-       req.num_tx_rings = cpu_to_le16(tx_rings);
+       req->num_tx_rings = cpu_to_le16(tx_rings);
        if (bp->flags & BNXT_FLAG_NEW_RM) {
                enables |= rx_rings ? FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
                enables |= cp_rings ? FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
@@ -4578,16 +4580,53 @@ bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
                           FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
                enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
 
-               req.num_rx_rings = cpu_to_le16(rx_rings);
-               req.num_hw_ring_grps = cpu_to_le16(ring_grps);
-               req.num_cmpl_rings = cpu_to_le16(cp_rings);
-               req.num_stat_ctxs = req.num_cmpl_rings;
-               req.num_vnics = cpu_to_le16(vnics);
+               req->num_rx_rings = cpu_to_le16(rx_rings);
+               req->num_hw_ring_grps = cpu_to_le16(ring_grps);
+               req->num_cmpl_rings = cpu_to_le16(cp_rings);
+               req->num_stat_ctxs = req->num_cmpl_rings;
+               req->num_vnics = cpu_to_le16(vnics);
        }
-       if (!enables)
+       req->enables = cpu_to_le32(enables);
+}
+
+static void
+__bnxt_hwrm_reserve_vf_rings(struct bnxt *bp,
+                            struct hwrm_func_vf_cfg_input *req, int tx_rings,
+                            int rx_rings, int ring_grps, int cp_rings,
+                            int vnics)
+{
+       u32 enables = 0;
+
+       bnxt_hwrm_cmd_hdr_init(bp, req, HWRM_FUNC_VF_CFG, -1, -1);
+       enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
+       enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
+       enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
+                             FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
+       enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
+       enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
+
+       req->num_tx_rings = cpu_to_le16(tx_rings);
+       req->num_rx_rings = cpu_to_le16(rx_rings);
+       req->num_hw_ring_grps = cpu_to_le16(ring_grps);
+       req->num_cmpl_rings = cpu_to_le16(cp_rings);
+       req->num_stat_ctxs = req->num_cmpl_rings;
+       req->num_vnics = cpu_to_le16(vnics);
+
+       req->enables = cpu_to_le32(enables);
+}
+
+static int
+bnxt_hwrm_reserve_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
+                          int ring_grps, int cp_rings, int vnics)
+{
+       struct hwrm_func_cfg_input req = {0};
+       int rc;
+
+       __bnxt_hwrm_reserve_pf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
+                                    cp_rings, vnics);
+       if (!req.enables)
                return 0;
 
-       req.enables = cpu_to_le32(enables);
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                return -ENOMEM;
@@ -4604,7 +4643,6 @@ bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
                           int ring_grps, int cp_rings, int vnics)
 {
        struct hwrm_func_vf_cfg_input req = {0};
-       u32 enables = 0;
        int rc;
 
        if (!(bp->flags & BNXT_FLAG_NEW_RM)) {
@@ -4612,22 +4650,8 @@ bnxt_hwrm_reserve_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
                return 0;
        }
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
-       enables |= tx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS : 0;
-       enables |= rx_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS : 0;
-       enables |= cp_rings ? FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
-                             FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS : 0;
-       enables |= ring_grps ? FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS : 0;
-       enables |= vnics ? FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS : 0;
-
-       req.num_tx_rings = cpu_to_le16(tx_rings);
-       req.num_rx_rings = cpu_to_le16(rx_rings);
-       req.num_hw_ring_grps = cpu_to_le16(ring_grps);
-       req.num_cmpl_rings = cpu_to_le16(cp_rings);
-       req.num_stat_ctxs = req.num_cmpl_rings;
-       req.num_vnics = cpu_to_le16(vnics);
-
-       req.enables = cpu_to_le32(enables);
+       __bnxt_hwrm_reserve_vf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
+                                    cp_rings, vnics);
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                return -ENOMEM;
@@ -4743,39 +4767,25 @@ static bool bnxt_need_reserve_rings(struct bnxt *bp)
 }
 
 static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
-                                   int ring_grps, int cp_rings)
+                                   int ring_grps, int cp_rings, int vnics)
 {
        struct hwrm_func_vf_cfg_input req = {0};
-       u32 flags, enables;
+       u32 flags;
        int rc;
 
        if (!(bp->flags & BNXT_FLAG_NEW_RM))
                return 0;
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1);
+       __bnxt_hwrm_reserve_vf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
+                                    cp_rings, vnics);
        flags = FUNC_VF_CFG_REQ_FLAGS_TX_ASSETS_TEST |
                FUNC_VF_CFG_REQ_FLAGS_RX_ASSETS_TEST |
                FUNC_VF_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
                FUNC_VF_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
                FUNC_VF_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
                FUNC_VF_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
-       enables = FUNC_VF_CFG_REQ_ENABLES_NUM_TX_RINGS |
-                 FUNC_VF_CFG_REQ_ENABLES_NUM_RX_RINGS |
-                 FUNC_VF_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
-                 FUNC_VF_CFG_REQ_ENABLES_NUM_HW_RING_GRPS |
-                 FUNC_VF_CFG_REQ_ENABLES_NUM_STAT_CTXS |
-                 FUNC_VF_CFG_REQ_ENABLES_NUM_VNICS;
 
        req.flags = cpu_to_le32(flags);
-       req.enables = cpu_to_le32(enables);
-       req.num_tx_rings = cpu_to_le16(tx_rings);
-       req.num_rx_rings = cpu_to_le16(rx_rings);
-       req.num_cmpl_rings = cpu_to_le16(cp_rings);
-       req.num_hw_ring_grps = cpu_to_le16(ring_grps);
-       req.num_stat_ctxs = cpu_to_le16(cp_rings);
-       req.num_vnics = cpu_to_le16(1);
-       if (bp->flags & BNXT_FLAG_RFS)
-               req.num_vnics = cpu_to_le16(rx_rings + 1);
        rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                return -ENOMEM;
@@ -4783,38 +4793,23 @@ static int bnxt_hwrm_check_vf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
 }
 
 static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
-                                   int ring_grps, int cp_rings)
+                                   int ring_grps, int cp_rings, int vnics)
 {
        struct hwrm_func_cfg_input req = {0};
-       u32 flags, enables;
+       u32 flags;
        int rc;
 
-       bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_CFG, -1, -1);
-       req.fid = cpu_to_le16(0xffff);
+       __bnxt_hwrm_reserve_pf_rings(bp, &req, tx_rings, rx_rings, ring_grps,
+                                    cp_rings, vnics);
        flags = FUNC_CFG_REQ_FLAGS_TX_ASSETS_TEST;
-       enables = FUNC_CFG_REQ_ENABLES_NUM_TX_RINGS;
-       req.num_tx_rings = cpu_to_le16(tx_rings);
-       if (bp->flags & BNXT_FLAG_NEW_RM) {
+       if (bp->flags & BNXT_FLAG_NEW_RM)
                flags |= FUNC_CFG_REQ_FLAGS_RX_ASSETS_TEST |
                         FUNC_CFG_REQ_FLAGS_CMPL_ASSETS_TEST |
                         FUNC_CFG_REQ_FLAGS_RING_GRP_ASSETS_TEST |
                         FUNC_CFG_REQ_FLAGS_STAT_CTX_ASSETS_TEST |
                         FUNC_CFG_REQ_FLAGS_VNIC_ASSETS_TEST;
-               enables |= FUNC_CFG_REQ_ENABLES_NUM_RX_RINGS |
-                          FUNC_CFG_REQ_ENABLES_NUM_CMPL_RINGS |
-                          FUNC_CFG_REQ_ENABLES_NUM_HW_RING_GRPS |
-                          FUNC_CFG_REQ_ENABLES_NUM_STAT_CTXS |
-                          FUNC_CFG_REQ_ENABLES_NUM_VNICS;
-               req.num_rx_rings = cpu_to_le16(rx_rings);
-               req.num_cmpl_rings = cpu_to_le16(cp_rings);
-               req.num_hw_ring_grps = cpu_to_le16(ring_grps);
-               req.num_stat_ctxs = cpu_to_le16(cp_rings);
-               req.num_vnics = cpu_to_le16(1);
-               if (bp->flags & BNXT_FLAG_RFS)
-                       req.num_vnics = cpu_to_le16(rx_rings + 1);
-       }
+
        req.flags = cpu_to_le32(flags);
-       req.enables = cpu_to_le32(enables);
        rc = hwrm_send_message_silent(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                return -ENOMEM;
@@ -4822,17 +4817,17 @@ static int bnxt_hwrm_check_pf_rings(struct bnxt *bp, int tx_rings, int rx_rings,
 }
 
 static int bnxt_hwrm_check_rings(struct bnxt *bp, int tx_rings, int rx_rings,
-                                int ring_grps, int cp_rings)
+                                int ring_grps, int cp_rings, int vnics)
 {
        if (bp->hwrm_spec_code < 0x10801)
                return 0;
 
        if (BNXT_PF(bp))
                return bnxt_hwrm_check_pf_rings(bp, tx_rings, rx_rings,
-                                               ring_grps, cp_rings);
+                                               ring_grps, cp_rings, vnics);
 
        return bnxt_hwrm_check_vf_rings(bp, tx_rings, rx_rings, ring_grps,
-                                       cp_rings);
+                                       cp_rings, vnics);
 }
 
 static void bnxt_hwrm_set_coal_params(struct bnxt_coal *hw_coal,
@@ -5865,7 +5860,6 @@ static int bnxt_init_msix(struct bnxt *bp)
                if (rc)
                        goto msix_setup_exit;
 
-               bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
                bp->cp_nr_rings = (min == 1) ?
                                  max_t(int, bp->tx_nr_rings, bp->rx_nr_rings) :
                                  bp->tx_nr_rings + bp->rx_nr_rings;
@@ -5897,7 +5891,6 @@ static int bnxt_init_inta(struct bnxt *bp)
        bp->rx_nr_rings = 1;
        bp->tx_nr_rings = 1;
        bp->cp_nr_rings = 1;
-       bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
        bp->flags |= BNXT_FLAG_SHARED_RINGS;
        bp->irq_tbl[0].vector = bp->pdev->irq;
        return 0;
@@ -7531,7 +7524,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
        int max_rx, max_tx, tx_sets = 1;
        int tx_rings_needed;
        int rx_rings = rx;
-       int cp, rc;
+       int cp, vnics, rc;
 
        if (tcs)
                tx_sets = tcs;
@@ -7547,10 +7540,15 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs,
        if (max_tx < tx_rings_needed)
                return -ENOMEM;
 
+       vnics = 1;
+       if (bp->flags & BNXT_FLAG_RFS)
+               vnics += rx_rings;
+
        if (bp->flags & BNXT_FLAG_AGG_RINGS)
                rx_rings <<= 1;
        cp = sh ? max_t(int, tx_rings_needed, rx) : tx_rings_needed + rx;
-       return bnxt_hwrm_check_rings(bp, tx_rings_needed, rx_rings, rx, cp);
+       return bnxt_hwrm_check_rings(bp, tx_rings_needed, rx_rings, rx, cp,
+                                    vnics);
 }
 
 static void bnxt_unmap_bars(struct bnxt *bp, struct pci_dev *pdev)
@@ -8437,13 +8435,20 @@ int bnxt_restore_pf_fw_resources(struct bnxt *bp)
                return 0;
 
        bnxt_hwrm_func_qcaps(bp);
-       __bnxt_close_nic(bp, true, false);
+
+       if (netif_running(bp->dev))
+               __bnxt_close_nic(bp, true, false);
+
        bnxt_clear_int_mode(bp);
        rc = bnxt_init_int_mode(bp);
-       if (rc)
-               dev_close(bp->dev);
-       else
-               rc = bnxt_open_nic(bp, true, false);
+
+       if (netif_running(bp->dev)) {
+               if (rc)
+                       dev_close(bp->dev);
+               else
+                       rc = bnxt_open_nic(bp, true, false);
+       }
+
        return rc;
 }
 
@@ -8664,6 +8669,11 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (rc)
                goto init_err_pci_clean;
 
+       /* No TC has been set yet and rings may have been trimmed due to
+        * limited MSIX, so we re-initialize the TX rings per TC.
+        */
+       bp->tx_nr_rings_per_tc = bp->tx_nr_rings;
+
        bnxt_get_wol_settings(bp);
        if (bp->flags & BNXT_FLAG_WOL_CAP)
                device_set_wakeup_enable(&pdev->dev, bp->wol);
index 1989c47..5e3d621 100644 (file)
@@ -189,6 +189,7 @@ struct rx_cmp_ext {
        #define RX_CMP_FLAGS2_T_L4_CS_CALC                      (0x1 << 3)
        #define RX_CMP_FLAGS2_META_FORMAT_VLAN                  (0x1 << 4)
        __le32 rx_cmp_meta_data;
+       #define RX_CMP_FLAGS2_METADATA_TCI_MASK                 0xffff
        #define RX_CMP_FLAGS2_METADATA_VID_MASK                 0xfff
        #define RX_CMP_FLAGS2_METADATA_TPID_MASK                0xffff0000
         #define RX_CMP_FLAGS2_METADATA_TPID_SFT                 16
index fbe6e20..65c2cee 100644 (file)
@@ -349,6 +349,9 @@ static int bnxt_hwrm_cfa_flow_free(struct bnxt *bp, __le16 flow_handle)
        if (rc)
                netdev_info(bp->dev, "Error: %s: flow_handle=0x%x rc=%d",
                            __func__, flow_handle, rc);
+
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -484,13 +487,15 @@ static int bnxt_hwrm_cfa_flow_alloc(struct bnxt *bp, struct bnxt_tc_flow *flow,
        req.action_flags = cpu_to_le16(action_flags);
 
        mutex_lock(&bp->hwrm_cmd_lock);
-
        rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (!rc)
                *flow_handle = resp->flow_handle;
-
        mutex_unlock(&bp->hwrm_cmd_lock);
 
+       if (rc == HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR)
+               rc = -ENOSPC;
+       else if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -561,6 +566,8 @@ static int hwrm_cfa_decap_filter_alloc(struct bnxt *bp,
                netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
        mutex_unlock(&bp->hwrm_cmd_lock);
 
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -576,6 +583,9 @@ static int hwrm_cfa_decap_filter_free(struct bnxt *bp,
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -624,6 +634,8 @@ static int hwrm_cfa_encap_record_alloc(struct bnxt *bp,
                netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
        mutex_unlock(&bp->hwrm_cmd_lock);
 
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -639,6 +651,9 @@ static int hwrm_cfa_encap_record_free(struct bnxt *bp,
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                netdev_info(bp->dev, "%s: Error rc=%d", __func__, rc);
+
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
@@ -1269,11 +1284,8 @@ static int bnxt_tc_del_flow(struct bnxt *bp,
        flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
                                           &tc_flow_cmd->cookie,
                                           tc_info->flow_ht_params);
-       if (!flow_node) {
-               netdev_info(bp->dev, "ERROR: no flow_node for cookie %lx",
-                           tc_flow_cmd->cookie);
+       if (!flow_node)
                return -EINVAL;
-       }
 
        return __bnxt_tc_del_flow(bp, flow_node);
 }
@@ -1290,11 +1302,8 @@ static int bnxt_tc_get_flow_stats(struct bnxt *bp,
        flow_node = rhashtable_lookup_fast(&tc_info->flow_table,
                                           &tc_flow_cmd->cookie,
                                           tc_info->flow_ht_params);
-       if (!flow_node) {
-               netdev_info(bp->dev, "Error: no flow_node for cookie %lx",
-                           tc_flow_cmd->cookie);
+       if (!flow_node)
                return -1;
-       }
 
        flow = &flow_node->flow;
        curr_stats = &flow->stats;
@@ -1344,8 +1353,10 @@ bnxt_hwrm_cfa_flow_stats_get(struct bnxt *bp, int num_flows,
        } else {
                netdev_info(bp->dev, "error rc=%d", rc);
        }
-
        mutex_unlock(&bp->hwrm_cmd_lock);
+
+       if (rc)
+               rc = -EIO;
        return rc;
 }
 
index a77ee2f..f259397 100644 (file)
@@ -922,8 +922,8 @@ static int tg3_ape_send_event(struct tg3 *tp, u32 event)
        if (!(apedata & APE_FW_STATUS_READY))
                return -EAGAIN;
 
-       /* Wait for up to 1 millisecond for APE to service previous event. */
-       err = tg3_ape_event_lock(tp, 1000);
+       /* Wait for up to 20 millisecond for APE to service previous event. */
+       err = tg3_ape_event_lock(tp, 20000);
        if (err)
                return err;
 
@@ -946,6 +946,7 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
 
        switch (kind) {
        case RESET_KIND_INIT:
+               tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
                tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
                                APE_HOST_SEG_SIG_MAGIC);
                tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
@@ -962,13 +963,6 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
                event = APE_EVENT_STATUS_STATE_START;
                break;
        case RESET_KIND_SHUTDOWN:
-               /* With the interface we are currently using,
-                * APE does not track driver state.  Wiping
-                * out the HOST SEGMENT SIGNATURE forces
-                * the APE to assume OS absent status.
-                */
-               tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0);
-
                if (device_may_wakeup(&tp->pdev->dev) &&
                    tg3_flag(tp, WOL_ENABLE)) {
                        tg3_ape_write32(tp, TG3_APE_HOST_WOL_SPEED,
@@ -990,6 +984,18 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
        tg3_ape_send_event(tp, event);
 }
 
+static void tg3_send_ape_heartbeat(struct tg3 *tp,
+                                  unsigned long interval)
+{
+       /* Check if hb interval has exceeded */
+       if (!tg3_flag(tp, ENABLE_APE) ||
+           time_before(jiffies, tp->ape_hb_jiffies + interval))
+               return;
+
+       tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_COUNT, tp->ape_hb++);
+       tp->ape_hb_jiffies = jiffies;
+}
+
 static void tg3_disable_ints(struct tg3 *tp)
 {
        int i;
@@ -7262,6 +7268,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget)
                }
        }
 
+       tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
        return work_done;
 
 tx_recovery:
@@ -7344,6 +7351,7 @@ static int tg3_poll(struct napi_struct *napi, int budget)
                }
        }
 
+       tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL << 1);
        return work_done;
 
 tx_recovery:
@@ -10732,7 +10740,7 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy)
        if (tg3_flag(tp, ENABLE_APE))
                /* Write our heartbeat update interval to APE. */
                tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
-                               APE_HOST_HEARTBEAT_INT_DISABLE);
+                               APE_HOST_HEARTBEAT_INT_5SEC);
 
        tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
 
@@ -11077,6 +11085,9 @@ static void tg3_timer(struct timer_list *t)
                tp->asf_counter = tp->asf_multiplier;
        }
 
+       /* Update the APE heartbeat every 5 seconds.*/
+       tg3_send_ape_heartbeat(tp, TG3_APE_HB_INTERVAL);
+
        spin_unlock(&tp->lock);
 
 restart_timer:
@@ -16653,6 +16664,8 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
                                       pci_state_reg);
 
                tg3_ape_lock_init(tp);
+               tp->ape_hb_interval =
+                       msecs_to_jiffies(APE_HOST_HEARTBEAT_INT_5SEC);
        }
 
        /* Set up tp->grc_local_ctrl before calling
index 47f51cc..1d61aa3 100644 (file)
 #define TG3_APE_LOCK_PHY3              5
 #define TG3_APE_LOCK_GPIO              7
 
+#define TG3_APE_HB_INTERVAL             (tp->ape_hb_interval)
 #define TG3_EEPROM_SB_F1R2_MBA_OFF     0x10
 
 
@@ -3423,6 +3424,10 @@ struct tg3 {
        struct device                   *hwmon_dev;
        bool                            link_up;
        bool                            pcierr_recovery;
+
+       u32                             ape_hb;
+       unsigned long                   ape_hb_interval;
+       unsigned long                   ape_hb_jiffies;
 };
 
 /* Accessor macros for chip and asic attributes
index c87c9c6..d59497a 100644 (file)
@@ -75,6 +75,8 @@ EXPORT_SYMBOL(cavium_ptp_get);
 
 void cavium_ptp_put(struct cavium_ptp *ptp)
 {
+       if (!ptp)
+               return;
        pci_dev_put(ptp->pdev);
 }
 EXPORT_SYMBOL(cavium_ptp_put);
index b68cde9..7d9c5ff 100644 (file)
@@ -67,11 +67,6 @@ module_param(cpi_alg, int, S_IRUGO);
 MODULE_PARM_DESC(cpi_alg,
                 "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)");
 
-struct nicvf_xdp_tx {
-       u64 dma_addr;
-       u8  qidx;
-};
-
 static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx)
 {
        if (nic->sqs_mode)
@@ -507,29 +502,14 @@ static int nicvf_init_resources(struct nicvf *nic)
        return 0;
 }
 
-static void nicvf_unmap_page(struct nicvf *nic, struct page *page, u64 dma_addr)
-{
-       /* Check if it's a recycled page, if not unmap the DMA mapping.
-        * Recycled page holds an extra reference.
-        */
-       if (page_ref_count(page) == 1) {
-               dma_addr &= PAGE_MASK;
-               dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
-                                    RCV_FRAG_LEN + XDP_HEADROOM,
-                                    DMA_FROM_DEVICE,
-                                    DMA_ATTR_SKIP_CPU_SYNC);
-       }
-}
-
 static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
                                struct cqe_rx_t *cqe_rx, struct snd_queue *sq,
                                struct rcv_queue *rq, struct sk_buff **skb)
 {
        struct xdp_buff xdp;
        struct page *page;
-       struct nicvf_xdp_tx *xdp_tx = NULL;
        u32 action;
-       u16 len, err, offset = 0;
+       u16 len, offset = 0;
        u64 dma_addr, cpu_addr;
        void *orig_data;
 
@@ -543,7 +523,7 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
        cpu_addr = (u64)phys_to_virt(cpu_addr);
        page = virt_to_page((void *)cpu_addr);
 
-       xdp.data_hard_start = page_address(page) + RCV_BUF_HEADROOM;
+       xdp.data_hard_start = page_address(page);
        xdp.data = (void *)cpu_addr;
        xdp_set_data_meta_invalid(&xdp);
        xdp.data_end = xdp.data + len;
@@ -563,7 +543,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
 
        switch (action) {
        case XDP_PASS:
-               nicvf_unmap_page(nic, page, dma_addr);
+               /* Check if it's a recycled page, if not
+                * unmap the DMA mapping.
+                *
+                * Recycled page holds an extra reference.
+                */
+               if (page_ref_count(page) == 1) {
+                       dma_addr &= PAGE_MASK;
+                       dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
+                                            RCV_FRAG_LEN + XDP_PACKET_HEADROOM,
+                                            DMA_FROM_DEVICE,
+                                            DMA_ATTR_SKIP_CPU_SYNC);
+               }
 
                /* Build SKB and pass on packet to network stack */
                *skb = build_skb(xdp.data,
@@ -576,20 +567,6 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
        case XDP_TX:
                nicvf_xdp_sq_append_pkt(nic, sq, (u64)xdp.data, dma_addr, len);
                return true;
-       case XDP_REDIRECT:
-               /* Save DMA address for use while transmitting */
-               xdp_tx = (struct nicvf_xdp_tx *)page_address(page);
-               xdp_tx->dma_addr = dma_addr;
-               xdp_tx->qidx = nicvf_netdev_qidx(nic, cqe_rx->rq_idx);
-
-               err = xdp_do_redirect(nic->pnicvf->netdev, &xdp, prog);
-               if (!err)
-                       return true;
-
-               /* Free the page on error */
-               nicvf_unmap_page(nic, page, dma_addr);
-               put_page(page);
-               break;
        default:
                bpf_warn_invalid_xdp_action(action);
                /* fall through */
@@ -597,7 +574,18 @@ static inline bool nicvf_xdp_rx(struct nicvf *nic, struct bpf_prog *prog,
                trace_xdp_exception(nic->netdev, prog, action);
                /* fall through */
        case XDP_DROP:
-               nicvf_unmap_page(nic, page, dma_addr);
+               /* Check if it's a recycled page, if not
+                * unmap the DMA mapping.
+                *
+                * Recycled page holds an extra reference.
+                */
+               if (page_ref_count(page) == 1) {
+                       dma_addr &= PAGE_MASK;
+                       dma_unmap_page_attrs(&nic->pdev->dev, dma_addr,
+                                            RCV_FRAG_LEN + XDP_PACKET_HEADROOM,
+                                            DMA_FROM_DEVICE,
+                                            DMA_ATTR_SKIP_CPU_SYNC);
+               }
                put_page(page);
                return true;
        }
@@ -1864,50 +1852,6 @@ static int nicvf_xdp(struct net_device *netdev, struct netdev_bpf *xdp)
        }
 }
 
-static int nicvf_xdp_xmit(struct net_device *netdev, struct xdp_buff *xdp)
-{
-       struct nicvf *nic = netdev_priv(netdev);
-       struct nicvf *snic = nic;
-       struct nicvf_xdp_tx *xdp_tx;
-       struct snd_queue *sq;
-       struct page *page;
-       int err, qidx;
-
-       if (!netif_running(netdev) || !nic->xdp_prog)
-               return -EINVAL;
-
-       page = virt_to_page(xdp->data);
-       xdp_tx = (struct nicvf_xdp_tx *)page_address(page);
-       qidx = xdp_tx->qidx;
-
-       if (xdp_tx->qidx >= nic->xdp_tx_queues)
-               return -EINVAL;
-
-       /* Get secondary Qset's info */
-       if (xdp_tx->qidx >= MAX_SND_QUEUES_PER_QS) {
-               qidx = xdp_tx->qidx / MAX_SND_QUEUES_PER_QS;
-               snic = (struct nicvf *)nic->snicvf[qidx - 1];
-               if (!snic)
-                       return -EINVAL;
-               qidx = xdp_tx->qidx % MAX_SND_QUEUES_PER_QS;
-       }
-
-       sq = &snic->qs->sq[qidx];
-       err = nicvf_xdp_sq_append_pkt(snic, sq, (u64)xdp->data,
-                                     xdp_tx->dma_addr,
-                                     xdp->data_end - xdp->data);
-       if (err)
-               return -ENOMEM;
-
-       nicvf_xdp_sq_doorbell(snic, sq, qidx);
-       return 0;
-}
-
-static void nicvf_xdp_flush(struct net_device *dev)
-{
-       return;
-}
-
 static int nicvf_config_hwtstamp(struct net_device *netdev, struct ifreq *ifr)
 {
        struct hwtstamp_config config;
@@ -1986,8 +1930,6 @@ static const struct net_device_ops nicvf_netdev_ops = {
        .ndo_fix_features       = nicvf_fix_features,
        .ndo_set_features       = nicvf_set_features,
        .ndo_bpf                = nicvf_xdp,
-       .ndo_xdp_xmit           = nicvf_xdp_xmit,
-       .ndo_xdp_flush          = nicvf_xdp_flush,
        .ndo_do_ioctl           = nicvf_ioctl,
 };
 
index 3eae9ff..d42704d 100644 (file)
@@ -204,7 +204,7 @@ static inline int nicvf_alloc_rcv_buffer(struct nicvf *nic, struct rbdr *rbdr,
 
        /* Reserve space for header modifications by BPF program */
        if (rbdr->is_xdp)
-               buf_len += XDP_HEADROOM;
+               buf_len += XDP_PACKET_HEADROOM;
 
        /* Check if it's recycled */
        if (pgcache)
@@ -224,9 +224,8 @@ ret:
                        nic->rb_page = NULL;
                        return -ENOMEM;
                }
-
                if (pgcache)
-                       pgcache->dma_addr = *rbuf + XDP_HEADROOM;
+                       pgcache->dma_addr = *rbuf + XDP_PACKET_HEADROOM;
                nic->rb_page_offset += buf_len;
        }
 
@@ -1244,7 +1243,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq,
        int qentry;
 
        if (subdesc_cnt > sq->xdp_free_cnt)
-               return -1;
+               return 0;
 
        qentry = nicvf_get_sq_desc(sq, subdesc_cnt);
 
@@ -1255,7 +1254,7 @@ int nicvf_xdp_sq_append_pkt(struct nicvf *nic, struct snd_queue *sq,
 
        sq->xdp_desc_cnt += subdesc_cnt;
 
-       return 0;
+       return 1;
 }
 
 /* Calculate no of SQ subdescriptors needed to transmit all
@@ -1656,7 +1655,7 @@ static void nicvf_unmap_rcv_buffer(struct nicvf *nic, u64 dma_addr,
                if (page_ref_count(page) != 1)
                        return;
 
-               len += XDP_HEADROOM;
+               len += XDP_PACKET_HEADROOM;
                /* Receive buffers in XDP mode are mapped from page start */
                dma_addr &= PAGE_MASK;
        }
index ce1eed7..5e9a03c 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/netdevice.h>
 #include <linux/iommu.h>
-#include <linux/bpf.h>
 #include <net/xdp.h>
 #include "q_struct.h"
 
@@ -94,9 +93,6 @@
 #define RCV_FRAG_LEN    (SKB_DATA_ALIGN(DMA_BUFFER_LEN + NET_SKB_PAD) + \
                         SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
-#define RCV_BUF_HEADROOM       128 /* To store dma address for XDP redirect */
-#define XDP_HEADROOM           (XDP_PACKET_HEADROOM + RCV_BUF_HEADROOM)
-
 #define MAX_CQES_FOR_TX                ((SND_QUEUE_LEN / MIN_SQ_DESC_PER_PKT_XMIT) * \
                                 MAX_CQE_PER_PKT_XMIT)
 
index 557fd8b..00a1d2d 100644 (file)
@@ -472,7 +472,7 @@ int cudbg_collect_cim_la(struct cudbg_init *pdbg_init,
 
        if (is_t6(padap->params.chip)) {
                size = padap->params.cim_la_size / 10 + 1;
-               size *= 11 * sizeof(u32);
+               size *= 10 * sizeof(u32);
        } else {
                size = padap->params.cim_la_size / 8;
                size *= 8 * sizeof(u32);
index 30485f9..143686c 100644 (file)
@@ -102,7 +102,7 @@ static u32 cxgb4_get_entity_length(struct adapter *adap, u32 entity)
        case CUDBG_CIM_LA:
                if (is_t6(adap->params.chip)) {
                        len = adap->params.cim_la_size / 10 + 1;
-                       len *= 11 * sizeof(u32);
+                       len *= 10 * sizeof(u32);
                } else {
                        len = adap->params.cim_la_size / 8;
                        len *= 8 * sizeof(u32);
index 56bc626..61022b5 100644 (file)
@@ -4970,7 +4970,6 @@ static void cxgb4_mgmt_setup(struct net_device *dev)
        /* Initialize the device structure. */
        dev->netdev_ops = &cxgb4_mgmt_netdev_ops;
        dev->ethtool_ops = &cxgb4_mgmt_ethtool_ops;
-       dev->needs_free_netdev = true;
 }
 
 static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
@@ -4982,9 +4981,10 @@ static int cxgb4_iov_configure(struct pci_dev *pdev, int num_vfs)
 
        pcie_fw = readl(adap->regs + PCIE_FW_A);
        /* Check if cxgb4 is the MASTER and fw is initialized */
-       if (!(pcie_fw & PCIE_FW_INIT_F) ||
+       if (num_vfs &&
+           (!(pcie_fw & PCIE_FW_INIT_F) ||
            !(pcie_fw & PCIE_FW_MASTER_VLD_F) ||
-           PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF) {
+           PCIE_FW_MASTER_G(pcie_fw) != CXGB4_UNIFIED_PF)) {
                dev_warn(&pdev->dev,
                         "cxgb4 driver needs to be MASTER to support SRIOV\n");
                return -EOPNOTSUPP;
@@ -5180,6 +5180,8 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        adapter->name = pci_name(pdev);
        adapter->mbox = func;
        adapter->pf = func;
+       adapter->params.chip = chip;
+       adapter->adap_idx = adap_idx;
        adapter->msg_enable = DFLT_MSG_ENABLE;
        adapter->mbox_log = kzalloc(sizeof(*adapter->mbox_log) +
                                    (sizeof(struct mbox_cmd) *
@@ -5599,24 +5601,24 @@ static void remove_one(struct pci_dev *pdev)
 #if IS_ENABLED(CONFIG_IPV6)
                t4_cleanup_clip_tbl(adapter);
 #endif
-               iounmap(adapter->regs);
                if (!is_t4(adapter->params.chip))
                        iounmap(adapter->bar2);
-               pci_disable_pcie_error_reporting(pdev);
-               if ((adapter->flags & DEV_ENABLED)) {
-                       pci_disable_device(pdev);
-                       adapter->flags &= ~DEV_ENABLED;
-               }
-               pci_release_regions(pdev);
-               kfree(adapter->mbox_log);
-               synchronize_rcu();
-               kfree(adapter);
        }
 #ifdef CONFIG_PCI_IOV
        else {
                cxgb4_iov_configure(adapter->pdev, 0);
        }
 #endif
+       iounmap(adapter->regs);
+       pci_disable_pcie_error_reporting(pdev);
+       if ((adapter->flags & DEV_ENABLED)) {
+               pci_disable_device(pdev);
+               adapter->flags &= ~DEV_ENABLED;
+       }
+       pci_release_regions(pdev);
+       kfree(adapter->mbox_log);
+       synchronize_rcu();
+       kfree(adapter);
 }
 
 /* "Shutdown" quiesces the device, stopping Ingress Packet and Interrupt
index 047609e..920bccd 100644 (file)
@@ -2637,7 +2637,6 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size)
 }
 
 #define EEPROM_STAT_ADDR   0x7bfc
-#define VPD_SIZE           0x800
 #define VPD_BASE           0x400
 #define VPD_BASE_OLD       0
 #define VPD_LEN            1024
@@ -2704,15 +2703,6 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p)
        if (!vpd)
                return -ENOMEM;
 
-       /* We have two VPD data structures stored in the adapter VPD area.
-        * By default, Linux calculates the size of the VPD area by traversing
-        * the first VPD area at offset 0x0, so we need to tell the OS what
-        * our real VPD size is.
-        */
-       ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE);
-       if (ret < 0)
-               goto out;
-
        /* Card information normally starts at VPD_BASE but early cards had
         * it at 0.
         */
index 5eb999a..bd3f6e4 100644 (file)
@@ -540,6 +540,7 @@ static int gmac_setup_txqs(struct net_device *netdev)
 
        if (port->txq_dma_base & ~DMA_Q_BASE_MASK) {
                dev_warn(geth->dev, "TX queue base it not aligned\n");
+               kfree(skb_tab);
                return -ENOMEM;
        }
 
index 7caa8da..e4ec32a 100644 (file)
@@ -2008,7 +2008,6 @@ static inline int dpaa_xmit(struct dpaa_priv *priv,
        }
 
        if (unlikely(err < 0)) {
-               percpu_stats->tx_errors++;
                percpu_stats->tx_fifo_errors++;
                return err;
        }
@@ -2278,7 +2277,6 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
        vaddr = phys_to_virt(addr);
        prefetch(vaddr + qm_fd_get_offset(fd));
 
-       fd_format = qm_fd_get_format(fd);
        /* The only FD types that we may receive are contig and S/G */
        WARN_ON((fd_format != qm_fd_contig) && (fd_format != qm_fd_sg));
 
@@ -2311,8 +2309,10 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal,
 
        skb_len = skb->len;
 
-       if (unlikely(netif_receive_skb(skb) == NET_RX_DROP))
+       if (unlikely(netif_receive_skb(skb) == NET_RX_DROP)) {
+               percpu_stats->rx_dropped++;
                return qman_cb_dqrr_consume;
+       }
 
        percpu_stats->rx_packets++;
        percpu_stats->rx_bytes += skb_len;
@@ -2860,7 +2860,7 @@ static int dpaa_remove(struct platform_device *pdev)
        struct device *dev;
        int err;
 
-       dev = &pdev->dev;
+       dev = pdev->dev.parent;
        net_dev = dev_get_drvdata(dev);
 
        priv = netdev_priv(net_dev);
index 7a7f3a4..d4604bc 100644 (file)
@@ -3600,6 +3600,8 @@ fec_drv_remove(struct platform_device *pdev)
        fec_enet_mii_remove(fep);
        if (fep->reg_phy)
                regulator_disable(fep->reg_phy);
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        if (of_phy_is_fixed_link(np))
                of_phy_deregister_fixed_link(np);
        of_node_put(fep->phy_node);
index ea43b49..7af31dd 100644 (file)
@@ -1100,7 +1100,7 @@ int dtsec_add_hash_mac_address(struct fman_mac *dtsec, enet_addr_t *eth_addr)
        set_bucket(dtsec->regs, bucket, true);
 
        /* Create element to be added to the driver hash table */
-       hash_entry = kmalloc(sizeof(*hash_entry), GFP_KERNEL);
+       hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC);
        if (!hash_entry)
                return -ENOMEM;
        hash_entry->addr = addr;
index 3bdeb29..f27f9ba 100644 (file)
@@ -2934,29 +2934,17 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
 {
        int size = lstatus & BD_LENGTH_MASK;
        struct page *page = rxb->page;
-       bool last = !!(lstatus & BD_LFLAG(RXBD_LAST));
-
-       /* Remove the FCS from the packet length */
-       if (last)
-               size -= ETH_FCS_LEN;
 
        if (likely(first)) {
                skb_put(skb, size);
        } else {
                /* the last fragments' length contains the full frame length */
-               if (last)
+               if (lstatus & BD_LFLAG(RXBD_LAST))
                        size -= skb->len;
 
-               /* Add the last fragment if it contains something other than
-                * the FCS, otherwise drop it and trim off any part of the FCS
-                * that was already received.
-                */
-               if (size > 0)
-                       skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
-                                       rxb->page_offset + RXBUF_ALIGNMENT,
-                                       size, GFAR_RXB_TRUESIZE);
-               else if (size < 0)
-                       pskb_trim(skb, skb->len + size);
+               skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+                               rxb->page_offset + RXBUF_ALIGNMENT,
+                               size, GFAR_RXB_TRUESIZE);
        }
 
        /* try reuse page */
@@ -3069,12 +3057,12 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
        if (priv->padding)
                skb_pull(skb, priv->padding);
 
+       /* Trim off the FCS */
+       pskb_trim(skb, skb->len - ETH_FCS_LEN);
+
        if (ndev->features & NETIF_F_RXCSUM)
                gfar_rx_checksum(skb, fcb);
 
-       /* Tell the skb what kind of packet this is */
-       skb->protocol = eth_type_trans(skb, ndev);
-
        /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here.
         * Even if vlan rx accel is disabled, on some chips
         * RXFCB_VLN is pseudo randomly set.
@@ -3145,13 +3133,15 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit)
                        continue;
                }
 
+               gfar_process_frame(ndev, skb);
+
                /* Increment the number of packets */
                total_pkts++;
                total_bytes += skb->len;
 
                skb_record_rx_queue(skb, rx_queue->qindex);
 
-               gfar_process_frame(ndev, skb);
+               skb->protocol = eth_type_trans(skb, ndev);
 
                /* Send the packet up the stack */
                napi_gro_receive(&rx_queue->grp->napi_rx, skb);
index 86944bc..74bd260 100644 (file)
@@ -666,7 +666,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data)
 
 static int hns_gmac_get_sset_count(int stringset)
 {
-       if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+       if (stringset == ETH_SS_STATS)
                return ARRAY_SIZE(g_gmac_stats_string);
 
        return 0;
index b62816c..93e71e2 100644 (file)
@@ -422,7 +422,7 @@ void hns_ppe_update_stats(struct hns_ppe_cb *ppe_cb)
 
 int hns_ppe_get_sset_count(int stringset)
 {
-       if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+       if (stringset == ETH_SS_STATS)
                return ETH_PPE_STATIC_NUM;
        return 0;
 }
index 6f3570c..e2e2853 100644 (file)
@@ -876,7 +876,7 @@ void hns_rcb_get_stats(struct hnae_queue *queue, u64 *data)
  */
 int hns_rcb_get_ring_sset_count(int stringset)
 {
-       if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS)
+       if (stringset == ETH_SS_STATS)
                return HNS_RING_STATIC_REG_NUM;
 
        return 0;
index 7ea7f8a..2e14a3a 100644 (file)
@@ -993,8 +993,10 @@ int hns_get_sset_count(struct net_device *netdev, int stringset)
                        cnt--;
 
                return cnt;
-       } else {
+       } else if (stringset == ETH_SS_STATS) {
                return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset));
+       } else {
+               return -EOPNOTSUPP;
        }
 }
 
index 2744726..1b3cc8b 100644 (file)
@@ -791,6 +791,18 @@ static int ibmvnic_login(struct net_device *netdev)
        return 0;
 }
 
+static void release_login_buffer(struct ibmvnic_adapter *adapter)
+{
+       kfree(adapter->login_buf);
+       adapter->login_buf = NULL;
+}
+
+static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
+{
+       kfree(adapter->login_rsp_buf);
+       adapter->login_rsp_buf = NULL;
+}
+
 static void release_resources(struct ibmvnic_adapter *adapter)
 {
        int i;
@@ -813,6 +825,10 @@ static void release_resources(struct ibmvnic_adapter *adapter)
                        }
                }
        }
+       kfree(adapter->napi);
+       adapter->napi = NULL;
+
+       release_login_rsp_buffer(adapter);
 }
 
 static int set_link_state(struct ibmvnic_adapter *adapter, u8 link_state)
@@ -1057,6 +1073,35 @@ static int ibmvnic_open(struct net_device *netdev)
        return rc;
 }
 
+static void clean_rx_pools(struct ibmvnic_adapter *adapter)
+{
+       struct ibmvnic_rx_pool *rx_pool;
+       u64 rx_entries;
+       int rx_scrqs;
+       int i, j;
+
+       if (!adapter->rx_pool)
+               return;
+
+       rx_scrqs = be32_to_cpu(adapter->login_rsp_buf->num_rxadd_subcrqs);
+       rx_entries = adapter->req_rx_add_entries_per_subcrq;
+
+       /* Free any remaining skbs in the rx buffer pools */
+       for (i = 0; i < rx_scrqs; i++) {
+               rx_pool = &adapter->rx_pool[i];
+               if (!rx_pool)
+                       continue;
+
+               netdev_dbg(adapter->netdev, "Cleaning rx_pool[%d]\n", i);
+               for (j = 0; j < rx_entries; j++) {
+                       if (rx_pool->rx_buff[j].skb) {
+                               dev_kfree_skb_any(rx_pool->rx_buff[j].skb);
+                               rx_pool->rx_buff[j].skb = NULL;
+                       }
+               }
+       }
+}
+
 static void clean_tx_pools(struct ibmvnic_adapter *adapter)
 {
        struct ibmvnic_tx_pool *tx_pool;
@@ -1134,7 +1179,7 @@ static int __ibmvnic_close(struct net_device *netdev)
                        }
                }
        }
-
+       clean_rx_pools(adapter);
        clean_tx_pools(adapter);
        adapter->state = VNIC_CLOSED;
        return rc;
@@ -1670,8 +1715,6 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                return 0;
        }
 
-       netif_carrier_on(netdev);
-
        /* kick napi */
        for (i = 0; i < adapter->req_rx_queues; i++)
                napi_schedule(&adapter->napi[i]);
@@ -1679,6 +1722,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
        if (adapter->reset_reason != VNIC_RESET_FAILOVER)
                netdev_notify_peers(netdev);
 
+       netif_carrier_on(netdev);
+
        return 0;
 }
 
@@ -1853,6 +1898,12 @@ restart_poll:
                                   be16_to_cpu(next->rx_comp.rc));
                        /* free the entry */
                        next->rx_comp.first = 0;
+                       dev_kfree_skb_any(rx_buff->skb);
+                       remove_buff_from_pool(adapter, rx_buff);
+                       continue;
+               } else if (!rx_buff->skb) {
+                       /* free the entry */
+                       next->rx_comp.first = 0;
                        remove_buff_from_pool(adapter, rx_buff);
                        continue;
                }
@@ -3013,6 +3064,7 @@ static void send_login(struct ibmvnic_adapter *adapter)
        struct vnic_login_client_data *vlcd;
        int i;
 
+       release_login_rsp_buffer(adapter);
        client_data_len = vnic_client_data_len(adapter);
 
        buffer_size =
@@ -3738,6 +3790,7 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
                ibmvnic_remove(adapter->vdev);
                return -EIO;
        }
+       release_login_buffer(adapter);
        complete(&adapter->init_done);
 
        return 0;
index afb7ebe..824fd44 100644 (file)
 #define E1000_ICR_RXDMT0        0x00000010 /* Rx desc min. threshold (0) */
 #define E1000_ICR_RXO           0x00000040 /* Receiver Overrun */
 #define E1000_ICR_RXT0          0x00000080 /* Rx timer intr (ring 0) */
+#define E1000_ICR_MDAC          0x00000200 /* MDIO Access Complete */
+#define E1000_ICR_SRPD          0x00010000 /* Small Receive Packet Detected */
+#define E1000_ICR_ACK           0x00020000 /* Receive ACK Frame Detected */
+#define E1000_ICR_MNG           0x00040000 /* Manageability Event Detected */
 #define E1000_ICR_ECCER         0x00400000 /* Uncorrectable ECC Error */
 /* If this bit asserted, the driver should claim the interrupt */
 #define E1000_ICR_INT_ASSERTED 0x80000000
 #define E1000_ICR_RXQ1          0x00200000 /* Rx Queue 1 Interrupt */
 #define E1000_ICR_TXQ0          0x00400000 /* Tx Queue 0 Interrupt */
 #define E1000_ICR_TXQ1          0x00800000 /* Tx Queue 1 Interrupt */
-#define E1000_ICR_OTHER         0x01000000 /* Other Interrupts */
+#define E1000_ICR_OTHER         0x01000000 /* Other Interrupt */
 
 /* PBA ECC Register */
 #define E1000_PBA_ECC_COUNTER_MASK  0xFFF00000 /* ECC counter mask */
        E1000_IMS_RXSEQ  |    \
        E1000_IMS_LSC)
 
+/* These are all of the events related to the OTHER interrupt.
+ */
+#define IMS_OTHER_MASK ( \
+       E1000_IMS_LSC  | \
+       E1000_IMS_RXO  | \
+       E1000_IMS_MDAC | \
+       E1000_IMS_SRPD | \
+       E1000_IMS_ACK  | \
+       E1000_IMS_MNG)
+
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
 #define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* Rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* Rx desc min. threshold */
+#define E1000_IMS_RXO       E1000_ICR_RXO       /* Receiver Overrun */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* Rx timer intr */
+#define E1000_IMS_MDAC      E1000_ICR_MDAC      /* MDIO Access Complete */
+#define E1000_IMS_SRPD      E1000_ICR_SRPD      /* Small Receive Packet */
+#define E1000_IMS_ACK       E1000_ICR_ACK       /* Receive ACK Frame Detected */
+#define E1000_IMS_MNG       E1000_ICR_MNG       /* Manageability Event */
 #define E1000_IMS_ECCER     E1000_ICR_ECCER     /* Uncorrectable ECC Error */
 #define E1000_IMS_RXQ0      E1000_ICR_RXQ0      /* Rx Queue 0 Interrupt */
 #define E1000_IMS_RXQ1      E1000_ICR_RXQ1      /* Rx Queue 1 Interrupt */
index 31277d3..1dddfb7 100644 (file)
@@ -1367,9 +1367,6 @@ out:
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
- *
- *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
- *  up).
  **/
 static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 {
@@ -1385,7 +1382,8 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         * Change or Rx Sequence Error interrupt.
         */
        if (!mac->get_link_status)
-               return 1;
+               return 0;
+       mac->get_link_status = false;
 
        /* First we want to see if the MII Status Register reports
         * link.  If so, then we want to get the current speed/duplex
@@ -1393,12 +1391,12 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         */
        ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
        if (ret_val)
-               return ret_val;
+               goto out;
 
        if (hw->mac.type == e1000_pchlan) {
                ret_val = e1000_k1_gig_workaround_hv(hw, link);
                if (ret_val)
-                       return ret_val;
+                       goto out;
        }
 
        /* When connected at 10Mbps half-duplex, some parts are excessively
@@ -1431,7 +1429,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 
                ret_val = hw->phy.ops.acquire(hw);
                if (ret_val)
-                       return ret_val;
+                       goto out;
 
                if (hw->mac.type == e1000_pch2lan)
                        emi_addr = I82579_RX_CONFIG;
@@ -1453,7 +1451,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                hw->phy.ops.release(hw);
 
                if (ret_val)
-                       return ret_val;
+                       goto out;
 
                if (hw->mac.type >= e1000_pch_spt) {
                        u16 data;
@@ -1462,14 +1460,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                        if (speed == SPEED_1000) {
                                ret_val = hw->phy.ops.acquire(hw);
                                if (ret_val)
-                                       return ret_val;
+                                       goto out;
 
                                ret_val = e1e_rphy_locked(hw,
                                                          PHY_REG(776, 20),
                                                          &data);
                                if (ret_val) {
                                        hw->phy.ops.release(hw);
-                                       return ret_val;
+                                       goto out;
                                }
 
                                ptr_gap = (data & (0x3FF << 2)) >> 2;
@@ -1483,18 +1481,18 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                                }
                                hw->phy.ops.release(hw);
                                if (ret_val)
-                                       return ret_val;
+                                       goto out;
                        } else {
                                ret_val = hw->phy.ops.acquire(hw);
                                if (ret_val)
-                                       return ret_val;
+                                       goto out;
 
                                ret_val = e1e_wphy_locked(hw,
                                                          PHY_REG(776, 20),
                                                          0xC023);
                                hw->phy.ops.release(hw);
                                if (ret_val)
-                                       return ret_val;
+                                       goto out;
 
                        }
                }
@@ -1521,7 +1519,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
            (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3)) {
                ret_val = e1000_k1_workaround_lpt_lp(hw, link);
                if (ret_val)
-                       return ret_val;
+                       goto out;
        }
        if (hw->mac.type >= e1000_pch_lpt) {
                /* Set platform power management values for
@@ -1529,7 +1527,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
                 */
                ret_val = e1000_platform_pm_pch_lpt(hw, link);
                if (ret_val)
-                       return ret_val;
+                       goto out;
        }
 
        /* Clear link partner's EEE ability */
@@ -1552,9 +1550,7 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
        }
 
        if (!link)
-               return 0;       /* No link detected */
-
-       mac->get_link_status = false;
+               goto out;
 
        switch (hw->mac.type) {
        case e1000_pch2lan:
@@ -1616,12 +1612,14 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
         * different link partner.
         */
        ret_val = e1000e_config_fc_after_link_up(hw);
-       if (ret_val) {
+       if (ret_val)
                e_dbg("Error configuring flow control\n");
-               return ret_val;
-       }
 
-       return 1;
+       return ret_val;
+
+out:
+       mac->get_link_status = true;
+       return ret_val;
 }
 
 static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
index f457c57..5bdc3a2 100644 (file)
@@ -410,9 +410,6 @@ void e1000e_clear_hw_cntrs_base(struct e1000_hw *hw)
  *  Checks to see of the link status of the hardware has changed.  If a
  *  change in link status has been detected, then we read the PHY registers
  *  to get the current speed/duplex if link exists.
- *
- *  Returns a negative error code (-E1000_ERR_*) or 0 (link down) or 1 (link
- *  up).
  **/
 s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
 {
@@ -426,20 +423,16 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
         * Change or Rx Sequence Error interrupt.
         */
        if (!mac->get_link_status)
-               return 1;
+               return 0;
+       mac->get_link_status = false;
 
        /* First we want to see if the MII Status Register reports
         * link.  If so, then we want to get the current speed/duplex
         * of the PHY.
         */
        ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);
-       if (ret_val)
-               return ret_val;
-
-       if (!link)
-               return 0;       /* No link detected */
-
-       mac->get_link_status = false;
+       if (ret_val || !link)
+               goto out;
 
        /* Check if there was DownShift, must be checked
         * immediately after link-up
@@ -464,12 +457,14 @@ s32 e1000e_check_for_copper_link(struct e1000_hw *hw)
         * different link partner.
         */
        ret_val = e1000e_config_fc_after_link_up(hw);
-       if (ret_val) {
+       if (ret_val)
                e_dbg("Error configuring flow control\n");
-               return ret_val;
-       }
 
-       return 1;
+       return ret_val;
+
+out:
+       mac->get_link_status = true;
+       return ret_val;
 }
 
 /**
index 1298b69..dc853b0 100644 (file)
@@ -1914,30 +1914,20 @@ static irqreturn_t e1000_msix_other(int __always_unused irq, void *data)
        struct net_device *netdev = data;
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       u32 icr;
-       bool enable = true;
-
-       icr = er32(ICR);
-       if (icr & E1000_ICR_RXO) {
-               ew32(ICR, E1000_ICR_RXO);
-               enable = false;
-               /* napi poll will re-enable Other, make sure it runs */
-               if (napi_schedule_prep(&adapter->napi)) {
-                       adapter->total_rx_bytes = 0;
-                       adapter->total_rx_packets = 0;
-                       __napi_schedule(&adapter->napi);
-               }
-       }
+       u32 icr = er32(ICR);
+
+       if (icr & adapter->eiac_mask)
+               ew32(ICS, (icr & adapter->eiac_mask));
+
        if (icr & E1000_ICR_LSC) {
-               ew32(ICR, E1000_ICR_LSC);
                hw->mac.get_link_status = true;
                /* guard against interrupt when we're going down */
                if (!test_bit(__E1000_DOWN, &adapter->state))
                        mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
-       if (enable && !test_bit(__E1000_DOWN, &adapter->state))
-               ew32(IMS, E1000_IMS_OTHER);
+       if (!test_bit(__E1000_DOWN, &adapter->state))
+               ew32(IMS, E1000_IMS_OTHER | IMS_OTHER_MASK);
 
        return IRQ_HANDLED;
 }
@@ -2040,7 +2030,6 @@ static void e1000_configure_msix(struct e1000_adapter *adapter)
                       hw->hw_addr + E1000_EITR_82574(vector));
        else
                writel(1, hw->hw_addr + E1000_EITR_82574(vector));
-       adapter->eiac_mask |= E1000_IMS_OTHER;
 
        /* Cause Tx interrupts on every write back */
        ivar |= BIT(31);
@@ -2265,7 +2254,8 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
 
        if (adapter->msix_entries) {
                ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
-               ew32(IMS, adapter->eiac_mask | E1000_IMS_LSC);
+               ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER |
+                    IMS_OTHER_MASK);
        } else if (hw->mac.type >= e1000_pch_lpt) {
                ew32(IMS, IMS_ENABLE_MASK | E1000_IMS_ECCER);
        } else {
@@ -2333,8 +2323,8 @@ static int e1000_alloc_ring_dma(struct e1000_adapter *adapter,
 {
        struct pci_dev *pdev = adapter->pdev;
 
-       ring->desc = dma_alloc_coherent(&pdev->dev, ring->size, &ring->dma,
-                                       GFP_KERNEL);
+       ring->desc = dma_zalloc_coherent(&pdev->dev, ring->size, &ring->dma,
+                                        GFP_KERNEL);
        if (!ring->desc)
                return -ENOMEM;
 
@@ -2707,8 +2697,7 @@ static int e1000e_poll(struct napi_struct *napi, int weight)
                napi_complete_done(napi, work_done);
                if (!test_bit(__E1000_DOWN, &adapter->state)) {
                        if (adapter->msix_entries)
-                               ew32(IMS, adapter->rx_ring->ims_val |
-                                    E1000_IMS_OTHER);
+                               ew32(IMS, adapter->rx_ring->ims_val);
                        else
                                e1000_irq_enable(adapter);
                }
@@ -5101,7 +5090,7 @@ static bool e1000e_has_link(struct e1000_adapter *adapter)
        case e1000_media_type_copper:
                if (hw->mac.get_link_status) {
                        ret_val = hw->mac.ops.check_for_link(hw);
-                       link_active = ret_val > 0;
+                       link_active = !hw->mac.get_link_status;
                } else {
                        link_active = true;
                }
index 0da5aa2..9fc063a 100644 (file)
@@ -1888,6 +1888,14 @@ static void ixgbe_dma_sync_frag(struct ixgbe_ring *rx_ring,
                                     ixgbe_rx_pg_size(rx_ring),
                                     DMA_FROM_DEVICE,
                                     IXGBE_RX_DMA_ATTR);
+       } else if (ring_uses_build_skb(rx_ring)) {
+               unsigned long offset = (unsigned long)(skb->data) & ~PAGE_MASK;
+
+               dma_sync_single_range_for_cpu(rx_ring->dev,
+                                             IXGBE_CB(skb)->dma,
+                                             offset,
+                                             skb_headlen(skb),
+                                             DMA_FROM_DEVICE);
        } else {
                struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
 
index 25e9a55..3f6fb63 100644 (file)
@@ -1132,6 +1132,7 @@ static void mvneta_port_up(struct mvneta_port *pp)
        }
        mvreg_write(pp, MVNETA_TXQ_CMD, q_map);
 
+       q_map = 0;
        /* Enable all initialized RXQs. */
        for (queue = 0; queue < rxq_number; queue++) {
                struct mvneta_rx_queue *rxq = &pp->rxqs[queue];
index a1d7b88..5a1668c 100644 (file)
@@ -7137,6 +7137,7 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
        int id = port->id;
        bool allmulti = dev->flags & IFF_ALLMULTI;
 
+retry:
        mvpp2_prs_mac_promisc_set(priv, id, dev->flags & IFF_PROMISC);
        mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_ALL, allmulti);
        mvpp2_prs_mac_multi_set(priv, id, MVPP2_PE_MAC_MC_IP6, allmulti);
@@ -7144,9 +7145,13 @@ static void mvpp2_set_rx_mode(struct net_device *dev)
        /* Remove all port->id's mcast enries */
        mvpp2_prs_mcast_del_all(priv, id);
 
-       if (allmulti && !netdev_mc_empty(dev)) {
-               netdev_for_each_mc_addr(ha, dev)
-                       mvpp2_prs_mac_da_accept(priv, id, ha->addr, true);
+       if (!allmulti) {
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (mvpp2_prs_mac_da_accept(priv, id, ha->addr, true)) {
+                               allmulti = true;
+                               goto retry;
+                       }
+               }
        }
 }
 
index 1a0c3bf..752a724 100644 (file)
@@ -156,57 +156,63 @@ static int mlx4_en_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num)
 static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev)
 {
        struct mlx4_en_priv *priv = netdev_priv(netdev);
+       struct mlx4_en_port_profile *prof = priv->prof;
        struct mlx4_en_dev *mdev = priv->mdev;
+       u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
 
        if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE))
                return 1;
 
        if (priv->cee_config.pfc_state) {
                int tc;
+               rx_ppp = prof->rx_ppp;
+               tx_ppp = prof->tx_ppp;
 
-               priv->prof->rx_pause = 0;
-               priv->prof->tx_pause = 0;
                for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) {
                        u8 tc_mask = 1 << tc;
 
                        switch (priv->cee_config.dcb_pfc[tc]) {
                        case pfc_disabled:
-                               priv->prof->tx_ppp &= ~tc_mask;
-                               priv->prof->rx_ppp &= ~tc_mask;
+                               tx_ppp &= ~tc_mask;
+                               rx_ppp &= ~tc_mask;
                                break;
                        case pfc_enabled_full:
-                               priv->prof->tx_ppp |= tc_mask;
-                               priv->prof->rx_ppp |= tc_mask;
+                               tx_ppp |= tc_mask;
+                               rx_ppp |= tc_mask;
                                break;
                        case pfc_enabled_tx:
-                               priv->prof->tx_ppp |= tc_mask;
-                               priv->prof->rx_ppp &= ~tc_mask;
+                               tx_ppp |= tc_mask;
+                               rx_ppp &= ~tc_mask;
                                break;
                        case pfc_enabled_rx:
-                               priv->prof->tx_ppp &= ~tc_mask;
-                               priv->prof->rx_ppp |= tc_mask;
+                               tx_ppp &= ~tc_mask;
+                               rx_ppp |= tc_mask;
                                break;
                        default:
                                break;
                        }
                }
-               en_dbg(DRV, priv, "Set pfc on\n");
+               rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause;
+               tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause;
        } else {
-               priv->prof->rx_pause = 1;
-               priv->prof->tx_pause = 1;
-               en_dbg(DRV, priv, "Set pfc off\n");
+               rx_ppp = 0;
+               tx_ppp = 0;
+               rx_pause = prof->rx_pause;
+               tx_pause = prof->tx_pause;
        }
 
        if (mlx4_SET_PORT_general(mdev->dev, priv->port,
                                  priv->rx_skb_size + ETH_FCS_LEN,
-                                 priv->prof->tx_pause,
-                                 priv->prof->tx_ppp,
-                                 priv->prof->rx_pause,
-                                 priv->prof->rx_ppp)) {
+                                 tx_pause, tx_ppp, rx_pause, rx_ppp)) {
                en_err(priv, "Failed setting pause params\n");
                return 1;
        }
 
+       prof->tx_ppp = tx_ppp;
+       prof->rx_ppp = rx_ppp;
+       prof->tx_pause = tx_pause;
+       prof->rx_pause = rx_pause;
+
        return 0;
 }
 
@@ -408,6 +414,7 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev,
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_port_profile *prof = priv->prof;
        struct mlx4_en_dev *mdev = priv->mdev;
+       u32 tx_pause, tx_ppp, rx_pause, rx_ppp;
        int err;
 
        en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n",
@@ -416,23 +423,26 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev,
                        pfc->mbc,
                        pfc->delay);
 
-       prof->rx_pause = !pfc->pfc_en;
-       prof->tx_pause = !pfc->pfc_en;
-       prof->rx_ppp = pfc->pfc_en;
-       prof->tx_ppp = pfc->pfc_en;
+       rx_pause = prof->rx_pause && !pfc->pfc_en;
+       tx_pause = prof->tx_pause && !pfc->pfc_en;
+       rx_ppp = pfc->pfc_en;
+       tx_ppp = pfc->pfc_en;
 
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
                                    priv->rx_skb_size + ETH_FCS_LEN,
-                                   prof->tx_pause,
-                                   prof->tx_ppp,
-                                   prof->rx_pause,
-                                   prof->rx_ppp);
-       if (err)
+                                   tx_pause, tx_ppp, rx_pause, rx_ppp);
+       if (err) {
                en_err(priv, "Failed setting pause params\n");
-       else
-               mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
-                                               prof->rx_ppp, prof->rx_pause,
-                                               prof->tx_ppp, prof->tx_pause);
+               return err;
+       }
+
+       mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+                                       rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+       prof->tx_ppp = tx_ppp;
+       prof->rx_ppp = rx_ppp;
+       prof->rx_pause = rx_pause;
+       prof->tx_pause = tx_pause;
 
        return err;
 }
index ebc1f56..f3302ed 100644 (file)
@@ -1046,27 +1046,32 @@ static int mlx4_en_set_pauseparam(struct net_device *dev,
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
+       u8 tx_pause, tx_ppp, rx_pause, rx_ppp;
        int err;
 
        if (pause->autoneg)
                return -EINVAL;
 
-       priv->prof->tx_pause = pause->tx_pause != 0;
-       priv->prof->rx_pause = pause->rx_pause != 0;
+       tx_pause = !!(pause->tx_pause);
+       rx_pause = !!(pause->rx_pause);
+       rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause);
+       tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause);
+
        err = mlx4_SET_PORT_general(mdev->dev, priv->port,
                                    priv->rx_skb_size + ETH_FCS_LEN,
-                                   priv->prof->tx_pause,
-                                   priv->prof->tx_ppp,
-                                   priv->prof->rx_pause,
-                                   priv->prof->rx_ppp);
-       if (err)
-               en_err(priv, "Failed setting pause params\n");
-       else
-               mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
-                                               priv->prof->rx_ppp,
-                                               priv->prof->rx_pause,
-                                               priv->prof->tx_ppp,
-                                               priv->prof->tx_pause);
+                                   tx_pause, tx_ppp, rx_pause, rx_ppp);
+       if (err) {
+               en_err(priv, "Failed setting pause params, err = %d\n", err);
+               return err;
+       }
+
+       mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+                                       rx_ppp, rx_pause, tx_ppp, tx_pause);
+
+       priv->prof->tx_pause = tx_pause;
+       priv->prof->rx_pause = rx_pause;
+       priv->prof->tx_ppp = tx_ppp;
+       priv->prof->rx_ppp = rx_ppp;
 
        return err;
 }
index 2c29654..d25e16d 100644 (file)
@@ -163,9 +163,9 @@ static void mlx4_en_get_profile(struct mlx4_en_dev *mdev)
                params->udp_rss = 0;
        }
        for (i = 1; i <= MLX4_MAX_PORTS; i++) {
-               params->prof[i].rx_pause = 1;
+               params->prof[i].rx_pause = !(pfcrx || pfctx);
                params->prof[i].rx_ppp = pfcrx;
-               params->prof[i].tx_pause = 1;
+               params->prof[i].tx_pause = !(pfcrx || pfctx);
                params->prof[i].tx_ppp = pfctx;
                params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE;
                params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE;
index 606a0e0..29e50f7 100644 (file)
@@ -5088,6 +5088,7 @@ static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave)
                                                 &tracker->res_tree[RES_FS_RULE]);
                                        list_del(&fs_rule->com.list);
                                        spin_unlock_irq(mlx4_tlock(dev));
+                                       kfree(fs_rule->mirr_mbox);
                                        kfree(fs_rule);
                                        state = 0;
                                        break;
index 25deaa5..c032319 100644 (file)
@@ -46,7 +46,7 @@ config MLX5_MPFS
 
 config MLX5_ESWITCH
        bool "Mellanox Technologies MLX5 SRIOV E-Switch support"
-       depends on MLX5_CORE_EN
+       depends on MLX5_CORE_EN && NET_SWITCHDEV
        default y
        ---help---
          Mellanox Technologies Ethernet SRIOV E-Switch support in ConnectX NIC.
index 0be4575..fd50916 100644 (file)
@@ -96,10 +96,10 @@ static void print_lyr_2_4_hdrs(struct trace_seq *p,
                                          "%pI4");
                } else if (ethertype.v == ETH_P_IPV6) {
                        static const struct in6_addr full_ones = {
-                               .in6_u.u6_addr32 = {htonl(0xffffffff),
-                                                   htonl(0xffffffff),
-                                                   htonl(0xffffffff),
-                                                   htonl(0xffffffff)},
+                               .in6_u.u6_addr32 = {__constant_htonl(0xffffffff),
+                                                   __constant_htonl(0xffffffff),
+                                                   __constant_htonl(0xffffffff),
+                                                   __constant_htonl(0xffffffff)},
                        };
                        DECLARE_MASK_VAL(struct in6_addr, src_ipv6);
                        DECLARE_MASK_VAL(struct in6_addr, dst_ipv6);
index cc8048f..59ebfda 100644 (file)
@@ -477,6 +477,9 @@ static int mlx5e_get_coalesce(struct net_device *netdev,
        return mlx5e_ethtool_get_coalesce(priv, coal);
 }
 
+#define MLX5E_MAX_COAL_TIME            MLX5_MAX_CQ_PERIOD
+#define MLX5E_MAX_COAL_FRAMES          MLX5_MAX_CQ_COUNT
+
 static void
 mlx5e_set_priv_channels_coalesce(struct mlx5e_priv *priv, struct ethtool_coalesce *coal)
 {
@@ -511,6 +514,20 @@ int mlx5e_ethtool_set_coalesce(struct mlx5e_priv *priv,
        if (!MLX5_CAP_GEN(mdev, cq_moderation))
                return -EOPNOTSUPP;
 
+       if (coal->tx_coalesce_usecs > MLX5E_MAX_COAL_TIME ||
+           coal->rx_coalesce_usecs > MLX5E_MAX_COAL_TIME) {
+               netdev_info(priv->netdev, "%s: maximum coalesce time supported is %lu usecs\n",
+                           __func__, MLX5E_MAX_COAL_TIME);
+               return -ERANGE;
+       }
+
+       if (coal->tx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES ||
+           coal->rx_max_coalesced_frames > MLX5E_MAX_COAL_FRAMES) {
+               netdev_info(priv->netdev, "%s: maximum coalesced frames supported is %lu\n",
+                           __func__, MLX5E_MAX_COAL_FRAMES);
+               return -ERANGE;
+       }
+
        mutex_lock(&priv->state_lock);
        new_channels.params = priv->channels.params;
 
index 47bab84..9b4827d 100644 (file)
@@ -1768,13 +1768,16 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv,
        param->wq.linear = 1;
 }
 
-static void mlx5e_build_drop_rq_param(struct mlx5e_rq_param *param)
+static void mlx5e_build_drop_rq_param(struct mlx5_core_dev *mdev,
+                                     struct mlx5e_rq_param *param)
 {
        void *rqc = param->rqc;
        void *wq = MLX5_ADDR_OF(rqc, rqc, wq);
 
        MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_LINKED_LIST);
        MLX5_SET(wq, wq, log_wq_stride,    ilog2(sizeof(struct mlx5e_rx_wqe)));
+
+       param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev);
 }
 
 static void mlx5e_build_sq_param_common(struct mlx5e_priv *priv,
@@ -2569,6 +2572,9 @@ int mlx5e_open(struct net_device *netdev)
                mlx5_set_port_admin_status(priv->mdev, MLX5_PORT_UP);
        mutex_unlock(&priv->state_lock);
 
+       if (mlx5e_vxlan_allowed(priv->mdev))
+               udp_tunnel_get_rx_info(netdev);
+
        return err;
 }
 
@@ -2634,6 +2640,9 @@ static int mlx5e_alloc_drop_cq(struct mlx5_core_dev *mdev,
                               struct mlx5e_cq *cq,
                               struct mlx5e_cq_param *param)
 {
+       param->wq.buf_numa_node = dev_to_node(&mdev->pdev->dev);
+       param->wq.db_numa_node  = dev_to_node(&mdev->pdev->dev);
+
        return mlx5e_alloc_cq_common(mdev, param, cq);
 }
 
@@ -2645,7 +2654,7 @@ static int mlx5e_open_drop_rq(struct mlx5_core_dev *mdev,
        struct mlx5e_cq *cq = &drop_rq->cq;
        int err;
 
-       mlx5e_build_drop_rq_param(&rq_param);
+       mlx5e_build_drop_rq_param(mdev, &rq_param);
 
        err = mlx5e_alloc_drop_cq(mdev, cq, &cq_param);
        if (err)
@@ -2994,8 +3003,8 @@ static int mlx5e_setup_tc_block(struct net_device *dev,
 }
 #endif
 
-int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
-                  void *type_data)
+static int mlx5e_setup_tc(struct net_device *dev, enum tc_setup_type type,
+                         void *type_data)
 {
        switch (type) {
 #ifdef CONFIG_MLX5_ESWITCH
@@ -4063,7 +4072,7 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev)
        }
 }
 
-#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH)
+#if IS_ENABLED(CONFIG_MLX5_ESWITCH)
 static const struct switchdev_ops mlx5e_switchdev_ops = {
        .switchdev_port_attr_get        = mlx5e_attr_get,
 };
@@ -4169,7 +4178,7 @@ static void mlx5e_build_nic_netdev(struct net_device *netdev)
 
        mlx5e_set_netdev_dev_addr(netdev);
 
-#if IS_ENABLED(CONFIG_NET_SWITCHDEV) && IS_ENABLED(CONFIG_MLX5_ESWITCH)
+#if IS_ENABLED(CONFIG_MLX5_ESWITCH)
        if (MLX5_VPORT_MANAGER(mdev))
                netdev->switchdev_ops = &mlx5e_switchdev_ops;
 #endif
@@ -4321,12 +4330,6 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv)
 #ifdef CONFIG_MLX5_CORE_EN_DCB
        mlx5e_dcbnl_init_app(priv);
 #endif
-       /* Device already registered: sync netdev system state */
-       if (mlx5e_vxlan_allowed(mdev)) {
-               rtnl_lock();
-               udp_tunnel_get_rx_info(netdev);
-               rtnl_unlock();
-       }
 
        queue_work(priv->wq, &priv->set_rx_mode_work);
 
index 363d8dc..500d817 100644 (file)
 #include "en_tc.h"
 #include "fs_core.h"
 
+#define MLX5E_REP_PARAMS_LOG_SQ_SIZE \
+       max(0x6, MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE)
+#define MLX5E_REP_PARAMS_LOG_RQ_SIZE \
+       max(0x6, MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE)
+
 static const char mlx5e_rep_driver_name[] = "mlx5e_rep";
 
 static void mlx5e_rep_get_drvinfo(struct net_device *dev,
@@ -209,7 +214,7 @@ static void mlx5e_sqs2vport_stop(struct mlx5_eswitch *esw,
 
 static int mlx5e_sqs2vport_start(struct mlx5_eswitch *esw,
                                 struct mlx5_eswitch_rep *rep,
-                                u16 *sqns_array, int sqns_num)
+                                u32 *sqns_array, int sqns_num)
 {
        struct mlx5_flow_handle *flow_rule;
        struct mlx5e_rep_priv *rpriv;
@@ -255,9 +260,9 @@ int mlx5e_add_sqs_fwd_rules(struct mlx5e_priv *priv)
        struct mlx5e_channel *c;
        int n, tc, num_sqs = 0;
        int err = -ENOMEM;
-       u16 *sqs;
+       u32 *sqs;
 
-       sqs = kcalloc(priv->channels.num * priv->channels.params.num_tc, sizeof(u16), GFP_KERNEL);
+       sqs = kcalloc(priv->channels.num * priv->channels.params.num_tc, sizeof(*sqs), GFP_KERNEL);
        if (!sqs)
                goto out;
 
@@ -288,7 +293,7 @@ void mlx5e_remove_sqs_fwd_rules(struct mlx5e_priv *priv)
 static void mlx5e_rep_neigh_update_init_interval(struct mlx5e_rep_priv *rpriv)
 {
 #if IS_ENABLED(CONFIG_IPV6)
-       unsigned long ipv6_interval = NEIGH_VAR(&ipv6_stub->nd_tbl->parms,
+       unsigned long ipv6_interval = NEIGH_VAR(&nd_tbl.parms,
                                                DELAY_PROBE_TIME);
 #else
        unsigned long ipv6_interval = ~0UL;
@@ -424,7 +429,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
        case NETEVENT_NEIGH_UPDATE:
                n = ptr;
 #if IS_ENABLED(CONFIG_IPV6)
-               if (n->tbl != ipv6_stub->nd_tbl && n->tbl != &arp_tbl)
+               if (n->tbl != &nd_tbl && n->tbl != &arp_tbl)
 #else
                if (n->tbl != &arp_tbl)
 #endif
@@ -472,7 +477,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
                 * done per device delay prob time parameter.
                 */
 #if IS_ENABLED(CONFIG_IPV6)
-               if (!p->dev || (p->tbl != ipv6_stub->nd_tbl && p->tbl != &arp_tbl))
+               if (!p->dev || (p->tbl != &nd_tbl && p->tbl != &arp_tbl))
 #else
                if (!p->dev || p->tbl != &arp_tbl)
 #endif
@@ -668,7 +673,6 @@ static int mlx5e_rep_open(struct net_device *dev)
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5_eswitch_rep *rep = rpriv->rep;
-       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        int err;
 
        mutex_lock(&priv->state_lock);
@@ -676,8 +680,9 @@ static int mlx5e_rep_open(struct net_device *dev)
        if (err)
                goto unlock;
 
-       if (!mlx5_eswitch_set_vport_state(esw, rep->vport,
-                                         MLX5_ESW_VPORT_ADMIN_STATE_UP))
+       if (!mlx5_modify_vport_admin_state(priv->mdev,
+                       MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+                       rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_UP))
                netif_carrier_on(dev);
 
 unlock:
@@ -690,11 +695,12 @@ static int mlx5e_rep_close(struct net_device *dev)
        struct mlx5e_priv *priv = netdev_priv(dev);
        struct mlx5e_rep_priv *rpriv = priv->ppriv;
        struct mlx5_eswitch_rep *rep = rpriv->rep;
-       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
        int ret;
 
        mutex_lock(&priv->state_lock);
-       (void)mlx5_eswitch_set_vport_state(esw, rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
+       mlx5_modify_vport_admin_state(priv->mdev,
+                       MLX5_QUERY_VPORT_STATE_IN_OP_MOD_ESW_VPORT,
+                       rep->vport, MLX5_ESW_VPORT_ADMIN_STATE_DOWN);
        ret = mlx5e_close_locked(dev);
        mutex_unlock(&priv->state_lock);
        return ret;
@@ -877,9 +883,9 @@ static void mlx5e_build_rep_params(struct mlx5_core_dev *mdev,
                                         MLX5_CQ_PERIOD_MODE_START_FROM_CQE :
                                         MLX5_CQ_PERIOD_MODE_START_FROM_EQE;
 
-       params->log_sq_size = MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE;
+       params->log_sq_size = MLX5E_REP_PARAMS_LOG_SQ_SIZE;
        params->rq_wq_type  = MLX5_WQ_TYPE_LINKED_LIST;
-       params->log_rq_size = MLX5E_PARAMS_MINIMUM_LOG_RQ_SIZE;
+       params->log_rq_size = MLX5E_REP_PARAMS_LOG_RQ_SIZE;
 
        params->rx_dim_enabled = MLX5_CAP_GEN(mdev, cq_moderation);
        mlx5e_set_rx_cq_mode_params(params, cq_period_mode);
@@ -899,9 +905,7 @@ static void mlx5e_build_rep_netdev(struct net_device *netdev)
 
        netdev->ethtool_ops       = &mlx5e_rep_ethtool_ops;
 
-#ifdef CONFIG_NET_SWITCHDEV
        netdev->switchdev_ops = &mlx5e_rep_switchdev_ops;
-#endif
 
        netdev->features         |= NETIF_F_VLAN_CHALLENGED | NETIF_F_HW_TC | NETIF_F_NETNS_LOCAL;
        netdev->hw_features      |= NETIF_F_HW_TC;
index 0d4bb06..e5c3ab4 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/tcp.h>
 #include <linux/bpf_trace.h>
 #include <net/busy_poll.h>
+#include <net/ip6_checksum.h>
 #include "en.h"
 #include "en_tc.h"
 #include "eswitch.h"
@@ -546,20 +547,33 @@ bool mlx5e_post_rx_mpwqes(struct mlx5e_rq *rq)
        return true;
 }
 
+static void mlx5e_lro_update_tcp_hdr(struct mlx5_cqe64 *cqe, struct tcphdr *tcp)
+{
+       u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe);
+       u8 tcp_ack     = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) ||
+                        (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA);
+
+       tcp->check                      = 0;
+       tcp->psh                        = get_cqe_lro_tcppsh(cqe);
+
+       if (tcp_ack) {
+               tcp->ack                = 1;
+               tcp->ack_seq            = cqe->lro_ack_seq_num;
+               tcp->window             = cqe->lro_tcp_win;
+       }
+}
+
 static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe,
                                 u32 cqe_bcnt)
 {
        struct ethhdr   *eth = (struct ethhdr *)(skb->data);
        struct tcphdr   *tcp;
        int network_depth = 0;
+       __wsum check;
        __be16 proto;
        u16 tot_len;
        void *ip_p;
 
-       u8 l4_hdr_type = get_cqe_l4_hdr_type(cqe);
-       u8 tcp_ack = (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_NO_DATA) ||
-               (l4_hdr_type == CQE_L4_HDR_TYPE_TCP_ACK_AND_DATA);
-
        proto = __vlan_get_protocol(skb, eth->h_proto, &network_depth);
 
        tot_len = cqe_bcnt - network_depth;
@@ -576,23 +590,30 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe,
                ipv4->check             = 0;
                ipv4->check             = ip_fast_csum((unsigned char *)ipv4,
                                                       ipv4->ihl);
+
+               mlx5e_lro_update_tcp_hdr(cqe, tcp);
+               check = csum_partial(tcp, tcp->doff * 4,
+                                    csum_unfold((__force __sum16)cqe->check_sum));
+               /* Almost done, don't forget the pseudo header */
+               tcp->check = csum_tcpudp_magic(ipv4->saddr, ipv4->daddr,
+                                              tot_len - sizeof(struct iphdr),
+                                              IPPROTO_TCP, check);
        } else {
+               u16 payload_len = tot_len - sizeof(struct ipv6hdr);
                struct ipv6hdr *ipv6 = ip_p;
 
                tcp = ip_p + sizeof(struct ipv6hdr);
                skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
 
                ipv6->hop_limit         = cqe->lro_min_ttl;
-               ipv6->payload_len       = cpu_to_be16(tot_len -
-                                                     sizeof(struct ipv6hdr));
-       }
-
-       tcp->psh = get_cqe_lro_tcppsh(cqe);
-
-       if (tcp_ack) {
-               tcp->ack                = 1;
-               tcp->ack_seq            = cqe->lro_ack_seq_num;
-               tcp->window             = cqe->lro_tcp_win;
+               ipv6->payload_len       = cpu_to_be16(payload_len);
+
+               mlx5e_lro_update_tcp_hdr(cqe, tcp);
+               check = csum_partial(tcp, tcp->doff * 4,
+                                    csum_unfold((__force __sum16)cqe->check_sum));
+               /* Almost done, don't forget the pseudo header */
+               tcp->check = csum_ipv6_magic(&ipv6->saddr, &ipv6->daddr, payload_len,
+                                            IPPROTO_TCP, check);
        }
 }
 
index 5a46082..7079764 100644 (file)
@@ -216,7 +216,8 @@ mlx5e_test_loopback_validate(struct sk_buff *skb,
        if (iph->protocol != IPPROTO_UDP)
                goto out;
 
-       udph = udp_hdr(skb);
+       /* Don't assume skb_transport_header() was set */
+       udph = (struct udphdr *)((u8 *)iph + 4 * iph->ihl);
        if (udph->dest != htons(9))
                goto out;
 
index fd98b0d..43234ca 100644 (file)
@@ -963,7 +963,7 @@ void mlx5e_tc_update_neigh_used_value(struct mlx5e_neigh_hash_entry *nhe)
                tbl = &arp_tbl;
 #if IS_ENABLED(CONFIG_IPV6)
        else if (m_neigh->family == AF_INET6)
-               tbl = ipv6_stub->nd_tbl;
+               tbl = &nd_tbl;
 #endif
        else
                return;
@@ -2529,7 +2529,8 @@ static int parse_tc_fdb_actions(struct mlx5e_priv *priv, struct tcf_exts *exts,
                        if (tcf_vlan_action(a) == TCA_VLAN_ACT_POP) {
                                attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_POP;
                        } else if (tcf_vlan_action(a) == TCA_VLAN_ACT_PUSH) {
-                               if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q))
+                               if (tcf_vlan_push_proto(a) != htons(ETH_P_8021Q) ||
+                                   tcf_vlan_push_prio(a))
                                        return -EOPNOTSUPP;
 
                                attr->action |= MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH;
@@ -2607,19 +2608,19 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv,
        if (err != -EAGAIN)
                flow->flags |= MLX5E_TC_FLOW_OFFLOADED;
 
+       if (!(flow->flags & MLX5E_TC_FLOW_ESWITCH) ||
+           !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP))
+               kvfree(parse_attr);
+
        err = rhashtable_insert_fast(&tc->ht, &flow->node,
                                     tc->ht_params);
-       if (err)
-               goto err_del_rule;
+       if (err) {
+               mlx5e_tc_del_flow(priv, flow);
+               kfree(flow);
+       }
 
-       if (flow->flags & MLX5E_TC_FLOW_ESWITCH &&
-           !(flow->esw_attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP))
-               kvfree(parse_attr);
        return err;
 
-err_del_rule:
-       mlx5e_tc_del_flow(priv, flow);
-
 err_free:
        kvfree(parse_attr);
        kfree(flow);
index 569b42a..11b4f10 100644 (file)
@@ -176,7 +176,7 @@ static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode,
        default:
                hlen = mlx5e_skb_l2_header_offset(skb);
        }
-       return min_t(u16, hlen, skb->len);
+       return min_t(u16, hlen, skb_headlen(skb));
 }
 
 static inline void mlx5e_tx_skb_pull_inline(unsigned char **skb_data,
index 5ecf2cd..c2b1d7d 100644 (file)
@@ -1529,6 +1529,10 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
 
        esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
 
+       /* Create steering drop counters for ingress and egress ACLs */
+       if (vport_num && esw->mode == SRIOV_LEGACY)
+               esw_vport_create_drop_counters(vport);
+
        /* Restore old vport configuration */
        esw_apply_vport_conf(esw, vport);
 
@@ -1545,10 +1549,6 @@ static void esw_enable_vport(struct mlx5_eswitch *esw, int vport_num,
        if (!vport_num)
                vport->info.trusted = true;
 
-       /* create steering drop counters for ingress and egress ACLs */
-       if (vport_num && esw->mode == SRIOV_LEGACY)
-               esw_vport_create_drop_counters(vport);
-
        esw_vport_change_handle_locked(vport);
 
        esw->enabled_vports++;
index c025c98..31fc2cf 100644 (file)
@@ -1429,7 +1429,8 @@ static bool check_conflicting_actions(u32 action1, u32 action2)
 
        if (xored_actions & (MLX5_FLOW_CONTEXT_ACTION_DROP  |
                             MLX5_FLOW_CONTEXT_ACTION_ENCAP |
-                            MLX5_FLOW_CONTEXT_ACTION_DECAP))
+                            MLX5_FLOW_CONTEXT_ACTION_DECAP |
+                            MLX5_FLOW_CONTEXT_ACTION_MOD_HDR))
                return true;
 
        return false;
@@ -1758,8 +1759,11 @@ search_again_locked:
 
        /* Collect all fgs which has a matching match_criteria */
        err = build_match_list(&match_head, ft, spec);
-       if (err)
+       if (err) {
+               if (take_write)
+                       up_write_ref_node(&ft->node);
                return ERR_PTR(err);
+       }
 
        if (!take_write)
                up_read_ref_node(&ft->node);
@@ -1768,8 +1772,11 @@ search_again_locked:
                                      dest_num, version);
        free_match_list(&match_head);
        if (!IS_ERR(rule) ||
-           (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN))
+           (PTR_ERR(rule) != -ENOENT && PTR_ERR(rule) != -EAGAIN)) {
+               if (take_write)
+                       up_write_ref_node(&ft->node);
                return rule;
+       }
 
        if (!take_write) {
                nested_down_write_ref_node(&ft->node, FS_LOCK_GRANDPARENT);
index 21d29f7..d39b0b7 100644 (file)
@@ -124,7 +124,7 @@ void mlx5_enter_error_state(struct mlx5_core_dev *dev, bool force)
                trigger_cmd_completions(dev);
        }
 
-       mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 0);
+       mlx5_core_event(dev, MLX5_DEV_EVENT_SYS_ERROR, 1);
        mlx5_core_err(dev, "end\n");
 
 unlock:
index e159243..8570355 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/highmem.h>
 #include <rdma/mlx5-abi.h>
 #include "en.h"
+#include "clock.h"
 
 enum {
        MLX5_CYCLES_SHIFT       = 23
index 2ef641c..ae391e4 100644 (file)
@@ -551,7 +551,7 @@ static int handle_hca_cap(struct mlx5_core_dev *dev)
                MLX5_SET(cmd_hca_cap,
                         set_hca_cap,
                         cache_line_128byte,
-                        cache_line_size() == 128 ? 1 : 0);
+                        cache_line_size() >= 128 ? 1 : 0);
 
        if (MLX5_CAP_GEN_MAX(dev, dct))
                MLX5_SET(cmd_hca_cap, set_hca_cap, dct, 1);
index b698fb4..996dc09 100644 (file)
@@ -443,6 +443,17 @@ int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id)
 }
 EXPORT_SYMBOL(mlxsw_afa_block_jump);
 
+int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block)
+{
+       if (block->finished)
+               return -EINVAL;
+       mlxsw_afa_set_goto_set(block->cur_set,
+                              MLXSW_AFA_SET_GOTO_BINDING_CMD_TERM, 0);
+       block->finished = true;
+       return 0;
+}
+EXPORT_SYMBOL(mlxsw_afa_block_terminate);
+
 static struct mlxsw_afa_fwd_entry *
 mlxsw_afa_fwd_entry_create(struct mlxsw_afa *mlxsw_afa, u8 local_port)
 {
index 4313229..b91f2b0 100644 (file)
@@ -65,6 +65,7 @@ char *mlxsw_afa_block_first_set(struct mlxsw_afa_block *block);
 u32 mlxsw_afa_block_first_set_kvdl_index(struct mlxsw_afa_block *block);
 int mlxsw_afa_block_continue(struct mlxsw_afa_block *block);
 int mlxsw_afa_block_jump(struct mlxsw_afa_block *block, u16 group_id);
+int mlxsw_afa_block_terminate(struct mlxsw_afa_block *block);
 int mlxsw_afa_block_append_drop(struct mlxsw_afa_block *block);
 int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id);
 int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block,
index f6963b0..122506d 100644 (file)
@@ -107,20 +107,20 @@ static const struct mlxsw_afk_element_info mlxsw_afk_element_infos[] = {
        MLXSW_AFK_ELEMENT_INFO_U32(VID, 0x10, 8, 12),
        MLXSW_AFK_ELEMENT_INFO_U32(PCP, 0x10, 20, 3),
        MLXSW_AFK_ELEMENT_INFO_U32(TCP_FLAGS, 0x10, 23, 9),
-       MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x14, 0, 8),
-       MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x14, 9, 2),
-       MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x14, 11, 6),
-       MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x18, 0, 32),
-       MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x1C, 0, 32),
-       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x18, 8),
-       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x20, 8),
-       MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x28, 8),
-       MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x30, 8),
        MLXSW_AFK_ELEMENT_INFO_U32(DST_L4_PORT, 0x14, 0, 16),
        MLXSW_AFK_ELEMENT_INFO_U32(SRC_L4_PORT, 0x14, 16, 16),
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_TTL_, 0x18, 0, 8),
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_ECN, 0x18, 9, 2),
+       MLXSW_AFK_ELEMENT_INFO_U32(IP_DSCP, 0x18, 11, 6),
+       MLXSW_AFK_ELEMENT_INFO_U32(SRC_IP4, 0x20, 0, 32),
+       MLXSW_AFK_ELEMENT_INFO_U32(DST_IP4, 0x24, 0, 32),
+       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_HI, 0x20, 8),
+       MLXSW_AFK_ELEMENT_INFO_BUF(SRC_IP6_LO, 0x28, 8),
+       MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_HI, 0x30, 8),
+       MLXSW_AFK_ELEMENT_INFO_BUF(DST_IP6_LO, 0x38, 8),
 };
 
-#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x38
+#define MLXSW_AFK_ELEMENT_STORAGE_SIZE 0x40
 
 struct mlxsw_afk_element_inst { /* element instance in actual block */
        const struct mlxsw_afk_element_info *info;
index 3dcc58d..bf400c7 100644 (file)
@@ -655,13 +655,17 @@ static int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu)
 }
 
 static struct mlxsw_sp_span_inspected_port *
-mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_port *port,
-                                   struct mlxsw_sp_span_entry *span_entry)
+mlxsw_sp_span_entry_bound_port_find(struct mlxsw_sp_span_entry *span_entry,
+                                   enum mlxsw_sp_span_type type,
+                                   struct mlxsw_sp_port *port,
+                                   bool bind)
 {
        struct mlxsw_sp_span_inspected_port *p;
 
        list_for_each_entry(p, &span_entry->bound_ports_list, list)
-               if (port->local_port == p->local_port)
+               if (type == p->type &&
+                   port->local_port == p->local_port &&
+                   bind == p->bound)
                        return p;
        return NULL;
 }
@@ -691,8 +695,22 @@ mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
        struct mlxsw_sp_span_inspected_port *inspected_port;
        struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
        char sbib_pl[MLXSW_REG_SBIB_LEN];
+       int i;
        int err;
 
+       /* A given (source port, direction) can only be bound to one analyzer,
+        * so if a binding is requested, check for conflicts.
+        */
+       if (bind)
+               for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
+                       struct mlxsw_sp_span_entry *curr =
+                               &mlxsw_sp->span.entries[i];
+
+                       if (mlxsw_sp_span_entry_bound_port_find(curr, type,
+                                                               port, bind))
+                               return -EEXIST;
+               }
+
        /* if it is an egress SPAN, bind a shared buffer to it */
        if (type == MLXSW_SP_SPAN_EGRESS) {
                u32 buffsize = mlxsw_sp_span_mtu_to_buffsize(mlxsw_sp,
@@ -720,6 +738,7 @@ mlxsw_sp_span_inspected_port_add(struct mlxsw_sp_port *port,
        }
        inspected_port->local_port = port->local_port;
        inspected_port->type = type;
+       inspected_port->bound = bind;
        list_add_tail(&inspected_port->list, &span_entry->bound_ports_list);
 
        return 0;
@@ -746,7 +765,8 @@ mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
        struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp;
        char sbib_pl[MLXSW_REG_SBIB_LEN];
 
-       inspected_port = mlxsw_sp_span_entry_bound_port_find(port, span_entry);
+       inspected_port = mlxsw_sp_span_entry_bound_port_find(span_entry, type,
+                                                            port, bind);
        if (!inspected_port)
                return;
 
@@ -1459,6 +1479,7 @@ mlxsw_sp_port_vlan_create(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
        }
 
        mlxsw_sp_port_vlan->mlxsw_sp_port = mlxsw_sp_port;
+       mlxsw_sp_port_vlan->ref_count = 1;
        mlxsw_sp_port_vlan->vid = vid;
        list_add(&mlxsw_sp_port_vlan->list, &mlxsw_sp_port->vlans_list);
 
@@ -1486,8 +1507,10 @@ mlxsw_sp_port_vlan_get(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid)
        struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan;
 
        mlxsw_sp_port_vlan = mlxsw_sp_port_vlan_find_by_vid(mlxsw_sp_port, vid);
-       if (mlxsw_sp_port_vlan)
+       if (mlxsw_sp_port_vlan) {
+               mlxsw_sp_port_vlan->ref_count++;
                return mlxsw_sp_port_vlan;
+       }
 
        return mlxsw_sp_port_vlan_create(mlxsw_sp_port, vid);
 }
@@ -1496,6 +1519,9 @@ void mlxsw_sp_port_vlan_put(struct mlxsw_sp_port_vlan *mlxsw_sp_port_vlan)
 {
        struct mlxsw_sp_fid *fid = mlxsw_sp_port_vlan->fid;
 
+       if (--mlxsw_sp_port_vlan->ref_count != 0)
+               return;
+
        if (mlxsw_sp_port_vlan->bridge_port)
                mlxsw_sp_port_vlan_bridge_leave(mlxsw_sp_port_vlan);
        else if (fid)
@@ -4207,13 +4233,12 @@ static struct devlink_resource_ops mlxsw_sp_resource_kvd_hash_double_ops = {
        .size_validate = mlxsw_sp_resource_kvd_hash_double_size_validate,
 };
 
-static struct devlink_resource_size_params mlxsw_sp_kvd_size_params;
-static struct devlink_resource_size_params mlxsw_sp_linear_size_params;
-static struct devlink_resource_size_params mlxsw_sp_hash_single_size_params;
-static struct devlink_resource_size_params mlxsw_sp_hash_double_size_params;
-
 static void
-mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core)
+mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core,
+                                     struct devlink_resource_size_params *kvd_size_params,
+                                     struct devlink_resource_size_params *linear_size_params,
+                                     struct devlink_resource_size_params *hash_double_size_params,
+                                     struct devlink_resource_size_params *hash_single_size_params)
 {
        u32 single_size_min = MLXSW_CORE_RES_GET(mlxsw_core,
                                                 KVD_SINGLE_MIN_SIZE);
@@ -4222,37 +4247,35 @@ mlxsw_sp_resource_size_params_prepare(struct mlxsw_core *mlxsw_core)
        u32 kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
        u32 linear_size_min = 0;
 
-       /* KVD top resource */
-       mlxsw_sp_kvd_size_params.size_min = kvd_size;
-       mlxsw_sp_kvd_size_params.size_max = kvd_size;
-       mlxsw_sp_kvd_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
-       mlxsw_sp_kvd_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
-
-       /* Linear part init */
-       mlxsw_sp_linear_size_params.size_min = linear_size_min;
-       mlxsw_sp_linear_size_params.size_max = kvd_size - single_size_min -
-                                              double_size_min;
-       mlxsw_sp_linear_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
-       mlxsw_sp_linear_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
-
-       /* Hash double part init */
-       mlxsw_sp_hash_double_size_params.size_min = double_size_min;
-       mlxsw_sp_hash_double_size_params.size_max = kvd_size - single_size_min -
-                                                   linear_size_min;
-       mlxsw_sp_hash_double_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
-       mlxsw_sp_hash_double_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
-
-       /* Hash single part init */
-       mlxsw_sp_hash_single_size_params.size_min = single_size_min;
-       mlxsw_sp_hash_single_size_params.size_max = kvd_size - double_size_min -
-                                                   linear_size_min;
-       mlxsw_sp_hash_single_size_params.size_granularity = MLXSW_SP_KVD_GRANULARITY;
-       mlxsw_sp_hash_single_size_params.unit = DEVLINK_RESOURCE_UNIT_ENTRY;
+       devlink_resource_size_params_init(kvd_size_params, kvd_size, kvd_size,
+                                         MLXSW_SP_KVD_GRANULARITY,
+                                         DEVLINK_RESOURCE_UNIT_ENTRY);
+       devlink_resource_size_params_init(linear_size_params, linear_size_min,
+                                         kvd_size - single_size_min -
+                                         double_size_min,
+                                         MLXSW_SP_KVD_GRANULARITY,
+                                         DEVLINK_RESOURCE_UNIT_ENTRY);
+       devlink_resource_size_params_init(hash_double_size_params,
+                                         double_size_min,
+                                         kvd_size - single_size_min -
+                                         linear_size_min,
+                                         MLXSW_SP_KVD_GRANULARITY,
+                                         DEVLINK_RESOURCE_UNIT_ENTRY);
+       devlink_resource_size_params_init(hash_single_size_params,
+                                         single_size_min,
+                                         kvd_size - double_size_min -
+                                         linear_size_min,
+                                         MLXSW_SP_KVD_GRANULARITY,
+                                         DEVLINK_RESOURCE_UNIT_ENTRY);
 }
 
 static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
 {
        struct devlink *devlink = priv_to_devlink(mlxsw_core);
+       struct devlink_resource_size_params hash_single_size_params;
+       struct devlink_resource_size_params hash_double_size_params;
+       struct devlink_resource_size_params linear_size_params;
+       struct devlink_resource_size_params kvd_size_params;
        u32 kvd_size, single_size, double_size, linear_size;
        const struct mlxsw_config_profile *profile;
        int err;
@@ -4261,13 +4284,17 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
        if (!MLXSW_CORE_RES_VALID(mlxsw_core, KVD_SIZE))
                return -EIO;
 
-       mlxsw_sp_resource_size_params_prepare(mlxsw_core);
+       mlxsw_sp_resource_size_params_prepare(mlxsw_core, &kvd_size_params,
+                                             &linear_size_params,
+                                             &hash_double_size_params,
+                                             &hash_single_size_params);
+
        kvd_size = MLXSW_CORE_RES_GET(mlxsw_core, KVD_SIZE);
        err = devlink_resource_register(devlink, MLXSW_SP_RESOURCE_NAME_KVD,
                                        true, kvd_size,
                                        MLXSW_SP_RESOURCE_KVD,
                                        DEVLINK_RESOURCE_ID_PARENT_TOP,
-                                       &mlxsw_sp_kvd_size_params,
+                                       &kvd_size_params,
                                        &mlxsw_sp_resource_kvd_ops);
        if (err)
                return err;
@@ -4277,7 +4304,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
                                        false, linear_size,
                                        MLXSW_SP_RESOURCE_KVD_LINEAR,
                                        MLXSW_SP_RESOURCE_KVD,
-                                       &mlxsw_sp_linear_size_params,
+                                       &linear_size_params,
                                        &mlxsw_sp_resource_kvd_linear_ops);
        if (err)
                return err;
@@ -4291,7 +4318,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
                                        false, double_size,
                                        MLXSW_SP_RESOURCE_KVD_HASH_DOUBLE,
                                        MLXSW_SP_RESOURCE_KVD,
-                                       &mlxsw_sp_hash_double_size_params,
+                                       &hash_double_size_params,
                                        &mlxsw_sp_resource_kvd_hash_double_ops);
        if (err)
                return err;
@@ -4301,7 +4328,7 @@ static int mlxsw_sp_resources_register(struct mlxsw_core *mlxsw_core)
                                        false, single_size,
                                        MLXSW_SP_RESOURCE_KVD_HASH_SINGLE,
                                        MLXSW_SP_RESOURCE_KVD,
-                                       &mlxsw_sp_hash_single_size_params,
+                                       &hash_single_size_params,
                                        &mlxsw_sp_resource_kvd_hash_single_ops);
        if (err)
                return err;
index bdd8f94..92064db 100644 (file)
@@ -120,6 +120,9 @@ struct mlxsw_sp_span_inspected_port {
        struct list_head list;
        enum mlxsw_sp_span_type type;
        u8 local_port;
+
+       /* Whether this is a directly bound mirror (port-to-port) or an ACL. */
+       bool bound;
 };
 
 struct mlxsw_sp_span_entry {
@@ -211,6 +214,7 @@ struct mlxsw_sp_port_vlan {
        struct list_head list;
        struct mlxsw_sp_port *mlxsw_sp_port;
        struct mlxsw_sp_fid *fid;
+       unsigned int ref_count;
        u16 vid;
        struct mlxsw_sp_bridge_port *bridge_port;
        struct list_head bridge_vlan_node;
@@ -552,6 +556,7 @@ void mlxsw_sp_acl_rulei_keymask_buf(struct mlxsw_sp_acl_rule_info *rulei,
 int mlxsw_sp_acl_rulei_act_continue(struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei,
                                u16 group_id);
+int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_act_trap(struct mlxsw_sp_acl_rule_info *rulei);
 int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
index 0897a54..92d90ed 100644 (file)
@@ -528,6 +528,11 @@ int mlxsw_sp_acl_rulei_act_jump(struct mlxsw_sp_acl_rule_info *rulei,
        return mlxsw_afa_block_jump(rulei->act_block, group_id);
 }
 
+int mlxsw_sp_acl_rulei_act_terminate(struct mlxsw_sp_acl_rule_info *rulei)
+{
+       return mlxsw_afa_block_terminate(rulei->act_block);
+}
+
 int mlxsw_sp_acl_rulei_act_drop(struct mlxsw_sp_acl_rule_info *rulei)
 {
        return mlxsw_afa_block_append_drop(rulei->act_block);
index 93728c6..0a9adc5 100644 (file)
@@ -385,13 +385,13 @@ static const struct mlxsw_sp_sb_cm mlxsw_sp_sb_cms_egress[] = {
 
 static const struct mlxsw_sp_sb_cm mlxsw_sp_cpu_port_sb_cms[] = {
        MLXSW_SP_CPU_PORT_SB_CM,
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
        MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_CPU_PORT_SB_CM,
-       MLXSW_SP_SB_CM(10000, 0, 0),
+       MLXSW_SP_SB_CM(MLXSW_PORT_MAX_MTU, 0, 0),
        MLXSW_SP_CPU_PORT_SB_CM,
        MLXSW_SP_CPU_PORT_SB_CM,
        MLXSW_SP_CPU_PORT_SB_CM,
index bbd238e..54262af 100644 (file)
@@ -112,11 +112,11 @@ static const int mlxsw_sp_sfgc_bc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
        [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_NON_IP]     = 1,
        [MLXSW_REG_SFGC_TYPE_IPV4_LINK_LOCAL]                   = 1,
        [MLXSW_REG_SFGC_TYPE_IPV6_ALL_HOST]                     = 1,
+       [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]       = 1,
 };
 
 static const int mlxsw_sp_sfgc_mc_packet_types[MLXSW_REG_SFGC_TYPE_MAX] = {
        [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV4]       = 1,
-       [MLXSW_REG_SFGC_TYPE_UNREGISTERED_MULTICAST_IPV6]       = 1,
 };
 
 static const int *mlxsw_sp_packet_type_sfgc_types[] = {
index 6ce00e2..89dbf56 100644 (file)
@@ -65,7 +65,7 @@ static int mlxsw_sp_flower_parse_actions(struct mlxsw_sp *mlxsw_sp,
        tcf_exts_to_list(exts, &actions);
        list_for_each_entry(a, &actions, list) {
                if (is_tcf_gact_ok(a)) {
-                       err = mlxsw_sp_acl_rulei_act_continue(rulei);
+                       err = mlxsw_sp_acl_rulei_act_terminate(rulei);
                        if (err)
                                return err;
                } else if (is_tcf_gact_shot(a)) {
index f0b25ba..997e24d 100644 (file)
@@ -788,6 +788,9 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
                                              u32 tb_id,
                                              struct netlink_ext_ack *extack)
 {
+       struct mlxsw_sp_mr_table *mr4_table;
+       struct mlxsw_sp_fib *fib4;
+       struct mlxsw_sp_fib *fib6;
        struct mlxsw_sp_vr *vr;
        int err;
 
@@ -796,29 +799,30 @@ static struct mlxsw_sp_vr *mlxsw_sp_vr_create(struct mlxsw_sp *mlxsw_sp,
                NL_SET_ERR_MSG(extack, "spectrum: Exceeded number of supported virtual routers");
                return ERR_PTR(-EBUSY);
        }
-       vr->fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
-       if (IS_ERR(vr->fib4))
-               return ERR_CAST(vr->fib4);
-       vr->fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
-       if (IS_ERR(vr->fib6)) {
-               err = PTR_ERR(vr->fib6);
+       fib4 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV4);
+       if (IS_ERR(fib4))
+               return ERR_CAST(fib4);
+       fib6 = mlxsw_sp_fib_create(mlxsw_sp, vr, MLXSW_SP_L3_PROTO_IPV6);
+       if (IS_ERR(fib6)) {
+               err = PTR_ERR(fib6);
                goto err_fib6_create;
        }
-       vr->mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
-                                                MLXSW_SP_L3_PROTO_IPV4);
-       if (IS_ERR(vr->mr4_table)) {
-               err = PTR_ERR(vr->mr4_table);
+       mr4_table = mlxsw_sp_mr_table_create(mlxsw_sp, vr->id,
+                                            MLXSW_SP_L3_PROTO_IPV4);
+       if (IS_ERR(mr4_table)) {
+               err = PTR_ERR(mr4_table);
                goto err_mr_table_create;
        }
+       vr->fib4 = fib4;
+       vr->fib6 = fib6;
+       vr->mr4_table = mr4_table;
        vr->tb_id = tb_id;
        return vr;
 
 err_mr_table_create:
-       mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib6);
-       vr->fib6 = NULL;
+       mlxsw_sp_fib_destroy(mlxsw_sp, fib6);
 err_fib6_create:
-       mlxsw_sp_fib_destroy(mlxsw_sp, vr->fib4);
-       vr->fib4 = NULL;
+       mlxsw_sp_fib_destroy(mlxsw_sp, fib4);
        return ERR_PTR(err);
 }
 
@@ -1376,6 +1380,55 @@ mlxsw_sp_ipip_entry_ol_up_event(struct mlxsw_sp *mlxsw_sp,
                                                  decap_fib_entry);
 }
 
+static int
+mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif,
+                       struct mlxsw_sp_vr *ul_vr, bool enable)
+{
+       struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
+       struct mlxsw_sp_rif *rif = &lb_rif->common;
+       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
+       char ritr_pl[MLXSW_REG_RITR_LEN];
+       u32 saddr4;
+
+       switch (lb_cf.ul_protocol) {
+       case MLXSW_SP_L3_PROTO_IPV4:
+               saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
+               mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
+                                   rif->rif_index, rif->vr_id, rif->dev->mtu);
+               mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
+                           MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,
+                           ul_vr->id, saddr4, lb_cf.okey);
+               break;
+
+       case MLXSW_SP_L3_PROTO_IPV6:
+               return -EAFNOSUPPORT;
+       }
+
+       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
+}
+
+static int mlxsw_sp_netdevice_ipip_ol_update_mtu(struct mlxsw_sp *mlxsw_sp,
+                                                struct net_device *ol_dev)
+{
+       struct mlxsw_sp_ipip_entry *ipip_entry;
+       struct mlxsw_sp_rif_ipip_lb *lb_rif;
+       struct mlxsw_sp_vr *ul_vr;
+       int err = 0;
+
+       ipip_entry = mlxsw_sp_ipip_entry_find_by_ol_dev(mlxsw_sp, ol_dev);
+       if (ipip_entry) {
+               lb_rif = ipip_entry->ol_lb;
+               ul_vr = &mlxsw_sp->router->vrs[lb_rif->ul_vr_id];
+               err = mlxsw_sp_rif_ipip_lb_op(lb_rif, ul_vr, true);
+               if (err)
+                       goto out;
+               lb_rif->common.mtu = ol_dev->mtu;
+       }
+
+out:
+       return err;
+}
+
 static void mlxsw_sp_netdevice_ipip_ol_up_event(struct mlxsw_sp *mlxsw_sp,
                                                struct net_device *ol_dev)
 {
@@ -1656,6 +1709,8 @@ int mlxsw_sp_netdevice_ipip_ol_event(struct mlxsw_sp *mlxsw_sp,
                extack = info->extack;
                return mlxsw_sp_netdevice_ipip_ol_change_event(mlxsw_sp,
                                                               ol_dev, extack);
+       case NETDEV_CHANGEMTU:
+               return mlxsw_sp_netdevice_ipip_ol_update_mtu(mlxsw_sp, ol_dev);
        }
        return 0;
 }
@@ -3790,6 +3845,9 @@ mlxsw_sp_fib4_entry_offload_unset(struct mlxsw_sp_fib_entry *fib_entry)
        struct mlxsw_sp_nexthop_group *nh_grp = fib_entry->nh_group;
        int i;
 
+       if (!list_is_singular(&nh_grp->fib_list))
+               return;
+
        for (i = 0; i < nh_grp->count; i++) {
                struct mlxsw_sp_nexthop *nh = &nh_grp->nexthops[i];
 
@@ -6837,33 +6895,6 @@ mlxsw_sp_rif_ipip_lb_setup(struct mlxsw_sp_rif *rif,
 }
 
 static int
-mlxsw_sp_rif_ipip_lb_op(struct mlxsw_sp_rif_ipip_lb *lb_rif,
-                       struct mlxsw_sp_vr *ul_vr, bool enable)
-{
-       struct mlxsw_sp_rif_ipip_lb_config lb_cf = lb_rif->lb_config;
-       struct mlxsw_sp_rif *rif = &lb_rif->common;
-       struct mlxsw_sp *mlxsw_sp = rif->mlxsw_sp;
-       char ritr_pl[MLXSW_REG_RITR_LEN];
-       u32 saddr4;
-
-       switch (lb_cf.ul_protocol) {
-       case MLXSW_SP_L3_PROTO_IPV4:
-               saddr4 = be32_to_cpu(lb_cf.saddr.addr4);
-               mlxsw_reg_ritr_pack(ritr_pl, enable, MLXSW_REG_RITR_LOOPBACK_IF,
-                                   rif->rif_index, rif->vr_id, rif->dev->mtu);
-               mlxsw_reg_ritr_loopback_ipip4_pack(ritr_pl, lb_cf.lb_ipipt,
-                           MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,
-                           ul_vr->id, saddr4, lb_cf.okey);
-               break;
-
-       case MLXSW_SP_L3_PROTO_IPV6:
-               return -EAFNOSUPPORT;
-       }
-
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ritr), ritr_pl);
-}
-
-static int
 mlxsw_sp_rif_ipip_lb_configure(struct mlxsw_sp_rif *rif)
 {
        struct mlxsw_sp_rif_ipip_lb *lb_rif = mlxsw_sp_rif_ipip_lb_rif(rif);
index 593ad31..161bcdc 100644 (file)
@@ -1203,6 +1203,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                                     bool dynamic)
 {
        char *sfd_pl;
+       u8 num_rec;
        int err;
 
        sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
@@ -1212,9 +1213,16 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port,
        mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
        mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
                              mac, fid, action, local_port);
+       num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
-       kfree(sfd_pl);
+       if (err)
+               goto out;
+
+       if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
+               err = -EBUSY;
 
+out:
+       kfree(sfd_pl);
        return err;
 }
 
@@ -1239,6 +1247,7 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
                                       bool adding, bool dynamic)
 {
        char *sfd_pl;
+       u8 num_rec;
        int err;
 
        sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
@@ -1249,9 +1258,16 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id,
        mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic),
                                  mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP,
                                  lag_vid, lag_id);
+       num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
-       kfree(sfd_pl);
+       if (err)
+               goto out;
+
+       if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
+               err = -EBUSY;
 
+out:
+       kfree(sfd_pl);
        return err;
 }
 
@@ -1296,6 +1312,7 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
                                u16 fid, u16 mid_idx, bool adding)
 {
        char *sfd_pl;
+       u8 num_rec;
        int err;
 
        sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL);
@@ -1305,7 +1322,15 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr,
        mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0);
        mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid,
                              MLXSW_REG_SFD_REC_ACTION_NOP, mid_idx);
+       num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl);
        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl);
+       if (err)
+               goto out;
+
+       if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl))
+               err = -EBUSY;
+
+out:
        kfree(sfd_pl);
        return err;
 }
index a10ef50..017fb23 100644 (file)
@@ -1,16 +1,16 @@
 #
-# National Semi-conductor device configuration
+# National Semiconductor device configuration
 #
 
 config NET_VENDOR_NATSEMI
-       bool "National Semi-conductor devices"
+       bool "National Semiconductor devices"
        default y
        ---help---
          If you have a network (Ethernet) card belonging to this class, say Y.
 
          Note that the answer to this question doesn't directly affect the
          kernel: saying N will just cause the configurator to skip all
-         the questions about National Semi-conductor devices. If you say Y,
+         the questions about National Semiconductor devices. If you say Y,
          you will be asked for your specific card in the following questions.
 
 if NET_VENDOR_NATSEMI
index cc66497..a759aa0 100644 (file)
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 #
-# Makefile for the National Semi-conductor Sonic devices.
+# Makefile for the National Semiconductor Sonic devices.
 #
 
 obj-$(CONFIG_MACSONIC) += macsonic.o
index 56451ed..ecd7c33 100644 (file)
@@ -74,7 +74,9 @@ nfp_meta_has_prev(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
 
 static void nfp_prog_push(struct nfp_prog *nfp_prog, u64 insn)
 {
-       if (nfp_prog->__prog_alloc_len == nfp_prog->prog_len) {
+       if (nfp_prog->__prog_alloc_len / sizeof(u64) == nfp_prog->prog_len) {
+               pr_warn("instruction limit reached (%u NFP instructions)\n",
+                       nfp_prog->prog_len);
                nfp_prog->error = -ENOSPC;
                return;
        }
@@ -2463,6 +2465,8 @@ static int nfp_translate(struct nfp_prog *nfp_prog)
                err = cb(nfp_prog, meta);
                if (err)
                        return err;
+               if (nfp_prog->error)
+                       return nfp_prog->error;
 
                nfp_prog->n_translated++;
        }
index 6f546e8..00f41c1 100644 (file)
@@ -2480,7 +2480,10 @@ int qed_cxt_free_proto_ilt(struct qed_hwfn *p_hwfn, enum protocol_type proto)
        if (rc)
                return rc;
 
-       /* Free Task CXT */
+       /* Free Task CXT ( Intentionally RoCE as task-id is shared between
+        * RoCE and iWARP )
+        */
+       proto = PROTOCOLID_ROCE;
        rc = qed_cxt_free_ilt_range(p_hwfn, QED_ELEM_TASK, 0,
                                    qed_cxt_get_proto_tid_count(p_hwfn, proto));
        if (rc)
index ca4a81d..d5d02be 100644 (file)
@@ -1703,6 +1703,13 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
        iph = (struct iphdr *)((u8 *)(ethh) + eth_hlen);
 
        if (eth_type == ETH_P_IP) {
+               if (iph->protocol != IPPROTO_TCP) {
+                       DP_NOTICE(p_hwfn,
+                                 "Unexpected ip protocol on ll2 %x\n",
+                                 iph->protocol);
+                       return -EINVAL;
+               }
+
                cm_info->local_ip[0] = ntohl(iph->daddr);
                cm_info->remote_ip[0] = ntohl(iph->saddr);
                cm_info->ip_version = TCP_IPV4;
@@ -1711,6 +1718,14 @@ qed_iwarp_parse_rx_pkt(struct qed_hwfn *p_hwfn,
                *payload_len = ntohs(iph->tot_len) - ip_hlen;
        } else if (eth_type == ETH_P_IPV6) {
                ip6h = (struct ipv6hdr *)iph;
+
+               if (ip6h->nexthdr != IPPROTO_TCP) {
+                       DP_NOTICE(p_hwfn,
+                                 "Unexpected ip protocol on ll2 %x\n",
+                                 iph->protocol);
+                       return -EINVAL;
+               }
+
                for (i = 0; i < 4; i++) {
                        cm_info->local_ip[i] =
                            ntohl(ip6h->daddr.in6_u.u6_addr32[i]);
@@ -1928,8 +1943,8 @@ qed_iwarp_update_fpdu_length(struct qed_hwfn *p_hwfn,
                /* Missing lower byte is now available */
                mpa_len = fpdu->fpdu_length | *mpa_data;
                fpdu->fpdu_length = QED_IWARP_FPDU_LEN_WITH_PAD(mpa_len);
-               fpdu->mpa_frag_len = fpdu->fpdu_length;
                /* one byte of hdr */
+               fpdu->mpa_frag_len = 1;
                fpdu->incomplete_bytes = fpdu->fpdu_length - 1;
                DP_VERBOSE(p_hwfn,
                           QED_MSG_RDMA,
index 5d040b8..a411f9c 100644 (file)
@@ -379,6 +379,7 @@ static void qed_rdma_free(struct qed_hwfn *p_hwfn)
        DP_VERBOSE(p_hwfn, QED_MSG_RDMA, "Freeing RDMA\n");
 
        qed_rdma_free_reserved_lkey(p_hwfn);
+       qed_cxt_free_proto_ilt(p_hwfn, p_hwfn->p_rdma_info->proto);
        qed_rdma_resc_free(p_hwfn);
 }
 
index dafc079..1494130 100644 (file)
@@ -320,13 +320,11 @@ static inline void qede_update_tx_producer(struct qede_tx_queue *txq)
        barrier();
        writel(txq->tx_db.raw, txq->doorbell_addr);
 
-       /* mmiowb is needed to synchronize doorbell writes from more than one
-        * processor. It guarantees that the write arrives to the device before
-        * the queue lock is released and another start_xmit is called (possibly
-        * on another CPU). Without this barrier, the next doorbell can bypass
-        * this doorbell. This is applicable to IA64/Altix systems.
+       /* Fence required to flush the write combined buffer, since another
+        * CPU may write to the same doorbell address and data may be lost
+        * due to relaxed order nature of write combined bar.
         */
-       mmiowb();
+       wmb();
 }
 
 static int qede_xdp_xmit(struct qede_dev *edev, struct qede_fastpath *fp,
@@ -1249,16 +1247,10 @@ static int qede_rx_process_cqe(struct qede_dev *edev,
 
        csum_flag = qede_check_csum(parse_flag);
        if (unlikely(csum_flag == QEDE_CSUM_ERROR)) {
-               if (qede_pkt_is_ip_fragmented(fp_cqe, parse_flag)) {
+               if (qede_pkt_is_ip_fragmented(fp_cqe, parse_flag))
                        rxq->rx_ip_frags++;
-               } else {
-                       DP_NOTICE(edev,
-                                 "CQE has error, flags = %x, dropping incoming packet\n",
-                                 parse_flag);
+               else
                        rxq->rx_hw_errors++;
-                       qede_recycle_rx_bd_ring(rxq, fp_cqe->bd_num);
-                       return 0;
-               }
        }
 
        /* Basic validation passed; Need to prepare an SKB. This would also
index 2db70ea..a01e7d6 100644 (file)
@@ -288,7 +288,7 @@ int __init qede_init(void)
        }
 
        /* Must register notifier before pci ops, since we might miss
-        * interface rename after pci probe and netdev registeration.
+        * interface rename after pci probe and netdev registration.
         */
        ret = register_netdevice_notifier(&qede_netdev_notifier);
        if (ret) {
@@ -988,7 +988,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
        if (rc)
                goto err3;
 
-       /* Prepare the lock prior to the registeration of the netdev,
+       /* Prepare the lock prior to the registration of the netdev,
         * as once it's registered we might reach flows requiring it
         * [it's even possible to reach a flow needing it directly
         * from there, although it's unlikely].
@@ -2067,8 +2067,6 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode,
        link_params.link_up = true;
        edev->ops->common->set_link(edev->cdev, &link_params);
 
-       qede_rdma_dev_event_open(edev);
-
        edev->state = QEDE_STATE_OPEN;
 
        DP_INFO(edev, "Ending successfully qede load\n");
@@ -2169,12 +2167,14 @@ static void qede_link_update(void *dev, struct qed_link_output *link)
                        DP_NOTICE(edev, "Link is up\n");
                        netif_tx_start_all_queues(edev->ndev);
                        netif_carrier_on(edev->ndev);
+                       qede_rdma_dev_event_open(edev);
                }
        } else {
                if (netif_carrier_ok(edev->ndev)) {
                        DP_NOTICE(edev, "Link is down\n");
                        netif_tx_disable(edev->ndev);
                        netif_carrier_off(edev->ndev);
+                       qede_rdma_dev_event_close(edev);
                }
        }
 }
index 9b2280b..02adb51 100644 (file)
@@ -485,7 +485,7 @@ int qede_ptp_enable(struct qede_dev *edev, bool init_tc)
        ptp->clock = ptp_clock_register(&ptp->clock_info, &edev->pdev->dev);
        if (IS_ERR(ptp->clock)) {
                rc = -EINVAL;
-               DP_ERR(edev, "PTP clock registeration failed\n");
+               DP_ERR(edev, "PTP clock registration failed\n");
                goto err2;
        }
 
index 9cbb272..d5a32b7 100644 (file)
@@ -1194,9 +1194,9 @@ void emac_mac_tx_process(struct emac_adapter *adpt, struct emac_tx_queue *tx_q)
        while (tx_q->tpd.consume_idx != hw_consume_idx) {
                tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.consume_idx);
                if (tpbuf->dma_addr) {
-                       dma_unmap_single(adpt->netdev->dev.parent,
-                                        tpbuf->dma_addr, tpbuf->length,
-                                        DMA_TO_DEVICE);
+                       dma_unmap_page(adpt->netdev->dev.parent,
+                                      tpbuf->dma_addr, tpbuf->length,
+                                      DMA_TO_DEVICE);
                        tpbuf->dma_addr = 0;
                }
 
@@ -1353,9 +1353,11 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt,
 
                tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
                tpbuf->length = mapped_len;
-               tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent,
-                                                skb->data, tpbuf->length,
-                                                DMA_TO_DEVICE);
+               tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent,
+                                              virt_to_page(skb->data),
+                                              offset_in_page(skb->data),
+                                              tpbuf->length,
+                                              DMA_TO_DEVICE);
                ret = dma_mapping_error(adpt->netdev->dev.parent,
                                        tpbuf->dma_addr);
                if (ret)
@@ -1371,9 +1373,12 @@ static void emac_tx_fill_tpd(struct emac_adapter *adpt,
        if (mapped_len < len) {
                tpbuf = GET_TPD_BUFFER(tx_q, tx_q->tpd.produce_idx);
                tpbuf->length = len - mapped_len;
-               tpbuf->dma_addr = dma_map_single(adpt->netdev->dev.parent,
-                                                skb->data + mapped_len,
-                                                tpbuf->length, DMA_TO_DEVICE);
+               tpbuf->dma_addr = dma_map_page(adpt->netdev->dev.parent,
+                                              virt_to_page(skb->data +
+                                                           mapped_len),
+                                              offset_in_page(skb->data +
+                                                             mapped_len),
+                                              tpbuf->length, DMA_TO_DEVICE);
                ret = dma_mapping_error(adpt->netdev->dev.parent,
                                        tpbuf->dma_addr);
                if (ret)
index 7e7704d..c494918 100644 (file)
 
 /* Local Definitions and Declarations */
 
-struct rmnet_walk_data {
-       struct net_device *real_dev;
-       struct list_head *head;
-       struct rmnet_port *port;
-};
-
 static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
 {
        return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler;
@@ -112,17 +106,14 @@ static int rmnet_register_real_device(struct net_device *real_dev)
 static void rmnet_unregister_bridge(struct net_device *dev,
                                    struct rmnet_port *port)
 {
-       struct net_device *rmnet_dev, *bridge_dev;
        struct rmnet_port *bridge_port;
+       struct net_device *bridge_dev;
 
        if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
                return;
 
        /* bridge slave handling */
        if (!port->nr_rmnet_devs) {
-               rmnet_dev = netdev_master_upper_dev_get_rcu(dev);
-               netdev_upper_dev_unlink(dev, rmnet_dev);
-
                bridge_dev = port->bridge_ep;
 
                bridge_port = rmnet_get_port_rtnl(bridge_dev);
@@ -132,9 +123,6 @@ static void rmnet_unregister_bridge(struct net_device *dev,
                bridge_dev = port->bridge_ep;
 
                bridge_port = rmnet_get_port_rtnl(bridge_dev);
-               rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev);
-               netdev_upper_dev_unlink(bridge_dev, rmnet_dev);
-
                rmnet_unregister_real_device(bridge_dev, bridge_port);
        }
 }
@@ -173,10 +161,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
        if (err)
                goto err1;
 
-       err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack);
-       if (err)
-               goto err2;
-
        port->rmnet_mode = mode;
 
        hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
@@ -193,8 +177,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
 
        return 0;
 
-err2:
-       rmnet_vnd_dellink(mux_id, port, ep);
 err1:
        rmnet_unregister_real_device(real_dev, port);
 err0:
@@ -204,14 +186,13 @@ err0:
 
 static void rmnet_dellink(struct net_device *dev, struct list_head *head)
 {
+       struct rmnet_priv *priv = netdev_priv(dev);
        struct net_device *real_dev;
        struct rmnet_endpoint *ep;
        struct rmnet_port *port;
        u8 mux_id;
 
-       rcu_read_lock();
-       real_dev = netdev_master_upper_dev_get_rcu(dev);
-       rcu_read_unlock();
+       real_dev = priv->real_dev;
 
        if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
                return;
@@ -219,7 +200,6 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
        port = rmnet_get_port_rtnl(real_dev);
 
        mux_id = rmnet_vnd_get_mux(dev);
-       netdev_upper_dev_unlink(dev, real_dev);
 
        ep = rmnet_get_endpoint(port, mux_id);
        if (ep) {
@@ -233,30 +213,13 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
        unregister_netdevice_queue(dev, head);
 }
 
-static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data)
-{
-       struct rmnet_walk_data *d = data;
-       struct rmnet_endpoint *ep;
-       u8 mux_id;
-
-       mux_id = rmnet_vnd_get_mux(rmnet_dev);
-       ep = rmnet_get_endpoint(d->port, mux_id);
-       if (ep) {
-               hlist_del_init_rcu(&ep->hlnode);
-               rmnet_vnd_dellink(mux_id, d->port, ep);
-               kfree(ep);
-       }
-       netdev_upper_dev_unlink(rmnet_dev, d->real_dev);
-       unregister_netdevice_queue(rmnet_dev, d->head);
-
-       return 0;
-}
-
 static void rmnet_force_unassociate_device(struct net_device *dev)
 {
        struct net_device *real_dev = dev;
-       struct rmnet_walk_data d;
+       struct hlist_node *tmp_ep;
+       struct rmnet_endpoint *ep;
        struct rmnet_port *port;
+       unsigned long bkt_ep;
        LIST_HEAD(list);
 
        if (!rmnet_is_real_dev_registered(real_dev))
@@ -264,16 +227,19 @@ static void rmnet_force_unassociate_device(struct net_device *dev)
 
        ASSERT_RTNL();
 
-       d.real_dev = real_dev;
-       d.head = &list;
-
        port = rmnet_get_port_rtnl(dev);
-       d.port = port;
 
        rcu_read_lock();
        rmnet_unregister_bridge(dev, port);
 
-       netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d);
+       hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
+               unregister_netdevice_queue(ep->egress_dev, &list);
+               rmnet_vnd_dellink(ep->mux_id, port, ep);
+
+               hlist_del_init_rcu(&ep->hlnode);
+               kfree(ep);
+       }
+
        rcu_read_unlock();
        unregister_netdevice_many(&list);
 
@@ -422,11 +388,6 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
        if (err)
                return -EBUSY;
 
-       err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
-                                          extack);
-       if (err)
-               return -EINVAL;
-
        slave_port = rmnet_get_port(slave_dev);
        slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
        slave_port->bridge_ep = real_dev;
@@ -449,7 +410,6 @@ int rmnet_del_bridge(struct net_device *rmnet_dev,
        port->rmnet_mode = RMNET_EPMODE_VND;
        port->bridge_ep = NULL;
 
-       netdev_upper_dev_unlink(slave_dev, rmnet_dev);
        slave_port = rmnet_get_port(slave_dev);
        rmnet_unregister_real_device(slave_dev, slave_port);
 
index 6bc328f..b0dbca0 100644 (file)
@@ -38,6 +38,11 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
        }
 
        ep = rmnet_get_endpoint(port, mux_id);
+       if (!ep) {
+               kfree_skb(skb);
+               return RX_HANDLER_CONSUMED;
+       }
+
        vnd = ep->egress_dev;
 
        ip_family = cmd->flow_control.ip_family;
index 570a227..346d310 100644 (file)
@@ -121,7 +121,7 @@ static void rmnet_get_stats64(struct net_device *dev,
        memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats));
 
        for_each_possible_cpu(cpu) {
-               pcpu_ptr = this_cpu_ptr(priv->pcpu_stats);
+               pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu);
 
                do {
                        start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp);
index 0bf7d17..b4779ac 100644 (file)
@@ -8660,12 +8660,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (!tp->counters)
                return -ENOMEM;
 
+       pci_set_drvdata(pdev, dev);
+
        rc = register_netdev(dev);
        if (rc < 0)
                return rc;
 
-       pci_set_drvdata(pdev, dev);
-
        netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n",
                   rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr,
                   (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq);
index c87f57c..a95fbd5 100644 (file)
@@ -2255,9 +2255,6 @@ static int ravb_wol_setup(struct net_device *ndev)
        /* Enable MagicPacket */
        ravb_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
 
-       /* Increased clock usage so device won't be suspended */
-       clk_enable(priv->clk);
-
        return enable_irq_wake(priv->emac_irq);
 }
 
@@ -2276,9 +2273,6 @@ static int ravb_wol_restore(struct net_device *ndev)
        if (ret < 0)
                return ret;
 
-       /* Restore clock usage count */
-       clk_disable(priv->clk);
-
        return disable_irq_wake(priv->emac_irq);
 }
 
index a197e11..14c839b 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/slab.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
-#include <linux/clk.h>
 #include <linux/sh_eth.h>
 #include <linux/of_mdio.h>
 
@@ -440,6 +439,17 @@ static void sh_eth_modify(struct net_device *ndev, int enum_index, u32 clear,
                     enum_index);
 }
 
+static void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data,
+                            int enum_index)
+{
+       iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
+}
+
+static u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index)
+{
+       return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]);
+}
+
 static bool sh_eth_is_gether(struct sh_eth_private *mdp)
 {
        return mdp->reg_offset == sh_eth_offset_gigabit;
@@ -2304,7 +2314,7 @@ static void sh_eth_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
        wol->supported = 0;
        wol->wolopts = 0;
 
-       if (mdp->cd->magic && mdp->clk) {
+       if (mdp->cd->magic) {
                wol->supported = WAKE_MAGIC;
                wol->wolopts = mdp->wol_enabled ? WAKE_MAGIC : 0;
        }
@@ -2314,7 +2324,7 @@ static int sh_eth_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
 {
        struct sh_eth_private *mdp = netdev_priv(ndev);
 
-       if (!mdp->cd->magic || !mdp->clk || wol->wolopts & ~WAKE_MAGIC)
+       if (!mdp->cd->magic || wol->wolopts & ~WAKE_MAGIC)
                return -EOPNOTSUPP;
 
        mdp->wol_enabled = !!(wol->wolopts & WAKE_MAGIC);
@@ -3153,11 +3163,6 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
                goto out_release;
        }
 
-       /* Get clock, if not found that's OK but Wake-On-Lan is unavailable */
-       mdp->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(mdp->clk))
-               mdp->clk = NULL;
-
        ndev->base_addr = res->start;
 
        spin_lock_init(&mdp->lock);
@@ -3278,7 +3283,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
        if (ret)
                goto out_napi_del;
 
-       if (mdp->cd->magic && mdp->clk)
+       if (mdp->cd->magic)
                device_set_wakeup_capable(&pdev->dev, 1);
 
        /* print device information */
@@ -3331,9 +3336,6 @@ static int sh_eth_wol_setup(struct net_device *ndev)
        /* Enable MagicPacket */
        sh_eth_modify(ndev, ECMR, ECMR_MPDE, ECMR_MPDE);
 
-       /* Increased clock usage so device won't be suspended */
-       clk_enable(mdp->clk);
-
        return enable_irq_wake(ndev->irq);
 }
 
@@ -3359,9 +3361,6 @@ static int sh_eth_wol_restore(struct net_device *ndev)
        if (ret < 0)
                return ret;
 
-       /* Restore clock usage count */
-       clk_disable(mdp->clk);
-
        return disable_irq_wake(ndev->irq);
 }
 
index a6753cc..e5fe701 100644 (file)
@@ -567,15 +567,4 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,
        return mdp->tsu_addr + mdp->reg_offset[enum_index];
 }
 
-static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data,
-                                   int enum_index)
-{
-       iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
-}
-
-static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index)
-{
-       return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]);
-}
-
 #endif /* #ifndef __SH_ETH_H__ */
index 63aca9f..4c2f612 100644 (file)
@@ -20,7 +20,7 @@ if NET_VENDOR_SMSC
 
 config SMC9194
        tristate "SMC 9194 support"
-       depends on (ISA || MAC && BROKEN)
+       depends on ISA
        select CRC32
        ---help---
          This is support for the SMC9xxx based Ethernet cards. Choose this
index 012fb66..f0afb88 100644 (file)
@@ -2335,14 +2335,14 @@ static int smsc911x_drv_remove(struct platform_device *pdev)
        pdata = netdev_priv(dev);
        BUG_ON(!pdata);
        BUG_ON(!pdata->ioaddr);
-       WARN_ON(dev->phydev);
 
        SMSC_TRACE(pdata, ifdown, "Stopping driver");
 
+       unregister_netdev(dev);
+
        mdiobus_unregister(pdata->mii_bus);
        mdiobus_free(pdata->mii_bus);
 
-       unregister_netdev(dev);
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
                                           "smsc911x-memory");
        if (!res)
index 111e7ca..f5c5984 100644 (file)
@@ -1295,7 +1295,7 @@ static int ave_open(struct net_device *ndev)
        val |= AVE_IIRQC_EN0 | (AVE_INTM_COUNT << 16);
        writel(val, priv->base + AVE_IIRQC);
 
-       val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX;
+       val = AVE_GI_RXIINT | AVE_GI_RXOVF | AVE_GI_TX | AVE_GI_RXDROP;
        ave_irq_restore(ndev, val);
 
        napi_enable(&priv->napi_rx);
index 63d3d6b..a94f504 100644 (file)
@@ -312,7 +312,7 @@ static struct vnet *vnet_new(const u64 *local_mac,
        dev->ethtool_ops = &vnet_ethtool_ops;
        dev->watchdog_timeo = VNET_TX_TIMEOUT;
 
-       dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_GSO_SOFTWARE |
+       dev->hw_features = NETIF_F_TSO | NETIF_F_GSO | NETIF_F_ALL_TSO |
                           NETIF_F_HW_CSUM | NETIF_F_SG;
        dev->features = dev->hw_features;
 
index 1b1b78f..b2b30c9 100644 (file)
@@ -1014,7 +1014,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave,
                /* set speed_in input in case RMII mode is used in 100Mbps */
                if (phy->speed == 100)
                        mac_control |= BIT(15);
-               else if (phy->speed == 10)
+               /* in band mode only works in 10Mbps RGMII mode */
+               else if ((phy->speed == 10) && phy_interface_is_rgmii(phy))
                        mac_control |= BIT(18); /* In Band mode */
 
                if (priv->rx_pause)
index 0db3bd1..3286103 100644 (file)
@@ -173,6 +173,7 @@ struct rndis_device {
        struct list_head req_list;
 
        struct work_struct mcast_work;
+       u32 filter;
 
        bool link_state;        /* 0 - link up, 1 - link down */
 
@@ -211,7 +212,6 @@ void netvsc_channel_cb(void *context);
 int netvsc_poll(struct napi_struct *napi, int budget);
 
 void rndis_set_subchannel(struct work_struct *w);
-bool rndis_filter_opened(const struct netvsc_device *nvdev);
 int rndis_filter_open(struct netvsc_device *nvdev);
 int rndis_filter_close(struct netvsc_device *nvdev);
 struct netvsc_device *rndis_filter_device_add(struct hv_device *dev,
index 17e529a..7472172 100644 (file)
@@ -90,6 +90,11 @@ static void free_netvsc_device(struct rcu_head *head)
                = container_of(head, struct netvsc_device, rcu);
        int i;
 
+       kfree(nvdev->extension);
+       vfree(nvdev->recv_buf);
+       vfree(nvdev->send_buf);
+       kfree(nvdev->send_section_map);
+
        for (i = 0; i < VRSS_CHANNEL_MAX; i++)
                vfree(nvdev->chan_table[i].mrc.slots);
 
@@ -211,12 +216,6 @@ static void netvsc_teardown_gpadl(struct hv_device *device,
                net_device->recv_buf_gpadl_handle = 0;
        }
 
-       if (net_device->recv_buf) {
-               /* Free up the receive buffer */
-               vfree(net_device->recv_buf);
-               net_device->recv_buf = NULL;
-       }
-
        if (net_device->send_buf_gpadl_handle) {
                ret = vmbus_teardown_gpadl(device->channel,
                                           net_device->send_buf_gpadl_handle);
@@ -231,12 +230,6 @@ static void netvsc_teardown_gpadl(struct hv_device *device,
                }
                net_device->send_buf_gpadl_handle = 0;
        }
-       if (net_device->send_buf) {
-               /* Free up the send buffer */
-               vfree(net_device->send_buf);
-               net_device->send_buf = NULL;
-       }
-       kfree(net_device->send_section_map);
 }
 
 int netvsc_alloc_recv_comp_ring(struct netvsc_device *net_device, u32 q_idx)
@@ -562,26 +555,29 @@ void netvsc_device_remove(struct hv_device *device)
                = rtnl_dereference(net_device_ctx->nvdev);
        int i;
 
-       cancel_work_sync(&net_device->subchan_work);
-
        netvsc_revoke_buf(device, net_device);
 
        RCU_INIT_POINTER(net_device_ctx->nvdev, NULL);
 
+       /* And disassociate NAPI context from device */
+       for (i = 0; i < net_device->num_chn; i++)
+               netif_napi_del(&net_device->chan_table[i].napi);
+
        /*
         * At this point, no one should be accessing net_device
         * except in here
         */
        netdev_dbg(ndev, "net device safe to remove\n");
 
+       /* older versions require that buffer be revoked before close */
+       if (net_device->nvsp_version < NVSP_PROTOCOL_VERSION_4)
+               netvsc_teardown_gpadl(device, net_device);
+
        /* Now, we can close the channel safely */
        vmbus_close(device->channel);
 
-       netvsc_teardown_gpadl(device, net_device);
-
-       /* And dissassociate NAPI context from device */
-       for (i = 0; i < net_device->num_chn; i++)
-               netif_napi_del(&net_device->chan_table[i].napi);
+       if (net_device->nvsp_version >= NVSP_PROTOCOL_VERSION_4)
+               netvsc_teardown_gpadl(device, net_device);
 
        /* Release all resources */
        free_netvsc_device_rcu(net_device);
@@ -645,14 +641,18 @@ static void netvsc_send_tx_complete(struct netvsc_device *net_device,
        queue_sends =
                atomic_dec_return(&net_device->chan_table[q_idx].queue_sends);
 
-       if (net_device->destroy && queue_sends == 0)
-               wake_up(&net_device->wait_drain);
+       if (unlikely(net_device->destroy)) {
+               if (queue_sends == 0)
+                       wake_up(&net_device->wait_drain);
+       } else {
+               struct netdev_queue *txq = netdev_get_tx_queue(ndev, q_idx);
 
-       if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
-           (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER ||
-            queue_sends < 1)) {
-               netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
-               ndev_ctx->eth_stats.wake_queue++;
+               if (netif_tx_queue_stopped(txq) &&
+                   (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER ||
+                    queue_sends < 1)) {
+                       netif_tx_wake_queue(txq);
+                       ndev_ctx->eth_stats.wake_queue++;
+               }
        }
 }
 
@@ -852,13 +852,6 @@ int netvsc_send(struct net_device *ndev,
        if (unlikely(!net_device || net_device->destroy))
                return -ENODEV;
 
-       /* We may race with netvsc_connect_vsp()/netvsc_init_buf() and get
-        * here before the negotiation with the host is finished and
-        * send_section_map may not be allocated yet.
-        */
-       if (unlikely(!net_device->send_section_map))
-               return -EAGAIN;
-
        nvchan = &net_device->chan_table[packet->q_idx];
        packet->send_buf_index = NETVSC_INVALID_INDEX;
        packet->cp_partial = false;
@@ -866,10 +859,8 @@ int netvsc_send(struct net_device *ndev,
        /* Send control message directly without accessing msd (Multi-Send
         * Data) field which may be changed during data packet processing.
         */
-       if (!skb) {
-               cur_send = packet;
-               goto send_now;
-       }
+       if (!skb)
+               return netvsc_send_pkt(device, packet, net_device, pb, skb);
 
        /* batch packets in send buffer if possible */
        msdp = &nvchan->msd;
@@ -953,7 +944,6 @@ int netvsc_send(struct net_device *ndev,
                }
        }
 
-send_now:
        if (cur_send)
                ret = netvsc_send_pkt(device, cur_send, net_device, pb, skb);
 
@@ -1217,9 +1207,10 @@ int netvsc_poll(struct napi_struct *napi, int budget)
        if (send_recv_completions(ndev, net_device, nvchan) == 0 &&
            work_done < budget &&
            napi_complete_done(napi, work_done) &&
-           hv_end_read(&channel->inbound)) {
+           hv_end_read(&channel->inbound) &&
+           napi_schedule_prep(napi)) {
                hv_begin_read(&channel->inbound);
-               napi_reschedule(napi);
+               __napi_schedule(napi);
        }
 
        /* Driver may overshoot since multiple packets per descriptor */
@@ -1242,7 +1233,7 @@ void netvsc_channel_cb(void *context)
                /* disable interupts from host */
                hv_begin_read(rbi);
 
-               __napi_schedule(&nvchan->napi);
+               __napi_schedule_irqoff(&nvchan->napi);
        }
 }
 
@@ -1296,7 +1287,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
                         netvsc_channel_cb, net_device->chan_table);
 
        if (ret != 0) {
-               netif_napi_del(&net_device->chan_table[0].napi);
                netdev_err(ndev, "unable to open channel: %d\n", ret);
                goto cleanup;
        }
@@ -1306,11 +1296,6 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
 
        napi_enable(&net_device->chan_table[0].napi);
 
-       /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
-        * populated.
-        */
-       rcu_assign_pointer(net_device_ctx->nvdev, net_device);
-
        /* Connect with the NetVsp */
        ret = netvsc_connect_vsp(device, net_device, device_info);
        if (ret != 0) {
@@ -1319,6 +1304,11 @@ struct netvsc_device *netvsc_device_add(struct hv_device *device,
                goto close;
        }
 
+       /* Writing nvdev pointer unlocks netvsc_send(), make sure chn_table is
+        * populated.
+        */
+       rcu_assign_pointer(net_device_ctx->nvdev, net_device);
+
        return net_device;
 
 close:
@@ -1329,6 +1319,7 @@ close:
        vmbus_close(device->channel);
 
 cleanup:
+       netif_napi_del(&net_device->chan_table[0].napi);
        free_netvsc_device(&net_device->rcu);
 
        return ERR_PTR(ret);
index c5584c2..f28c85d 100644 (file)
 
 #include "hyperv_net.h"
 
-#define RING_SIZE_MIN          64
+#define RING_SIZE_MIN  64
+#define RETRY_US_LO    5000
+#define RETRY_US_HI    10000
+#define RETRY_MAX      2000    /* >10 sec */
 
 #define LINKCHANGE_INT (2 * HZ)
 #define VF_TAKEOVER_INT (HZ / 10)
@@ -66,12 +69,43 @@ static int debug = -1;
 module_param(debug, int, S_IRUGO);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
-static void netvsc_set_multicast_list(struct net_device *net)
+static void netvsc_change_rx_flags(struct net_device *net, int change)
 {
-       struct net_device_context *net_device_ctx = netdev_priv(net);
-       struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
+       struct net_device_context *ndev_ctx = netdev_priv(net);
+       struct net_device *vf_netdev = rtnl_dereference(ndev_ctx->vf_netdev);
+       int inc;
+
+       if (!vf_netdev)
+               return;
+
+       if (change & IFF_PROMISC) {
+               inc = (net->flags & IFF_PROMISC) ? 1 : -1;
+               dev_set_promiscuity(vf_netdev, inc);
+       }
+
+       if (change & IFF_ALLMULTI) {
+               inc = (net->flags & IFF_ALLMULTI) ? 1 : -1;
+               dev_set_allmulti(vf_netdev, inc);
+       }
+}
 
-       rndis_filter_update(nvdev);
+static void netvsc_set_rx_mode(struct net_device *net)
+{
+       struct net_device_context *ndev_ctx = netdev_priv(net);
+       struct net_device *vf_netdev;
+       struct netvsc_device *nvdev;
+
+       rcu_read_lock();
+       vf_netdev = rcu_dereference(ndev_ctx->vf_netdev);
+       if (vf_netdev) {
+               dev_uc_sync(vf_netdev, net);
+               dev_mc_sync(vf_netdev, net);
+       }
+
+       nvdev = rcu_dereference(ndev_ctx->nvdev);
+       if (nvdev)
+               rndis_filter_update(nvdev);
+       rcu_read_unlock();
 }
 
 static int netvsc_open(struct net_device *net)
@@ -91,10 +125,7 @@ static int netvsc_open(struct net_device *net)
                return ret;
        }
 
-       netif_tx_wake_all_queues(net);
-
        rdev = nvdev->extension;
-
        if (!rdev->link_state)
                netif_carrier_on(net);
 
@@ -112,36 +143,25 @@ static int netvsc_open(struct net_device *net)
        return 0;
 }
 
-static int netvsc_close(struct net_device *net)
+static int netvsc_wait_until_empty(struct netvsc_device *nvdev)
 {
-       struct net_device_context *net_device_ctx = netdev_priv(net);
-       struct net_device *vf_netdev
-               = rtnl_dereference(net_device_ctx->vf_netdev);
-       struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
-       int ret = 0;
-       u32 aread, i, msec = 10, retry = 0, retry_max = 20;
-       struct vmbus_channel *chn;
-
-       netif_tx_disable(net);
-
-       /* No need to close rndis filter if it is removed already */
-       if (!nvdev)
-               goto out;
-
-       ret = rndis_filter_close(nvdev);
-       if (ret != 0) {
-               netdev_err(net, "unable to close device (ret %d).\n", ret);
-               return ret;
-       }
+       unsigned int retry = 0;
+       int i;
 
        /* Ensure pending bytes in ring are read */
-       while (true) {
-               aread = 0;
+       for (;;) {
+               u32 aread = 0;
+
                for (i = 0; i < nvdev->num_chn; i++) {
-                       chn = nvdev->chan_table[i].channel;
+                       struct vmbus_channel *chn
+                               = nvdev->chan_table[i].channel;
+
                        if (!chn)
                                continue;
 
+                       /* make sure receive not running now */
+                       napi_synchronize(&nvdev->chan_table[i].napi);
+
                        aread = hv_get_bytes_to_read(&chn->inbound);
                        if (aread)
                                break;
@@ -151,22 +171,40 @@ static int netvsc_close(struct net_device *net)
                                break;
                }
 
-               retry++;
-               if (retry > retry_max || aread == 0)
-                       break;
+               if (aread == 0)
+                       return 0;
 
-               msleep(msec);
+               if (++retry > RETRY_MAX)
+                       return -ETIMEDOUT;
 
-               if (msec < 1000)
-                       msec *= 2;
+               usleep_range(RETRY_US_LO, RETRY_US_HI);
        }
+}
 
-       if (aread) {
-               netdev_err(net, "Ring buffer not empty after closing rndis\n");
-               ret = -ETIMEDOUT;
+static int netvsc_close(struct net_device *net)
+{
+       struct net_device_context *net_device_ctx = netdev_priv(net);
+       struct net_device *vf_netdev
+               = rtnl_dereference(net_device_ctx->vf_netdev);
+       struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
+       int ret;
+
+       netif_tx_disable(net);
+
+       /* No need to close rndis filter if it is removed already */
+       if (!nvdev)
+               return 0;
+
+       ret = rndis_filter_close(nvdev);
+       if (ret != 0) {
+               netdev_err(net, "unable to close device (ret %d).\n", ret);
+               return ret;
        }
 
-out:
+       ret = netvsc_wait_until_empty(nvdev);
+       if (ret)
+               netdev_err(net, "Ring buffer not empty after closing rndis\n");
+
        if (vf_netdev)
                dev_close(vf_netdev);
 
@@ -299,8 +337,19 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
        rcu_read_lock();
        vf_netdev = rcu_dereference(ndc->vf_netdev);
        if (vf_netdev) {
-               txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) : 0;
-               qdisc_skb_cb(skb)->slave_dev_queue_mapping = skb->queue_mapping;
+               const struct net_device_ops *vf_ops = vf_netdev->netdev_ops;
+
+               if (vf_ops->ndo_select_queue)
+                       txq = vf_ops->ndo_select_queue(vf_netdev, skb,
+                                                      accel_priv, fallback);
+               else
+                       txq = fallback(vf_netdev, skb);
+
+               /* Record the queue selected by VF so that it can be
+                * used for common case where VF has more queues than
+                * the synthetic device.
+                */
+               qdisc_skb_cb(skb)->slave_dev_queue_mapping = txq;
        } else {
                txq = netvsc_pick_tx(ndev, skb);
        }
@@ -804,16 +853,81 @@ static void netvsc_get_channels(struct net_device *net,
        }
 }
 
+static int netvsc_detach(struct net_device *ndev,
+                        struct netvsc_device *nvdev)
+{
+       struct net_device_context *ndev_ctx = netdev_priv(ndev);
+       struct hv_device *hdev = ndev_ctx->device_ctx;
+       int ret;
+
+       /* Don't try continuing to try and setup sub channels */
+       if (cancel_work_sync(&nvdev->subchan_work))
+               nvdev->num_chn = 1;
+
+       /* If device was up (receiving) then shutdown */
+       if (netif_running(ndev)) {
+               netif_tx_disable(ndev);
+
+               ret = rndis_filter_close(nvdev);
+               if (ret) {
+                       netdev_err(ndev,
+                                  "unable to close device (ret %d).\n", ret);
+                       return ret;
+               }
+
+               ret = netvsc_wait_until_empty(nvdev);
+               if (ret) {
+                       netdev_err(ndev,
+                                  "Ring buffer not empty after closing rndis\n");
+                       return ret;
+               }
+       }
+
+       netif_device_detach(ndev);
+
+       rndis_filter_device_remove(hdev, nvdev);
+
+       return 0;
+}
+
+static int netvsc_attach(struct net_device *ndev,
+                        struct netvsc_device_info *dev_info)
+{
+       struct net_device_context *ndev_ctx = netdev_priv(ndev);
+       struct hv_device *hdev = ndev_ctx->device_ctx;
+       struct netvsc_device *nvdev;
+       struct rndis_device *rdev;
+       int ret;
+
+       nvdev = rndis_filter_device_add(hdev, dev_info);
+       if (IS_ERR(nvdev))
+               return PTR_ERR(nvdev);
+
+       /* Note: enable and attach happen when sub-channels setup */
+
+       netif_carrier_off(ndev);
+
+       if (netif_running(ndev)) {
+               ret = rndis_filter_open(nvdev);
+               if (ret)
+                       return ret;
+
+               rdev = nvdev->extension;
+               if (!rdev->link_state)
+                       netif_carrier_on(ndev);
+       }
+
+       return 0;
+}
+
 static int netvsc_set_channels(struct net_device *net,
                               struct ethtool_channels *channels)
 {
        struct net_device_context *net_device_ctx = netdev_priv(net);
-       struct hv_device *dev = net_device_ctx->device_ctx;
        struct netvsc_device *nvdev = rtnl_dereference(net_device_ctx->nvdev);
        unsigned int orig, count = channels->combined_count;
        struct netvsc_device_info device_info;
-       bool was_opened;
-       int ret = 0;
+       int ret;
 
        /* We do not support separate count for rx, tx, or other */
        if (count == 0 ||
@@ -830,9 +944,6 @@ static int netvsc_set_channels(struct net_device *net,
                return -EINVAL;
 
        orig = nvdev->num_chn;
-       was_opened = rndis_filter_opened(nvdev);
-       if (was_opened)
-               rndis_filter_close(nvdev);
 
        memset(&device_info, 0, sizeof(device_info));
        device_info.num_chn = count;
@@ -841,28 +952,17 @@ static int netvsc_set_channels(struct net_device *net,
        device_info.recv_sections = nvdev->recv_section_cnt;
        device_info.recv_section_size = nvdev->recv_section_size;
 
-       rndis_filter_device_remove(dev, nvdev);
+       ret = netvsc_detach(net, nvdev);
+       if (ret)
+               return ret;
 
-       nvdev = rndis_filter_device_add(dev, &device_info);
-       if (IS_ERR(nvdev)) {
-               ret = PTR_ERR(nvdev);
+       ret = netvsc_attach(net, &device_info);
+       if (ret) {
                device_info.num_chn = orig;
-               nvdev = rndis_filter_device_add(dev, &device_info);
-
-               if (IS_ERR(nvdev)) {
-                       netdev_err(net, "restoring channel setting failed: %ld\n",
-                                  PTR_ERR(nvdev));
-                       return ret;
-               }
+               if (netvsc_attach(net, &device_info))
+                       netdev_err(net, "restoring channel setting failed\n");
        }
 
-       if (was_opened)
-               rndis_filter_open(nvdev);
-
-       /* We may have missed link change notifications */
-       net_device_ctx->last_reconfig = 0;
-       schedule_delayed_work(&net_device_ctx->dwork, 0);
-
        return ret;
 }
 
@@ -928,10 +1028,8 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        struct net_device_context *ndevctx = netdev_priv(ndev);
        struct net_device *vf_netdev = rtnl_dereference(ndevctx->vf_netdev);
        struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
-       struct hv_device *hdev = ndevctx->device_ctx;
        int orig_mtu = ndev->mtu;
        struct netvsc_device_info device_info;
-       bool was_opened;
        int ret = 0;
 
        if (!nvdev || nvdev->destroy)
@@ -944,11 +1042,6 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
                        return ret;
        }
 
-       netif_device_detach(ndev);
-       was_opened = rndis_filter_opened(nvdev);
-       if (was_opened)
-               rndis_filter_close(nvdev);
-
        memset(&device_info, 0, sizeof(device_info));
        device_info.num_chn = nvdev->num_chn;
        device_info.send_sections = nvdev->send_section_cnt;
@@ -956,35 +1049,27 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu)
        device_info.recv_sections = nvdev->recv_section_cnt;
        device_info.recv_section_size = nvdev->recv_section_size;
 
-       rndis_filter_device_remove(hdev, nvdev);
+       ret = netvsc_detach(ndev, nvdev);
+       if (ret)
+               goto rollback_vf;
 
        ndev->mtu = mtu;
 
-       nvdev = rndis_filter_device_add(hdev, &device_info);
-       if (IS_ERR(nvdev)) {
-               ret = PTR_ERR(nvdev);
-
-               /* Attempt rollback to original MTU */
-               ndev->mtu = orig_mtu;
-               nvdev = rndis_filter_device_add(hdev, &device_info);
-
-               if (vf_netdev)
-                       dev_set_mtu(vf_netdev, orig_mtu);
-
-               if (IS_ERR(nvdev)) {
-                       netdev_err(ndev, "restoring mtu failed: %ld\n",
-                                  PTR_ERR(nvdev));
-                       return ret;
-               }
-       }
+       ret = netvsc_attach(ndev, &device_info);
+       if (ret)
+               goto rollback;
 
-       if (was_opened)
-               rndis_filter_open(nvdev);
+       return 0;
 
-       netif_device_attach(ndev);
+rollback:
+       /* Attempt rollback to original MTU */
+       ndev->mtu = orig_mtu;
 
-       /* We may have missed link change notifications */
-       schedule_delayed_work(&ndevctx->dwork, 0);
+       if (netvsc_attach(ndev, &device_info))
+               netdev_err(ndev, "restoring mtu failed\n");
+rollback_vf:
+       if (vf_netdev)
+               dev_set_mtu(vf_netdev, orig_mtu);
 
        return ret;
 }
@@ -1490,11 +1575,9 @@ static int netvsc_set_ringparam(struct net_device *ndev,
 {
        struct net_device_context *ndevctx = netdev_priv(ndev);
        struct netvsc_device *nvdev = rtnl_dereference(ndevctx->nvdev);
-       struct hv_device *hdev = ndevctx->device_ctx;
        struct netvsc_device_info device_info;
        struct ethtool_ringparam orig;
        u32 new_tx, new_rx;
-       bool was_opened;
        int ret = 0;
 
        if (!nvdev || nvdev->destroy)
@@ -1519,34 +1602,18 @@ static int netvsc_set_ringparam(struct net_device *ndev,
        device_info.recv_sections = new_rx;
        device_info.recv_section_size = nvdev->recv_section_size;
 
-       netif_device_detach(ndev);
-       was_opened = rndis_filter_opened(nvdev);
-       if (was_opened)
-               rndis_filter_close(nvdev);
-
-       rndis_filter_device_remove(hdev, nvdev);
-
-       nvdev = rndis_filter_device_add(hdev, &device_info);
-       if (IS_ERR(nvdev)) {
-               ret = PTR_ERR(nvdev);
+       ret = netvsc_detach(ndev, nvdev);
+       if (ret)
+               return ret;
 
+       ret = netvsc_attach(ndev, &device_info);
+       if (ret) {
                device_info.send_sections = orig.tx_pending;
                device_info.recv_sections = orig.rx_pending;
-               nvdev = rndis_filter_device_add(hdev, &device_info);
-               if (IS_ERR(nvdev)) {
-                       netdev_err(ndev, "restoring ringparam failed: %ld\n",
-                                  PTR_ERR(nvdev));
-                       return ret;
-               }
-       }
 
-       if (was_opened)
-               rndis_filter_open(nvdev);
-       netif_device_attach(ndev);
-
-       /* We may have missed link change notifications */
-       ndevctx->last_reconfig = 0;
-       schedule_delayed_work(&ndevctx->dwork, 0);
+               if (netvsc_attach(ndev, &device_info))
+                       netdev_err(ndev, "restoring ringparam failed");
+       }
 
        return ret;
 }
@@ -1576,7 +1643,8 @@ static const struct net_device_ops device_ops = {
        .ndo_open =                     netvsc_open,
        .ndo_stop =                     netvsc_close,
        .ndo_start_xmit =               netvsc_start_xmit,
-       .ndo_set_rx_mode =              netvsc_set_multicast_list,
+       .ndo_change_rx_flags =          netvsc_change_rx_flags,
+       .ndo_set_rx_mode =              netvsc_set_rx_mode,
        .ndo_change_mtu =               netvsc_change_mtu,
        .ndo_validate_addr =            eth_validate_addr,
        .ndo_set_mac_address =          netvsc_set_mac_addr,
@@ -1807,6 +1875,15 @@ static void __netvsc_vf_setup(struct net_device *ndev,
                netdev_warn(vf_netdev,
                            "unable to change mtu to %u\n", ndev->mtu);
 
+       /* set multicast etc flags on VF */
+       dev_change_flags(vf_netdev, ndev->flags | IFF_SLAVE);
+
+       /* sync address list from ndev to VF */
+       netif_addr_lock_bh(ndev);
+       dev_uc_sync(vf_netdev, ndev);
+       dev_mc_sync(vf_netdev, ndev);
+       netif_addr_unlock_bh(ndev);
+
        if (netif_running(ndev)) {
                ret = dev_open(vf_netdev);
                if (ret)
@@ -2021,8 +2098,8 @@ no_net:
 static int netvsc_remove(struct hv_device *dev)
 {
        struct net_device_context *ndev_ctx;
-       struct net_device *vf_netdev;
-       struct net_device *net;
+       struct net_device *vf_netdev, *net;
+       struct netvsc_device *nvdev;
 
        net = hv_get_drvdata(dev);
        if (net == NULL) {
@@ -2032,10 +2109,14 @@ static int netvsc_remove(struct hv_device *dev)
 
        ndev_ctx = netdev_priv(net);
 
-       netif_device_detach(net);
-
        cancel_delayed_work_sync(&ndev_ctx->dwork);
 
+       rcu_read_lock();
+       nvdev = rcu_dereference(ndev_ctx->nvdev);
+
+       if  (nvdev)
+               cancel_work_sync(&nvdev->subchan_work);
+
        /*
         * Call to the vsc driver to let it know that the device is being
         * removed. Also blocks mtu and channel changes.
@@ -2045,11 +2126,13 @@ static int netvsc_remove(struct hv_device *dev)
        if (vf_netdev)
                netvsc_unregister_vf(vf_netdev);
 
+       if (nvdev)
+               rndis_filter_device_remove(dev, nvdev);
+
        unregister_netdevice(net);
 
-       rndis_filter_device_remove(dev,
-                                  rtnl_dereference(ndev_ctx->nvdev));
        rtnl_unlock();
+       rcu_read_unlock();
 
        hv_set_drvdata(dev, NULL);
 
index c3ca191..465c42e 100644 (file)
@@ -264,13 +264,23 @@ static void rndis_set_link_state(struct rndis_device *rdev,
        }
 }
 
-static void rndis_filter_receive_response(struct rndis_device *dev,
-                                      struct rndis_message *resp)
+static void rndis_filter_receive_response(struct net_device *ndev,
+                                         struct netvsc_device *nvdev,
+                                         const struct rndis_message *resp)
 {
+       struct rndis_device *dev = nvdev->extension;
        struct rndis_request *request = NULL;
        bool found = false;
        unsigned long flags;
-       struct net_device *ndev = dev->ndev;
+
+       /* This should never happen, it means control message
+        * response received after device removed.
+        */
+       if (dev->state == RNDIS_DEV_UNINITIALIZED) {
+               netdev_err(ndev,
+                          "got rndis message uninitialized\n");
+               return;
+       }
 
        spin_lock_irqsave(&dev->request_lock, flags);
        list_for_each_entry(request, &dev->req_list, list_ent) {
@@ -352,7 +362,6 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
 
 static int rndis_filter_receive_data(struct net_device *ndev,
                                     struct netvsc_device *nvdev,
-                                    struct rndis_device *dev,
                                     struct rndis_message *msg,
                                     struct vmbus_channel *channel,
                                     void *data, u32 data_buflen)
@@ -372,7 +381,7 @@ static int rndis_filter_receive_data(struct net_device *ndev,
         * should be the data packet size plus the trailer padding size
         */
        if (unlikely(data_buflen < rndis_pkt->data_len)) {
-               netdev_err(dev->ndev, "rndis message buffer "
+               netdev_err(ndev, "rndis message buffer "
                           "overflow detected (got %u, min %u)"
                           "...dropping this message!\n",
                           data_buflen, rndis_pkt->data_len);
@@ -400,35 +409,20 @@ int rndis_filter_receive(struct net_device *ndev,
                         void *data, u32 buflen)
 {
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
-       struct rndis_device *rndis_dev = net_dev->extension;
        struct rndis_message *rndis_msg = data;
 
-       /* Make sure the rndis device state is initialized */
-       if (unlikely(!rndis_dev)) {
-               netif_dbg(net_device_ctx, rx_err, ndev,
-                         "got rndis message but no rndis device!\n");
-               return NVSP_STAT_FAIL;
-       }
-
-       if (unlikely(rndis_dev->state == RNDIS_DEV_UNINITIALIZED)) {
-               netif_dbg(net_device_ctx, rx_err, ndev,
-                         "got rndis message uninitialized\n");
-               return NVSP_STAT_FAIL;
-       }
-
        if (netif_msg_rx_status(net_device_ctx))
                dump_rndis_message(ndev, rndis_msg);
 
        switch (rndis_msg->ndis_msg_type) {
        case RNDIS_MSG_PACKET:
-               return rndis_filter_receive_data(ndev, net_dev,
-                                                rndis_dev, rndis_msg,
+               return rndis_filter_receive_data(ndev, net_dev, rndis_msg,
                                                 channel, data, buflen);
        case RNDIS_MSG_INIT_C:
        case RNDIS_MSG_QUERY_C:
        case RNDIS_MSG_SET_C:
                /* completion msgs */
-               rndis_filter_receive_response(rndis_dev, rndis_msg);
+               rndis_filter_receive_response(ndev, net_dev, rndis_msg);
                break;
 
        case RNDIS_MSG_INDICATE:
@@ -825,13 +819,15 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
        struct rndis_set_request *set;
        int ret;
 
+       if (dev->filter == new_filter)
+               return 0;
+
        request = get_rndis_request(dev, RNDIS_MSG_SET,
                        RNDIS_MESSAGE_SIZE(struct rndis_set_request) +
                        sizeof(u32));
        if (!request)
                return -ENOMEM;
 
-
        /* Setup the rndis set */
        set = &request->request_msg.msg.set_req;
        set->oid = RNDIS_OID_GEN_CURRENT_PACKET_FILTER;
@@ -842,8 +838,10 @@ static int rndis_filter_set_packet_filter(struct rndis_device *dev,
               &new_filter, sizeof(u32));
 
        ret = rndis_filter_send_request(dev, request);
-       if (ret == 0)
+       if (ret == 0) {
                wait_for_completion(&request->wait_event);
+               dev->filter = new_filter;
+       }
 
        put_rndis_request(dev, request);
 
@@ -854,15 +852,19 @@ static void rndis_set_multicast(struct work_struct *w)
 {
        struct rndis_device *rdev
                = container_of(w, struct rndis_device, mcast_work);
+       u32 filter = NDIS_PACKET_TYPE_DIRECTED;
+       unsigned int flags = rdev->ndev->flags;
 
-       if (rdev->ndev->flags & IFF_PROMISC)
-               rndis_filter_set_packet_filter(rdev,
-                                              NDIS_PACKET_TYPE_PROMISCUOUS);
-       else
-               rndis_filter_set_packet_filter(rdev,
-                                              NDIS_PACKET_TYPE_BROADCAST |
-                                              NDIS_PACKET_TYPE_ALL_MULTICAST |
-                                              NDIS_PACKET_TYPE_DIRECTED);
+       if (flags & IFF_PROMISC) {
+               filter = NDIS_PACKET_TYPE_PROMISCUOUS;
+       } else {
+               if (!netdev_mc_empty(rdev->ndev) || (flags & IFF_ALLMULTI))
+                       filter |= NDIS_PACKET_TYPE_ALL_MULTICAST;
+               if (flags & IFF_BROADCAST)
+                       filter |= NDIS_PACKET_TYPE_BROADCAST;
+       }
+
+       rndis_filter_set_packet_filter(rdev, filter);
 }
 
 void rndis_filter_update(struct netvsc_device *nvdev)
@@ -1116,6 +1118,7 @@ void rndis_set_subchannel(struct work_struct *w)
        for (i = 0; i < VRSS_SEND_TAB_SIZE; i++)
                ndev_ctx->tx_table[i] = i % nvdev->num_chn;
 
+       netif_device_attach(ndev);
        rtnl_unlock();
        return;
 
@@ -1126,6 +1129,8 @@ failed:
 
        nvdev->max_chn = 1;
        nvdev->num_chn = 1;
+
+       netif_device_attach(ndev);
 unlock:
        rtnl_unlock();
 }
@@ -1328,6 +1333,10 @@ out:
                net_device->num_chn = 1;
        }
 
+       /* No sub channels, device is ready */
+       if (net_device->num_chn == 1)
+               netif_device_attach(net);
+
        return net_device;
 
 err_dev_remv:
@@ -1346,7 +1355,6 @@ void rndis_filter_device_remove(struct hv_device *dev,
        net_dev->extension = NULL;
 
        netvsc_device_remove(dev);
-       kfree(rndis_dev);
 }
 
 int rndis_filter_open(struct netvsc_device *nvdev)
@@ -1364,10 +1372,3 @@ int rndis_filter_close(struct netvsc_device *nvdev)
 
        return rndis_filter_close_device(nvdev->extension);
 }
-
-bool rndis_filter_opened(const struct netvsc_device *nvdev)
-{
-       const struct rndis_device *dev = nvdev->extension;
-
-       return dev->state == RNDIS_DEV_DATAINITIALIZED;
-}
index 7de88b3..9cbb0c8 100644 (file)
@@ -3277,7 +3277,7 @@ static int macsec_newlink(struct net *net, struct net_device *dev,
 
        err = netdev_upper_dev_link(real_dev, dev, extack);
        if (err < 0)
-               goto unregister;
+               goto put_dev;
 
        /* need to be already registered so that ->init has run and
         * the MAC addr is set
@@ -3316,7 +3316,8 @@ del_dev:
        macsec_del_dev(macsec);
 unlink:
        netdev_upper_dev_unlink(real_dev, dev);
-unregister:
+put_dev:
+       dev_put(real_dev);
        unregister_netdevice(dev);
        return err;
 }
index a0f2be8..725f4b4 100644 (file)
@@ -1036,7 +1036,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev,
        lowerdev_features &= (features | ~NETIF_F_LRO);
        features = netdev_increment_features(lowerdev_features, features, mask);
        features |= ALWAYS_ON_FEATURES;
-       features &= ~NETIF_F_NETNS_LOCAL;
+       features &= (ALWAYS_ON_FEATURES | MACVLAN_FEATURES);
 
        return features;
 }
@@ -1451,7 +1451,7 @@ destroy_macvlan_port:
        /* the macvlan port may be freed by macvlan_uninit when fail to register.
         * so we destroy the macvlan port only when it's valid.
         */
-       if (create && macvlan_port_get_rtnl(dev))
+       if (create && macvlan_port_get_rtnl(lowerdev))
                macvlan_port_destroy(port->dev);
        return err;
 }
index 171010e..5ad130c 100644 (file)
@@ -341,8 +341,8 @@ void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
-               memcpy(data + i * ETH_GSTRING_LEN,
-                      bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
+               strlcpy(data + i * ETH_GSTRING_LEN,
+                       bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
 }
 EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
 
index 22d9bc9..0e0978d 100644 (file)
@@ -1452,8 +1452,8 @@ static void marvell_get_strings(struct phy_device *phydev, u8 *data)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(marvell_hw_stats); i++) {
-               memcpy(data + i * ETH_GSTRING_LEN,
-                      marvell_hw_stats[i].string, ETH_GSTRING_LEN);
+               strlcpy(data + i * ETH_GSTRING_LEN,
+                       marvell_hw_stats[i].string, ETH_GSTRING_LEN);
        }
 }
 
index 0f45310..f41b224 100644 (file)
@@ -635,25 +635,6 @@ static int ksz8873mll_config_aneg(struct phy_device *phydev)
        return 0;
 }
 
-/* This routine returns -1 as an indication to the caller that the
- * Micrel ksz9021 10/100/1000 PHY does not support standard IEEE
- * MMD extended PHY registers.
- */
-static int
-ksz9021_rd_mmd_phyreg(struct phy_device *phydev, int devad, u16 regnum)
-{
-       return -1;
-}
-
-/* This routine does nothing since the Micrel ksz9021 does not support
- * standard IEEE MMD extended PHY registers.
- */
-static int
-ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int devad, u16 regnum, u16 val)
-{
-       return -1;
-}
-
 static int kszphy_get_sset_count(struct phy_device *phydev)
 {
        return ARRAY_SIZE(kszphy_hw_stats);
@@ -664,8 +645,8 @@ static void kszphy_get_strings(struct phy_device *phydev, u8 *data)
        int i;
 
        for (i = 0; i < ARRAY_SIZE(kszphy_hw_stats); i++) {
-               memcpy(data + i * ETH_GSTRING_LEN,
-                      kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
+               strlcpy(data + i * ETH_GSTRING_LEN,
+                       kszphy_hw_stats[i].string, ETH_GSTRING_LEN);
        }
 }
 
@@ -946,8 +927,8 @@ static struct phy_driver ksphy_driver[] = {
        .get_stats      = kszphy_get_stats,
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
-       .read_mmd       = ksz9021_rd_mmd_phyreg,
-       .write_mmd      = ksz9021_wr_mmd_phyreg,
+       .read_mmd       = genphy_read_mmd_unsupported,
+       .write_mmd      = genphy_write_mmd_unsupported,
 }, {
        .phy_id         = PHY_ID_KSZ9031,
        .phy_id_mask    = MICREL_PHY_ID_MASK,
index e3e29c2..9aabfa1 100644 (file)
@@ -618,6 +618,77 @@ static void phy_error(struct phy_device *phydev)
 }
 
 /**
+ * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
+ * @phydev: target phy_device struct
+ */
+static int phy_disable_interrupts(struct phy_device *phydev)
+{
+       int err;
+
+       /* Disable PHY interrupts */
+       err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
+       if (err)
+               goto phy_err;
+
+       /* Clear the interrupt */
+       err = phy_clear_interrupt(phydev);
+       if (err)
+               goto phy_err;
+
+       return 0;
+
+phy_err:
+       phy_error(phydev);
+
+       return err;
+}
+
+/**
+ * phy_change - Called by the phy_interrupt to handle PHY changes
+ * @phydev: phy_device struct that interrupted
+ */
+static irqreturn_t phy_change(struct phy_device *phydev)
+{
+       if (phy_interrupt_is_valid(phydev)) {
+               if (phydev->drv->did_interrupt &&
+                   !phydev->drv->did_interrupt(phydev))
+                       return IRQ_NONE;
+
+               if (phydev->state == PHY_HALTED)
+                       if (phy_disable_interrupts(phydev))
+                               goto phy_err;
+       }
+
+       mutex_lock(&phydev->lock);
+       if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
+               phydev->state = PHY_CHANGELINK;
+       mutex_unlock(&phydev->lock);
+
+       /* reschedule state queue work to run as soon as possible */
+       phy_trigger_machine(phydev, true);
+
+       if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev))
+               goto phy_err;
+       return IRQ_HANDLED;
+
+phy_err:
+       phy_error(phydev);
+       return IRQ_NONE;
+}
+
+/**
+ * phy_change_work - Scheduled by the phy_mac_interrupt to handle PHY changes
+ * @work: work_struct that describes the work to be done
+ */
+void phy_change_work(struct work_struct *work)
+{
+       struct phy_device *phydev =
+               container_of(work, struct phy_device, phy_queue);
+
+       phy_change(phydev);
+}
+
+/**
  * phy_interrupt - PHY interrupt handler
  * @irq: interrupt line
  * @phy_dat: phy_device pointer
@@ -632,9 +703,7 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
        if (PHY_HALTED == phydev->state)
                return IRQ_NONE;                /* It can't be ours.  */
 
-       phy_change(phydev);
-
-       return IRQ_HANDLED;
+       return phy_change(phydev);
 }
 
 /**
@@ -652,32 +721,6 @@ static int phy_enable_interrupts(struct phy_device *phydev)
 }
 
 /**
- * phy_disable_interrupts - Disable the PHY interrupts from the PHY side
- * @phydev: target phy_device struct
- */
-static int phy_disable_interrupts(struct phy_device *phydev)
-{
-       int err;
-
-       /* Disable PHY interrupts */
-       err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED);
-       if (err)
-               goto phy_err;
-
-       /* Clear the interrupt */
-       err = phy_clear_interrupt(phydev);
-       if (err)
-               goto phy_err;
-
-       return 0;
-
-phy_err:
-       phy_error(phydev);
-
-       return err;
-}
-
-/**
  * phy_start_interrupts - request and enable interrupts for a PHY device
  * @phydev: target phy_device struct
  *
@@ -720,50 +763,6 @@ int phy_stop_interrupts(struct phy_device *phydev)
 EXPORT_SYMBOL(phy_stop_interrupts);
 
 /**
- * phy_change - Called by the phy_interrupt to handle PHY changes
- * @phydev: phy_device struct that interrupted
- */
-void phy_change(struct phy_device *phydev)
-{
-       if (phy_interrupt_is_valid(phydev)) {
-               if (phydev->drv->did_interrupt &&
-                   !phydev->drv->did_interrupt(phydev))
-                       return;
-
-               if (phydev->state == PHY_HALTED)
-                       if (phy_disable_interrupts(phydev))
-                               goto phy_err;
-       }
-
-       mutex_lock(&phydev->lock);
-       if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
-               phydev->state = PHY_CHANGELINK;
-       mutex_unlock(&phydev->lock);
-
-       /* reschedule state queue work to run as soon as possible */
-       phy_trigger_machine(phydev, true);
-
-       if (phy_interrupt_is_valid(phydev) && phy_clear_interrupt(phydev))
-               goto phy_err;
-       return;
-
-phy_err:
-       phy_error(phydev);
-}
-
-/**
- * phy_change_work - Scheduled by the phy_mac_interrupt to handle PHY changes
- * @work: work_struct that describes the work to be done
- */
-void phy_change_work(struct work_struct *work)
-{
-       struct phy_device *phydev =
-               container_of(work, struct phy_device, phy_queue);
-
-       phy_change(phydev);
-}
-
-/**
  * phy_stop - Bring down the PHY link, and stop checking the status
  * @phydev: target phy_device struct
  */
@@ -819,7 +818,7 @@ void phy_start(struct phy_device *phydev)
                break;
        case PHY_HALTED:
                /* if phy was suspended, bring the physical link up again */
-               phy_resume(phydev);
+               __phy_resume(phydev);
 
                /* make sure interrupts are re-enabled for the PHY */
                if (phy_interrupt_is_valid(phydev)) {
index b13eed2..74664a6 100644 (file)
@@ -135,9 +135,7 @@ static int mdio_bus_phy_resume(struct device *dev)
        if (!mdio_bus_phy_may_suspend(phydev))
                goto no_resume;
 
-       mutex_lock(&phydev->lock);
        ret = phy_resume(phydev);
-       mutex_unlock(&phydev->lock);
        if (ret < 0)
                return ret;
 
@@ -1014,10 +1012,17 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
        err = sysfs_create_link(&phydev->mdio.dev.kobj, &dev->dev.kobj,
                                "attached_dev");
        if (!err) {
-               err = sysfs_create_link(&dev->dev.kobj, &phydev->mdio.dev.kobj,
-                                       "phydev");
-               if (err)
-                       goto error;
+               err = sysfs_create_link_nowarn(&dev->dev.kobj,
+                                              &phydev->mdio.dev.kobj,
+                                              "phydev");
+               if (err) {
+                       dev_err(&dev->dev, "could not add device link to %s err %d\n",
+                               kobject_name(&phydev->mdio.dev.kobj),
+                               err);
+                       /* non-fatal - some net drivers can use one netdevice
+                        * with more then one phy
+                        */
+               }
 
                phydev->sysfs_links = true;
        }
@@ -1041,9 +1046,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
        if (err)
                goto error;
 
-       mutex_lock(&phydev->lock);
        phy_resume(phydev);
-       mutex_unlock(&phydev->lock);
        phy_led_triggers_register(phydev);
 
        return err;
@@ -1172,7 +1175,7 @@ int phy_suspend(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(phy_suspend);
 
-int phy_resume(struct phy_device *phydev)
+int __phy_resume(struct phy_device *phydev)
 {
        struct phy_driver *phydrv = to_phy_driver(phydev->mdio.dev.driver);
        int ret = 0;
@@ -1189,6 +1192,18 @@ int phy_resume(struct phy_device *phydev)
 
        return ret;
 }
+EXPORT_SYMBOL(__phy_resume);
+
+int phy_resume(struct phy_device *phydev)
+{
+       int ret;
+
+       mutex_lock(&phydev->lock);
+       ret = __phy_resume(phydev);
+       mutex_unlock(&phydev->lock);
+
+       return ret;
+}
 EXPORT_SYMBOL(phy_resume);
 
 int phy_loopback(struct phy_device *phydev, bool enable)
@@ -1382,7 +1397,7 @@ int genphy_setup_forced(struct phy_device *phydev)
                ctl |= BMCR_FULLDPLX;
 
        return phy_modify(phydev, MII_BMCR,
-                         BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN, ctl);
+                         ~(BMCR_LOOPBACK | BMCR_ISOLATE | BMCR_PDOWN), ctl);
 }
 EXPORT_SYMBOL(genphy_setup_forced);
 
@@ -1658,6 +1673,23 @@ int genphy_config_init(struct phy_device *phydev)
 }
 EXPORT_SYMBOL(genphy_config_init);
 
+/* This is used for the phy device which doesn't support the MMD extended
+ * register access, but it does have side effect when we are trying to access
+ * the MMD register via indirect method.
+ */
+int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad, u16 regnum)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(genphy_read_mmd_unsupported);
+
+int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
+                                u16 regnum, u16 val)
+{
+       return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(genphy_write_mmd_unsupported);
+
 int genphy_suspend(struct phy_device *phydev)
 {
        return phy_set_bits(phydev, MII_BMCR, BMCR_PDOWN);
index ee3ca4a..9f48ecf 100644 (file)
@@ -172,6 +172,8 @@ static struct phy_driver realtek_drvs[] = {
                .flags          = PHY_HAS_INTERRUPT,
                .ack_interrupt  = &rtl821x_ack_interrupt,
                .config_intr    = &rtl8211b_config_intr,
+               .read_mmd       = &genphy_read_mmd_unsupported,
+               .write_mmd      = &genphy_write_mmd_unsupported,
        }, {
                .phy_id         = 0x001cc914,
                .name           = "RTL8211DN Gigabit Ethernet",
index 255a5de..da19378 100644 (file)
@@ -257,7 +257,7 @@ struct ppp_net {
 /* Prototypes. */
 static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf,
                        struct file *file, unsigned int cmd, unsigned long arg);
-static void ppp_xmit_process(struct ppp *ppp);
+static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb);
 static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb);
 static void ppp_push(struct ppp *ppp);
 static void ppp_channel_push(struct channel *pch);
@@ -513,13 +513,12 @@ static ssize_t ppp_write(struct file *file, const char __user *buf,
                goto out;
        }
 
-       skb_queue_tail(&pf->xq, skb);
-
        switch (pf->kind) {
        case INTERFACE:
-               ppp_xmit_process(PF_TO_PPP(pf));
+               ppp_xmit_process(PF_TO_PPP(pf), skb);
                break;
        case CHANNEL:
+               skb_queue_tail(&pf->xq, skb);
                ppp_channel_push(PF_TO_CHANNEL(pf));
                break;
        }
@@ -1267,8 +1266,8 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
        put_unaligned_be16(proto, pp);
 
        skb_scrub_packet(skb, !net_eq(ppp->ppp_net, dev_net(dev)));
-       skb_queue_tail(&ppp->file.xq, skb);
-       ppp_xmit_process(ppp);
+       ppp_xmit_process(ppp, skb);
+
        return NETDEV_TX_OK;
 
  outf:
@@ -1420,13 +1419,14 @@ static void ppp_setup(struct net_device *dev)
  */
 
 /* Called to do any work queued up on the transmit side that can now be done */
-static void __ppp_xmit_process(struct ppp *ppp)
+static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb)
 {
-       struct sk_buff *skb;
-
        ppp_xmit_lock(ppp);
        if (!ppp->closing) {
                ppp_push(ppp);
+
+               if (skb)
+                       skb_queue_tail(&ppp->file.xq, skb);
                while (!ppp->xmit_pending &&
                       (skb = skb_dequeue(&ppp->file.xq)))
                        ppp_send_frame(ppp, skb);
@@ -1440,7 +1440,7 @@ static void __ppp_xmit_process(struct ppp *ppp)
        ppp_xmit_unlock(ppp);
 }
 
-static void ppp_xmit_process(struct ppp *ppp)
+static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb)
 {
        local_bh_disable();
 
@@ -1448,7 +1448,7 @@ static void ppp_xmit_process(struct ppp *ppp)
                goto err;
 
        (*this_cpu_ptr(ppp->xmit_recursion))++;
-       __ppp_xmit_process(ppp);
+       __ppp_xmit_process(ppp, skb);
        (*this_cpu_ptr(ppp->xmit_recursion))--;
 
        local_bh_enable();
@@ -1458,6 +1458,8 @@ static void ppp_xmit_process(struct ppp *ppp)
 err:
        local_bh_enable();
 
+       kfree_skb(skb);
+
        if (net_ratelimit())
                netdev_err(ppp->dev, "recursion detected\n");
 }
@@ -1942,7 +1944,7 @@ static void __ppp_channel_push(struct channel *pch)
        if (skb_queue_empty(&pch->file.xq)) {
                ppp = pch->ppp;
                if (ppp)
-                       __ppp_xmit_process(ppp);
+                       __ppp_xmit_process(ppp, NULL);
        }
 }
 
@@ -3161,6 +3163,15 @@ ppp_connect_channel(struct channel *pch, int unit)
                goto outl;
 
        ppp_lock(ppp);
+       spin_lock_bh(&pch->downl);
+       if (!pch->chan) {
+               /* Don't connect unregistered channels */
+               spin_unlock_bh(&pch->downl);
+               ppp_unlock(ppp);
+               ret = -ENOTCONN;
+               goto outl;
+       }
+       spin_unlock_bh(&pch->downl);
        if (pch->file.hdrlen > ppp->file.hdrlen)
                ppp->file.hdrlen = pch->file.hdrlen;
        hdrlen = pch->file.hdrlen + 2;  /* for protocol bytes */
index a468439..befed2d 100644 (file)
@@ -1197,11 +1197,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_dev_open;
        }
 
-       netif_addr_lock_bh(dev);
-       dev_uc_sync_multiple(port_dev, dev);
-       dev_mc_sync_multiple(port_dev, dev);
-       netif_addr_unlock_bh(dev);
-
        err = vlan_vids_add_by_dev(port_dev, dev);
        if (err) {
                netdev_err(dev, "Failed to add vlan ids to device %s\n",
@@ -1241,6 +1236,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
                goto err_option_port_add;
        }
 
+       netif_addr_lock_bh(dev);
+       dev_uc_sync_multiple(port_dev, dev);
+       dev_mc_sync_multiple(port_dev, dev);
+       netif_addr_unlock_bh(dev);
+
        port->index = -1;
        list_add_tail_rcu(&port->list, &team->port_list);
        team_port_enable(team, port);
@@ -1265,8 +1265,6 @@ err_enable_netpoll:
        vlan_vids_del_by_dev(port_dev, dev);
 
 err_vids_add:
-       dev_uc_unsync(port_dev, dev);
-       dev_mc_unsync(port_dev, dev);
        dev_close(port_dev);
 
 err_dev_open:
@@ -2395,7 +2393,7 @@ send_done:
        if (!nlh) {
                err = __send_and_alloc_skb(&skb, team, portid, send_func);
                if (err)
-                       goto errout;
+                       return err;
                goto send_done;
        }
 
@@ -2681,7 +2679,7 @@ send_done:
        if (!nlh) {
                err = __send_and_alloc_skb(&skb, team, portid, send_func);
                if (err)
-                       goto errout;
+                       return err;
                goto send_done;
        }
 
index ca5e375..e0d6760 100644 (file)
@@ -166,6 +166,8 @@ struct tbnet_ring {
  * @connected_work: Worker that finalizes the ThunderboltIP connection
  *                 setup and enables DMA paths for high speed data
  *                 transfers
+ * @disconnect_work: Worker that handles tearing down the ThunderboltIP
+ *                  connection
  * @rx_hdr: Copy of the currently processed Rx frame. Used when a
  *         network packet consists of multiple Thunderbolt frames.
  *         In host byte order.
@@ -190,6 +192,7 @@ struct tbnet {
        int login_retries;
        struct delayed_work login_work;
        struct work_struct connected_work;
+       struct work_struct disconnect_work;
        struct thunderbolt_ip_frame_header rx_hdr;
        struct tbnet_ring rx_ring;
        atomic_t frame_id;
@@ -445,7 +448,7 @@ static int tbnet_handle_packet(const void *buf, size_t size, void *data)
        case TBIP_LOGOUT:
                ret = tbnet_logout_response(net, route, sequence, command_id);
                if (!ret)
-                       tbnet_tear_down(net, false);
+                       queue_work(system_long_wq, &net->disconnect_work);
                break;
 
        default:
@@ -659,6 +662,13 @@ static void tbnet_login_work(struct work_struct *work)
        }
 }
 
+static void tbnet_disconnect_work(struct work_struct *work)
+{
+       struct tbnet *net = container_of(work, typeof(*net), disconnect_work);
+
+       tbnet_tear_down(net, false);
+}
+
 static bool tbnet_check_frame(struct tbnet *net, const struct tbnet_frame *tf,
                              const struct thunderbolt_ip_frame_header *hdr)
 {
@@ -881,6 +891,7 @@ static int tbnet_stop(struct net_device *dev)
 
        napi_disable(&net->napi);
 
+       cancel_work_sync(&net->disconnect_work);
        tbnet_tear_down(net, true);
 
        tb_ring_free(net->rx_ring.ring);
@@ -1195,6 +1206,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id)
        net = netdev_priv(dev);
        INIT_DELAYED_WORK(&net->login_work, tbnet_login_work);
        INIT_WORK(&net->connected_work, tbnet_connected_work);
+       INIT_WORK(&net->disconnect_work, tbnet_disconnect_work);
        mutex_init(&net->connection_lock);
        atomic_set(&net->command_id, 0);
        atomic_set(&net->frame_id, 0);
@@ -1270,10 +1282,7 @@ static int __maybe_unused tbnet_suspend(struct device *dev)
        stop_login(net);
        if (netif_running(net->dev)) {
                netif_device_detach(net->dev);
-               tb_ring_stop(net->rx_ring.ring);
-               tb_ring_stop(net->tx_ring.ring);
-               tbnet_free_buffers(&net->rx_ring);
-               tbnet_free_buffers(&net->tx_ring);
+               tbnet_tear_down(net, true);
        }
 
        return 0;
index 81e6cc9..28cfa64 100644 (file)
@@ -181,7 +181,6 @@ struct tun_file {
        struct tun_struct *detached;
        struct ptr_ring tx_ring;
        struct xdp_rxq_info xdp_rxq;
-       int xdp_pending_pkts;
 };
 
 struct tun_flow_entry {
@@ -656,7 +655,7 @@ static struct tun_struct *tun_enable_queue(struct tun_file *tfile)
        return tun;
 }
 
-static void tun_ptr_free(void *ptr)
+void tun_ptr_free(void *ptr)
 {
        if (!ptr)
                return;
@@ -668,6 +667,7 @@ static void tun_ptr_free(void *ptr)
                __skb_array_destroy_skb(ptr);
        }
 }
+EXPORT_SYMBOL_GPL(tun_ptr_free);
 
 static void tun_queue_purge(struct tun_file *tfile)
 {
@@ -1489,27 +1489,23 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile,
        skb->truesize += skb->data_len;
 
        for (i = 1; i < it->nr_segs; i++) {
+               struct page_frag *pfrag = &current->task_frag;
                size_t fragsz = it->iov[i].iov_len;
-               unsigned long offset;
-               struct page *page;
-               void *data;
 
                if (fragsz == 0 || fragsz > PAGE_SIZE) {
                        err = -EINVAL;
                        goto free;
                }
 
-               local_bh_disable();
-               data = napi_alloc_frag(fragsz);
-               local_bh_enable();
-               if (!data) {
+               if (!skb_page_frag_refill(fragsz, pfrag, GFP_KERNEL)) {
                        err = -ENOMEM;
                        goto free;
                }
 
-               page = virt_to_head_page(data);
-               offset = data - page_address(page);
-               skb_fill_page_desc(skb, i - 1, page, offset, fragsz);
+               skb_fill_page_desc(skb, i - 1, pfrag->page,
+                                  pfrag->offset, fragsz);
+               page_ref_inc(pfrag->page);
+               pfrag->offset += fragsz;
        }
 
        return skb;
@@ -1647,6 +1643,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
        else
                *skb_xdp = 0;
 
+       preempt_disable();
        rcu_read_lock();
        xdp_prog = rcu_dereference(tun->xdp_prog);
        if (xdp_prog && !*skb_xdp) {
@@ -1666,11 +1663,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
                case XDP_REDIRECT:
                        get_page(alloc_frag->page);
                        alloc_frag->offset += buflen;
-                       ++tfile->xdp_pending_pkts;
                        err = xdp_do_redirect(tun->dev, &xdp, xdp_prog);
+                       xdp_do_flush_map();
                        if (err)
                                goto err_redirect;
                        rcu_read_unlock();
+                       preempt_enable();
                        return NULL;
                case XDP_TX:
                        xdp_xmit = true;
@@ -1692,6 +1690,7 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
        skb = build_skb(buf, buflen);
        if (!skb) {
                rcu_read_unlock();
+               preempt_enable();
                return ERR_PTR(-ENOMEM);
        }
 
@@ -1704,10 +1703,12 @@ static struct sk_buff *tun_build_skb(struct tun_struct *tun,
                skb->dev = tun->dev;
                generic_xdp_tx(skb, xdp_prog);
                rcu_read_unlock();
+               preempt_enable();
                return NULL;
        }
 
        rcu_read_unlock();
+       preempt_enable();
 
        return skb;
 
@@ -1715,6 +1716,7 @@ err_redirect:
        put_page(alloc_frag->page);
 err_xdp:
        rcu_read_unlock();
+       preempt_enable();
        this_cpu_inc(tun->pcpu_stats->rx_dropped);
        return NULL;
 }
@@ -1988,11 +1990,6 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)
        result = tun_get_user(tun, tfile, NULL, from,
                              file->f_flags & O_NONBLOCK, false);
 
-       if (tfile->xdp_pending_pkts) {
-               tfile->xdp_pending_pkts = 0;
-               xdp_do_flush_map();
-       }
-
        tun_put(tun);
        return result;
 }
@@ -2329,13 +2326,6 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
        ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter,
                           m->msg_flags & MSG_DONTWAIT,
                           m->msg_flags & MSG_MORE);
-
-       if (tfile->xdp_pending_pkts >= NAPI_POLL_WEIGHT ||
-           !(m->msg_flags & MSG_MORE)) {
-               tfile->xdp_pending_pkts = 0;
-               xdp_do_flush_map();
-       }
-
        tun_put(tun);
        return ret;
 }
@@ -3167,7 +3157,6 @@ static int tun_chr_open(struct inode *inode, struct file * file)
        sock_set_flag(&tfile->sk, SOCK_ZEROCOPY);
 
        memset(&tfile->tx_ring, 0, sizeof(tfile->tx_ring));
-       tfile->xdp_pending_pkts = 0;
 
        return 0;
 }
index 05dca3e..fff4b13 100644 (file)
@@ -896,6 +896,12 @@ static const struct usb_device_id  products[] = {
                                      USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
 }, {
+       /* Cinterion PLS8 modem by GEMALTO */
+       USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0061, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long)&wwan_info,
+}, {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
                        USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long) &cdc_info,
index 60a604c..55a78eb 100644 (file)
@@ -2351,6 +2351,7 @@ static int lan78xx_reset(struct lan78xx_net *dev)
        u32 buf;
        int ret = 0;
        unsigned long timeout;
+       u8 sig;
 
        ret = lan78xx_read_reg(dev, HW_CFG, &buf);
        buf |= HW_CFG_LRST_;
@@ -2450,6 +2451,15 @@ static int lan78xx_reset(struct lan78xx_net *dev)
        /* LAN7801 only has RGMII mode */
        if (dev->chipid == ID_REV_CHIP_ID_7801_)
                buf &= ~MAC_CR_GMII_EN_;
+
+       if (dev->chipid == ID_REV_CHIP_ID_7800_) {
+               ret = lan78xx_read_raw_eeprom(dev, 0, 1, &sig);
+               if (!ret && sig != EEPROM_INDICATOR) {
+                       /* Implies there is no external eeprom. Set mac speed */
+                       netdev_info(dev->net, "No External EEPROM. Setting MAC Speed\n");
+                       buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_;
+               }
+       }
        ret = lan78xx_write_reg(dev, MAC_CR, buf);
 
        ret = lan78xx_read_reg(dev, MAC_TX, &buf);
@@ -2863,8 +2873,7 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
        if (ret < 0) {
                netdev_warn(dev->net,
                            "lan78xx_setup_irq_domain() failed : %d", ret);
-               kfree(pdata);
-               return ret;
+               goto out1;
        }
 
        dev->net->hard_header_len += TX_OVERHEAD;
@@ -2872,14 +2881,32 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf)
 
        /* Init all registers */
        ret = lan78xx_reset(dev);
+       if (ret) {
+               netdev_warn(dev->net, "Registers INIT FAILED....");
+               goto out2;
+       }
 
        ret = lan78xx_mdio_init(dev);
+       if (ret) {
+               netdev_warn(dev->net, "MDIO INIT FAILED.....");
+               goto out2;
+       }
 
        dev->net->flags |= IFF_MULTICAST;
 
        pdata->wol = WAKE_MAGIC;
 
        return ret;
+
+out2:
+       lan78xx_remove_irq_domain(dev);
+
+out1:
+       netdev_warn(dev->net, "Bind routine FAILED");
+       cancel_work_sync(&pdata->set_multicast);
+       cancel_work_sync(&pdata->set_vlan);
+       kfree(pdata);
+       return ret;
 }
 
 static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf)
@@ -2891,6 +2918,8 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf)
        lan78xx_remove_mdio(dev);
 
        if (pdata) {
+               cancel_work_sync(&pdata->set_multicast);
+               cancel_work_sync(&pdata->set_vlan);
                netif_dbg(dev, ifdown, dev->net, "free pdata");
                kfree(pdata);
                pdata = NULL;
index 76ac480..ca066b7 100644 (file)
@@ -1104,6 +1104,9 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x0846, 0x68a2, 8)},
        {QMI_FIXED_INTF(0x12d1, 0x140c, 1)},    /* Huawei E173 */
        {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)},    /* Huawei E1820 */
+       {QMI_FIXED_INTF(0x1435, 0xd181, 3)},    /* Wistron NeWeb D18Q1 */
+       {QMI_FIXED_INTF(0x1435, 0xd181, 4)},    /* Wistron NeWeb D18Q1 */
+       {QMI_FIXED_INTF(0x1435, 0xd181, 5)},    /* Wistron NeWeb D18Q1 */
        {QMI_FIXED_INTF(0x16d8, 0x6003, 0)},    /* CMOTech 6003 */
        {QMI_FIXED_INTF(0x16d8, 0x6007, 0)},    /* CMOTech CHE-628S */
        {QMI_FIXED_INTF(0x16d8, 0x6008, 0)},    /* CMOTech CMU-301 */
@@ -1180,6 +1183,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x19d2, 0x2002, 4)},    /* ZTE (Vodafone) K3765-Z */
        {QMI_FIXED_INTF(0x2001, 0x7e19, 4)},    /* D-Link DWM-221 B1 */
        {QMI_FIXED_INTF(0x2001, 0x7e35, 4)},    /* D-Link DWM-222 */
+       {QMI_FIXED_INTF(0x2020, 0x2033, 4)},    /* BroadMobi BM806U */
        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
@@ -1240,6 +1244,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x413c, 0x81b6, 8)},    /* Dell Wireless 5811e */
        {QMI_FIXED_INTF(0x413c, 0x81b6, 10)},   /* Dell Wireless 5811e */
        {QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)},    /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
+       {QMI_FIXED_INTF(0x03f0, 0x9d1d, 1)},    /* HP lt4120 Snapdragon X5 LTE */
        {QMI_FIXED_INTF(0x22de, 0x9061, 3)},    /* WeTelecom WPD-600N */
        {QMI_FIXED_INTF(0x1e0e, 0x9001, 5)},    /* SIMCom 7230E */
        {QMI_QUIRK_SET_DTR(0x2c7c, 0x0125, 4)}, /* Quectel EC25, EC20 R2.0  Mini PCIe */
index 958b2e8..86f7196 100644 (file)
@@ -1794,7 +1794,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
 
                tx_data += len;
                agg->skb_len += len;
-               agg->skb_num++;
+               agg->skb_num += skb_shinfo(skb)->gso_segs ?: 1;
 
                dev_kfree_skb_any(skb);
 
index d0a1137..7a6a1fe 100644 (file)
@@ -954,10 +954,11 @@ static int smsc75xx_set_features(struct net_device *netdev,
        /* it's racing here! */
 
        ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl);
-       if (ret < 0)
+       if (ret < 0) {
                netdev_warn(dev->net, "Error writing RFE_CTL\n");
-
-       return ret;
+               return ret;
+       }
+       return 0;
 }
 
 static int smsc75xx_wait_ready(struct usbnet *dev, int in_pm)
index 8a22ff6..d9eea8c 100644 (file)
@@ -315,6 +315,7 @@ static void __usbnet_status_stop_force(struct usbnet *dev)
 void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
 {
        struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
+       unsigned long flags;
        int     status;
 
        if (test_bit(EVENT_RX_PAUSED, &dev->flags)) {
@@ -326,10 +327,10 @@ void usbnet_skb_return (struct usbnet *dev, struct sk_buff *skb)
        if (skb->protocol == 0)
                skb->protocol = eth_type_trans (skb, dev->net);
 
-       u64_stats_update_begin(&stats64->syncp);
+       flags = u64_stats_update_begin_irqsave(&stats64->syncp);
        stats64->rx_packets++;
        stats64->rx_bytes += skb->len;
-       u64_stats_update_end(&stats64->syncp);
+       u64_stats_update_end_irqrestore(&stats64->syncp, flags);
 
        netif_dbg(dev, rx_status, dev->net, "< rx, len %zu, type 0x%x\n",
                  skb->len + sizeof (struct ethhdr), skb->protocol);
@@ -1248,11 +1249,12 @@ static void tx_complete (struct urb *urb)
 
        if (urb->status == 0) {
                struct pcpu_sw_netstats *stats64 = this_cpu_ptr(dev->stats64);
+               unsigned long flags;
 
-               u64_stats_update_begin(&stats64->syncp);
+               flags = u64_stats_update_begin_irqsave(&stats64->syncp);
                stats64->tx_packets += entry->packets;
                stats64->tx_bytes += entry->length;
-               u64_stats_update_end(&stats64->syncp);
+               u64_stats_update_end_irqrestore(&stats64->syncp, flags);
        } else {
                dev->net->stats.tx_errors++;
 
index 626c273..2337460 100644 (file)
@@ -443,12 +443,8 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
        sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data);
 
        err = virtqueue_add_outbuf(sq->vq, sq->sg, 1, xdp->data, GFP_ATOMIC);
-       if (unlikely(err)) {
-               struct page *page = virt_to_head_page(xdp->data);
-
-               put_page(page);
-               return false;
-       }
+       if (unlikely(err))
+               return false; /* Caller handle free/refcnt */
 
        return true;
 }
@@ -456,8 +452,18 @@ static bool __virtnet_xdp_xmit(struct virtnet_info *vi,
 static int virtnet_xdp_xmit(struct net_device *dev, struct xdp_buff *xdp)
 {
        struct virtnet_info *vi = netdev_priv(dev);
-       bool sent = __virtnet_xdp_xmit(vi, xdp);
+       struct receive_queue *rq = vi->rq;
+       struct bpf_prog *xdp_prog;
+       bool sent;
+
+       /* Only allow ndo_xdp_xmit if XDP is loaded on dev, as this
+        * indicate XDP resources have been successfully allocated.
+        */
+       xdp_prog = rcu_dereference(rq->xdp_prog);
+       if (!xdp_prog)
+               return -ENXIO;
 
+       sent = __virtnet_xdp_xmit(vi, xdp);
        if (!sent)
                return -ENOSPC;
        return 0;
@@ -498,6 +504,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq,
        page_off += *len;
 
        while (--*num_buf) {
+               int tailroom = SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
                unsigned int buflen;
                void *buf;
                int off;
@@ -512,7 +519,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq,
                /* guard against a misconfigured or uncooperative backend that
                 * is sending packet larger than the MTU.
                 */
-               if ((page_off + buflen) > PAGE_SIZE) {
+               if ((page_off + buflen + tailroom) > PAGE_SIZE) {
                        put_page(p);
                        goto err_buf;
                }
@@ -546,8 +553,11 @@ static struct sk_buff *receive_small(struct net_device *dev,
        unsigned int buflen = SKB_DATA_ALIGN(GOOD_PACKET_LEN + headroom) +
                              SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
        struct page *page = virt_to_head_page(buf);
-       unsigned int delta = 0, err;
+       unsigned int delta = 0;
        struct page *xdp_page;
+       bool sent;
+       int err;
+
        len -= vi->hdr_len;
 
        rcu_read_lock();
@@ -558,7 +568,7 @@ static struct sk_buff *receive_small(struct net_device *dev,
                void *orig_data;
                u32 act;
 
-               if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags))
+               if (unlikely(hdr->hdr.gso_type))
                        goto err_xdp;
 
                if (unlikely(xdp_headroom < virtnet_get_headroom(vi))) {
@@ -596,16 +606,19 @@ static struct sk_buff *receive_small(struct net_device *dev,
                        delta = orig_data - xdp.data;
                        break;
                case XDP_TX:
-                       if (unlikely(!__virtnet_xdp_xmit(vi, &xdp)))
+                       sent = __virtnet_xdp_xmit(vi, &xdp);
+                       if (unlikely(!sent)) {
                                trace_xdp_exception(vi->dev, xdp_prog, act);
-                       else
-                               *xdp_xmit = true;
+                               goto err_xdp;
+                       }
+                       *xdp_xmit = true;
                        rcu_read_unlock();
                        goto xdp_xmit;
                case XDP_REDIRECT:
                        err = xdp_do_redirect(dev, &xdp, xdp_prog);
-                       if (!err)
-                               *xdp_xmit = true;
+                       if (err)
+                               goto err_xdp;
+                       *xdp_xmit = true;
                        rcu_read_unlock();
                        goto xdp_xmit;
                default:
@@ -677,6 +690,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
        struct bpf_prog *xdp_prog;
        unsigned int truesize;
        unsigned int headroom = mergeable_ctx_to_headroom(ctx);
+       bool sent;
        int err;
 
        head_skb = NULL;
@@ -689,7 +703,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                void *data;
                u32 act;
 
-               /* This happens when rx buffer size is underestimated */
+               /* This happens when rx buffer size is underestimated
+                * or headroom is not enough because of the buffer
+                * was refilled before XDP is set. This should only
+                * happen for the first several packets, so we don't
+                * care much about its performance.
+                */
                if (unlikely(num_buf > 1 ||
                             headroom < virtnet_get_headroom(vi))) {
                        /* linearize data for XDP */
@@ -724,9 +743,6 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
 
                act = bpf_prog_run_xdp(xdp_prog, &xdp);
 
-               if (act != XDP_PASS)
-                       ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len);
-
                switch (act) {
                case XDP_PASS:
                        /* recalculate offset to account for any header
@@ -746,18 +762,28 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
                        }
                        break;
                case XDP_TX:
-                       if (unlikely(!__virtnet_xdp_xmit(vi, &xdp)))
+                       sent = __virtnet_xdp_xmit(vi, &xdp);
+                       if (unlikely(!sent)) {
                                trace_xdp_exception(vi->dev, xdp_prog, act);
-                       else
-                               *xdp_xmit = true;
+                               if (unlikely(xdp_page != page))
+                                       put_page(xdp_page);
+                               goto err_xdp;
+                       }
+                       *xdp_xmit = true;
                        if (unlikely(xdp_page != page))
                                goto err_xdp;
                        rcu_read_unlock();
                        goto xdp_xmit;
                case XDP_REDIRECT:
                        err = xdp_do_redirect(dev, &xdp, xdp_prog);
-                       if (!err)
-                               *xdp_xmit = true;
+                       if (err) {
+                               if (unlikely(xdp_page != page))
+                                       put_page(xdp_page);
+                               goto err_xdp;
+                       }
+                       *xdp_xmit = true;
+                       if (unlikely(xdp_page != page))
+                               goto err_xdp;
                        rcu_read_unlock();
                        goto xdp_xmit;
                default:
@@ -1003,13 +1029,18 @@ static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
 }
 
 static unsigned int get_mergeable_buf_len(struct receive_queue *rq,
-                                         struct ewma_pkt_len *avg_pkt_len)
+                                         struct ewma_pkt_len *avg_pkt_len,
+                                         unsigned int room)
 {
        const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
        unsigned int len;
 
-       len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len),
+       if (room)
+               return PAGE_SIZE - room;
+
+       len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len),
                                rq->min_buf_len, PAGE_SIZE - hdr_len);
+
        return ALIGN(len, L1_CACHE_BYTES);
 }
 
@@ -1018,21 +1049,27 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi,
 {
        struct page_frag *alloc_frag = &rq->alloc_frag;
        unsigned int headroom = virtnet_get_headroom(vi);
+       unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
+       unsigned int room = SKB_DATA_ALIGN(headroom + tailroom);
        char *buf;
        void *ctx;
        int err;
        unsigned int len, hole;
 
-       len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len);
-       if (unlikely(!skb_page_frag_refill(len + headroom, alloc_frag, gfp)))
+       /* Extra tailroom is needed to satisfy XDP's assumption. This
+        * means rx frags coalescing won't work, but consider we've
+        * disabled GSO for XDP, it won't be a big issue.
+        */
+       len = get_mergeable_buf_len(rq, &rq->mrg_avg_pkt_len, room);
+       if (unlikely(!skb_page_frag_refill(len + room, alloc_frag, gfp)))
                return -ENOMEM;
 
        buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset;
        buf += headroom; /* advance address leaving hole at front of pkt */
        get_page(alloc_frag->page);
-       alloc_frag->offset += len + headroom;
+       alloc_frag->offset += len + room;
        hole = alloc_frag->size - alloc_frag->offset;
-       if (hole < len + headroom) {
+       if (hole < len + room) {
                /* To avoid internal fragmentation, if there is very likely not
                 * enough space for another buffer, add the remaining space to
                 * the current buffer.
@@ -2175,8 +2212,9 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
        }
 
        /* Make sure NAPI is not using any XDP TX queues for RX. */
-       for (i = 0; i < vi->max_queue_pairs; i++)
-               napi_disable(&vi->rq[i].napi);
+       if (netif_running(dev))
+               for (i = 0; i < vi->max_queue_pairs; i++)
+                       napi_disable(&vi->rq[i].napi);
 
        netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp);
        err = _virtnet_set_queues(vi, curr_qp + xdp_qp);
@@ -2195,7 +2233,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
                }
                if (old_prog)
                        bpf_prog_put(old_prog);
-               virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
+               if (netif_running(dev))
+                       virtnet_napi_enable(vi->rq[i].vq, &vi->rq[i].napi);
        }
 
        return 0;
@@ -2566,12 +2605,15 @@ static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue,
 {
        struct virtnet_info *vi = netdev_priv(queue->dev);
        unsigned int queue_index = get_netdev_rx_queue_index(queue);
+       unsigned int headroom = virtnet_get_headroom(vi);
+       unsigned int tailroom = headroom ? sizeof(struct skb_shared_info) : 0;
        struct ewma_pkt_len *avg;
 
        BUG_ON(queue_index >= vi->max_queue_pairs);
        avg = &vi->rq[queue_index].mrg_avg_pkt_len;
        return sprintf(buf, "%u\n",
-                      get_mergeable_buf_len(&vi->rq[queue_index], avg));
+                      get_mergeable_buf_len(&vi->rq[queue_index], avg,
+                                      SKB_DATA_ALIGN(headroom + tailroom)));
 }
 
 static struct rx_queue_attribute mergeable_rx_buffer_size_attribute =
index 8b39c16..e04937f 100644 (file)
@@ -977,6 +977,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
 {
        int ret;
        u32 count;
+       int num_pkts;
+       int tx_num_deferred;
        unsigned long flags;
        struct vmxnet3_tx_ctx ctx;
        union Vmxnet3_GenericDesc *gdesc;
@@ -1075,12 +1077,12 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
 #else
        gdesc = ctx.sop_txd;
 #endif
+       tx_num_deferred = le32_to_cpu(tq->shared->txNumDeferred);
        if (ctx.mss) {
                gdesc->txd.hlen = ctx.eth_ip_hdr_size + ctx.l4_hdr_size;
                gdesc->txd.om = VMXNET3_OM_TSO;
                gdesc->txd.msscof = ctx.mss;
-               le32_add_cpu(&tq->shared->txNumDeferred, (skb->len -
-                            gdesc->txd.hlen + ctx.mss - 1) / ctx.mss);
+               num_pkts = (skb->len - gdesc->txd.hlen + ctx.mss - 1) / ctx.mss;
        } else {
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
                        gdesc->txd.hlen = ctx.eth_ip_hdr_size;
@@ -1091,8 +1093,10 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
                        gdesc->txd.om = 0;
                        gdesc->txd.msscof = 0;
                }
-               le32_add_cpu(&tq->shared->txNumDeferred, 1);
+               num_pkts = 1;
        }
+       le32_add_cpu(&tq->shared->txNumDeferred, num_pkts);
+       tx_num_deferred += num_pkts;
 
        if (skb_vlan_tag_present(skb)) {
                gdesc->txd.ti = 1;
@@ -1118,8 +1122,7 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
 
        spin_unlock_irqrestore(&tq->tx_lock, flags);
 
-       if (le32_to_cpu(tq->shared->txNumDeferred) >=
-                                       le32_to_cpu(tq->shared->txThreshold)) {
+       if (tx_num_deferred >= le32_to_cpu(tq->shared->txThreshold)) {
                tq->shared->txNumDeferred = 0;
                VMXNET3_WRITE_BAR0_REG(adapter,
                                       VMXNET3_REG_TXPROD + tq->qid * 8,
@@ -1470,7 +1473,8 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
                        vmxnet3_rx_csum(adapter, skb,
                                        (union Vmxnet3_GenericDesc *)rcd);
                        skb->protocol = eth_type_trans(skb, adapter->netdev);
-                       if (!rcd->tcp || !adapter->lro)
+                       if (!rcd->tcp ||
+                           !(adapter->netdev->features & NETIF_F_LRO))
                                goto not_lro;
 
                        if (segCnt != 0 && mss != 0) {
index 5ba2229..59ec340 100644 (file)
 /*
  * Version numbers
  */
-#define VMXNET3_DRIVER_VERSION_STRING   "1.4.11.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING   "1.4.13.0-k"
 
 /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM      0x01040b00
+#define VMXNET3_DRIVER_VERSION_NUM      0x01040d00
 
 #if defined(CONFIG_PCI_MSI)
        /* RSS only makes sense if MSI-X is supported. */
@@ -342,9 +342,6 @@ struct vmxnet3_adapter {
        u8                      __iomem *hw_addr1; /* for BAR 1 */
        u8                              version;
 
-       bool                            rxcsum;
-       bool                            lro;
-
 #ifdef VMXNET3_RSS
        struct UPT1_RSSConf             *rss_conf;
        bool                            rss;
index 139c61c..ac40924 100644 (file)
@@ -578,12 +578,13 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s
        if (!IS_ERR(neigh)) {
                sock_confirm_neigh(skb, neigh);
                ret = neigh_output(neigh, skb);
+               rcu_read_unlock_bh();
+               return ret;
        }
 
        rcu_read_unlock_bh();
 err:
-       if (unlikely(ret < 0))
-               vrf_tx_error(skb->dev, skb);
+       vrf_tx_error(skb->dev, skb);
        return ret;
 }
 
index afeca6b..ab8b3cb 100644 (file)
@@ -574,7 +574,10 @@ static void ppp_timer(struct timer_list *t)
                        ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
                                     0, NULL);
                        proto->restart_counter--;
-               } else
+               } else if (netif_carrier_ok(proto->dev))
+                       ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0,
+                                    0, NULL);
+               else
                        ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0,
                                     0, NULL);
                break;
index e89e5ef..f246e9e 100644 (file)
@@ -729,6 +729,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
        ieee80211_hw_set(hw, SPECTRUM_MGMT);
        ieee80211_hw_set(hw, SIGNAL_DBM);
        ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+       ieee80211_hw_set(hw, DOESNT_SUPPORT_QOS_NDP);
 
        if (ath9k_ps_enable)
                ieee80211_hw_set(hw, SUPPORTS_PS);
index 15fa00d..1ad97a4 100644 (file)
@@ -6802,7 +6802,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
                return;
 
        /* ignore non-ISO3166 country codes */
-       for (i = 0; i < sizeof(req->alpha2); i++)
+       for (i = 0; i < 2; i++)
                if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
                        brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
                                  req->alpha2[0], req->alpha2[1]);
index 9be0b05..ebe35e6 100644 (file)
@@ -75,6 +75,10 @@ static int brcmf_roamoff;
 module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR);
 MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine");
 
+static int brcmf_iapp_enable;
+module_param_named(iapp, brcmf_iapp_enable, int, 0);
+MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol");
+
 #ifdef DEBUG
 /* always succeed brcmf_bus_started() */
 static int brcmf_ignore_probe_fail;
@@ -441,6 +445,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
        settings->feature_disable = brcmf_feature_disable;
        settings->fcmode = brcmf_fcmode;
        settings->roamoff = !!brcmf_roamoff;
+       settings->iapp = !!brcmf_iapp_enable;
 #ifdef DEBUG
        settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
 #endif
index a62f8e7..ef91461 100644 (file)
@@ -58,6 +58,7 @@ struct brcmf_mp_device {
        unsigned int    feature_disable;
        int             fcmode;
        bool            roamoff;
+       bool            iapp;
        bool            ignore_probe_fail;
        struct brcmfmac_pd_cc *country_codes;
        union {
index 930e423..44b7774 100644 (file)
@@ -230,6 +230,37 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
        schedule_work(&ifp->multicast_work);
 }
 
+/**
+ * brcmf_skb_is_iapp - checks if skb is an IAPP packet
+ *
+ * @skb: skb to check
+ */
+static bool brcmf_skb_is_iapp(struct sk_buff *skb)
+{
+       static const u8 iapp_l2_update_packet[6] __aligned(2) = {
+               0x00, 0x01, 0xaf, 0x81, 0x01, 0x00,
+       };
+       unsigned char *eth_data;
+#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+       const u16 *a, *b;
+#endif
+
+       if (skb->len - skb->mac_len != 6 ||
+           !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+               return false;
+
+       eth_data = skb_mac_header(skb) + ETH_HLEN;
+#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
+       return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) |
+                ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4))));
+#else
+       a = (const u16 *)eth_data;
+       b = (const u16 *)iapp_l2_update_packet;
+
+       return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2]));
+#endif
+}
+
 static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
                                           struct net_device *ndev)
 {
@@ -250,6 +281,23 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
                goto done;
        }
 
+       /* Some recent Broadcom's firmwares disassociate STA when they receive
+        * an 802.11f ADD frame. This behavior can lead to a local DoS security
+        * issue. Attacker may trigger disassociation of any STA by sending a
+        * proper Ethernet frame to the wireless interface.
+        *
+        * Moreover this feature may break AP interfaces in some specific
+        * setups. This applies e.g. to the bridge with hairpin mode enabled and
+        * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware
+        * will get passed back to the wireless interface and cause immediate
+        * disassociation of a just-connected STA.
+        */
+       if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
+               dev_kfree_skb(skb);
+               ret = -EINVAL;
+               goto done;
+       }
+
        /* Make sure there's enough writeable headroom */
        if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
                head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0);
@@ -325,6 +373,15 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 {
+       /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new
+        * STA connects to the AP interface. This is an obsoleted standard most
+        * users don't use, so don't pass these frames up unless requested.
+        */
+       if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) {
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+       }
+
        if (skb->pkt_type == PACKET_MULTICAST)
                ifp->ndev->stats.multicast++;
 
index df8a1ec..232dcbb 100644 (file)
@@ -181,6 +181,7 @@ enum brcmf_netif_stop_reason {
  * @netif_stop_lock: spinlock for update netif_stop from multiple sources.
  * @pend_8021x_cnt: tracks outstanding number of 802.1x frames.
  * @pend_8021x_wait: used for signalling change in count.
+ * @fwil_fwerr: flag indicating fwil layer should return firmware error codes.
  */
 struct brcmf_if {
        struct brcmf_pub *drvr;
@@ -198,6 +199,7 @@ struct brcmf_if {
        wait_queue_head_t pend_8021x_wait;
        struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
        u8 ipv6addr_idx;
+       bool fwil_fwerr;
 };
 
 int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
index 47de35a..bede7b7 100644 (file)
@@ -104,6 +104,9 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
        u32 data;
        int err;
 
+       /* we need to know firmware error */
+       ifp->fwil_fwerr = true;
+
        err = brcmf_fil_iovar_int_get(ifp, name, &data);
        if (err == 0) {
                brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
@@ -112,6 +115,8 @@ static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
                brcmf_dbg(TRACE, "%s feature check failed: %d\n",
                          brcmf_feat_names[id], err);
        }
+
+       ifp->fwil_fwerr = false;
 }
 
 static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
@@ -120,6 +125,9 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
 {
        int err;
 
+       /* we need to know firmware error */
+       ifp->fwil_fwerr = true;
+
        err = brcmf_fil_iovar_data_set(ifp, name, data, len);
        if (err != -BRCMF_FW_UNSUPPORTED) {
                brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
@@ -128,6 +136,8 @@ static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
                brcmf_dbg(TRACE, "%s feature check failed: %d\n",
                          brcmf_feat_names[id], err);
        }
+
+       ifp->fwil_fwerr = false;
 }
 
 #define MAX_CAPS_BUFFER_SIZE   512
index f2cfdd3..fc57511 100644 (file)
@@ -131,6 +131,9 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
                          brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
                err = -EBADE;
        }
+       if (ifp->fwil_fwerr)
+               return fwerr;
+
        return err;
 }
 
index 2ee5413..82064e9 100644 (file)
@@ -462,25 +462,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac)
  * @dev_addr: optional device address.
  *
  * P2P needs mac addresses for P2P device and interface. If no device
- * address it specified, these are derived from the primary net device, ie.
- * the permanent ethernet address of the device.
+ * address it specified, these are derived from a random ethernet
+ * address.
  */
 static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr)
 {
-       struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
-       bool local_admin = false;
+       bool random_addr = false;
 
-       if (!dev_addr || is_zero_ether_addr(dev_addr)) {
-               dev_addr = pri_ifp->mac_addr;
-               local_admin = true;
-       }
+       if (!dev_addr || is_zero_ether_addr(dev_addr))
+               random_addr = true;
 
-       /* Generate the P2P Device Address.  This consists of the device's
-        * primary MAC address with the locally administered bit set.
+       /* Generate the P2P Device Address obtaining a random ethernet
+        * address with the locally administered bit set.
         */
-       memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
-       if (local_admin)
-               p2p->dev_addr[0] |= 0x02;
+       if (random_addr)
+               eth_random_addr(p2p->dev_addr);
+       else
+               memcpy(p2p->dev_addr, dev_addr, ETH_ALEN);
 
        /* Generate the P2P Interface Address.  If the discovery and connection
         * BSSCFGs need to simultaneously co-exist, then this address must be
index c5f2ddf..e5a2fc7 100644 (file)
@@ -91,7 +91,6 @@ config IWLWIFI_BCAST_FILTERING
 config IWLWIFI_PCIE_RTPM
        bool "Enable runtime power management mode for PCIe devices"
        depends on IWLMVM && PM && EXPERT
-       default false
        help
          Say Y here to enable runtime power management for PCIe
          devices.  If enabled, the device will go into low power mode
index 90a1d14..ab14694 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/stringify.h>
 #include "iwl-config.h"
 #include "iwl-agn-hw.h"
+#include "fw/file.h"
 
 /* Highest firmware API version supported */
 #define IWL9000_UCODE_API_MAX  36
@@ -265,6 +266,67 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = {
        .integrated = true,
        .soc_latency = 5000,
 };
+
+const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = {
+       .name = "Intel(R) Dual Band Wireless AC 9460",
+       .fw_name_pre = IWL9000A_FW_PRE,
+       .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+       .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+       IWL_DEVICE_9000,
+       .ht_params = &iwl9000_ht_params,
+       .nvm_ver = IWL9000_NVM_VERSION,
+       .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+       .integrated = true,
+       .soc_latency = 5000,
+       .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = {
+       .name = "Intel(R) Dual Band Wireless AC 9461",
+       .fw_name_pre = IWL9000A_FW_PRE,
+       .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+       .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+       IWL_DEVICE_9000,
+       .ht_params = &iwl9000_ht_params,
+       .nvm_ver = IWL9000_NVM_VERSION,
+       .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+       .integrated = true,
+       .soc_latency = 5000,
+       .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = {
+       .name = "Intel(R) Dual Band Wireless AC 9462",
+       .fw_name_pre = IWL9000A_FW_PRE,
+       .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+       .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+       IWL_DEVICE_9000,
+       .ht_params = &iwl9000_ht_params,
+       .nvm_ver = IWL9000_NVM_VERSION,
+       .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+       .integrated = true,
+       .soc_latency = 5000,
+       .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
+const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = {
+       .name = "Intel(R) Dual Band Wireless AC 9560",
+       .fw_name_pre = IWL9000A_FW_PRE,
+       .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE,
+       .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE,
+       IWL_DEVICE_9000,
+       .ht_params = &iwl9000_ht_params,
+       .nvm_ver = IWL9000_NVM_VERSION,
+       .nvm_calib_ver = IWL9000_TX_POWER_VERSION,
+       .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+       .integrated = true,
+       .soc_latency = 5000,
+       .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK
+};
+
 MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX));
index 3721a3e..f824beb 100644 (file)
@@ -211,7 +211,7 @@ enum {
  * @TE_V2_NOTIF_HOST_FRAG_END:request/receive notification on frag end
  * @TE_V2_NOTIF_INTERNAL_FRAG_START: internal FW use.
  * @TE_V2_NOTIF_INTERNAL_FRAG_END: internal FW use.
- * @T2_V2_START_IMMEDIATELY: start time event immediately
+ * @TE_V2_START_IMMEDIATELY: start time event immediately
  * @TE_V2_DEP_OTHER: depends on another time event
  * @TE_V2_DEP_TSF: depends on a specific time
  * @TE_V2_EVENT_SOCIOPATHIC: can't co-exist with other events of tha same MAC
@@ -230,7 +230,7 @@ enum iwl_time_event_policy {
        TE_V2_NOTIF_HOST_FRAG_END = BIT(5),
        TE_V2_NOTIF_INTERNAL_FRAG_START = BIT(6),
        TE_V2_NOTIF_INTERNAL_FRAG_END = BIT(7),
-       T2_V2_START_IMMEDIATELY = BIT(11),
+       TE_V2_START_IMMEDIATELY = BIT(11),
 
        /* placement characteristics */
        TE_V2_DEP_OTHER = BIT(TE_V2_PLACEMENT_POS),
index 67aefc8..7bd704a 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -33,6 +34,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -942,7 +944,6 @@ dump_trans_data:
 
 out:
        iwl_fw_free_dump_desc(fwrt);
-       fwrt->dump.trig = NULL;
        clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
        IWL_DEBUG_INFO(fwrt, "WRT dump done\n");
 }
@@ -1112,6 +1113,14 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
            fwrt->ops->dump_start(fwrt->ops_ctx))
                return;
 
+       if (fwrt->ops && fwrt->ops->fw_running &&
+           !fwrt->ops->fw_running(fwrt->ops_ctx)) {
+               IWL_ERR(fwrt, "Firmware not running - cannot dump error\n");
+               iwl_fw_free_dump_desc(fwrt);
+               clear_bit(IWL_FWRT_STATUS_DUMPING, &fwrt->status);
+               goto out;
+       }
+
        if (fwrt->trans->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
                /* stop recording */
                iwl_fw_dbg_stop_recording(fwrt);
@@ -1145,7 +1154,7 @@ void iwl_fw_error_dump_wk(struct work_struct *work)
                        iwl_write_prph(fwrt->trans, DBGC_OUT_CTRL, out_ctrl);
                }
        }
-
+out:
        if (fwrt->ops && fwrt->ops->dump_end)
                fwrt->ops->dump_end(fwrt->ops_ctx);
 }
index 223fb77..72259bf 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -33,6 +34,7 @@
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -91,6 +93,7 @@ static inline void iwl_fw_free_dump_desc(struct iwl_fw_runtime *fwrt)
        if (fwrt->dump.desc != &iwl_dump_desc_assert)
                kfree(fwrt->dump.desc);
        fwrt->dump.desc = NULL;
+       fwrt->dump.trig = NULL;
 }
 
 void iwl_fw_error_dump(struct iwl_fw_runtime *fwrt);
index e57ff92..3da468d 100644 (file)
@@ -75,6 +75,20 @@ static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt)
        cancel_delayed_work_sync(&fwrt->timestamp.wk);
 }
 
+static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt)
+{
+       cancel_delayed_work_sync(&fwrt->timestamp.wk);
+}
+
+static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt)
+{
+       if (!fwrt->timestamp.delay)
+               return;
+
+       schedule_delayed_work(&fwrt->timestamp.wk,
+                             round_jiffies_relative(fwrt->timestamp.delay));
+}
+
 #else
 static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
                                          struct dentry *dbgfs_dir)
@@ -84,4 +98,8 @@ static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt,
 
 static inline void iwl_fw_cancel_timestamp(struct iwl_fw_runtime *fwrt) {}
 
+static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {}
+
+static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {}
+
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
index 1a05d50..2cb303c 100644 (file)
@@ -441,6 +441,7 @@ enum iwl_fw_phy_cfg {
        FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS,
        FW_PHY_CFG_RX_CHAIN_POS = 20,
        FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS,
+       FW_PHY_CFG_SHARED_CLK = BIT(31),
 };
 
 #define IWL_UCODE_MAX_CS               1
index c39fe84..2efac30 100644 (file)
@@ -77,8 +77,14 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
 }
 IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
 
-void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt)
+void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)
 {
-       iwl_fw_cancel_timestamp(fwrt);
+       iwl_fw_suspend_timestamp(fwrt);
 }
-IWL_EXPORT_SYMBOL(iwl_fw_runtime_exit);
+IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend);
+
+void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt)
+{
+       iwl_fw_resume_timestamp(fwrt);
+}
+IWL_EXPORT_SYMBOL(iwl_fw_runtime_resume);
index e25c049..3fb940e 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
  *
  * 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
@@ -26,6 +27,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -68,6 +70,7 @@
 struct iwl_fw_runtime_ops {
        int (*dump_start)(void *ctx);
        void (*dump_end)(void *ctx);
+       bool (*fw_running)(void *ctx);
 };
 
 #define MAX_NUM_LMAC 2
@@ -150,6 +153,10 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
 
 void iwl_fw_runtime_exit(struct iwl_fw_runtime *fwrt);
 
+void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt);
+
+void iwl_fw_runtime_resume(struct iwl_fw_runtime *fwrt);
+
 static inline void iwl_fw_set_current_image(struct iwl_fw_runtime *fwrt,
                                            enum iwl_ucode_type cur_fw_img)
 {
index 258d439..f0f5636 100644 (file)
@@ -398,6 +398,7 @@ struct iwl_cfg {
        u8 ucode_api_max;
        u8 ucode_api_min;
        u32 min_umac_error_event_table;
+       u32 extra_phy_cfg_flags;
 };
 
 /*
@@ -477,6 +478,10 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc;
 extern const struct iwl_cfg iwl9461_2ac_cfg_soc;
 extern const struct iwl_cfg iwl9462_2ac_cfg_soc;
 extern const struct iwl_cfg iwl9560_2ac_cfg_soc;
+extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk;
+extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk;
 extern const struct iwl_cfg iwl22000_2ac_cfg_hr;
 extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb;
 extern const struct iwl_cfg iwl22000_2ac_cfg_jf;
index 0e6cf39..2efe9b0 100644 (file)
@@ -1098,6 +1098,8 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        /* make sure the d0i3 exit work is not pending */
        flush_work(&mvm->d0i3_exit_work);
 
+       iwl_fw_runtime_suspend(&mvm->fwrt);
+
        ret = iwl_trans_suspend(trans);
        if (ret)
                return ret;
@@ -2012,6 +2014,8 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
 
        mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
 
+       iwl_fw_runtime_resume(&mvm->fwrt);
+
        return ret;
 }
 
@@ -2038,6 +2042,8 @@ static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file)
 
        mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3;
 
+       iwl_fw_runtime_suspend(&mvm->fwrt);
+
        /* start pseudo D3 */
        rtnl_lock();
        err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true);
@@ -2098,6 +2104,8 @@ static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file)
        __iwl_mvm_resume(mvm, true);
        rtnl_unlock();
 
+       iwl_fw_runtime_resume(&mvm->fwrt);
+
        mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
 
        iwl_abort_notification_waits(&mvm->notif_wait);
index a7892c1..9c436d8 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -35,6 +36,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1281,9 +1283,6 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
 {
        int ret;
 
-       if (!iwl_mvm_firmware_running(mvm))
-               return -EIO;
-
        ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
        if (ret)
                return ret;
index 0920be6..3c59109 100644 (file)
@@ -433,6 +433,10 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
 
        /* Set parameters */
        phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm));
+
+       /* set flags extra PHY configuration flags from the device's cfg */
+       phy_cfg_cmd.phy_cfg |= cpu_to_le32(mvm->cfg->extra_phy_cfg_flags);
+
        phy_cfg_cmd.calib_control.event_trigger =
                mvm->fw->default_calib[ucode_type].event_trigger;
        phy_cfg_cmd.calib_control.flow_trigger =
index 2f22e14..8ba16fc 100644 (file)
@@ -438,7 +438,8 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        }
 
        /* Allocate the CAB queue for softAP and GO interfaces */
-       if (vif->type == NL80211_IFTYPE_AP) {
+       if (vif->type == NL80211_IFTYPE_AP ||
+           vif->type == NL80211_IFTYPE_ADHOC) {
                /*
                 * For TVQM this will be overwritten later with the FW assigned
                 * queue value (when queue is enabled).
index 8aed40a..7152fdc 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -2106,15 +2107,40 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
        if (ret)
                goto out_remove;
 
-       ret = iwl_mvm_add_mcast_sta(mvm, vif);
-       if (ret)
-               goto out_unbind;
-
-       /* Send the bcast station. At this stage the TBTT and DTIM time events
-        * are added and applied to the scheduler */
-       ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
-       if (ret)
-               goto out_rm_mcast;
+       /*
+        * This is not very nice, but the simplest:
+        * For older FWs adding the mcast sta before the bcast station may
+        * cause assert 0x2b00.
+        * This is fixed in later FW so make the order of removal depend on
+        * the TLV
+        */
+       if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_STA_TYPE)) {
+               ret = iwl_mvm_add_mcast_sta(mvm, vif);
+               if (ret)
+                       goto out_unbind;
+               /*
+                * Send the bcast station. At this stage the TBTT and DTIM time
+                * events are added and applied to the scheduler
+                */
+               ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
+               if (ret) {
+                       iwl_mvm_rm_mcast_sta(mvm, vif);
+                       goto out_unbind;
+               }
+       } else {
+               /*
+                * Send the bcast station. At this stage the TBTT and DTIM time
+                * events are added and applied to the scheduler
+                */
+               ret = iwl_mvm_send_add_bcast_sta(mvm, vif);
+               if (ret)
+                       goto out_unbind;
+               ret = iwl_mvm_add_mcast_sta(mvm, vif);
+               if (ret) {
+                       iwl_mvm_send_rm_bcast_sta(mvm, vif);
+                       goto out_unbind;
+               }
+       }
 
        /* must be set before quota calculations */
        mvmvif->ap_ibss_active = true;
@@ -2144,7 +2170,6 @@ out_quota_failed:
        iwl_mvm_power_update_mac(mvm);
        mvmvif->ap_ibss_active = false;
        iwl_mvm_send_rm_bcast_sta(mvm, vif);
-out_rm_mcast:
        iwl_mvm_rm_mcast_sta(mvm, vif);
 out_unbind:
        iwl_mvm_binding_remove_vif(mvm, vif);
@@ -2682,6 +2707,10 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
 
                /* enable beacon filtering */
                WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, 0));
+
+               iwl_mvm_rs_rate_init(mvm, sta, mvmvif->phy_ctxt->channel->band,
+                                    false);
+
                ret = 0;
        } else if (old_state == IEEE80211_STA_AUTHORIZED &&
                   new_state == IEEE80211_STA_ASSOC) {
@@ -3465,6 +3494,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
                ret = 0;
                goto out;
        case NL80211_IFTYPE_STATION:
+               mvmvif->csa_bcn_pending = false;
                break;
        case NL80211_IFTYPE_MONITOR:
                /* always disable PS when a monitor interface is active */
@@ -3508,7 +3538,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
        }
 
        if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) {
-               u32 duration = 2 * vif->bss_conf.beacon_int;
+               u32 duration = 3 * vif->bss_conf.beacon_int;
 
                /* iwl_mvm_protect_session() reads directly from the
                 * device (the system time), so make sure it is
@@ -3521,6 +3551,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm,
                /* Protect the session to make sure we hear the first
                 * beacon on the new channel.
                 */
+               mvmvif->csa_bcn_pending = true;
                iwl_mvm_protect_session(mvm, vif, duration, duration,
                                        vif->bss_conf.beacon_int / 2,
                                        true);
@@ -3959,6 +3990,7 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
        if (vif->type == NL80211_IFTYPE_STATION) {
                struct iwl_mvm_sta *mvmsta;
 
+               mvmvif->csa_bcn_pending = false;
                mvmsta = iwl_mvm_sta_from_staid_protected(mvm,
                                                          mvmvif->ap_sta_id);
 
index 2d28e08..625b238 100644 (file)
@@ -90,6 +90,7 @@
 #include "fw/runtime.h"
 #include "fw/dbg.h"
 #include "fw/acpi.h"
+#include "fw/debugfs.h"
 
 #define IWL_MVM_MAX_ADDRESSES          5
 /* RSSI offset for WkP */
@@ -437,6 +438,9 @@ struct iwl_mvm_vif {
        bool csa_failed;
        u16 csa_target_freq;
 
+       /* Indicates that we are waiting for a beacon on a new channel */
+       bool csa_bcn_pending;
+
        /* TCP Checksum Offload */
        netdev_features_t features;
 };
@@ -1783,6 +1787,7 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm)
 
 static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm)
 {
+       iwl_fw_cancel_timestamp(&mvm->fwrt);
        iwl_free_fw_paging(&mvm->fwrt);
        clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status);
        iwl_fw_dump_conf_clear(&mvm->fwrt);
index 5d525a0..ab7fb5a 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  *
  * 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
@@ -35,6 +36,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018        Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -552,9 +554,15 @@ static void iwl_mvm_fwrt_dump_end(void *ctx)
        iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
 }
 
+static bool iwl_mvm_fwrt_fw_running(void *ctx)
+{
+       return iwl_mvm_firmware_running(ctx);
+}
+
 static const struct iwl_fw_runtime_ops iwl_mvm_fwrt_ops = {
        .dump_start = iwl_mvm_fwrt_dump_start,
        .dump_end = iwl_mvm_fwrt_dump_end,
+       .fw_running = iwl_mvm_fwrt_fw_running,
 };
 
 static struct iwl_op_mode *
@@ -802,7 +810,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        iwl_mvm_leds_exit(mvm);
        iwl_mvm_thermal_exit(mvm);
  out_free:
-       iwl_fw_runtime_exit(&mvm->fwrt);
        iwl_fw_flush_dump(&mvm->fwrt);
 
        if (iwlmvm_mod_params.init_dbg)
@@ -843,7 +850,6 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
 #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_IWLWIFI_DEBUGFS)
        kfree(mvm->d3_resume_sram);
 #endif
-       iwl_fw_runtime_exit(&mvm->fwrt);
        iwl_trans_op_mode_leave(mvm->trans);
 
        iwl_phy_db_free(mvm->phy_db);
index 305cd56..7f5434b 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
  * Copyright(c) 2017           Intel Deutschland GmbH
+ * Copyright(c) 2018           Intel Corporation
  *
  * 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
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
  * The full GNU General Public License is included in this distribution
  * in the file called COPYING.
  *
@@ -34,6 +30,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2018           Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -286,6 +283,20 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt)
                return;
 
        ctxt->ref--;
+
+       /*
+        * Move unused phy's to a default channel. When the phy is moved the,
+        * fw will cleanup immediate quiet bit if it was previously set,
+        * otherwise we might not be able to reuse this phy.
+        */
+       if (ctxt->ref == 0) {
+               struct ieee80211_channel *chan;
+               struct cfg80211_chan_def chandef;
+
+               chan = &mvm->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[0];
+               cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT);
+               iwl_mvm_phy_ctxt_changed(mvm, ctxt, &chandef, 1, 1);
+       }
 }
 
 static void iwl_mvm_binding_iterator(void *_data, u8 *mac,
index 60abb00..47f4c7a 100644 (file)
@@ -2684,7 +2684,8 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
                                struct ieee80211_sta *sta,
                                struct iwl_lq_sta *lq_sta,
                                enum nl80211_band band,
-                               struct rs_rate *rate)
+                               struct rs_rate *rate,
+                               bool init)
 {
        int i, nentries;
        unsigned long active_rate;
@@ -2738,14 +2739,25 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
         */
        if (sta->vht_cap.vht_supported &&
            best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
-               switch (sta->bandwidth) {
-               case IEEE80211_STA_RX_BW_160:
-               case IEEE80211_STA_RX_BW_80:
-               case IEEE80211_STA_RX_BW_40:
+               /*
+                * In AP mode, when a new station associates, rs is initialized
+                * immediately upon association completion, before the phy
+                * context is updated with the association parameters, so the
+                * sta bandwidth might be wider than the phy context allows.
+                * To avoid this issue, always initialize rs with 20mhz
+                * bandwidth rate, and after authorization, when the phy context
+                * is already up-to-date, re-init rs with the correct bw.
+                */
+               u32 bw = init ? RATE_MCS_CHAN_WIDTH_20 : rs_bw_from_sta_bw(sta);
+
+               switch (bw) {
+               case RATE_MCS_CHAN_WIDTH_40:
+               case RATE_MCS_CHAN_WIDTH_80:
+               case RATE_MCS_CHAN_WIDTH_160:
                        initial_rates = rs_optimal_rates_vht;
                        nentries = ARRAY_SIZE(rs_optimal_rates_vht);
                        break;
-               case IEEE80211_STA_RX_BW_20:
+               case RATE_MCS_CHAN_WIDTH_20:
                        initial_rates = rs_optimal_rates_vht_20mhz;
                        nentries = ARRAY_SIZE(rs_optimal_rates_vht_20mhz);
                        break;
@@ -2756,7 +2768,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
 
                active_rate = lq_sta->active_siso_rate;
                rate->type = LQ_VHT_SISO;
-               rate->bw = rs_bw_from_sta_bw(sta);
+               rate->bw = bw;
        } else if (sta->ht_cap.ht_supported &&
                   best_rssi > IWL_RS_LOW_RSSI_THRESHOLD) {
                initial_rates = rs_optimal_rates_ht;
@@ -2839,7 +2851,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
        tbl = &(lq_sta->lq_info[active_tbl]);
        rate = &tbl->rate;
 
-       rs_get_initial_rate(mvm, sta, lq_sta, band, rate);
+       rs_get_initial_rate(mvm, sta, lq_sta, band, rate, init);
        rs_init_optimal_rate(mvm, sta, lq_sta);
 
        WARN_ONCE(rate->ant != ANT_A && rate->ant != ANT_B,
index a3f7c1b..580de58 100644 (file)
@@ -71,6 +71,7 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ieee80211_rx_status *stats = IEEE80211_SKB_RXCB(skb);
        struct iwl_mvm_key_pn *ptk_pn;
+       int res;
        u8 tid, keyidx;
        u8 pn[IEEE80211_CCMP_PN_LEN];
        u8 *extiv;
@@ -127,12 +128,13 @@ static inline int iwl_mvm_check_pn(struct iwl_mvm *mvm, struct sk_buff *skb,
        pn[4] = extiv[1];
        pn[5] = extiv[0];
 
-       if (memcmp(pn, ptk_pn->q[queue].pn[tid],
-                  IEEE80211_CCMP_PN_LEN) <= 0)
+       res = memcmp(pn, ptk_pn->q[queue].pn[tid], IEEE80211_CCMP_PN_LEN);
+       if (res < 0)
+               return -1;
+       if (!res && !(stats->flag & RX_FLAG_ALLOW_SAME_PN))
                return -1;
 
-       if (!(stats->flag & RX_FLAG_AMSDU_MORE))
-               memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
+       memcpy(ptk_pn->q[queue].pn[tid], pn, IEEE80211_CCMP_PN_LEN);
        stats->flag |= RX_FLAG_PN_VALIDATED;
 
        return 0;
@@ -314,28 +316,21 @@ static void iwl_mvm_rx_csum(struct ieee80211_sta *sta,
 }
 
 /*
- * returns true if a packet outside BA session is a duplicate and
- * should be dropped
+ * returns true if a packet is a duplicate and should be dropped.
+ * Updates AMSDU PN tracking info
  */
-static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
-                                 struct ieee80211_rx_status *rx_status,
-                                 struct ieee80211_hdr *hdr,
-                                 struct iwl_rx_mpdu_desc *desc)
+static bool iwl_mvm_is_dup(struct ieee80211_sta *sta, int queue,
+                          struct ieee80211_rx_status *rx_status,
+                          struct ieee80211_hdr *hdr,
+                          struct iwl_rx_mpdu_desc *desc)
 {
        struct iwl_mvm_sta *mvm_sta;
        struct iwl_mvm_rxq_dup_data *dup_data;
-       u8 baid, tid, sub_frame_idx;
+       u8 tid, sub_frame_idx;
 
        if (WARN_ON(IS_ERR_OR_NULL(sta)))
                return false;
 
-       baid = (le32_to_cpu(desc->reorder_data) &
-               IWL_RX_MPDU_REORDER_BAID_MASK) >>
-               IWL_RX_MPDU_REORDER_BAID_SHIFT;
-
-       if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
-               return false;
-
        mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        dup_data = &mvm_sta->dup_data[queue];
 
@@ -365,6 +360,12 @@ static bool iwl_mvm_is_nonagg_dup(struct ieee80211_sta *sta, int queue,
                     dup_data->last_sub_frame[tid] >= sub_frame_idx))
                return true;
 
+       /* Allow same PN as the first subframe for following sub frames */
+       if (dup_data->last_seq[tid] == hdr->seq_ctrl &&
+           sub_frame_idx > dup_data->last_sub_frame[tid] &&
+           desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU)
+               rx_status->flag |= RX_FLAG_ALLOW_SAME_PN;
+
        dup_data->last_seq[tid] = hdr->seq_ctrl;
        dup_data->last_sub_frame[tid] = sub_frame_idx;
 
@@ -971,7 +972,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
                if (ieee80211_is_data(hdr->frame_control))
                        iwl_mvm_rx_csum(sta, skb, desc);
 
-               if (iwl_mvm_is_nonagg_dup(sta, queue, rx_status, hdr, desc)) {
+               if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) {
                        kfree_skb(skb);
                        goto out;
                }
index 6b2674e..80067eb 100644 (file)
@@ -1695,7 +1695,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm,
                             u32 qmask, enum nl80211_iftype iftype,
                             enum iwl_sta_type type)
 {
-       if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+       if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
+           sta->sta_id == IWL_MVM_INVALID_STA) {
                sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype);
                if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
                        return -ENOSPC;
@@ -2039,7 +2040,7 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        struct iwl_trans_txq_scd_cfg cfg = {
                .fifo = IWL_MVM_TX_FIFO_MCAST,
                .sta_id = msta->sta_id,
-               .tid = IWL_MAX_TID_COUNT,
+               .tid = 0,
                .aggregate = false,
                .frame_limit = IWL_FRAME_LIMIT,
        };
@@ -2053,6 +2054,17 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                return -ENOTSUPP;
 
        /*
+        * In IBSS, ieee80211_check_queues() sets the cab_queue to be
+        * invalid, so make sure we use the queue we want.
+        * Note that this is done here as we want to avoid making DQA
+        * changes in mac80211 layer.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC) {
+               vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
+               mvmvif->cab_queue = vif->cab_queue;
+       }
+
+       /*
         * While in previous FWs we had to exclude cab queue from TFD queue
         * mask, now it is needed as any other queue.
         */
@@ -2079,24 +2091,13 @@ int iwl_mvm_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        if (iwl_mvm_has_new_tx_api(mvm)) {
                int queue = iwl_mvm_tvqm_enable_txq(mvm, vif->cab_queue,
                                                    msta->sta_id,
-                                                   IWL_MAX_TID_COUNT,
+                                                   0,
                                                    timeout);
                mvmvif->cab_queue = queue;
        } else if (!fw_has_api(&mvm->fw->ucode_capa,
-                              IWL_UCODE_TLV_API_STA_TYPE)) {
-               /*
-                * In IBSS, ieee80211_check_queues() sets the cab_queue to be
-                * invalid, so make sure we use the queue we want.
-                * Note that this is done here as we want to avoid making DQA
-                * changes in mac80211 layer.
-                */
-               if (vif->type == NL80211_IFTYPE_ADHOC) {
-                       vif->cab_queue = IWL_MVM_DQA_GCAST_QUEUE;
-                       mvmvif->cab_queue = vif->cab_queue;
-               }
+                              IWL_UCODE_TLV_API_STA_TYPE))
                iwl_mvm_enable_txq(mvm, vif->cab_queue, vif->cab_queue, 0,
                                   &cfg, timeout);
-       }
 
        return 0;
 }
@@ -2115,7 +2116,7 @@ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
        iwl_mvm_flush_sta(mvm, &mvmvif->mcast_sta, true, 0);
 
        iwl_mvm_disable_txq(mvm, mvmvif->cab_queue, vif->cab_queue,
-                           IWL_MAX_TID_COUNT, 0);
+                           0, 0);
 
        ret = iwl_mvm_rm_sta_common(mvm, mvmvif->mcast_sta.sta_id);
        if (ret)
@@ -2478,28 +2479,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        /*
         * Note the possible cases:
-        *  1. In DQA mode with an enabled TXQ - TXQ needs to become agg'ed
-        *  2. Non-DQA mode: the TXQ hasn't yet been enabled, so find a free
-        *      one and mark it as reserved
-        *  3. In DQA mode, but no traffic yet on this TID: same treatment as in
-        *      non-DQA mode, since the TXQ hasn't yet been allocated
-        * Don't support case 3 for new TX path as it is not expected to happen
-        * and aggregation will be offloaded soon anyway
+        *  1. An enabled TXQ - TXQ needs to become agg'ed
+        *  2. The TXQ hasn't yet been enabled, so find a free one and mark
+        *      it as reserved
         */
        txq_id = mvmsta->tid_data[tid].txq_id;
-       if (iwl_mvm_has_new_tx_api(mvm)) {
-               if (txq_id == IWL_MVM_INVALID_QUEUE) {
-                       ret = -ENXIO;
-                       goto release_locks;
-               }
-       } else if (unlikely(mvm->queue_info[txq_id].status ==
-                           IWL_MVM_QUEUE_SHARED)) {
-               ret = -ENXIO;
-               IWL_DEBUG_TX_QUEUES(mvm,
-                                   "Can't start tid %d agg on shared queue!\n",
-                                   tid);
-               goto release_locks;
-       } else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) {
+       if (txq_id == IWL_MVM_INVALID_QUEUE) {
                txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id,
                                                 IWL_MVM_DQA_MIN_DATA_QUEUE,
                                                 IWL_MVM_DQA_MAX_DATA_QUEUE);
@@ -2508,16 +2493,16 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        IWL_ERR(mvm, "Failed to allocate agg queue\n");
                        goto release_locks;
                }
-               /*
-                * TXQ shouldn't be in inactive mode for non-DQA, so getting
-                * an inactive queue from iwl_mvm_find_free_queue() is
-                * certainly a bug
-                */
-               WARN_ON(mvm->queue_info[txq_id].status ==
-                       IWL_MVM_QUEUE_INACTIVE);
 
                /* TXQ hasn't yet been enabled, so mark it only as reserved */
                mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED;
+       } else if (unlikely(mvm->queue_info[txq_id].status ==
+                           IWL_MVM_QUEUE_SHARED)) {
+               ret = -ENXIO;
+               IWL_DEBUG_TX_QUEUES(mvm,
+                                   "Can't start tid %d agg on shared queue!\n",
+                                   tid);
+               goto release_locks;
        }
 
        spin_unlock(&mvm->queue_info_lock);
@@ -2696,8 +2681,10 @@ out:
 
 static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
                                        struct iwl_mvm_sta *mvmsta,
-                                       u16 txq_id)
+                                       struct iwl_mvm_tid_data *tid_data)
 {
+       u16 txq_id = tid_data->txq_id;
+
        if (iwl_mvm_has_new_tx_api(mvm))
                return;
 
@@ -2709,8 +2696,10 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm,
         * allocated through iwl_mvm_enable_txq, so we can just mark it back as
         * free.
         */
-       if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED)
+       if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) {
                mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE;
+               tid_data->txq_id = IWL_MVM_INVALID_QUEUE;
+       }
 
        spin_unlock_bh(&mvm->queue_info_lock);
 }
@@ -2741,7 +2730,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
 
        mvmsta->agg_tids &= ~BIT(tid);
 
-       iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id);
+       iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data);
 
        switch (tid_data->state) {
        case IWL_AGG_ON:
@@ -2808,7 +2797,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        mvmsta->agg_tids &= ~BIT(tid);
        spin_unlock_bh(&mvmsta->lock);
 
-       iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id);
+       iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data);
 
        if (old_state >= IWL_AGG_ON) {
                iwl_mvm_drain_sta(mvm, mvmsta, true);
@@ -3170,8 +3159,9 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id,
        int ret, size;
        u32 status;
 
+       /* This is a valid situation for GTK removal */
        if (sta_id == IWL_MVM_INVALID_STA)
-               return -EINVAL;
+               return 0;
 
        key_flags = cpu_to_le16((keyconf->keyidx << STA_KEY_FLG_KEYID_POS) &
                                 STA_KEY_FLG_KEYID_MSK);
@@ -3232,17 +3222,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
                }
                sta_id = mvm_sta->sta_id;
 
-               if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
-                   keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
-                   keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
-                       ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id,
-                                                   false);
-                       goto end;
-               }
-
                /*
                 * It is possible that the 'sta' parameter is NULL, and thus
-                * there is a need to retrieve  the sta from the local station
+                * there is a need to retrieve the sta from the local station
                 * table.
                 */
                if (!sta) {
@@ -3257,6 +3239,17 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
 
                if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
                        return -EINVAL;
+       } else {
+               struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+               sta_id = mvmvif->mcast_sta.sta_id;
+       }
+
+       if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+           keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) {
+               ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false);
+               goto end;
        }
 
        /* If the key_offset is not pre-assigned, we need to find a
index 200ab50..cd91bc4 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
  *
  * 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
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
  * The full GNU General Public License is included in this distribution
  * in the file called COPYING.
  *
@@ -35,6 +31,7 @@
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
  * Copyright(c) 2017 Intel Deutschland GmbH
+ * Copyright(c) 2018 Intel Corporation
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -198,9 +195,13 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm,
                                        struct ieee80211_vif *vif,
                                        const char *errmsg)
 {
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
        if (vif->type != NL80211_IFTYPE_STATION)
                return false;
-       if (vif->bss_conf.assoc && vif->bss_conf.dtim_period)
+
+       if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc &&
+           vif->bss_conf.dtim_period)
                return false;
        if (errmsg)
                IWL_ERR(mvm, "%s\n", errmsg);
@@ -344,7 +345,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm,
                         * and know the dtim period.
                         */
                        iwl_mvm_te_check_disconnect(mvm, te_data->vif,
-                               "No association and the time event is over already...");
+                               "No beacon heard and the time event is over already...");
                        break;
                default:
                        break;
@@ -616,7 +617,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
        time_cmd.repeat = 1;
        time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
                                      TE_V2_NOTIF_HOST_EVENT_END |
-                                     T2_V2_START_IMMEDIATELY);
+                                     TE_V2_START_IMMEDIATELY);
 
        if (!wait_for_notif) {
                iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
@@ -803,7 +804,7 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        time_cmd.repeat = 1;
        time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
                                      TE_V2_NOTIF_HOST_EVENT_END |
-                                     T2_V2_START_IMMEDIATELY);
+                                     TE_V2_START_IMMEDIATELY);
 
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
@@ -913,6 +914,8 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
        time_cmd.interval = cpu_to_le32(1);
        time_cmd.policy = cpu_to_le16(TE_V2_NOTIF_HOST_EVENT_START |
                                      TE_V2_ABSENCE);
+       if (!apply_time)
+               time_cmd.policy |= cpu_to_le16(TE_V2_START_IMMEDIATELY);
 
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
index dda77b3..7dfe4cd 100644 (file)
@@ -419,11 +419,11 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
 {
        struct ieee80211_key_conf *keyconf = info->control.hw_key;
        u8 *crypto_hdr = skb_frag->data + hdrlen;
+       enum iwl_tx_cmd_sec_ctrl type = TX_CMD_SEC_CCM;
        u64 pn;
 
        switch (keyconf->cipher) {
        case WLAN_CIPHER_SUITE_CCMP:
-       case WLAN_CIPHER_SUITE_CCMP_256:
                iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd);
                iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
                break;
@@ -447,13 +447,16 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
                break;
        case WLAN_CIPHER_SUITE_GCMP:
        case WLAN_CIPHER_SUITE_GCMP_256:
+               type = TX_CMD_SEC_GCMP;
+               /* Fall through */
+       case WLAN_CIPHER_SUITE_CCMP_256:
                /* TODO: Taking the key from the table might introduce a race
                 * when PTK rekeying is done, having an old packets with a PN
                 * based on the old key but the message encrypted with a new
                 * one.
                 * Need to handle this.
                 */
-               tx_cmd->sec_ctl |= TX_CMD_SEC_GCMP | TX_CMD_SEC_KEY_FROM_TABLE;
+               tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE;
                tx_cmd->key[0] = keyconf->hw_key_idx;
                iwl_mvm_set_tx_cmd_pn(info, crypto_hdr);
                break;
@@ -645,7 +648,11 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
                if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
                    info.control.vif->type == NL80211_IFTYPE_AP ||
                    info.control.vif->type == NL80211_IFTYPE_ADHOC) {
-                       sta_id = mvmvif->bcast_sta.sta_id;
+                       if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE)
+                               sta_id = mvmvif->bcast_sta.sta_id;
+                       else
+                               sta_id = mvmvif->mcast_sta.sta_id;
+
                        queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info,
                                                           hdr->frame_control);
                        if (queue < 0)
@@ -1887,14 +1894,12 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags)
        struct iwl_mvm_int_sta *int_sta = sta;
        struct iwl_mvm_sta *mvm_sta = sta;
 
-       if (iwl_mvm_has_new_tx_api(mvm)) {
-               if (internal)
-                       return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id,
-                                                     BIT(IWL_MGMT_TID), flags);
+       BUILD_BUG_ON(offsetof(struct iwl_mvm_int_sta, sta_id) !=
+                    offsetof(struct iwl_mvm_sta, sta_id));
 
+       if (iwl_mvm_has_new_tx_api(mvm))
                return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id,
-                                             0xFF, flags);
-       }
+                                             0xff | BIT(IWL_MGMT_TID), flags);
 
        if (internal)
                return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk,
index 56fc287..e323d3a 100644 (file)
@@ -579,25 +579,25 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_soc)},
-       {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_soc)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)},
+       {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)},
        {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)},
        {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)},
index 6d0a907..fabae0f 100644 (file)
@@ -147,7 +147,7 @@ static void iwl_pcie_gen2_tfd_unmap(struct iwl_trans *trans,
        /* Sanity check on number of chunks */
        num_tbs = iwl_pcie_gen2_get_num_tbs(trans, tfd);
 
-       if (num_tbs >= trans_pcie->max_tbs) {
+       if (num_tbs > trans_pcie->max_tbs) {
                IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
                return;
        }
index 3f85713..1a56628 100644 (file)
@@ -378,7 +378,7 @@ static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
        /* Sanity check on number of chunks */
        num_tbs = iwl_pcie_tfd_get_num_tbs(trans, tfd);
 
-       if (num_tbs >= trans_pcie->max_tbs) {
+       if (num_tbs > trans_pcie->max_tbs) {
                IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
                /* @todo issue fatal error, it is quite serious situation */
                return;
index 1cf22e6..35b21f8 100644 (file)
@@ -2727,6 +2727,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info,
        mutex_init(&data->mutex);
 
        data->netgroup = hwsim_net_get_netgroup(net);
+       data->wmediumd = hwsim_net_get_wmediumd(net);
 
        /* Enable frame retransmissions for lossy channels */
        hw->max_rates = 4;
@@ -3516,7 +3517,7 @@ static int __init init_mac80211_hwsim(void)
 
        spin_lock_init(&hwsim_radio_lock);
 
-       hwsim_wq = alloc_workqueue("hwsim_wq",WQ_MEM_RECLAIM,0);
+       hwsim_wq = alloc_workqueue("hwsim_wq", 0, 0);
        if (!hwsim_wq)
                return -ENOMEM;
        rhashtable_init(&hwsim_radios_rht, &hwsim_rht_params);
index f9ccd13..e7bbbc9 100644 (file)
@@ -1125,7 +1125,8 @@ static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw)
 
        /* Configuration Space offset 0x70f BIT7 is used to control L0S */
        tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f);
-       _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7));
+       _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) |
+                            ASPM_L1_LATENCY << 3);
 
        /* Configuration Space offset 0x719 Bit3 is for L1
         * BIT4 is for clock request
index 8328d39..3127bc8 100644 (file)
@@ -2005,7 +2005,10 @@ static void netback_changed(struct xenbus_device *dev,
        case XenbusStateInitialised:
        case XenbusStateReconfiguring:
        case XenbusStateReconfigured:
+               break;
+
        case XenbusStateUnknown:
+               wake_up_all(&module_unload_q);
                break;
 
        case XenbusStateInitWait:
@@ -2136,7 +2139,9 @@ static int xennet_remove(struct xenbus_device *dev)
                xenbus_switch_state(dev, XenbusStateClosing);
                wait_event(module_unload_q,
                           xenbus_read_driver_state(dev->otherend) ==
-                          XenbusStateClosing);
+                          XenbusStateClosing ||
+                          xenbus_read_driver_state(dev->otherend) ==
+                          XenbusStateUnknown);
 
                xenbus_switch_state(dev, XenbusStateClosed);
                wait_event(module_unload_q,
index 345acca..1bd7b37 100644 (file)
@@ -278,8 +278,6 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        disk->queue             = q;
        disk->flags             = GENHD_FL_EXT_DEVT;
        nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name);
-       set_capacity(disk, 0);
-       device_add_disk(dev, disk);
 
        if (devm_add_action_or_reset(dev, nd_blk_release_disk, disk))
                return -ENOMEM;
@@ -292,6 +290,7 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk)
        }
 
        set_capacity(disk, available_disk_size >> SECTOR_SHIFT);
+       device_add_disk(dev, disk);
        revalidate_disk(disk);
        return 0;
 }
index 2ef544f..4b95ac5 100644 (file)
@@ -1545,8 +1545,6 @@ static int btt_blk_init(struct btt *btt)
        queue_flag_set_unlocked(QUEUE_FLAG_NONROT, btt->btt_queue);
        btt->btt_queue->queuedata = btt;
 
-       set_capacity(btt->btt_disk, 0);
-       device_add_disk(&btt->nd_btt->dev, btt->btt_disk);
        if (btt_meta_size(btt)) {
                int rc = nd_integrity_init(btt->btt_disk, btt_meta_size(btt));
 
@@ -1558,6 +1556,7 @@ static int btt_blk_init(struct btt *btt)
                }
        }
        set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9);
+       device_add_disk(&btt->nd_btt->dev, btt->btt_disk);
        btt->nd_btt->size = btt->nlba * (u64)btt->sector_size;
        revalidate_disk(btt->btt_disk);
 
index f5c4e8c..2f4d187 100644 (file)
@@ -304,7 +304,7 @@ static const struct attribute_group *nd_pfn_attribute_groups[] = {
 struct device *nd_pfn_devinit(struct nd_pfn *nd_pfn,
                struct nd_namespace_common *ndns)
 {
-       struct device *dev = &nd_pfn->dev;
+       struct device *dev;
 
        if (!nd_pfn)
                return NULL;
index 10041ac..06f8dcc 100644 (file)
@@ -335,8 +335,7 @@ static int pmem_attach_disk(struct device *dev,
                dev_warn(dev, "unable to guarantee persistence of writes\n");
                fua = 0;
        }
-       wbc = nvdimm_has_cache(nd_region) &&
-               !test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags);
+       wbc = nvdimm_has_cache(nd_region);
 
        if (!devm_request_mem_region(dev, res->start, resource_size(res),
                                dev_name(&ndns->dev))) {
index e6d0191..1593e18 100644 (file)
@@ -532,11 +532,13 @@ static ssize_t persistence_domain_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct nd_region *nd_region = to_nd_region(dev);
-       unsigned long flags = nd_region->flags;
 
-       return sprintf(buf, "%s%s\n",
-                       flags & BIT(ND_REGION_PERSIST_CACHE) ? "cpu_cache " : "",
-                       flags & BIT(ND_REGION_PERSIST_MEMCTRL) ? "memory_controller " : "");
+       if (test_bit(ND_REGION_PERSIST_CACHE, &nd_region->flags))
+               return sprintf(buf, "cpu_cache\n");
+       else if (test_bit(ND_REGION_PERSIST_MEMCTRL, &nd_region->flags))
+               return sprintf(buf, "memory_controller\n");
+       else
+               return sprintf(buf, "\n");
 }
 static DEVICE_ATTR_RO(persistence_domain);
 
@@ -593,6 +595,13 @@ static umode_t region_visible(struct kobject *kobj, struct attribute *a, int n)
                        return 0;
        }
 
+       if (a == &dev_attr_persistence_domain.attr) {
+               if ((nd_region->flags & (BIT(ND_REGION_PERSIST_CACHE)
+                                       | BIT(ND_REGION_PERSIST_MEMCTRL))) == 0)
+                       return 0;
+               return a->mode;
+       }
+
        if (a != &dev_attr_set_cookie.attr
                        && a != &dev_attr_available_size.attr)
                return a->mode;
index f431c32..7aeca5d 100644 (file)
@@ -120,8 +120,12 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl)
        int ret;
 
        ret = nvme_reset_ctrl(ctrl);
-       if (!ret)
+       if (!ret) {
                flush_work(&ctrl->reset_work);
+               if (ctrl->state != NVME_CTRL_LIVE)
+                       ret = -ENETRESET;
+       }
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(nvme_reset_ctrl_sync);
@@ -265,7 +269,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
        switch (new_state) {
        case NVME_CTRL_ADMIN_ONLY:
                switch (old_state) {
-               case NVME_CTRL_RECONNECTING:
+               case NVME_CTRL_CONNECTING:
                        changed = true;
                        /* FALLTHRU */
                default:
@@ -276,7 +280,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                switch (old_state) {
                case NVME_CTRL_NEW:
                case NVME_CTRL_RESETTING:
-               case NVME_CTRL_RECONNECTING:
+               case NVME_CTRL_CONNECTING:
                        changed = true;
                        /* FALLTHRU */
                default:
@@ -294,9 +298,9 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                        break;
                }
                break;
-       case NVME_CTRL_RECONNECTING:
+       case NVME_CTRL_CONNECTING:
                switch (old_state) {
-               case NVME_CTRL_LIVE:
+               case NVME_CTRL_NEW:
                case NVME_CTRL_RESETTING:
                        changed = true;
                        /* FALLTHRU */
@@ -309,7 +313,7 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
                case NVME_CTRL_LIVE:
                case NVME_CTRL_ADMIN_ONLY:
                case NVME_CTRL_RESETTING:
-               case NVME_CTRL_RECONNECTING:
+               case NVME_CTRL_CONNECTING:
                        changed = true;
                        /* FALLTHRU */
                default:
@@ -518,9 +522,11 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
                u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector);
                u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift;
 
-               range[n].cattr = cpu_to_le32(0);
-               range[n].nlb = cpu_to_le32(nlb);
-               range[n].slba = cpu_to_le64(slba);
+               if (n < segments) {
+                       range[n].cattr = cpu_to_le32(0);
+                       range[n].nlb = cpu_to_le32(nlb);
+                       range[n].slba = cpu_to_le64(slba);
+               }
                n++;
        }
 
@@ -794,13 +800,9 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
 
 static int nvme_keep_alive(struct nvme_ctrl *ctrl)
 {
-       struct nvme_command c;
        struct request *rq;
 
-       memset(&c, 0, sizeof(c));
-       c.common.opcode = nvme_admin_keep_alive;
-
-       rq = nvme_alloc_request(ctrl->admin_q, &c, BLK_MQ_REQ_RESERVED,
+       rq = nvme_alloc_request(ctrl->admin_q, &ctrl->ka_cmd, BLK_MQ_REQ_RESERVED,
                        NVME_QID_ANY);
        if (IS_ERR(rq))
                return PTR_ERR(rq);
@@ -832,6 +834,8 @@ void nvme_start_keep_alive(struct nvme_ctrl *ctrl)
                return;
 
        INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work);
+       memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd));
+       ctrl->ka_cmd.common.opcode = nvme_admin_keep_alive;
        schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ);
 }
 EXPORT_SYMBOL_GPL(nvme_start_keep_alive);
@@ -1117,14 +1121,19 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
 
 static void nvme_update_formats(struct nvme_ctrl *ctrl)
 {
-       struct nvme_ns *ns;
+       struct nvme_ns *ns, *next;
+       LIST_HEAD(rm_list);
 
        mutex_lock(&ctrl->namespaces_mutex);
        list_for_each_entry(ns, &ctrl->namespaces, list) {
-               if (ns->disk && nvme_revalidate_disk(ns->disk))
-                       nvme_ns_remove(ns);
+               if (ns->disk && nvme_revalidate_disk(ns->disk)) {
+                       list_move_tail(&ns->list, &rm_list);
+               }
        }
        mutex_unlock(&ctrl->namespaces_mutex);
+
+       list_for_each_entry_safe(ns, next, &rm_list, list)
+               nvme_ns_remove(ns);
 }
 
 static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
@@ -2687,7 +2696,7 @@ static ssize_t nvme_sysfs_show_state(struct device *dev,
                [NVME_CTRL_LIVE]        = "live",
                [NVME_CTRL_ADMIN_ONLY]  = "only-admin",
                [NVME_CTRL_RESETTING]   = "resetting",
-               [NVME_CTRL_RECONNECTING]= "reconnecting",
+               [NVME_CTRL_CONNECTING]  = "connecting",
                [NVME_CTRL_DELETING]    = "deleting",
                [NVME_CTRL_DEAD]        = "dead",
        };
@@ -2835,7 +2844,7 @@ out:
 }
 
 static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
-               struct nvme_id_ns *id, bool *new)
+               struct nvme_id_ns *id)
 {
        struct nvme_ctrl *ctrl = ns->ctrl;
        bool is_shared = id->nmic & (1 << 0);
@@ -2851,8 +2860,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                        ret = PTR_ERR(head);
                        goto out_unlock;
                }
-
-               *new = true;
        } else {
                struct nvme_ns_ids ids;
 
@@ -2864,8 +2871,6 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                        ret = -EINVAL;
                        goto out_unlock;
                }
-
-               *new = false;
        }
 
        list_add_tail(&ns->siblings, &head->list);
@@ -2936,7 +2941,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        struct nvme_id_ns *id;
        char disk_name[DISK_NAME_LEN];
        int node = dev_to_node(ctrl->dev), flags = GENHD_FL_EXT_DEVT;
-       bool new = true;
 
        ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
        if (!ns)
@@ -2962,7 +2966,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
        if (id->ncap == 0)
                goto out_free_id;
 
-       if (nvme_init_ns_head(ns, nsid, id, &new))
+       if (nvme_init_ns_head(ns, nsid, id))
                goto out_free_id;
        nvme_setup_streams_ns(ctrl, ns);
        
@@ -3028,9 +3032,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
                pr_warn("%s: failed to register lightnvm sysfs group for identification\n",
                        ns->disk->disk_name);
 
-       if (new)
-               nvme_mpath_add_disk(ns->head);
-       nvme_mpath_add_disk_links(ns);
+       nvme_mpath_add_disk(ns->head);
        return;
  out_unlink_ns:
        mutex_lock(&ctrl->subsys->lock);
@@ -3050,7 +3052,6 @@ static void nvme_ns_remove(struct nvme_ns *ns)
                return;
 
        if (ns->disk && ns->disk->flags & GENHD_FL_UP) {
-               nvme_mpath_remove_disk_links(ns);
                sysfs_remove_group(&disk_to_dev(ns->disk)->kobj,
                                        &nvme_ns_id_attr_group);
                if (ns->ndev)
index 5dd4cee..8f0f34d 100644 (file)
@@ -493,7 +493,7 @@ EXPORT_SYMBOL_GPL(nvmf_should_reconnect);
  */
 int nvmf_register_transport(struct nvmf_transport_ops *ops)
 {
-       if (!ops->create_ctrl || !ops->module)
+       if (!ops->create_ctrl)
                return -EINVAL;
 
        down_write(&nvmf_transports_rwsem);
@@ -650,6 +650,11 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
                                ret = -EINVAL;
                                goto out;
                        }
+                       if (opts->discovery_nqn) {
+                               pr_debug("Ignoring nr_io_queues value for discovery controller\n");
+                               break;
+                       }
+
                        opts->nr_io_queues = min_t(unsigned int,
                                        num_online_cpus(), token);
                        break;
index 25b19f7..a3145d9 100644 (file)
@@ -171,13 +171,14 @@ static inline blk_status_t nvmf_check_init_req(struct nvme_ctrl *ctrl,
            cmd->common.opcode != nvme_fabrics_command ||
            cmd->fabrics.fctype != nvme_fabrics_type_connect) {
                /*
-                * Reconnecting state means transport disruption, which can take
-                * a long time and even might fail permanently, fail fast to
-                * give upper layers a chance to failover.
+                * Connecting state means transport disruption or initial
+                * establishment, which can take a long time and even might
+                * fail permanently, fail fast to give upper layers a chance
+                * to failover.
                 * Deleting state means that the ctrl will never accept commands
                 * again, fail it permanently.
                 */
-               if (ctrl->state == NVME_CTRL_RECONNECTING ||
+               if (ctrl->state == NVME_CTRL_CONNECTING ||
                    ctrl->state == NVME_CTRL_DELETING) {
                        nvme_req(rq)->status = NVME_SC_ABORT_REQ;
                        return BLK_STS_IOERR;
index b856d7c..1dc1387 100644 (file)
@@ -55,9 +55,7 @@ struct nvme_fc_queue {
 
 enum nvme_fcop_flags {
        FCOP_FLAGS_TERMIO       = (1 << 0),
-       FCOP_FLAGS_RELEASED     = (1 << 1),
-       FCOP_FLAGS_COMPLETE     = (1 << 2),
-       FCOP_FLAGS_AEN          = (1 << 3),
+       FCOP_FLAGS_AEN          = (1 << 1),
 };
 
 struct nvmefc_ls_req_op {
@@ -532,7 +530,7 @@ nvme_fc_resume_controller(struct nvme_fc_ctrl *ctrl)
 {
        switch (ctrl->ctrl.state) {
        case NVME_CTRL_NEW:
-       case NVME_CTRL_RECONNECTING:
+       case NVME_CTRL_CONNECTING:
                /*
                 * As all reconnects were suppressed, schedule a
                 * connect.
@@ -777,7 +775,7 @@ nvme_fc_ctrl_connectivity_loss(struct nvme_fc_ctrl *ctrl)
                }
                break;
 
-       case NVME_CTRL_RECONNECTING:
+       case NVME_CTRL_CONNECTING:
                /*
                 * The association has already been terminated and the
                 * controller is attempting reconnects.  No need to do anything
@@ -1208,7 +1206,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl,
                                sizeof(struct fcnvme_lsdesc_cr_assoc_cmd));
 
        assoc_rqst->assoc_cmd.ersp_ratio = cpu_to_be16(ersp_ratio);
-       assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize);
+       assoc_rqst->assoc_cmd.sqsize = cpu_to_be16(qsize - 1);
        /* Linux supports only Dynamic controllers */
        assoc_rqst->assoc_cmd.cntlid = cpu_to_be16(0xffff);
        uuid_copy(&assoc_rqst->assoc_cmd.hostid, &ctrl->ctrl.opts->host->id);
@@ -1323,7 +1321,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
                                sizeof(struct fcnvme_lsdesc_cr_conn_cmd));
        conn_rqst->connect_cmd.ersp_ratio = cpu_to_be16(ersp_ratio);
        conn_rqst->connect_cmd.qid  = cpu_to_be16(queue->qnum);
-       conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize);
+       conn_rqst->connect_cmd.sqsize = cpu_to_be16(qsize - 1);
 
        lsop->queue = queue;
        lsreq->rqstaddr = conn_rqst;
@@ -1470,7 +1468,6 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl)
 
 /* *********************** NVME Ctrl Routines **************************** */
 
-static void __nvme_fc_final_op_cleanup(struct request *rq);
 static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg);
 
 static int
@@ -1512,13 +1509,19 @@ nvme_fc_exit_request(struct blk_mq_tag_set *set, struct request *rq,
 static int
 __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op)
 {
-       int state;
+       unsigned long flags;
+       int opstate;
+
+       spin_lock_irqsave(&ctrl->lock, flags);
+       opstate = atomic_xchg(&op->state, FCPOP_STATE_ABORTED);
+       if (opstate != FCPOP_STATE_ACTIVE)
+               atomic_set(&op->state, opstate);
+       else if (ctrl->flags & FCCTRL_TERMIO)
+               ctrl->iocnt++;
+       spin_unlock_irqrestore(&ctrl->lock, flags);
 
-       state = atomic_xchg(&op->state, FCPOP_STATE_ABORTED);
-       if (state != FCPOP_STATE_ACTIVE) {
-               atomic_set(&op->state, state);
+       if (opstate != FCPOP_STATE_ACTIVE)
                return -ECANCELED;
-       }
 
        ctrl->lport->ops->fcp_abort(&ctrl->lport->localport,
                                        &ctrl->rport->remoteport,
@@ -1532,60 +1535,26 @@ static void
 nvme_fc_abort_aen_ops(struct nvme_fc_ctrl *ctrl)
 {
        struct nvme_fc_fcp_op *aen_op = ctrl->aen_ops;
-       unsigned long flags;
-       int i, ret;
-
-       for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) {
-               if (atomic_read(&aen_op->state) != FCPOP_STATE_ACTIVE)
-                       continue;
-
-               spin_lock_irqsave(&ctrl->lock, flags);
-               if (ctrl->flags & FCCTRL_TERMIO) {
-                       ctrl->iocnt++;
-                       aen_op->flags |= FCOP_FLAGS_TERMIO;
-               }
-               spin_unlock_irqrestore(&ctrl->lock, flags);
-
-               ret = __nvme_fc_abort_op(ctrl, aen_op);
-               if (ret) {
-                       /*
-                        * if __nvme_fc_abort_op failed the io wasn't
-                        * active. Thus this call path is running in
-                        * parallel to the io complete. Treat as non-error.
-                        */
+       int i;
 
-                       /* back out the flags/counters */
-                       spin_lock_irqsave(&ctrl->lock, flags);
-                       if (ctrl->flags & FCCTRL_TERMIO)
-                               ctrl->iocnt--;
-                       aen_op->flags &= ~FCOP_FLAGS_TERMIO;
-                       spin_unlock_irqrestore(&ctrl->lock, flags);
-                       return;
-               }
-       }
+       for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++)
+               __nvme_fc_abort_op(ctrl, aen_op);
 }
 
-static inline int
+static inline void
 __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl,
-               struct nvme_fc_fcp_op *op)
+               struct nvme_fc_fcp_op *op, int opstate)
 {
        unsigned long flags;
-       bool complete_rq = false;
 
-       spin_lock_irqsave(&ctrl->lock, flags);
-       if (unlikely(op->flags & FCOP_FLAGS_TERMIO)) {
+       if (opstate == FCPOP_STATE_ABORTED) {
+               spin_lock_irqsave(&ctrl->lock, flags);
                if (ctrl->flags & FCCTRL_TERMIO) {
                        if (!--ctrl->iocnt)
                                wake_up(&ctrl->ioabort_wait);
                }
+               spin_unlock_irqrestore(&ctrl->lock, flags);
        }
-       if (op->flags & FCOP_FLAGS_RELEASED)
-               complete_rq = true;
-       else
-               op->flags |= FCOP_FLAGS_COMPLETE;
-       spin_unlock_irqrestore(&ctrl->lock, flags);
-
-       return complete_rq;
 }
 
 static void
@@ -1601,6 +1570,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
        __le16 status = cpu_to_le16(NVME_SC_SUCCESS << 1);
        union nvme_result result;
        bool terminate_assoc = true;
+       int opstate;
 
        /*
         * WARNING:
@@ -1639,11 +1609,12 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
         * association to be terminated.
         */
 
+       opstate = atomic_xchg(&op->state, FCPOP_STATE_COMPLETE);
+
        fc_dma_sync_single_for_cpu(ctrl->lport->dev, op->fcp_req.rspdma,
                                sizeof(op->rsp_iu), DMA_FROM_DEVICE);
 
-       if (atomic_read(&op->state) == FCPOP_STATE_ABORTED ||
-                       op->flags & FCOP_FLAGS_TERMIO)
+       if (opstate == FCPOP_STATE_ABORTED)
                status = cpu_to_le16(NVME_SC_ABORT_REQ << 1);
        else if (freq->status)
                status = cpu_to_le16(NVME_SC_INTERNAL << 1);
@@ -1708,7 +1679,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req)
 done:
        if (op->flags & FCOP_FLAGS_AEN) {
                nvme_complete_async_event(&queue->ctrl->ctrl, status, &result);
-               __nvme_fc_fcpop_chk_teardowns(ctrl, op);
+               __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate);
                atomic_set(&op->state, FCPOP_STATE_IDLE);
                op->flags = FCOP_FLAGS_AEN;     /* clear other flags */
                nvme_fc_ctrl_put(ctrl);
@@ -1722,13 +1693,11 @@ done:
        if (status &&
            (blk_queue_dying(rq->q) ||
             ctrl->ctrl.state == NVME_CTRL_NEW ||
-            ctrl->ctrl.state == NVME_CTRL_RECONNECTING))
+            ctrl->ctrl.state == NVME_CTRL_CONNECTING))
                status |= cpu_to_le16(NVME_SC_DNR << 1);
 
-       if (__nvme_fc_fcpop_chk_teardowns(ctrl, op))
-               __nvme_fc_final_op_cleanup(rq);
-       else
-               nvme_end_request(rq, status, result);
+       __nvme_fc_fcpop_chk_teardowns(ctrl, op, opstate);
+       nvme_end_request(rq, status, result);
 
 check_error:
        if (terminate_assoc)
@@ -2415,46 +2384,16 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg)
 }
 
 static void
-__nvme_fc_final_op_cleanup(struct request *rq)
+nvme_fc_complete_rq(struct request *rq)
 {
        struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
        struct nvme_fc_ctrl *ctrl = op->ctrl;
 
        atomic_set(&op->state, FCPOP_STATE_IDLE);
-       op->flags &= ~(FCOP_FLAGS_TERMIO | FCOP_FLAGS_RELEASED |
-                       FCOP_FLAGS_COMPLETE);
 
        nvme_fc_unmap_data(ctrl, rq, op);
        nvme_complete_rq(rq);
        nvme_fc_ctrl_put(ctrl);
-
-}
-
-static void
-nvme_fc_complete_rq(struct request *rq)
-{
-       struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
-       struct nvme_fc_ctrl *ctrl = op->ctrl;
-       unsigned long flags;
-       bool completed = false;
-
-       /*
-        * the core layer, on controller resets after calling
-        * nvme_shutdown_ctrl(), calls complete_rq without our
-        * calling blk_mq_complete_request(), thus there may still
-        * be live i/o outstanding with the LLDD. Means transport has
-        * to track complete calls vs fcpio_done calls to know what
-        * path to take on completes and dones.
-        */
-       spin_lock_irqsave(&ctrl->lock, flags);
-       if (op->flags & FCOP_FLAGS_COMPLETE)
-               completed = true;
-       else
-               op->flags |= FCOP_FLAGS_RELEASED;
-       spin_unlock_irqrestore(&ctrl->lock, flags);
-
-       if (completed)
-               __nvme_fc_final_op_cleanup(rq);
 }
 
 /*
@@ -2476,35 +2415,11 @@ nvme_fc_terminate_exchange(struct request *req, void *data, bool reserved)
        struct nvme_ctrl *nctrl = data;
        struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
        struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(req);
-       unsigned long flags;
-       int status;
 
        if (!blk_mq_request_started(req))
                return;
 
-       spin_lock_irqsave(&ctrl->lock, flags);
-       if (ctrl->flags & FCCTRL_TERMIO) {
-               ctrl->iocnt++;
-               op->flags |= FCOP_FLAGS_TERMIO;
-       }
-       spin_unlock_irqrestore(&ctrl->lock, flags);
-
-       status = __nvme_fc_abort_op(ctrl, op);
-       if (status) {
-               /*
-                * if __nvme_fc_abort_op failed the io wasn't
-                * active. Thus this call path is running in
-                * parallel to the io complete. Treat as non-error.
-                */
-
-               /* back out the flags/counters */
-               spin_lock_irqsave(&ctrl->lock, flags);
-               if (ctrl->flags & FCCTRL_TERMIO)
-                       ctrl->iocnt--;
-               op->flags &= ~FCOP_FLAGS_TERMIO;
-               spin_unlock_irqrestore(&ctrl->lock, flags);
-               return;
-       }
+       __nvme_fc_abort_op(ctrl, op);
 }
 
 
@@ -2566,11 +2481,11 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
                goto out_free_tag_set;
        }
 
-       ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size);
+       ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1);
        if (ret)
                goto out_cleanup_blk_queue;
 
-       ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size);
+       ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1);
        if (ret)
                goto out_delete_hw_queues;
 
@@ -2617,11 +2532,11 @@ nvme_fc_reinit_io_queues(struct nvme_fc_ctrl *ctrl)
        if (ret)
                goto out_free_io_queues;
 
-       ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.opts->queue_size);
+       ret = nvme_fc_create_hw_io_queues(ctrl, ctrl->ctrl.sqsize + 1);
        if (ret)
                goto out_free_io_queues;
 
-       ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.opts->queue_size);
+       ret = nvme_fc_connect_io_queues(ctrl, ctrl->ctrl.sqsize + 1);
        if (ret)
                goto out_delete_hw_queues;
 
@@ -2717,13 +2632,12 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
        nvme_fc_init_queue(ctrl, 0);
 
        ret = __nvme_fc_create_hw_queue(ctrl, &ctrl->queues[0], 0,
-                               NVME_AQ_BLK_MQ_DEPTH);
+                               NVME_AQ_DEPTH);
        if (ret)
                goto out_free_queue;
 
        ret = nvme_fc_connect_admin_queue(ctrl, &ctrl->queues[0],
-                               NVME_AQ_BLK_MQ_DEPTH,
-                               (NVME_AQ_BLK_MQ_DEPTH / 4));
+                               NVME_AQ_DEPTH, (NVME_AQ_DEPTH / 4));
        if (ret)
                goto out_delete_hw_queue;
 
@@ -2751,7 +2665,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
        }
 
        ctrl->ctrl.sqsize =
-               min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap) + 1, ctrl->ctrl.sqsize);
+               min_t(int, NVME_CAP_MQES(ctrl->ctrl.cap), ctrl->ctrl.sqsize);
 
        ret = nvme_enable_ctrl(&ctrl->ctrl, ctrl->ctrl.cap);
        if (ret)
@@ -2784,6 +2698,14 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
                opts->queue_size = ctrl->ctrl.maxcmd;
        }
 
+       if (opts->queue_size > ctrl->ctrl.sqsize + 1) {
+               /* warn if sqsize is lower than queue_size */
+               dev_warn(ctrl->ctrl.device,
+                       "queue_size %zu > ctrl sqsize %u, clamping down\n",
+                       opts->queue_size, ctrl->ctrl.sqsize + 1);
+               opts->queue_size = ctrl->ctrl.sqsize + 1;
+       }
+
        ret = nvme_fc_init_aen_ops(ctrl);
        if (ret)
                goto out_term_aen_ops;
@@ -2943,7 +2865,7 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status)
        unsigned long recon_delay = ctrl->ctrl.opts->reconnect_delay * HZ;
        bool recon = true;
 
-       if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING)
+       if (ctrl->ctrl.state != NVME_CTRL_CONNECTING)
                return;
 
        if (portptr->port_state == FC_OBJSTATE_ONLINE)
@@ -2991,10 +2913,10 @@ nvme_fc_reset_ctrl_work(struct work_struct *work)
        /* will block will waiting for io to terminate */
        nvme_fc_delete_association(ctrl);
 
-       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) {
+       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
                dev_err(ctrl->ctrl.device,
                        "NVME-FC{%d}: error_recovery: Couldn't change state "
-                       "to RECONNECTING\n", ctrl->cnum);
+                       "to CONNECTING\n", ctrl->cnum);
                return;
        }
 
@@ -3195,7 +3117,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
         * transport errors (frame drop, LS failure) inherently must kill
         * the association. The transport is coded so that any command used
         * to create the association (prior to a LIVE state transition
-        * while NEW or RECONNECTING) will fail if it completes in error or
+        * while NEW or CONNECTING) will fail if it completes in error or
         * times out.
         *
         * As such: as the connect request was mostly likely due to a
index 3b211d9..060f69e 100644 (file)
@@ -198,30 +198,16 @@ void nvme_mpath_add_disk(struct nvme_ns_head *head)
 {
        if (!head->disk)
                return;
-       device_add_disk(&head->subsys->dev, head->disk);
-       if (sysfs_create_group(&disk_to_dev(head->disk)->kobj,
-                       &nvme_ns_id_attr_group))
-               pr_warn("%s: failed to create sysfs group for identification\n",
-                       head->disk->disk_name);
-}
-
-void nvme_mpath_add_disk_links(struct nvme_ns *ns)
-{
-       struct kobject *slave_disk_kobj, *holder_disk_kobj;
-
-       if (!ns->head->disk)
-               return;
-
-       slave_disk_kobj = &disk_to_dev(ns->disk)->kobj;
-       if (sysfs_create_link(ns->head->disk->slave_dir, slave_disk_kobj,
-                       kobject_name(slave_disk_kobj)))
-               return;
 
-       holder_disk_kobj = &disk_to_dev(ns->head->disk)->kobj;
-       if (sysfs_create_link(ns->disk->part0.holder_dir, holder_disk_kobj,
-                       kobject_name(holder_disk_kobj)))
-               sysfs_remove_link(ns->head->disk->slave_dir,
-                       kobject_name(slave_disk_kobj));
+       mutex_lock(&head->subsys->lock);
+       if (!(head->disk->flags & GENHD_FL_UP)) {
+               device_add_disk(&head->subsys->dev, head->disk);
+               if (sysfs_create_group(&disk_to_dev(head->disk)->kobj,
+                               &nvme_ns_id_attr_group))
+                       pr_warn("%s: failed to create sysfs group for identification\n",
+                               head->disk->disk_name);
+       }
+       mutex_unlock(&head->subsys->lock);
 }
 
 void nvme_mpath_remove_disk(struct nvme_ns_head *head)
@@ -238,14 +224,3 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
        blk_cleanup_queue(head->disk->queue);
        put_disk(head->disk);
 }
-
-void nvme_mpath_remove_disk_links(struct nvme_ns *ns)
-{
-       if (!ns->head->disk)
-               return;
-
-       sysfs_remove_link(ns->disk->part0.holder_dir,
-                       kobject_name(&disk_to_dev(ns->head->disk)->kobj));
-       sysfs_remove_link(ns->head->disk->slave_dir,
-                       kobject_name(&disk_to_dev(ns->disk)->kobj));
-}
index 8e4550f..d733b14 100644 (file)
@@ -123,7 +123,7 @@ enum nvme_ctrl_state {
        NVME_CTRL_LIVE,
        NVME_CTRL_ADMIN_ONLY,    /* Only admin queue live */
        NVME_CTRL_RESETTING,
-       NVME_CTRL_RECONNECTING,
+       NVME_CTRL_CONNECTING,
        NVME_CTRL_DELETING,
        NVME_CTRL_DEAD,
 };
@@ -183,6 +183,7 @@ struct nvme_ctrl {
        struct work_struct scan_work;
        struct work_struct async_event_work;
        struct delayed_work ka_work;
+       struct nvme_command ka_cmd;
        struct work_struct fw_act_work;
 
        /* Power saving configuration */
@@ -409,9 +410,7 @@ bool nvme_req_needs_failover(struct request *req, blk_status_t error);
 void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl);
 int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head);
 void nvme_mpath_add_disk(struct nvme_ns_head *head);
-void nvme_mpath_add_disk_links(struct nvme_ns *ns);
 void nvme_mpath_remove_disk(struct nvme_ns_head *head);
-void nvme_mpath_remove_disk_links(struct nvme_ns *ns);
 
 static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
 {
@@ -453,12 +452,6 @@ static inline void nvme_mpath_add_disk(struct nvme_ns_head *head)
 static inline void nvme_mpath_remove_disk(struct nvme_ns_head *head)
 {
 }
-static inline void nvme_mpath_add_disk_links(struct nvme_ns *ns)
-{
-}
-static inline void nvme_mpath_remove_disk_links(struct nvme_ns *ns)
-{
-}
 static inline void nvme_mpath_clear_current_path(struct nvme_ns *ns)
 {
 }
index 6fe7af0..b6f43b7 100644 (file)
@@ -1141,7 +1141,7 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts)
        /* If there is a reset/reinit ongoing, we shouldn't reset again. */
        switch (dev->ctrl.state) {
        case NVME_CTRL_RESETTING:
-       case NVME_CTRL_RECONNECTING:
+       case NVME_CTRL_CONNECTING:
                return false;
        default:
                break;
@@ -1153,12 +1153,6 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts)
        if (!(csts & NVME_CSTS_CFS) && !nssro)
                return false;
 
-       /* If PCI error recovery process is happening, we cannot reset or
-        * the recovery mechanism will surely fail.
-        */
-       if (pci_channel_offline(to_pci_dev(dev->dev)))
-               return false;
-
        return true;
 }
 
@@ -1189,6 +1183,13 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
        struct nvme_command cmd;
        u32 csts = readl(dev->bar + NVME_REG_CSTS);
 
+       /* If PCI error recovery process is happening, we cannot reset or
+        * the recovery mechanism will surely fail.
+        */
+       mb();
+       if (pci_channel_offline(to_pci_dev(dev->dev)))
+               return BLK_EH_RESET_TIMER;
+
        /*
         * Reset immediately if the controller is failed
         */
@@ -1215,13 +1216,17 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
         * cancellation error. All outstanding requests are completed on
         * shutdown, so we return BLK_EH_HANDLED.
         */
-       if (dev->ctrl.state == NVME_CTRL_RESETTING) {
+       switch (dev->ctrl.state) {
+       case NVME_CTRL_CONNECTING:
+       case NVME_CTRL_RESETTING:
                dev_warn(dev->ctrl.device,
                         "I/O %d QID %d timeout, disable controller\n",
                         req->tag, nvmeq->qid);
                nvme_dev_disable(dev, false);
                nvme_req(req)->flags |= NVME_REQ_CANCELLED;
                return BLK_EH_HANDLED;
+       default:
+               break;
        }
 
        /*
@@ -1364,18 +1369,14 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues,
 static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq,
                                int qid, int depth)
 {
-       if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
-               unsigned offset = (qid - 1) * roundup(SQ_SIZE(depth),
-                                                     dev->ctrl.page_size);
-               nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
-               nvmeq->sq_cmds_io = dev->cmb + offset;
-       } else {
-               nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
-                                       &nvmeq->sq_dma_addr, GFP_KERNEL);
-               if (!nvmeq->sq_cmds)
-                       return -ENOMEM;
-       }
+       /* CMB SQEs will be mapped before creation */
+       if (qid && dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS))
+               return 0;
 
+       nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth),
+                                           &nvmeq->sq_dma_addr, GFP_KERNEL);
+       if (!nvmeq->sq_cmds)
+               return -ENOMEM;
        return 0;
 }
 
@@ -1449,10 +1450,17 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
        struct nvme_dev *dev = nvmeq->dev;
        int result;
 
+       if (dev->cmb && use_cmb_sqes && (dev->cmbsz & NVME_CMBSZ_SQS)) {
+               unsigned offset = (qid - 1) * roundup(SQ_SIZE(nvmeq->q_depth),
+                                                     dev->ctrl.page_size);
+               nvmeq->sq_dma_addr = dev->cmb_bus_addr + offset;
+               nvmeq->sq_cmds_io = dev->cmb + offset;
+       }
+
        nvmeq->cq_vector = qid - 1;
        result = adapter_alloc_cq(dev, qid, nvmeq);
        if (result < 0)
-               return result;
+               goto release_vector;
 
        result = adapter_alloc_sq(dev, qid, nvmeq);
        if (result < 0)
@@ -1466,9 +1474,12 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
        return result;
 
  release_sq:
+       dev->online_queues--;
        adapter_delete_sq(dev, qid);
  release_cq:
        adapter_delete_cq(dev, qid);
+ release_vector:
+       nvmeq->cq_vector = -1;
        return result;
 }
 
@@ -1903,7 +1914,7 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
        int result, nr_io_queues;
        unsigned long size;
 
-       nr_io_queues = num_present_cpus();
+       nr_io_queues = num_possible_cpus();
        result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
        if (result < 0)
                return result;
@@ -2288,12 +2299,12 @@ static void nvme_reset_work(struct work_struct *work)
                nvme_dev_disable(dev, false);
 
        /*
-        * Introduce RECONNECTING state from nvme-fc/rdma transports to mark the
+        * Introduce CONNECTING state from nvme-fc/rdma transports to mark the
         * initializing procedure here.
         */
-       if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RECONNECTING)) {
+       if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_CONNECTING)) {
                dev_warn(dev->ctrl.device,
-                       "failed to mark controller RECONNECTING\n");
+                       "failed to mark controller CONNECTING\n");
                goto out;
        }
 
index 2bc059f..4d84a73 100644 (file)
@@ -887,7 +887,7 @@ free_ctrl:
 static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl)
 {
        /* If we are resetting/deleting then do nothing */
-       if (ctrl->ctrl.state != NVME_CTRL_RECONNECTING) {
+       if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) {
                WARN_ON_ONCE(ctrl->ctrl.state == NVME_CTRL_NEW ||
                        ctrl->ctrl.state == NVME_CTRL_LIVE);
                return;
@@ -973,7 +973,7 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
        blk_mq_unquiesce_queue(ctrl->ctrl.admin_q);
        nvme_start_queues(&ctrl->ctrl);
 
-       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) {
+       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
                /* state change failure should never happen */
                WARN_ON_ONCE(1);
                return;
@@ -1051,7 +1051,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue,
        struct nvme_rdma_device *dev = queue->device;
        struct ib_device *ibdev = dev->dev;
 
-       if (!blk_rq_bytes(rq))
+       if (!blk_rq_payload_bytes(rq))
                return;
 
        if (req->mr) {
@@ -1166,7 +1166,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue,
 
        c->common.flags |= NVME_CMD_SGL_METABUF;
 
-       if (!blk_rq_bytes(rq))
+       if (!blk_rq_payload_bytes(rq))
                return nvme_rdma_set_sg_null(c);
 
        req->sg_table.sgl = req->first_sgl;
@@ -1756,7 +1756,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work)
        nvme_stop_ctrl(&ctrl->ctrl);
        nvme_rdma_shutdown_ctrl(ctrl, false);
 
-       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) {
+       if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) {
                /* state change failure should never happen */
                WARN_ON_ONCE(1);
                return;
@@ -1784,11 +1784,8 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work)
        return;
 
 out_fail:
-       dev_warn(ctrl->ctrl.device, "Removing after reset failure\n");
-       nvme_remove_namespaces(&ctrl->ctrl);
-       nvme_rdma_shutdown_ctrl(ctrl, true);
-       nvme_uninit_ctrl(&ctrl->ctrl);
-       nvme_put_ctrl(&ctrl->ctrl);
+       ++ctrl->ctrl.nr_reconnects;
+       nvme_rdma_reconnect_or_remove(ctrl);
 }
 
 static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
@@ -1942,6 +1939,9 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
        if (!ctrl->queues)
                goto out_uninit_ctrl;
 
+       changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING);
+       WARN_ON_ONCE(!changed);
+
        ret = nvme_rdma_configure_admin_queue(ctrl, true);
        if (ret)
                goto out_kfree_queues;
index 0bd7371..a78029e 100644 (file)
@@ -520,9 +520,12 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq,
                goto fail;
        }
 
-       /* either variant of SGLs is fine, as we don't support metadata */
-       if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF &&
-                    (flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METASEG)) {
+       /*
+        * For fabrics, PSDT field shall describe metadata pointer (MPTR) that
+        * contains an address of a single contiguous physical buffer that is
+        * byte aligned.
+        */
+       if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) {
                status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
                goto fail;
        }
index 0a4372a..28bbdff 100644 (file)
@@ -105,10 +105,13 @@ static void nvmet_execute_flush(struct nvmet_req *req)
 static u16 nvmet_discard_range(struct nvmet_ns *ns,
                struct nvme_dsm_range *range, struct bio **bio)
 {
-       if (__blkdev_issue_discard(ns->bdev,
+       int ret;
+
+       ret = __blkdev_issue_discard(ns->bdev,
                        le64_to_cpu(range->slba) << (ns->blksize_shift - 9),
                        le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
-                       GFP_KERNEL, 0, bio))
+                       GFP_KERNEL, 0, bio);
+       if (ret && ret != -EOPNOTSUPP)
                return NVME_SC_INTERNAL | NVME_SC_DNR;
        return 0;
 }
index 7991ec3..861d150 100644 (file)
@@ -184,7 +184,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
                return BLK_STS_OK;
        }
 
-       if (blk_rq_bytes(req)) {
+       if (blk_rq_payload_bytes(req)) {
                iod->sg_table.sgl = iod->first_sgl;
                if (sg_alloc_table_chained(&iod->sg_table,
                                blk_rq_nr_phys_segments(req),
@@ -193,7 +193,7 @@ static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
 
                iod->req.sg = iod->sg_table.sgl;
                iod->req.sg_cnt = blk_rq_map_sg(req->q, req, iod->sg_table.sgl);
-               iod->req.transfer_len = blk_rq_bytes(req);
+               iod->req.transfer_len = blk_rq_payload_bytes(req);
        }
 
        blk_mq_start_request(req);
index 36ed84e..f46828e 100644 (file)
@@ -977,11 +977,11 @@ static int of_fwnode_graph_parse_endpoint(const struct fwnode_handle *fwnode,
        return 0;
 }
 
-static void *
+static const void *
 of_fwnode_device_get_match_data(const struct fwnode_handle *fwnode,
                                const struct device *dev)
 {
-       return (void *)of_device_get_match_data(dev);
+       return of_device_get_match_data(dev);
 }
 
 const struct fwnode_operations of_fwnode_ops = {
index 2d87bc1..0c09107 100644 (file)
@@ -55,7 +55,7 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev,
        if (max_opps <= 0)
                return max_opps ? max_opps : -ENODATA;
 
-       freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC);
+       freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_KERNEL);
        if (!freq_table)
                return -ENOMEM;
 
index 8de2d5c..dc9303a 100644 (file)
@@ -613,7 +613,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
        /* setup bus numbers */
        val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
        val &= 0xff000000;
-       val |= 0x00010100;
+       val |= 0x00ff0100;
        dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val);
 
        /* setup command register */
index fc73401..46d47bd 100644 (file)
@@ -3419,22 +3419,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE,
 
 static void quirk_chelsio_extend_vpd(struct pci_dev *dev)
 {
-       pci_set_vpd_size(dev, 8192);
-}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd);
+       int chip = (dev->device & 0xf000) >> 12;
+       int func = (dev->device & 0x0f00) >>  8;
+       int prod = (dev->device & 0x00ff) >>  0;
+
+       /*
+        * If this is a T3-based adapter, there's a 1KB VPD area at offset
+        * 0xc00 which contains the preferred VPD values.  If this is a T4 or
+        * later based adapter, the special VPD is at offset 0x400 for the
+        * Physical Functions (the SR-IOV Virtual Functions have no VPD
+        * Capabilities).  The PCI VPD Access core routines will normally
+        * compute the size of the VPD by parsing the VPD Data Structure at
+        * offset 0x000.  This will result in silent failures when attempting
+        * to accesses these other VPD areas which are beyond those computed
+        * limits.
+        */
+       if (chip == 0x0 && prod >= 0x20)
+               pci_set_vpd_size(dev, 8192);
+       else if (chip >= 0x4 && func < 0x8)
+               pci_set_vpd_size(dev, 2048);
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID,
+                       quirk_chelsio_extend_vpd);
 
 #ifdef CONFIG_ACPI
 /*
@@ -3901,6 +3908,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230,
                         quirk_dma_func1_alias);
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0642,
                         quirk_dma_func1_alias);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0645,
+                        quirk_dma_func1_alias);
 /* https://bugs.gentoo.org/show_bug.cgi?id=497630 */
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
                         PCI_DEVICE_ID_JMICRON_JMB388_ESD,
index 369d48d..3654472 100644 (file)
@@ -401,6 +401,10 @@ void pci_release_resource(struct pci_dev *dev, int resno)
        struct resource *res = dev->resource + resno;
 
        pci_info(dev, "BAR %d: releasing %pR\n", resno, res);
+
+       if (!res->parent)
+               return;
+
        release_resource(res);
        res->end = resource_size(res) - 1;
        res->start = 0;
index 7bc5eee..f63db34 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/perf/arm_pmu.h>
-#include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/sched/clock.h>
 #include <linux/spinlock.h>
@@ -26,6 +25,9 @@
 
 #include <asm/irq_regs.h>
 
+static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu);
+static DEFINE_PER_CPU(int, cpu_irq);
+
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
                                      [PERF_COUNT_HW_CACHE_MAX]
@@ -320,17 +322,9 @@ validate_group(struct perf_event *event)
        return 0;
 }
 
-static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu)
-{
-       struct platform_device *pdev = armpmu->plat_device;
-
-       return pdev ? dev_get_platdata(&pdev->dev) : NULL;
-}
-
 static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
 {
        struct arm_pmu *armpmu;
-       struct arm_pmu_platdata *plat;
        int ret;
        u64 start_clock, finish_clock;
 
@@ -341,14 +335,11 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
         * dereference.
         */
        armpmu = *(void **)dev;
-
-       plat = armpmu_get_platdata(armpmu);
+       if (WARN_ON_ONCE(!armpmu))
+               return IRQ_NONE;
 
        start_clock = sched_clock();
-       if (plat && plat->handle_irq)
-               ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq);
-       else
-               ret = armpmu->handle_irq(irq, armpmu);
+       ret = armpmu->handle_irq(irq, armpmu);
        finish_clock = sched_clock();
 
        perf_sample_event_took(finish_clock - start_clock);
@@ -531,54 +522,41 @@ int perf_num_counters(void)
 }
 EXPORT_SYMBOL_GPL(perf_num_counters);
 
-void armpmu_free_irq(struct arm_pmu *armpmu, int cpu)
+static int armpmu_count_irq_users(const int irq)
 {
-       struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
-       int irq = per_cpu(hw_events->irq, cpu);
+       int cpu, count = 0;
 
-       if (!cpumask_test_and_clear_cpu(cpu, &armpmu->active_irqs))
-               return;
-
-       if (irq_is_percpu_devid(irq)) {
-               free_percpu_irq(irq, &hw_events->percpu_pmu);
-               cpumask_clear(&armpmu->active_irqs);
-               return;
+       for_each_possible_cpu(cpu) {
+               if (per_cpu(cpu_irq, cpu) == irq)
+                       count++;
        }
 
-       free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu));
+       return count;
 }
 
-void armpmu_free_irqs(struct arm_pmu *armpmu)
+void armpmu_free_irq(int irq, int cpu)
 {
-       int cpu;
+       if (per_cpu(cpu_irq, cpu) == 0)
+               return;
+       if (WARN_ON(irq != per_cpu(cpu_irq, cpu)))
+               return;
+
+       if (!irq_is_percpu_devid(irq))
+               free_irq(irq, per_cpu_ptr(&cpu_armpmu, cpu));
+       else if (armpmu_count_irq_users(irq) == 1)
+               free_percpu_irq(irq, &cpu_armpmu);
 
-       for_each_cpu(cpu, &armpmu->supported_cpus)
-               armpmu_free_irq(armpmu, cpu);
+       per_cpu(cpu_irq, cpu) = 0;
 }
 
-int armpmu_request_irq(struct arm_pmu *armpmu, int cpu)
+int armpmu_request_irq(int irq, int cpu)
 {
        int err = 0;
-       struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
        const irq_handler_t handler = armpmu_dispatch_irq;
-       int irq = per_cpu(hw_events->irq, cpu);
        if (!irq)
                return 0;
 
-       if (irq_is_percpu_devid(irq) && cpumask_empty(&armpmu->active_irqs)) {
-               err = request_percpu_irq(irq, handler, "arm-pmu",
-                                        &hw_events->percpu_pmu);
-       } else if (irq_is_percpu_devid(irq)) {
-               int other_cpu = cpumask_first(&armpmu->active_irqs);
-               int other_irq = per_cpu(hw_events->irq, other_cpu);
-
-               if (irq != other_irq) {
-                       pr_warn("mismatched PPIs detected.\n");
-                       err = -EINVAL;
-                       goto err_out;
-               }
-       } else {
-               struct arm_pmu_platdata *platdata = armpmu_get_platdata(armpmu);
+       if (!irq_is_percpu_devid(irq)) {
                unsigned long irq_flags;
 
                err = irq_force_affinity(irq, cpumask_of(cpu));
@@ -589,22 +567,22 @@ int armpmu_request_irq(struct arm_pmu *armpmu, int cpu)
                        goto err_out;
                }
 
-               if (platdata && platdata->irq_flags) {
-                       irq_flags = platdata->irq_flags;
-               } else {
-                       irq_flags = IRQF_PERCPU |
-                                   IRQF_NOBALANCING |
-                                   IRQF_NO_THREAD;
-               }
+               irq_flags = IRQF_PERCPU |
+                           IRQF_NOBALANCING |
+                           IRQF_NO_THREAD;
 
+               irq_set_status_flags(irq, IRQ_NOAUTOEN);
                err = request_irq(irq, handler, irq_flags, "arm-pmu",
-                                 per_cpu_ptr(&hw_events->percpu_pmu, cpu));
+                                 per_cpu_ptr(&cpu_armpmu, cpu));
+       } else if (armpmu_count_irq_users(irq) == 0) {
+               err = request_percpu_irq(irq, handler, "arm-pmu",
+                                        &cpu_armpmu);
        }
 
        if (err)
                goto err_out;
 
-       cpumask_set_cpu(cpu, &armpmu->active_irqs);
+       per_cpu(cpu_irq, cpu) = irq;
        return 0;
 
 err_out:
@@ -612,19 +590,6 @@ err_out:
        return err;
 }
 
-int armpmu_request_irqs(struct arm_pmu *armpmu)
-{
-       int cpu, err;
-
-       for_each_cpu(cpu, &armpmu->supported_cpus) {
-               err = armpmu_request_irq(armpmu, cpu);
-               if (err)
-                       break;
-       }
-
-       return err;
-}
-
 static int armpmu_get_cpu_irq(struct arm_pmu *pmu, int cpu)
 {
        struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
@@ -647,12 +612,14 @@ static int arm_perf_starting_cpu(unsigned int cpu, struct hlist_node *node)
        if (pmu->reset)
                pmu->reset(pmu);
 
+       per_cpu(cpu_armpmu, cpu) = pmu;
+
        irq = armpmu_get_cpu_irq(pmu, cpu);
        if (irq) {
-               if (irq_is_percpu_devid(irq)) {
+               if (irq_is_percpu_devid(irq))
                        enable_percpu_irq(irq, IRQ_TYPE_NONE);
-                       return 0;
-               }
+               else
+                       enable_irq(irq);
        }
 
        return 0;
@@ -667,8 +634,14 @@ static int arm_perf_teardown_cpu(unsigned int cpu, struct hlist_node *node)
                return 0;
 
        irq = armpmu_get_cpu_irq(pmu, cpu);
-       if (irq && irq_is_percpu_devid(irq))
-               disable_percpu_irq(irq);
+       if (irq) {
+               if (irq_is_percpu_devid(irq))
+                       disable_percpu_irq(irq);
+               else
+                       disable_irq_nosync(irq);
+       }
+
+       per_cpu(cpu_armpmu, cpu) = NULL;
 
        return 0;
 }
@@ -800,18 +773,18 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
                                            &cpu_pmu->node);
 }
 
-struct arm_pmu *armpmu_alloc(void)
+static struct arm_pmu *__armpmu_alloc(gfp_t flags)
 {
        struct arm_pmu *pmu;
        int cpu;
 
-       pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
+       pmu = kzalloc(sizeof(*pmu), flags);
        if (!pmu) {
                pr_info("failed to allocate PMU device!\n");
                goto out;
        }
 
-       pmu->hw_events = alloc_percpu(struct pmu_hw_events);
+       pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
        if (!pmu->hw_events) {
                pr_info("failed to allocate per-cpu PMU data.\n");
                goto out_free_pmu;
@@ -857,6 +830,17 @@ out:
        return NULL;
 }
 
+struct arm_pmu *armpmu_alloc(void)
+{
+       return __armpmu_alloc(GFP_KERNEL);
+}
+
+struct arm_pmu *armpmu_alloc_atomic(void)
+{
+       return __armpmu_alloc(GFP_ATOMIC);
+}
+
+
 void armpmu_free(struct arm_pmu *pmu)
 {
        free_percpu(pmu->hw_events);
index 705f1a3..0f19751 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/acpi.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
 #include <linux/percpu.h>
 #include <linux/perf/arm_pmu.h>
 
@@ -87,7 +89,13 @@ static int arm_pmu_acpi_parse_irqs(void)
                        pr_warn("No ACPI PMU IRQ for CPU%d\n", cpu);
                }
 
+               /*
+                * Log and request the IRQ so the core arm_pmu code can manage
+                * it. We'll have to sanity-check IRQs later when we associate
+                * them with their PMUs.
+                */
                per_cpu(pmu_irqs, cpu) = irq;
+               armpmu_request_irq(irq, cpu);
        }
 
        return 0;
@@ -127,7 +135,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
                return pmu;
        }
 
-       pmu = armpmu_alloc();
+       pmu = armpmu_alloc_atomic();
        if (!pmu) {
                pr_warn("Unable to allocate PMU for CPU%d\n",
                        smp_processor_id());
@@ -140,6 +148,35 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
 }
 
 /*
+ * Check whether the new IRQ is compatible with those already associated with
+ * the PMU (e.g. we don't have mismatched PPIs).
+ */
+static bool pmu_irq_matches(struct arm_pmu *pmu, int irq)
+{
+       struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
+       int cpu;
+
+       if (!irq)
+               return true;
+
+       for_each_cpu(cpu, &pmu->supported_cpus) {
+               int other_irq = per_cpu(hw_events->irq, cpu);
+               if (!other_irq)
+                       continue;
+
+               if (irq == other_irq)
+                       continue;
+               if (!irq_is_percpu_devid(irq) && !irq_is_percpu_devid(other_irq))
+                       continue;
+
+               pr_warn("mismatched PPIs detected\n");
+               return false;
+       }
+
+       return true;
+}
+
+/*
  * This must run before the common arm_pmu hotplug logic, so that we can
  * associate a CPU and its interrupt before the common code tries to manage the
  * affinity and so on.
@@ -164,19 +201,14 @@ static int arm_pmu_acpi_cpu_starting(unsigned int cpu)
        if (!pmu)
                return -ENOMEM;
 
-       cpumask_set_cpu(cpu, &pmu->supported_cpus);
-
        per_cpu(probed_pmus, cpu) = pmu;
 
-       /*
-        * Log and request the IRQ so the core arm_pmu code can manage it.  In
-        * some situations (e.g. mismatched PPIs), we may fail to request the
-        * IRQ. However, it may be too late for us to do anything about it.
-        * The common ARM PMU code will log a warning in this case.
-        */
-       hw_events = pmu->hw_events;
-       per_cpu(hw_events->irq, cpu) = irq;
-       armpmu_request_irq(pmu, cpu);
+       if (pmu_irq_matches(pmu, irq)) {
+               hw_events = pmu->hw_events;
+               per_cpu(hw_events->irq, cpu) = irq;
+       }
+
+       cpumask_set_cpu(cpu, &pmu->supported_cpus);
 
        /*
         * Ideally, we'd probe the PMU here when we find the first matching
@@ -247,11 +279,6 @@ static int arm_pmu_acpi_init(void)
        if (acpi_disabled)
                return 0;
 
-       /*
-        * We can't request IRQs yet, since we don't know the cookie value
-        * until we know which CPUs share the same logical PMU. We'll handle
-        * that in arm_pmu_acpi_cpu_starting().
-        */
        ret = arm_pmu_acpi_parse_irqs();
        if (ret)
                return ret;
index 46501cc..7729eda 100644 (file)
@@ -127,13 +127,6 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
                        pdev->dev.of_node);
        }
 
-       /*
-        * Some platforms have all PMU IRQs OR'd into a single IRQ, with a
-        * special platdata function that attempts to demux them.
-        */
-       if (dev_get_platdata(&pdev->dev))
-               cpumask_setall(&pmu->supported_cpus);
-
        for (i = 0; i < num_irqs; i++) {
                int cpu, irq;
 
@@ -164,6 +157,36 @@ static int pmu_parse_irqs(struct arm_pmu *pmu)
        return 0;
 }
 
+static int armpmu_request_irqs(struct arm_pmu *armpmu)
+{
+       struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
+       int cpu, err;
+
+       for_each_cpu(cpu, &armpmu->supported_cpus) {
+               int irq = per_cpu(hw_events->irq, cpu);
+               if (!irq)
+                       continue;
+
+               err = armpmu_request_irq(irq, cpu);
+               if (err)
+                       break;
+       }
+
+       return err;
+}
+
+static void armpmu_free_irqs(struct arm_pmu *armpmu)
+{
+       int cpu;
+       struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
+
+       for_each_cpu(cpu, &armpmu->supported_cpus) {
+               int irq = per_cpu(hw_events->irq, cpu);
+
+               armpmu_free_irq(irq, cpu);
+       }
+}
+
 int arm_pmu_device_probe(struct platform_device *pdev,
                         const struct of_device_id *of_table,
                         const struct pmu_probe_info *probe_table)
index c5ff452..c5493ea 100644 (file)
@@ -675,3 +675,8 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy)
        return 0;
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off);
+
+MODULE_AUTHOR("Yaniv Gardi <ygardi@codeaurora.org>");
+MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY");
+MODULE_LICENSE("GPL v2");
index 1fda9d6..4b91ff7 100644 (file)
@@ -716,7 +716,7 @@ static const char * const uart_b_groups[] = {
        "uart_tx_b_x", "uart_rx_b_x", "uart_cts_b_x", "uart_rts_b_x",
 };
 
-static const char * const uart_ao_b_gpioz_groups[] = {
+static const char * const uart_ao_b_z_groups[] = {
        "uart_ao_tx_b_z", "uart_ao_rx_b_z",
        "uart_ao_cts_b_z", "uart_ao_rts_b_z",
 };
@@ -855,7 +855,7 @@ static struct meson_pmx_func meson_axg_periphs_functions[] = {
        FUNCTION(nand),
        FUNCTION(uart_a),
        FUNCTION(uart_b),
-       FUNCTION(uart_ao_b_gpioz),
+       FUNCTION(uart_ao_b_z),
        FUNCTION(i2c0),
        FUNCTION(i2c1),
        FUNCTION(i2c2),
index c32399f..90c2744 100644 (file)
@@ -124,7 +124,7 @@ static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = {
        EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
 };
 
-const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = s5pv210_pin_bank,
@@ -137,6 +137,11 @@ const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data s5pv210_of_data __initconst = {
+       .ctrl           = s5pv210_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s5pv210_pin_ctrl),
+};
+
 /* Pad retention control code for accessing PMU regmap */
 static atomic_t exynos_shared_retention_refcnt;
 
@@ -199,7 +204,7 @@ static const struct samsung_retention_data exynos3250_retention_data __initconst
  * Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
  * two gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos3250_pin_banks0,
@@ -220,6 +225,11 @@ const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos3250_of_data __initconst = {
+       .ctrl           = exynos3250_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos3250_pin_ctrl),
+};
+
 /* pin banks of exynos4210 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos4210_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -303,7 +313,7 @@ static const struct samsung_retention_data exynos4_audio_retention_data __initco
  * Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
  * three gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos4210_pin_banks0,
@@ -329,6 +339,11 @@ const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos4210_of_data __initconst = {
+       .ctrl           = exynos4210_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos4210_pin_ctrl),
+};
+
 /* pin banks of exynos4x12 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos4x12_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -391,7 +406,7 @@ static const struct samsung_pin_bank_data exynos4x12_pin_banks3[] __initconst =
  * Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes
  * four gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos4x12_pin_banks0,
@@ -427,6 +442,11 @@ const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos4x12_of_data __initconst = {
+       .ctrl           = exynos4x12_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos4x12_pin_ctrl),
+};
+
 /* pin banks of exynos5250 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -487,7 +507,7 @@ static const struct samsung_pin_bank_data exynos5250_pin_banks3[] __initconst =
  * Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
  * four gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5250_pin_banks0,
@@ -523,6 +543,11 @@ const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos5250_of_data __initconst = {
+       .ctrl           = exynos5250_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos5250_pin_ctrl),
+};
+
 /* pin banks of exynos5260 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5260_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
@@ -567,7 +592,7 @@ static const struct samsung_pin_bank_data exynos5260_pin_banks2[] __initconst =
  * Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
  * three gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5260_pin_banks0,
@@ -587,6 +612,11 @@ const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos5260_of_data __initconst = {
+       .ctrl           = exynos5260_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos5260_pin_ctrl),
+};
+
 /* pin banks of exynos5410 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5410_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
@@ -657,7 +687,7 @@ static const struct samsung_pin_bank_data exynos5410_pin_banks3[] __initconst =
  * Samsung pinctrl driver data for Exynos5410 SoC. Exynos5410 SoC includes
  * four gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5410_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos5410_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5410_pin_banks0,
@@ -690,6 +720,11 @@ const struct samsung_pin_ctrl exynos5410_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos5410_of_data __initconst = {
+       .ctrl           = exynos5410_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos5410_pin_ctrl),
+};
+
 /* pin banks of exynos5420 pin-controller 0 */
 static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
@@ -774,7 +809,7 @@ static const struct samsung_retention_data exynos5420_retention_data __initconst
  * Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
  * four gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5420_pin_banks0,
@@ -808,3 +843,8 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
                .retention_data = &exynos4_audio_retention_data,
        },
 };
+
+const struct samsung_pinctrl_of_match_data exynos5420_of_data __initconst = {
+       .ctrl           = exynos5420_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos5420_pin_ctrl),
+};
index fc8f783..71c9d1d 100644 (file)
@@ -175,7 +175,7 @@ static const struct samsung_retention_data exynos5433_fsys_retention_data __init
  * Samsung pinctrl driver data for Exynos5433 SoC. Exynos5433 SoC includes
  * ten gpio/pin-mux/pinconfig controllers.
  */
-const struct samsung_pin_ctrl exynos5433_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos5433_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 data */
                .pin_banks      = exynos5433_pin_banks0,
@@ -260,6 +260,11 @@ const struct samsung_pin_ctrl exynos5433_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data exynos5433_of_data __initconst = {
+       .ctrl           = exynos5433_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos5433_pin_ctrl),
+};
+
 /* pin banks of exynos7 pin-controller - ALIVE */
 static const struct samsung_pin_bank_data exynos7_pin_banks0[] __initconst = {
        EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
@@ -339,7 +344,7 @@ static const struct samsung_pin_bank_data exynos7_pin_banks9[] __initconst = {
        EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
 };
 
-const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 0 Alive data */
                .pin_banks      = exynos7_pin_banks0,
@@ -392,3 +397,8 @@ const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
                .eint_gpio_init = exynos_eint_gpio_init,
        },
 };
+
+const struct samsung_pinctrl_of_match_data exynos7_of_data __initconst = {
+       .ctrl           = exynos7_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(exynos7_pin_ctrl),
+};
index 10187cb..7e824e4 100644 (file)
@@ -565,7 +565,7 @@ static const struct samsung_pin_bank_data s3c2412_pin_banks[] __initconst = {
        PIN_BANK_2BIT(13, 0x080, "gpj"),
 };
 
-const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = {
        {
                .pin_banks      = s3c2412_pin_banks,
                .nr_banks       = ARRAY_SIZE(s3c2412_pin_banks),
@@ -573,6 +573,11 @@ const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data s3c2412_of_data __initconst = {
+       .ctrl           = s3c2412_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s3c2412_pin_ctrl),
+};
+
 static const struct samsung_pin_bank_data s3c2416_pin_banks[] __initconst = {
        PIN_BANK_A(27, 0x000, "gpa"),
        PIN_BANK_2BIT(11, 0x010, "gpb"),
@@ -587,7 +592,7 @@ static const struct samsung_pin_bank_data s3c2416_pin_banks[] __initconst = {
        PIN_BANK_2BIT(2, 0x100, "gpm"),
 };
 
-const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = {
        {
                .pin_banks      = s3c2416_pin_banks,
                .nr_banks       = ARRAY_SIZE(s3c2416_pin_banks),
@@ -595,6 +600,11 @@ const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data s3c2416_of_data __initconst = {
+       .ctrl           = s3c2416_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s3c2416_pin_ctrl),
+};
+
 static const struct samsung_pin_bank_data s3c2440_pin_banks[] __initconst = {
        PIN_BANK_A(25, 0x000, "gpa"),
        PIN_BANK_2BIT(11, 0x010, "gpb"),
@@ -607,7 +617,7 @@ static const struct samsung_pin_bank_data s3c2440_pin_banks[] __initconst = {
        PIN_BANK_2BIT(13, 0x0d0, "gpj"),
 };
 
-const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = {
        {
                .pin_banks      = s3c2440_pin_banks,
                .nr_banks       = ARRAY_SIZE(s3c2440_pin_banks),
@@ -615,6 +625,11 @@ const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = {
        },
 };
 
+const struct samsung_pinctrl_of_match_data s3c2440_of_data __initconst = {
+       .ctrl           = s3c2440_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s3c2440_pin_ctrl),
+};
+
 static const struct samsung_pin_bank_data s3c2450_pin_banks[] __initconst = {
        PIN_BANK_A(28, 0x000, "gpa"),
        PIN_BANK_2BIT(11, 0x010, "gpb"),
@@ -630,10 +645,15 @@ static const struct samsung_pin_bank_data s3c2450_pin_banks[] __initconst = {
        PIN_BANK_2BIT(2, 0x100, "gpm"),
 };
 
-const struct samsung_pin_ctrl s3c2450_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s3c2450_pin_ctrl[] __initconst = {
        {
                .pin_banks      = s3c2450_pin_banks,
                .nr_banks       = ARRAY_SIZE(s3c2450_pin_banks),
                .eint_wkup_init = s3c24xx_eint_init,
        },
 };
+
+const struct samsung_pinctrl_of_match_data s3c2450_of_data __initconst = {
+       .ctrl           = s3c2450_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s3c2450_pin_ctrl),
+};
index 679628a..288e656 100644 (file)
@@ -789,7 +789,7 @@ static const struct samsung_pin_bank_data s3c64xx_pin_banks0[] __initconst = {
  * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
  * one gpio/pin-mux/pinconfig controller.
  */
-const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
+static const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
        {
                /* pin-controller instance 1 data */
                .pin_banks      = s3c64xx_pin_banks0,
@@ -798,3 +798,8 @@ const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
                .eint_wkup_init = s3c64xx_eint_eint0_init,
        },
 };
+
+const struct samsung_pinctrl_of_match_data s3c64xx_of_data __initconst = {
+       .ctrl           = s3c64xx_pin_ctrl,
+       .num_ctrl       = ARRAY_SIZE(s3c64xx_pin_ctrl),
+};
index da58e45..336e88d 100644 (file)
@@ -942,12 +942,33 @@ static int samsung_gpiolib_register(struct platform_device *pdev,
        return 0;
 }
 
+static const struct samsung_pin_ctrl *
+samsung_pinctrl_get_soc_data_for_of_alias(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       const struct samsung_pinctrl_of_match_data *of_data;
+       int id;
+
+       id = of_alias_get_id(node, "pinctrl");
+       if (id < 0) {
+               dev_err(&pdev->dev, "failed to get alias id\n");
+               return NULL;
+       }
+
+       of_data = of_device_get_match_data(&pdev->dev);
+       if (id >= of_data->num_ctrl) {
+               dev_err(&pdev->dev, "invalid alias id %d\n", id);
+               return NULL;
+       }
+
+       return &(of_data->ctrl[id]);
+}
+
 /* retrieve the soc specific data */
 static const struct samsung_pin_ctrl *
 samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
                             struct platform_device *pdev)
 {
-       int id;
        struct device_node *node = pdev->dev.of_node;
        struct device_node *np;
        const struct samsung_pin_bank_data *bdata;
@@ -957,13 +978,9 @@ samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
        void __iomem *virt_base[SAMSUNG_PINCTRL_NUM_RESOURCES];
        unsigned int i;
 
-       id = of_alias_get_id(node, "pinctrl");
-       if (id < 0) {
-               dev_err(&pdev->dev, "failed to get alias id\n");
+       ctrl = samsung_pinctrl_get_soc_data_for_of_alias(pdev);
+       if (!ctrl)
                return ERR_PTR(-ENOENT);
-       }
-       ctrl = of_device_get_match_data(&pdev->dev);
-       ctrl += id;
 
        d->suspend = ctrl->suspend;
        d->resume = ctrl->resume;
@@ -1188,41 +1205,41 @@ static int __maybe_unused samsung_pinctrl_resume(struct device *dev)
 static const struct of_device_id samsung_pinctrl_dt_match[] = {
 #ifdef CONFIG_PINCTRL_EXYNOS_ARM
        { .compatible = "samsung,exynos3250-pinctrl",
-               .data = exynos3250_pin_ctrl },
+               .data = &exynos3250_of_data },
        { .compatible = "samsung,exynos4210-pinctrl",
-               .data = exynos4210_pin_ctrl },
+               .data = &exynos4210_of_data },
        { .compatible = "samsung,exynos4x12-pinctrl",
-               .data = exynos4x12_pin_ctrl },
+               .data = &exynos4x12_of_data },
        { .compatible = "samsung,exynos5250-pinctrl",
-               .data = exynos5250_pin_ctrl },
+               .data = &exynos5250_of_data },
        { .compatible = "samsung,exynos5260-pinctrl",
-               .data = exynos5260_pin_ctrl },
+               .data = &exynos5260_of_data },
        { .compatible = "samsung,exynos5410-pinctrl",
-               .data = exynos5410_pin_ctrl },
+               .data = &exynos5410_of_data },
        { .compatible = "samsung,exynos5420-pinctrl",
-               .data = exynos5420_pin_ctrl },
+               .data = &exynos5420_of_data },
        { .compatible = "samsung,s5pv210-pinctrl",
-               .data = s5pv210_pin_ctrl },
+               .data = &s5pv210_of_data },
 #endif
 #ifdef CONFIG_PINCTRL_EXYNOS_ARM64
        { .compatible = "samsung,exynos5433-pinctrl",
-               .data = exynos5433_pin_ctrl },
+               .data = &exynos5433_of_data },
        { .compatible = "samsung,exynos7-pinctrl",
-               .data = exynos7_pin_ctrl },
+               .data = &exynos7_of_data },
 #endif
 #ifdef CONFIG_PINCTRL_S3C64XX
        { .compatible = "samsung,s3c64xx-pinctrl",
-               .data = s3c64xx_pin_ctrl },
+               .data = &s3c64xx_of_data },
 #endif
 #ifdef CONFIG_PINCTRL_S3C24XX
        { .compatible = "samsung,s3c2412-pinctrl",
-               .data = s3c2412_pin_ctrl },
+               .data = &s3c2412_of_data },
        { .compatible = "samsung,s3c2416-pinctrl",
-               .data = s3c2416_pin_ctrl },
+               .data = &s3c2416_of_data },
        { .compatible = "samsung,s3c2440-pinctrl",
-               .data = s3c2440_pin_ctrl },
+               .data = &s3c2440_of_data },
        { .compatible = "samsung,s3c2450-pinctrl",
-               .data = s3c2450_pin_ctrl },
+               .data = &s3c2450_of_data },
 #endif
        {},
 };
index e204f60..f0cda94 100644 (file)
@@ -282,6 +282,16 @@ struct samsung_pinctrl_drv_data {
 };
 
 /**
+ * struct samsung_pinctrl_of_match_data: OF match device specific configuration data.
+ * @ctrl: array of pin controller data.
+ * @num_ctrl: size of array @ctrl.
+ */
+struct samsung_pinctrl_of_match_data {
+       const struct samsung_pin_ctrl   *ctrl;
+       unsigned int                    num_ctrl;
+};
+
+/**
  * struct samsung_pin_group: represent group of pins of a pinmux function.
  * @name: name of the pin group, used to lookup the group.
  * @pins: the pins included in this group.
@@ -309,20 +319,20 @@ struct samsung_pmx_func {
 };
 
 /* list of all exported SoC specific data */
-extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos5410_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos5433_pin_ctrl[];
-extern const struct samsung_pin_ctrl exynos7_pin_ctrl[];
-extern const struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
-extern const struct samsung_pin_ctrl s3c2412_pin_ctrl[];
-extern const struct samsung_pin_ctrl s3c2416_pin_ctrl[];
-extern const struct samsung_pin_ctrl s3c2440_pin_ctrl[];
-extern const struct samsung_pin_ctrl s3c2450_pin_ctrl[];
-extern const struct samsung_pin_ctrl s5pv210_pin_ctrl[];
+extern const struct samsung_pinctrl_of_match_data exynos3250_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos4210_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos4x12_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos5250_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos5260_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos5410_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos5420_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos5433_of_data;
+extern const struct samsung_pinctrl_of_match_data exynos7_of_data;
+extern const struct samsung_pinctrl_of_match_data s3c64xx_of_data;
+extern const struct samsung_pinctrl_of_match_data s3c2412_of_data;
+extern const struct samsung_pinctrl_of_match_data s3c2416_of_data;
+extern const struct samsung_pinctrl_of_match_data s3c2440_of_data;
+extern const struct samsung_pinctrl_of_match_data s3c2450_of_data;
+extern const struct samsung_pinctrl_of_match_data s5pv210_of_data;
 
 #endif /* __PINCTRL_SAMSUNG_H */
index 18aeee5..35951e7 100644 (file)
@@ -1538,7 +1538,6 @@ static const struct sh_pfc_pin pinmux_pins[] = {
        SH_PFC_PIN_NAMED_CFG('B', 18, AVB_TD1, CFG_FLAGS),
        SH_PFC_PIN_NAMED_CFG('B', 19, AVB_RXC, CFG_FLAGS),
        SH_PFC_PIN_NAMED_CFG('C',  1, PRESETOUT#, CFG_FLAGS),
-       SH_PFC_PIN_NAMED_CFG('F',  1, CLKOUT, CFG_FLAGS),
        SH_PFC_PIN_NAMED_CFG('H', 37, MLB_REF, CFG_FLAGS),
        SH_PFC_PIN_NAMED_CFG('V',  3, QSPI1_SPCLK, CFG_FLAGS),
        SH_PFC_PIN_NAMED_CFG('V',  5, QSPI1_SSL, CFG_FLAGS),
index 6dec6ab..d859973 100644 (file)
@@ -423,7 +423,7 @@ static int chromeos_laptop_probe(struct platform_device *pdev)
        return ret;
 }
 
-static const struct chromeos_laptop samsung_series_5_550 = {
+static struct chromeos_laptop samsung_series_5_550 = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
@@ -432,14 +432,14 @@ static const struct chromeos_laptop samsung_series_5_550 = {
        },
 };
 
-static const struct chromeos_laptop samsung_series_5 = {
+static struct chromeos_laptop samsung_series_5 = {
        .i2c_peripherals = {
                /* Light Sensor. */
                { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
        },
 };
 
-static const struct chromeos_laptop chromebook_pixel = {
+static struct chromeos_laptop chromebook_pixel = {
        .i2c_peripherals = {
                /* Touch Screen. */
                { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
@@ -450,14 +450,14 @@ static const struct chromeos_laptop chromebook_pixel = {
        },
 };
 
-static const struct chromeos_laptop hp_chromebook_14 = {
+static struct chromeos_laptop hp_chromebook_14 = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
        },
 };
 
-static const struct chromeos_laptop dell_chromebook_11 = {
+static struct chromeos_laptop dell_chromebook_11 = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
@@ -466,28 +466,28 @@ static const struct chromeos_laptop dell_chromebook_11 = {
        },
 };
 
-static const struct chromeos_laptop toshiba_cb35 = {
+static struct chromeos_laptop toshiba_cb35 = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
        },
 };
 
-static const struct chromeos_laptop acer_c7_chromebook = {
+static struct chromeos_laptop acer_c7_chromebook = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
        },
 };
 
-static const struct chromeos_laptop acer_ac700 = {
+static struct chromeos_laptop acer_ac700 = {
        .i2c_peripherals = {
                /* Light Sensor. */
                { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
        },
 };
 
-static const struct chromeos_laptop acer_c720 = {
+static struct chromeos_laptop acer_c720 = {
        .i2c_peripherals = {
                /* Touchscreen. */
                { .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 },
@@ -500,14 +500,14 @@ static const struct chromeos_laptop acer_c720 = {
        },
 };
 
-static const struct chromeos_laptop hp_pavilion_14_chromebook = {
+static struct chromeos_laptop hp_pavilion_14_chromebook = {
        .i2c_peripherals = {
                /* Touchpad. */
                { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
        },
 };
 
-static const struct chromeos_laptop cr48 = {
+static struct chromeos_laptop cr48 = {
        .i2c_peripherals = {
                /* Light Sensor. */
                { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
index 9a8f964..51ebc5a 100644 (file)
@@ -105,31 +105,45 @@ config ASUS_LAPTOP
 
          If you have an ACPI-compatible ASUS laptop, say Y or M here.
 
+#
+# The DELL_SMBIOS driver depends on ACPI_WMI and/or DCDBAS if those
+# backends are selected. The "depends" line prevents a configuration
+# where DELL_SMBIOS=y while either of those dependencies =m.
+#
 config DELL_SMBIOS
-       tristate
+       tristate "Dell SMBIOS driver"
+       depends on DCDBAS || DCDBAS=n
+       depends on ACPI_WMI || ACPI_WMI=n
+       ---help---
+       This provides support for the Dell SMBIOS calling interface.
+       If you have a Dell computer you should enable this option.
+
+       Be sure to select at least one backend for it to work properly.
 
 config DELL_SMBIOS_WMI
-       tristate "Dell SMBIOS calling interface (WMI implementation)"
+       bool "Dell SMBIOS driver WMI backend"
+       default y
        depends on ACPI_WMI
        select DELL_WMI_DESCRIPTOR
-       select DELL_SMBIOS
+       depends on DELL_SMBIOS
        ---help---
        This provides an implementation for the Dell SMBIOS calling interface
        communicated over ACPI-WMI.
 
-       If you have a Dell computer from >2007 you should say Y or M here.
+       If you have a Dell computer from >2007 you should say Y here.
        If you aren't sure and this module doesn't work for your computer
        it just won't load.
 
 config DELL_SMBIOS_SMM
-       tristate "Dell SMBIOS calling interface (SMM implementation)"
+       bool "Dell SMBIOS driver SMM backend"
+       default y
        depends on DCDBAS
-       select DELL_SMBIOS
+       depends on DELL_SMBIOS
        ---help---
        This provides an implementation for the Dell SMBIOS calling interface
        communicated over SMI/SMM.
 
-       If you have a Dell computer from <=2017 you should say Y or M here.
+       If you have a Dell computer from <=2017 you should say Y here.
        If you aren't sure and this module doesn't work for your computer
        it just won't load.
 
index c388608..2ba6cb7 100644 (file)
@@ -13,8 +13,9 @@ obj-$(CONFIG_MSI_LAPTOP)      += msi-laptop.o
 obj-$(CONFIG_ACPI_CMPC)                += classmate-laptop.o
 obj-$(CONFIG_COMPAL_LAPTOP)    += compal-laptop.o
 obj-$(CONFIG_DELL_SMBIOS)      += dell-smbios.o
-obj-$(CONFIG_DELL_SMBIOS_WMI)  += dell-smbios-wmi.o
-obj-$(CONFIG_DELL_SMBIOS_SMM)  += dell-smbios-smm.o
+dell-smbios-objs               := dell-smbios-base.o
+dell-smbios-$(CONFIG_DELL_SMBIOS_WMI)  += dell-smbios-wmi.o
+dell-smbios-$(CONFIG_DELL_SMBIOS_SMM)  += dell-smbios-smm.o
 obj-$(CONFIG_DELL_LAPTOP)      += dell-laptop.o
 obj-$(CONFIG_DELL_WMI)         += dell-wmi.o
 obj-$(CONFIG_DELL_WMI_DESCRIPTOR)      += dell-wmi-descriptor.o
index 2a68f59..c52c672 100644 (file)
@@ -127,24 +127,6 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
                },
        },
        {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_CHASSIS_TYPE, "30"), /*Tablet*/
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /*Convertible*/
-               },
-       },
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-                       DMI_MATCH(DMI_CHASSIS_TYPE, "32"), /*Detachable*/
-               },
-       },
-       {
                .ident = "Dell Computer Corporation",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -1279,7 +1261,7 @@ static int kbd_get_state(struct kbd_state *state)
        struct calling_interface_buffer buffer;
        int ret;
 
-       dell_fill_request(&buffer, 0, 0, 0, 0);
+       dell_fill_request(&buffer, 0x1, 0, 0, 0);
        ret = dell_send_request(&buffer,
                                CLASS_KBD_BACKLIGHT, SELECT_KBD_BACKLIGHT);
        if (ret)
similarity index 95%
rename from drivers/platform/x86/dell-smbios.c
rename to drivers/platform/x86/dell-smbios-base.c
index 8541cde..2485c80 100644 (file)
@@ -36,7 +36,7 @@ static DEFINE_MUTEX(smbios_mutex);
 struct smbios_device {
        struct list_head list;
        struct device *device;
-       int (*call_fn)(struct calling_interface_buffer *);
+       int (*call_fn)(struct calling_interface_buffer *arg);
 };
 
 struct smbios_call {
@@ -352,8 +352,10 @@ static void __init parse_da_table(const struct dmi_header *dm)
        struct calling_interface_structure *table =
                container_of(dm, struct calling_interface_structure, header);
 
-       /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least
-          6 bytes of entry */
+       /*
+        * 4 bytes of table header, plus 7 bytes of Dell header
+        * plus at least 6 bytes of entry
+        */
 
        if (dm->length < 17)
                return;
@@ -554,7 +556,7 @@ static void free_group(struct platform_device *pdev)
 static int __init dell_smbios_init(void)
 {
        const struct dmi_device *valid;
-       int ret;
+       int ret, wmi, smm;
 
        valid = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, "Dell System", NULL);
        if (!valid) {
@@ -589,8 +591,24 @@ static int __init dell_smbios_init(void)
        if (ret)
                goto fail_create_group;
 
+       /* register backends */
+       wmi = init_dell_smbios_wmi();
+       if (wmi)
+               pr_debug("Failed to initialize WMI backend: %d\n", wmi);
+       smm = init_dell_smbios_smm();
+       if (smm)
+               pr_debug("Failed to initialize SMM backend: %d\n", smm);
+       if (wmi && smm) {
+               pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n",
+                       wmi, smm);
+               goto fail_sysfs;
+       }
+
        return 0;
 
+fail_sysfs:
+       free_group(platform_device);
+
 fail_create_group:
        platform_device_del(platform_device);
 
@@ -607,6 +625,8 @@ fail_platform_driver:
 
 static void __exit dell_smbios_exit(void)
 {
+       exit_dell_smbios_wmi();
+       exit_dell_smbios_smm();
        mutex_lock(&smbios_mutex);
        if (platform_device) {
                free_group(platform_device);
@@ -617,11 +637,12 @@ static void __exit dell_smbios_exit(void)
        mutex_unlock(&smbios_mutex);
 }
 
-subsys_initcall(dell_smbios_init);
+module_init(dell_smbios_init);
 module_exit(dell_smbios_exit);
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
 MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
+MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
 MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS");
 MODULE_LICENSE("GPL");
index 89f65c4..e9e9da5 100644 (file)
@@ -58,7 +58,7 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, dell_device_table);
 
-static void __init parse_da_table(const struct dmi_header *dm)
+static void parse_da_table(const struct dmi_header *dm)
 {
        struct calling_interface_structure *table =
                container_of(dm, struct calling_interface_structure, header);
@@ -73,7 +73,7 @@ static void __init parse_da_table(const struct dmi_header *dm)
        da_command_code = table->cmdIOCode;
 }
 
-static void __init find_cmd_address(const struct dmi_header *dm, void *dummy)
+static void find_cmd_address(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
        case 0xda: /* Calling interface */
@@ -128,7 +128,7 @@ static bool test_wsmt_enabled(void)
        return false;
 }
 
-static int __init dell_smbios_smm_init(void)
+int init_dell_smbios_smm(void)
 {
        int ret;
        /*
@@ -176,7 +176,7 @@ fail_platform_device_alloc:
        return ret;
 }
 
-static void __exit dell_smbios_smm_exit(void)
+void exit_dell_smbios_smm(void)
 {
        if (platform_device) {
                dell_smbios_unregister_device(&platform_device->dev);
@@ -184,13 +184,3 @@ static void __exit dell_smbios_smm_exit(void)
                free_page((unsigned long)buffer);
        }
 }
-
-subsys_initcall(dell_smbios_smm_init);
-module_exit(dell_smbios_smm_exit);
-
-MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
-MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>");
-MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>");
-MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
-MODULE_DESCRIPTION("Dell SMBIOS communications over SMI");
-MODULE_LICENSE("GPL");
index 609557a..fbefedb 100644 (file)
@@ -228,7 +228,7 @@ static const struct wmi_device_id dell_smbios_wmi_id_table[] = {
        { },
 };
 
-static void __init parse_b1_table(const struct dmi_header *dm)
+static void parse_b1_table(const struct dmi_header *dm)
 {
        struct misc_bios_flags_structure *flags =
        container_of(dm, struct misc_bios_flags_structure, header);
@@ -242,7 +242,7 @@ static void __init parse_b1_table(const struct dmi_header *dm)
                wmi_supported = 1;
 }
 
-static void __init find_b1(const struct dmi_header *dm, void *dummy)
+static void find_b1(const struct dmi_header *dm, void *dummy)
 {
        switch (dm->type) {
        case 0xb1: /* misc bios flags */
@@ -261,7 +261,7 @@ static struct wmi_driver dell_smbios_wmi_driver = {
        .filter_callback = dell_smbios_wmi_filter,
 };
 
-static int __init init_dell_smbios_wmi(void)
+int init_dell_smbios_wmi(void)
 {
        dmi_walk(find_b1, NULL);
 
@@ -271,15 +271,9 @@ static int __init init_dell_smbios_wmi(void)
        return wmi_driver_register(&dell_smbios_wmi_driver);
 }
 
-static void __exit exit_dell_smbios_wmi(void)
+void exit_dell_smbios_wmi(void)
 {
        wmi_driver_unregister(&dell_smbios_wmi_driver);
 }
 
-module_init(init_dell_smbios_wmi);
-module_exit(exit_dell_smbios_wmi);
-
 MODULE_ALIAS("wmi:" DELL_WMI_SMBIOS_GUID);
-MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
-MODULE_DESCRIPTION("Dell SMBIOS communications over WMI");
-MODULE_LICENSE("GPL");
index 138d478..d8adaf9 100644 (file)
@@ -75,4 +75,29 @@ int dell_laptop_register_notifier(struct notifier_block *nb);
 int dell_laptop_unregister_notifier(struct notifier_block *nb);
 void dell_laptop_call_notifier(unsigned long action, void *data);
 
-#endif
+/* for the supported backends */
+#ifdef CONFIG_DELL_SMBIOS_WMI
+int init_dell_smbios_wmi(void);
+void exit_dell_smbios_wmi(void);
+#else /* CONFIG_DELL_SMBIOS_WMI */
+static inline int init_dell_smbios_wmi(void)
+{
+       return -ENODEV;
+}
+static inline void exit_dell_smbios_wmi(void)
+{}
+#endif /* CONFIG_DELL_SMBIOS_WMI */
+
+#ifdef CONFIG_DELL_SMBIOS_SMM
+int init_dell_smbios_smm(void);
+void exit_dell_smbios_smm(void);
+#else /* CONFIG_DELL_SMBIOS_SMM */
+static inline int init_dell_smbios_smm(void)
+{
+       return -ENODEV;
+}
+static inline void exit_dell_smbios_smm(void)
+{}
+#endif /* CONFIG_DELL_SMBIOS_SMM */
+
+#endif /* _DELL_SMBIOS_H_ */
index 2c99274..8d10219 100644 (file)
@@ -714,7 +714,7 @@ static int __init dell_wmi_init(void)
 
        return wmi_driver_register(&dell_wmi_driver);
 }
-module_init(dell_wmi_init);
+late_initcall(dell_wmi_init);
 
 static void __exit dell_wmi_exit(void)
 {
index 5b6f18b..535199c 100644 (file)
@@ -113,7 +113,7 @@ MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
 /*
  * ACPI Helpers
  */
-#define IDEAPAD_EC_TIMEOUT (100) /* in ms */
+#define IDEAPAD_EC_TIMEOUT (200) /* in ms */
 
 static int read_method_int(acpi_handle handle, const char *method, int *val)
 {
index d1a0131..5e3df19 100644 (file)
@@ -376,6 +376,7 @@ static int intel_hid_remove(struct platform_device *device)
 {
        acpi_handle handle = ACPI_HANDLE(&device->dev);
 
+       device_init_wakeup(&device->dev, false);
        acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
        intel_hid_set_enable(&device->dev, false);
        intel_button_array_enable(&device->dev, false);
index b703d6f..c13780b 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/dmi.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
 #include <linux/kernel.h>
@@ -97,9 +98,35 @@ out_unknown:
        dev_dbg(&device->dev, "unknown event index 0x%x\n", event);
 }
 
-static int intel_vbtn_probe(struct platform_device *device)
+static void detect_tablet_mode(struct platform_device *device)
 {
+       const char *chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
+       struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
+       acpi_handle handle = ACPI_HANDLE(&device->dev);
        struct acpi_buffer vgbs_output = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+       int m;
+
+       if (!(chassis_type && strcmp(chassis_type, "31") == 0))
+               goto out;
+
+       status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output);
+       if (ACPI_FAILURE(status))
+               goto out;
+
+       obj = vgbs_output.pointer;
+       if (!(obj && obj->type == ACPI_TYPE_INTEGER))
+               goto out;
+
+       m = !(obj->integer.value & TABLET_MODE_FLAG);
+       input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
+out:
+       kfree(vgbs_output.pointer);
+}
+
+static int intel_vbtn_probe(struct platform_device *device)
+{
        acpi_handle handle = ACPI_HANDLE(&device->dev);
        struct intel_vbtn_priv *priv;
        acpi_status status;
@@ -122,22 +149,7 @@ static int intel_vbtn_probe(struct platform_device *device)
                return err;
        }
 
-       /*
-        * VGBS being present and returning something means we have
-        * a tablet mode switch.
-        */
-       status = acpi_evaluate_object(handle, "VGBS", NULL, &vgbs_output);
-       if (ACPI_SUCCESS(status)) {
-               union acpi_object *obj = vgbs_output.pointer;
-
-               if (obj && obj->type == ACPI_TYPE_INTEGER) {
-                       int m = !(obj->integer.value & TABLET_MODE_FLAG);
-
-                       input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
-               }
-       }
-
-       kfree(vgbs_output.pointer);
+       detect_tablet_mode(device);
 
        status = acpi_install_notify_handler(handle,
                                             ACPI_DEVICE_NOTIFY,
@@ -154,6 +166,7 @@ static int intel_vbtn_remove(struct platform_device *device)
 {
        acpi_handle handle = ACPI_HANDLE(&device->dev);
 
+       device_init_wakeup(&device->dev, false);
        acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
 
        /*
index daa68ac..8796211 100644 (file)
@@ -933,7 +933,7 @@ static int wmi_dev_probe(struct device *dev)
                        goto probe_failure;
                }
 
-               buf = kmalloc(strlen(wdriver->driver.name) + 4, GFP_KERNEL);
+               buf = kmalloc(strlen(wdriver->driver.name) + 5, GFP_KERNEL);
                if (!buf) {
                        ret = -ENOMEM;
                        goto probe_string_failure;
@@ -945,7 +945,7 @@ static int wmi_dev_probe(struct device *dev)
                wblock->char_dev.mode = 0444;
                ret = misc_register(&wblock->char_dev);
                if (ret) {
-                       dev_warn(dev, "failed to register char dev: %d", ret);
+                       dev_warn(dev, "failed to register char dev: %d\n", ret);
                        ret = -ENOMEM;
                        goto probe_misc_failure;
                }
@@ -1048,7 +1048,7 @@ static int wmi_create_device(struct device *wmi_bus_dev,
 
        if (result) {
                dev_warn(wmi_bus_dev,
-                        "%s data block query control method not found",
+                        "%s data block query control method not found\n",
                         method);
                return result;
        }
@@ -1198,7 +1198,7 @@ static int parse_wdg(struct device *wmi_bus_dev, struct acpi_device *device)
 
                retval = device_add(&wblock->dev.dev);
                if (retval) {
-                       dev_err(wmi_bus_dev, "failed to register %pULL\n",
+                       dev_err(wmi_bus_dev, "failed to register %pUL\n",
                                wblock->gblock.guid);
                        if (debug_event)
                                wmi_method_enable(wblock, 0);
index dd4708c..1fc0c08 100644 (file)
@@ -4310,7 +4310,7 @@ static int _regulator_resume_early(struct device *dev, void *data)
 
        rstate = regulator_get_suspend_state(rdev, *state);
        if (rstate == NULL)
-               return -EINVAL;
+               return 0;
 
        mutex_lock(&rdev->mutex);
 
index 72c8b3e..e0a9c44 100644 (file)
@@ -51,7 +51,7 @@ static int stm32_vrefbuf_enable(struct regulator_dev *rdev)
         * arbitrary timeout.
         */
        ret = readl_poll_timeout(priv->base + STM32_VREFBUF_CSR, val,
-                                !(val & STM32_VRR), 650, 10000);
+                                val & STM32_VRR, 650, 10000);
        if (ret) {
                dev_err(&rdev->dev, "stm32 vrefbuf timed out!\n");
                val = readl_relaxed(priv->base + STM32_VREFBUF_CSR);
index a7c15f0..ecef8e7 100644 (file)
@@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
        case DASD_CQR_QUEUED:
                /* request was not started - just set to cleared */
                cqr->status = DASD_CQR_CLEARED;
-               if (cqr->callback_data == DASD_SLEEPON_START_TAG)
-                       cqr->callback_data = DASD_SLEEPON_END_TAG;
                break;
        case DASD_CQR_IN_IO:
                /* request in IO - terminate IO and release again */
@@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
                wait_event(dasd_flush_wq,
                           (cqr->status != DASD_CQR_CLEAR_PENDING));
 
-               /* mark sleepon requests as ended */
-               if (cqr->callback_data == DASD_SLEEPON_START_TAG)
-                       cqr->callback_data = DASD_SLEEPON_END_TAG;
+               /*
+                * requeue requests to blocklayer will only work
+                * for block device requests
+                */
+               if (_dasd_requeue_request(cqr))
+                       continue;
 
                /* remove requests from device and block queue */
                list_del_init(&cqr->devlist);
@@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
                        cqr = refers;
                }
 
-               /*
-                * requeue requests to blocklayer will only work
-                * for block device requests
-                */
-               if (_dasd_requeue_request(cqr))
-                       continue;
-
                if (cqr->block)
                        list_del_init(&cqr->blocklist);
                cqr->block->base->discipline->free_cp(
@@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
                list_splice_tail(&requeue_queue, &device->ccw_queue);
                spin_unlock_irq(get_ccwdev_lock(device->cdev));
        }
-       /* wake up generic waitqueue for eventually ended sleepon requests */
-       wake_up(&generic_waitq);
+       dasd_schedule_device_bh(device);
        return rc;
 }
 
index 1319122..9169af7 100644 (file)
@@ -795,6 +795,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
 
        ccw_device_set_timeout(cdev, 0);
        cdev->private->iretry = 255;
+       cdev->private->async_kill_io_rc = -ETIMEDOUT;
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
@@ -871,7 +872,7 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
        /* OK, i/o is dead now. Call interrupt handler. */
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
-                             ERR_PTR(-EIO));
+                             ERR_PTR(cdev->private->async_kill_io_rc));
 }
 
 static void
@@ -888,14 +889,16 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
        ccw_device_online_verify(cdev, 0);
        if (cdev->handler)
                cdev->handler(cdev, cdev->private->intparm,
-                             ERR_PTR(-EIO));
+                             ERR_PTR(cdev->private->async_kill_io_rc));
 }
 
 void ccw_device_kill_io(struct ccw_device *cdev)
 {
        int ret;
 
+       ccw_device_set_timeout(cdev, 0);
        cdev->private->iretry = 255;
+       cdev->private->async_kill_io_rc = -EIO;
        ret = ccw_device_cancel_halt_clear(cdev);
        if (ret == -EBUSY) {
                ccw_device_set_timeout(cdev, 3*HZ);
index 1caf6a3..75ce12a 100644 (file)
@@ -159,7 +159,7 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
 }
 
 /**
- * ccw_device_start_key() - start a s390 channel program with key
+ * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
  * @cdev: target ccw device
  * @cpa: logical start address of channel program
  * @intparm: user specific interruption parameter; will be presented back to
@@ -170,10 +170,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
  * @key: storage key to be used for the I/O
  * @flags: additional flags; defines the action to be performed for I/O
  *        processing.
+ * @expires: timeout value in jiffies
  *
  * Start a S/390 channel program. When the interrupt arrives, the
  * IRQ handler is called, either immediately, delayed (dev-end missing,
  * or sense required) or never (no IRQ handler registered).
+ * This function notifies the device driver if the channel program has not
+ * completed during the time specified by @expires. If a timeout occurs, the
+ * channel program is terminated via xsch, hsch or csch, and the device's
+ * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
  * Returns:
  *  %0, if the operation was successful;
  *  -%EBUSY, if the device is busy, or status pending;
@@ -182,9 +187,9 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
  * Context:
  *  Interrupts disabled, ccw device lock held
  */
-int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
-                        unsigned long intparm, __u8 lpm, __u8 key,
-                        unsigned long flags)
+int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
+                                unsigned long intparm, __u8 lpm, __u8 key,
+                                unsigned long flags, int expires)
 {
        struct subchannel *sch;
        int ret;
@@ -224,6 +229,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
        switch (ret) {
        case 0:
                cdev->private->intparm = intparm;
+               if (expires)
+                       ccw_device_set_timeout(cdev, expires);
                break;
        case -EACCES:
        case -ENODEV:
@@ -234,7 +241,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
 }
 
 /**
- * ccw_device_start_timeout_key() - start a s390 channel program with timeout and key
+ * ccw_device_start_key() - start a s390 channel program with key
  * @cdev: target ccw device
  * @cpa: logical start address of channel program
  * @intparm: user specific interruption parameter; will be presented back to
@@ -245,15 +252,10 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
  * @key: storage key to be used for the I/O
  * @flags: additional flags; defines the action to be performed for I/O
  *        processing.
- * @expires: timeout value in jiffies
  *
  * Start a S/390 channel program. When the interrupt arrives, the
  * IRQ handler is called, either immediately, delayed (dev-end missing,
  * or sense required) or never (no IRQ handler registered).
- * This function notifies the device driver if the channel program has not
- * completed during the time specified by @expires. If a timeout occurs, the
- * channel program is terminated via xsch, hsch or csch, and the device's
- * interrupt handler will be called with an irb containing ERR_PTR(-%ETIMEDOUT).
  * Returns:
  *  %0, if the operation was successful;
  *  -%EBUSY, if the device is busy, or status pending;
@@ -262,19 +264,12 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
  * Context:
  *  Interrupts disabled, ccw device lock held
  */
-int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
-                                unsigned long intparm, __u8 lpm, __u8 key,
-                                unsigned long flags, int expires)
+int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
+                        unsigned long intparm, __u8 lpm, __u8 key,
+                        unsigned long flags)
 {
-       int ret;
-
-       if (!cdev)
-               return -ENODEV;
-       ccw_device_set_timeout(cdev, expires);
-       ret = ccw_device_start_key(cdev, cpa, intparm, lpm, key, flags);
-       if (ret != 0)
-               ccw_device_set_timeout(cdev, 0);
-       return ret;
+       return ccw_device_start_timeout_key(cdev, cpa, intparm, lpm, key,
+                                           flags, 0);
 }
 
 /**
@@ -489,18 +484,20 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id)
 EXPORT_SYMBOL(ccw_device_get_id);
 
 /**
- * ccw_device_tm_start_key() - perform start function
+ * ccw_device_tm_start_timeout_key() - perform start function
  * @cdev: ccw device on which to perform the start function
  * @tcw: transport-command word to be started
  * @intparm: user defined parameter to be passed to the interrupt handler
  * @lpm: mask of paths to use
  * @key: storage key to use for storage access
+ * @expires: time span in jiffies after which to abort request
  *
  * Start the tcw on the given ccw device. Return zero on success, non-zero
  * otherwise.
  */
-int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
-                           unsigned long intparm, u8 lpm, u8 key)
+int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
+                                   unsigned long intparm, u8 lpm, u8 key,
+                                   int expires)
 {
        struct subchannel *sch;
        int rc;
@@ -527,37 +524,32 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
                        return -EACCES;
        }
        rc = cio_tm_start_key(sch, tcw, lpm, key);
-       if (rc == 0)
+       if (rc == 0) {
                cdev->private->intparm = intparm;
+               if (expires)
+                       ccw_device_set_timeout(cdev, expires);
+       }
        return rc;
 }
-EXPORT_SYMBOL(ccw_device_tm_start_key);
+EXPORT_SYMBOL(ccw_device_tm_start_timeout_key);
 
 /**
- * ccw_device_tm_start_timeout_key() - perform start function
+ * ccw_device_tm_start_key() - perform start function
  * @cdev: ccw device on which to perform the start function
  * @tcw: transport-command word to be started
  * @intparm: user defined parameter to be passed to the interrupt handler
  * @lpm: mask of paths to use
  * @key: storage key to use for storage access
- * @expires: time span in jiffies after which to abort request
  *
  * Start the tcw on the given ccw device. Return zero on success, non-zero
  * otherwise.
  */
-int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
-                                   unsigned long intparm, u8 lpm, u8 key,
-                                   int expires)
+int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw,
+                           unsigned long intparm, u8 lpm, u8 key)
 {
-       int ret;
-
-       ccw_device_set_timeout(cdev, expires);
-       ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key);
-       if (ret != 0)
-               ccw_device_set_timeout(cdev, 0);
-       return ret;
+       return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, key, 0);
 }
-EXPORT_SYMBOL(ccw_device_tm_start_timeout_key);
+EXPORT_SYMBOL(ccw_device_tm_start_key);
 
 /**
  * ccw_device_tm_start() - perform start function
index af571d8..90e4e3a 100644 (file)
@@ -157,6 +157,7 @@ struct ccw_device_private {
        unsigned long intparm;  /* user interruption parameter */
        struct qdio_irq *qdio_data;
        struct irb irb;         /* device status */
+       int async_kill_io_rc;
        struct senseid senseid; /* SenseID info */
        struct pgid pgid[8];    /* path group IDs per chpid*/
        struct ccw1 iccws[2];   /* ccws for SNID/SID/SPGID commands */
index ca72f33..3653bea 100644 (file)
@@ -527,8 +527,7 @@ static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue)
            queue == card->qdio.no_in_queues - 1;
 }
 
-
-static int qeth_issue_next_read(struct qeth_card *card)
+static int __qeth_issue_next_read(struct qeth_card *card)
 {
        int rc;
        struct qeth_cmd_buffer *iob;
@@ -559,6 +558,17 @@ static int qeth_issue_next_read(struct qeth_card *card)
        return rc;
 }
 
+static int qeth_issue_next_read(struct qeth_card *card)
+{
+       int ret;
+
+       spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card)));
+       ret = __qeth_issue_next_read(card);
+       spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card)));
+
+       return ret;
+}
+
 static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
 {
        struct qeth_reply *reply;
@@ -960,7 +970,7 @@ void qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
        spin_lock_irqsave(&card->thread_mask_lock, flags);
        card->thread_running_mask &= ~thread;
        spin_unlock_irqrestore(&card->thread_mask_lock, flags);
-       wake_up(&card->wait_q);
+       wake_up_all(&card->wait_q);
 }
 EXPORT_SYMBOL_GPL(qeth_clear_thread_running_bit);
 
@@ -1164,6 +1174,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                }
                rc = qeth_get_problem(cdev, irb);
                if (rc) {
+                       card->read_or_write_problem = 1;
                        qeth_clear_ipacmd_list(card);
                        qeth_schedule_recovery(card);
                        goto out;
@@ -1182,7 +1193,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
                return;
        if (channel == &card->read &&
            channel->state == CH_STATE_UP)
-               qeth_issue_next_read(card);
+               __qeth_issue_next_read(card);
 
        iob = channel->iob;
        index = channel->buf_no;
@@ -2134,24 +2145,25 @@ int qeth_send_control_data(struct qeth_card *card, int len,
        }
        reply->callback = reply_cb;
        reply->param = reply_param;
-       if (card->state == CARD_STATE_DOWN)
-               reply->seqno = QETH_IDX_COMMAND_SEQNO;
-       else
-               reply->seqno = card->seqno.ipa++;
+
        init_waitqueue_head(&reply->wait_q);
-       spin_lock_irqsave(&card->lock, flags);
-       list_add_tail(&reply->list, &card->cmd_waiter_list);
-       spin_unlock_irqrestore(&card->lock, flags);
 
        while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ;
-       qeth_prepare_control_data(card, len, iob);
 
        if (IS_IPA(iob->data)) {
                cmd = __ipa_cmd(iob);
+               cmd->hdr.seqno = card->seqno.ipa++;
+               reply->seqno = cmd->hdr.seqno;
                event_timeout = QETH_IPA_TIMEOUT;
        } else {
+               reply->seqno = QETH_IDX_COMMAND_SEQNO;
                event_timeout = QETH_TIMEOUT;
        }
+       qeth_prepare_control_data(card, len, iob);
+
+       spin_lock_irqsave(&card->lock, flags);
+       list_add_tail(&reply->list, &card->cmd_waiter_list);
+       spin_unlock_irqrestore(&card->lock, flags);
 
        timeout = jiffies + event_timeout;
 
@@ -2933,7 +2945,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card,
        memset(cmd, 0, sizeof(struct qeth_ipa_cmd));
        cmd->hdr.command = command;
        cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST;
-       cmd->hdr.seqno = card->seqno.ipa;
+       /* cmd->hdr.seqno is set by qeth_send_control_data() */
        cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type);
        cmd->hdr.rel_adapter_no = (__u8) card->info.portno;
        if (card->options.layer2)
@@ -3898,10 +3910,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags);
 int qeth_get_elements_no(struct qeth_card *card,
                     struct sk_buff *skb, int extra_elems, int data_offset)
 {
-       int elements = qeth_get_elements_for_range(
-                               (addr_t)skb->data + data_offset,
-                               (addr_t)skb->data + skb_headlen(skb)) +
-                       qeth_get_elements_for_frags(skb);
+       addr_t end = (addr_t)skb->data + skb_headlen(skb);
+       int elements = qeth_get_elements_for_frags(skb);
+       addr_t start = (addr_t)skb->data + data_offset;
+
+       if (start != end)
+               elements += qeth_get_elements_for_range(start, end);
 
        if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
                QETH_DBF_MESSAGE(2, "Invalid size of IP packet "
@@ -5084,8 +5098,6 @@ static void qeth_core_free_card(struct qeth_card *card)
        QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
        qeth_clean_channel(&card->read);
        qeth_clean_channel(&card->write);
-       if (card->dev)
-               free_netdev(card->dev);
        qeth_free_qdio_buffers(card);
        unregister_service_level(&card->qeth_service_level);
        kfree(card);
index 7f23644..5ef4c97 100644 (file)
@@ -915,8 +915,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
                qeth_l2_set_offline(cgdev);
 
        if (card->dev) {
-               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
+               free_netdev(card->dev);
                card->dev = NULL;
        }
        return;
index bdd45f4..498fe9a 100644 (file)
@@ -40,8 +40,40 @@ struct qeth_ipaddr {
                        unsigned int pfxlen;
                } a6;
        } u;
-
 };
+
+static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1,
+                                        struct qeth_ipaddr *a2)
+{
+       if (a1->proto != a2->proto)
+               return false;
+       if (a1->proto == QETH_PROT_IPV6)
+               return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr);
+       return a1->u.a4.addr == a2->u.a4.addr;
+}
+
+static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1,
+                                         struct qeth_ipaddr *a2)
+{
+       /* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(),
+        * so 'proto' and 'addr' match for sure.
+        *
+        * For ucast:
+        * -    'mac' is always 0.
+        * -    'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching
+        *      values are required to avoid mixups in takeover eligibility.
+        *
+        * For mcast,
+        * -    'mac' is mapped from the IP, and thus always matches.
+        * -    'mask'/'pfxlen' is always 0.
+        */
+       if (a1->type != a2->type)
+               return false;
+       if (a1->proto == QETH_PROT_IPV6)
+               return a1->u.a6.pfxlen == a2->u.a6.pfxlen;
+       return a1->u.a4.mask == a2->u.a4.mask;
+}
+
 static inline  u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr)
 {
        u64  ret = 0;
index b0c888e..b6b1222 100644 (file)
@@ -67,6 +67,24 @@ void qeth_l3_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr,
                qeth_l3_ipaddr6_to_string(addr, buf);
 }
 
+static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card,
+                                                  struct qeth_ipaddr *query)
+{
+       u64 key = qeth_l3_ipaddr_hash(query);
+       struct qeth_ipaddr *addr;
+
+       if (query->is_multicast) {
+               hash_for_each_possible(card->ip_mc_htable, addr, hnode, key)
+                       if (qeth_l3_addr_match_ip(addr, query))
+                               return addr;
+       } else {
+               hash_for_each_possible(card->ip_htable,  addr, hnode, key)
+                       if (qeth_l3_addr_match_ip(addr, query))
+                               return addr;
+       }
+       return NULL;
+}
+
 static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
 {
        int i, j;
@@ -120,34 +138,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card,
        return rc;
 }
 
-inline int
-qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2)
-{
-       return addr1->proto == addr2->proto &&
-              !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) &&
-              ether_addr_equal_64bits(addr1->mac, addr2->mac);
-}
-
-static struct qeth_ipaddr *
-qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
-{
-       struct qeth_ipaddr *addr;
-
-       if (tmp_addr->is_multicast) {
-               hash_for_each_possible(card->ip_mc_htable,  addr,
-                               hnode, qeth_l3_ipaddr_hash(tmp_addr))
-                       if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr))
-                               return addr;
-       } else {
-               hash_for_each_possible(card->ip_htable,  addr,
-                               hnode, qeth_l3_ipaddr_hash(tmp_addr))
-                       if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr))
-                               return addr;
-       }
-
-       return NULL;
-}
-
 int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
 {
        int rc = 0;
@@ -162,23 +152,18 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
                QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
        }
 
-       addr = qeth_l3_ip_from_hash(card, tmp_addr);
-       if (!addr)
+       addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
+       if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr))
                return -ENOENT;
 
        addr->ref_counter--;
-       if (addr->ref_counter > 0 && (addr->type == QETH_IP_TYPE_NORMAL ||
-                                     addr->type == QETH_IP_TYPE_RXIP))
+       if (addr->type == QETH_IP_TYPE_NORMAL && addr->ref_counter > 0)
                return rc;
        if (addr->in_progress)
                return -EINPROGRESS;
 
-       if (!qeth_card_hw_is_reachable(card)) {
-               addr->disp_flag = QETH_DISP_ADDR_DELETE;
-               return 0;
-       }
-
-       rc = qeth_l3_deregister_addr_entry(card, addr);
+       if (qeth_card_hw_is_reachable(card))
+               rc = qeth_l3_deregister_addr_entry(card, addr);
 
        hash_del(&addr->hnode);
        kfree(addr);
@@ -190,6 +175,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
 {
        int rc = 0;
        struct qeth_ipaddr *addr;
+       char buf[40];
 
        QETH_CARD_TEXT(card, 4, "addip");
 
@@ -200,8 +186,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
                QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8);
        }
 
-       addr = qeth_l3_ip_from_hash(card, tmp_addr);
-       if (!addr) {
+       addr = qeth_l3_find_addr_by_ip(card, tmp_addr);
+       if (addr) {
+               if (tmp_addr->type != QETH_IP_TYPE_NORMAL)
+                       return -EADDRINUSE;
+               if (qeth_l3_addr_match_all(addr, tmp_addr)) {
+                       addr->ref_counter++;
+                       return 0;
+               }
+               qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u,
+                                        buf);
+               dev_warn(&card->gdev->dev,
+                        "Registering IP address %s failed\n", buf);
+               return -EADDRINUSE;
+       } else {
                addr = qeth_l3_get_addr_buffer(tmp_addr->proto);
                if (!addr)
                        return -ENOMEM;
@@ -241,19 +239,15 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
                                (rc == IPA_RC_LAN_OFFLINE)) {
                        addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
                        if (addr->ref_counter < 1) {
-                               qeth_l3_delete_ip(card, addr);
+                               qeth_l3_deregister_addr_entry(card, addr);
+                               hash_del(&addr->hnode);
                                kfree(addr);
                        }
                } else {
                        hash_del(&addr->hnode);
                        kfree(addr);
                }
-       } else {
-               if (addr->type == QETH_IP_TYPE_NORMAL ||
-                   addr->type == QETH_IP_TYPE_RXIP)
-                       addr->ref_counter++;
        }
-
        return rc;
 }
 
@@ -321,11 +315,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card)
        spin_lock_bh(&card->ip_lock);
 
        hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) {
-               if (addr->disp_flag == QETH_DISP_ADDR_DELETE) {
-                       qeth_l3_deregister_addr_entry(card, addr);
-                       hash_del(&addr->hnode);
-                       kfree(addr);
-               } else if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
+               if (addr->disp_flag == QETH_DISP_ADDR_ADD) {
                        if (addr->proto == QETH_PROT_IPV4) {
                                addr->in_progress = 1;
                                spin_unlock_bh(&card->ip_lock);
@@ -643,12 +633,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto,
                return -ENOMEM;
 
        spin_lock_bh(&card->ip_lock);
-
-       if (qeth_l3_ip_from_hash(card, ipaddr))
-               rc = -EEXIST;
-       else
-               rc = qeth_l3_add_ip(card, ipaddr);
-
+       rc = qeth_l3_add_ip(card, ipaddr);
        spin_unlock_bh(&card->ip_lock);
 
        kfree(ipaddr);
@@ -713,12 +698,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto,
                return -ENOMEM;
 
        spin_lock_bh(&card->ip_lock);
-
-       if (qeth_l3_ip_from_hash(card, ipaddr))
-               rc = -EEXIST;
-       else
-               rc = qeth_l3_add_ip(card, ipaddr);
-
+       rc = qeth_l3_add_ip(card, ipaddr);
        spin_unlock_bh(&card->ip_lock);
 
        kfree(ipaddr);
@@ -1239,8 +1219,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev)
                tmp->u.a4.addr = be32_to_cpu(im4->multiaddr);
                tmp->is_multicast = 1;
 
-               ipm = qeth_l3_ip_from_hash(card, tmp);
+               ipm = qeth_l3_find_addr_by_ip(card, tmp);
                if (ipm) {
+                       /* for mcast, by-IP match means full match */
                        ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
                } else {
                        ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4);
@@ -1319,8 +1300,9 @@ static void qeth_l3_add_mc6_to_hash(struct qeth_card *card,
                       sizeof(struct in6_addr));
                tmp->is_multicast = 1;
 
-               ipm = qeth_l3_ip_from_hash(card, tmp);
+               ipm = qeth_l3_find_addr_by_ip(card, tmp);
                if (ipm) {
+                       /* for mcast, by-IP match means full match */
                        ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
                        continue;
                }
@@ -2450,11 +2432,12 @@ static void qeth_tso_fill_header(struct qeth_card *card,
 static int qeth_l3_get_elements_no_tso(struct qeth_card *card,
                        struct sk_buff *skb, int extra_elems)
 {
-       addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
-       int elements = qeth_get_elements_for_range(
-                               tcpdptr,
-                               (addr_t)skb->data + skb_headlen(skb)) +
-                               qeth_get_elements_for_frags(skb);
+       addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb);
+       addr_t end = (addr_t)skb->data + skb_headlen(skb);
+       int elements = qeth_get_elements_for_frags(skb);
+
+       if (start != end)
+               elements += qeth_get_elements_for_range(start, end);
 
        if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) {
                QETH_DBF_MESSAGE(2,
@@ -2882,8 +2865,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev)
                qeth_l3_set_offline(cgdev);
 
        if (card->dev) {
-               netif_napi_del(&card->napi);
                unregister_netdev(card->dev);
+               free_netdev(card->dev);
                card->dev = NULL;
        }
 
index ba2e085..8f5c1d7 100644 (file)
@@ -1297,6 +1297,9 @@ static int virtio_ccw_cio_notify(struct ccw_device *cdev, int event)
                vcdev->device_lost = true;
                rc = NOTIFY_DONE;
                break;
+       case CIO_OPER:
+               rc = NOTIFY_OK;
+               break;
        default:
                rc = NOTIFY_DONE;
                break;
@@ -1309,6 +1312,27 @@ static struct ccw_device_id virtio_ids[] = {
        {},
 };
 
+#ifdef CONFIG_PM_SLEEP
+static int virtio_ccw_freeze(struct ccw_device *cdev)
+{
+       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+
+       return virtio_device_freeze(&vcdev->vdev);
+}
+
+static int virtio_ccw_restore(struct ccw_device *cdev)
+{
+       struct virtio_ccw_device *vcdev = dev_get_drvdata(&cdev->dev);
+       int ret;
+
+       ret = virtio_ccw_set_transport_rev(vcdev);
+       if (ret)
+               return ret;
+
+       return virtio_device_restore(&vcdev->vdev);
+}
+#endif
+
 static struct ccw_driver virtio_ccw_driver = {
        .driver = {
                .owner = THIS_MODULE,
@@ -1321,6 +1345,11 @@ static struct ccw_driver virtio_ccw_driver = {
        .set_online = virtio_ccw_online,
        .notify = virtio_ccw_cio_notify,
        .int_class = IRQIO_VIR,
+#ifdef CONFIG_PM_SLEEP
+       .freeze = virtio_ccw_freeze,
+       .thaw = virtio_ccw_restore,
+       .restore = virtio_ccw_restore,
+#endif
 };
 
 static int __init pure_hex(char **cp, unsigned int *val, int min_digit,
index fcfd28d..de1b3fc 100644 (file)
@@ -185,7 +185,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
 CFLAGS_ncr53c8xx.o     := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
 zalon7xx-objs  := zalon.o ncr53c8xx.o
 NCR_Q720_mod-objs      := NCR_Q720.o ncr53c8xx.o
-oktagon_esp_mod-objs   := oktagon_esp.o oktagon_io.o
 
 # Files generated that shall be removed upon make clean
 clean-files := 53c700_d.h 53c700_u.h
index b3b931a..2664ea0 100644 (file)
@@ -1693,8 +1693,10 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
         *      Map in the registers from the adapter.
         */
        aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
-       if ((*aac_drivers[index].init)(aac))
+       if ((*aac_drivers[index].init)(aac)) {
+               error = -ENODEV;
                goto out_unmap;
+       }
 
        if (aac->sync_mode) {
                if (aac_sync_mode)
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
deleted file mode 100644 (file)
index 828ae3d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Implementation of Utility functions for all SCSI device types.
- *
- * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
- * Copyright (c) 1997, 1998 Kenneth D. Merry.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification, immediately at the beginning of the file.
- * 2. The name of the author may not be used to endorse or promote products
- *    derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $
- * $Id$
- */
-
-#include "aiclib.h"
-
index 8e2f767..5a645b8 100644 (file)
@@ -1889,6 +1889,7 @@ void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req,
                /* we will not receive ABTS response for this IO */
                BNX2FC_IO_DBG(io_req, "Timer context finished processing "
                           "this scsi cmd\n");
+               return;
        }
 
        /* Cancel the timeout_work, as we received IO completion */
index be5ee2d..7dbbbb8 100644 (file)
@@ -114,7 +114,7 @@ static enum csio_ln_ev fwevt_to_lnevt[] = {
 static struct csio_lnode *
 csio_ln_lookup_by_portid(struct csio_hw *hw, uint8_t portid)
 {
-       struct csio_lnode *ln = hw->rln;
+       struct csio_lnode *ln;
        struct list_head *tmp;
 
        /* Match siblings lnode with portid */
index 022e421..4b44325 100644 (file)
@@ -876,6 +876,11 @@ static void alua_rtpg_work(struct work_struct *work)
 
 /**
  * alua_rtpg_queue() - cause RTPG to be submitted asynchronously
+ * @pg: ALUA port group associated with @sdev.
+ * @sdev: SCSI device for which to submit an RTPG.
+ * @qdata: Information about the callback to invoke after the RTPG.
+ * @force: Whether or not to submit an RTPG if a work item that will submit an
+ *         RTPG already has been scheduled.
  *
  * Returns true if and only if alua_rtpg_work() will be called asynchronously.
  * That function is responsible for calling @qdata->fn().
index 57bf43e..ef22b27 100644 (file)
@@ -328,8 +328,6 @@ static void scsi_host_dev_release(struct device *dev)
        if (shost->work_q)
                destroy_workqueue(shost->work_q);
 
-       destroy_rcu_head(&shost->rcu);
-
        if (shost->shost_state == SHOST_CREATED) {
                /*
                 * Free the shost_dev device name here if scsi_host_alloc()
@@ -404,7 +402,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
        INIT_LIST_HEAD(&shost->starved_list);
        init_waitqueue_head(&shost->host_wait);
        mutex_init(&shost->scan_mutex);
-       init_rcu_head(&shost->rcu);
 
        index = ida_simple_get(&host_index_ida, 0, 0, GFP_KERNEL);
        if (index < 0)
@@ -477,6 +474,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
                shost->dma_boundary = 0xffffffff;
 
        shost->use_blk_mq = scsi_use_blk_mq;
+       shost->use_blk_mq = scsi_use_blk_mq || shost->hostt->force_blk_mq;
 
        device_initialize(&shost->shost_gendev);
        dev_set_name(&shost->shost_gendev, "host%d", shost->host_no);
index 5293e68..3a9eca1 100644 (file)
@@ -1045,11 +1045,7 @@ static void set_performant_mode(struct ctlr_info *h, struct CommandList *c,
                c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1);
                if (unlikely(!h->msix_vectors))
                        return;
-               if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
-                       c->Header.ReplyQueue =
-                               raw_smp_processor_id() % h->nreply_queues;
-               else
-                       c->Header.ReplyQueue = reply_queue % h->nreply_queues;
+               c->Header.ReplyQueue = reply_queue;
        }
 }
 
@@ -1063,10 +1059,7 @@ static void set_ioaccel1_performant_mode(struct ctlr_info *h,
         * Tell the controller to post the reply to the queue for this
         * processor.  This seems to give the best I/O throughput.
         */
-       if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
-               cp->ReplyQueue = smp_processor_id() % h->nreply_queues;
-       else
-               cp->ReplyQueue = reply_queue % h->nreply_queues;
+       cp->ReplyQueue = reply_queue;
        /*
         * Set the bits in the address sent down to include:
         *  - performant mode bit (bit 0)
@@ -1087,10 +1080,7 @@ static void set_ioaccel2_tmf_performant_mode(struct ctlr_info *h,
        /* Tell the controller to post the reply to the queue for this
         * processor.  This seems to give the best I/O throughput.
         */
-       if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
-               cp->reply_queue = smp_processor_id() % h->nreply_queues;
-       else
-               cp->reply_queue = reply_queue % h->nreply_queues;
+       cp->reply_queue = reply_queue;
        /* Set the bits in the address sent down to include:
         *  - performant mode bit not used in ioaccel mode 2
         *  - pull count (bits 0-3)
@@ -1109,10 +1099,7 @@ static void set_ioaccel2_performant_mode(struct ctlr_info *h,
         * Tell the controller to post the reply to the queue for this
         * processor.  This seems to give the best I/O throughput.
         */
-       if (likely(reply_queue == DEFAULT_REPLY_QUEUE))
-               cp->reply_queue = smp_processor_id() % h->nreply_queues;
-       else
-               cp->reply_queue = reply_queue % h->nreply_queues;
+       cp->reply_queue = reply_queue;
        /*
         * Set the bits in the address sent down to include:
         *  - performant mode bit not used in ioaccel mode 2
@@ -1157,6 +1144,8 @@ static void __enqueue_cmd_and_start_io(struct ctlr_info *h,
 {
        dial_down_lockup_detection_during_fw_flash(h, c);
        atomic_inc(&h->commands_outstanding);
+
+       reply_queue = h->reply_map[raw_smp_processor_id()];
        switch (c->cmd_type) {
        case CMD_IOACCEL1:
                set_ioaccel1_performant_mode(h, c, reply_queue);
@@ -7376,6 +7365,26 @@ static void hpsa_disable_interrupt_mode(struct ctlr_info *h)
        h->msix_vectors = 0;
 }
 
+static void hpsa_setup_reply_map(struct ctlr_info *h)
+{
+       const struct cpumask *mask;
+       unsigned int queue, cpu;
+
+       for (queue = 0; queue < h->msix_vectors; queue++) {
+               mask = pci_irq_get_affinity(h->pdev, queue);
+               if (!mask)
+                       goto fallback;
+
+               for_each_cpu(cpu, mask)
+                       h->reply_map[cpu] = queue;
+       }
+       return;
+
+fallback:
+       for_each_possible_cpu(cpu)
+               h->reply_map[cpu] = 0;
+}
+
 /* If MSI/MSI-X is supported by the kernel we will try to enable it on
  * controllers that are capable. If not, we use legacy INTx mode.
  */
@@ -7771,6 +7780,10 @@ static int hpsa_pci_init(struct ctlr_info *h)
        err = hpsa_interrupt_mode(h);
        if (err)
                goto clean1;
+
+       /* setup mapping between CPU and reply queue */
+       hpsa_setup_reply_map(h);
+
        err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
        if (err)
                goto clean2;    /* intmode+region, pci */
@@ -8480,6 +8493,28 @@ static struct workqueue_struct *hpsa_create_controller_wq(struct ctlr_info *h,
        return wq;
 }
 
+static void hpda_free_ctlr_info(struct ctlr_info *h)
+{
+       kfree(h->reply_map);
+       kfree(h);
+}
+
+static struct ctlr_info *hpda_alloc_ctlr_info(void)
+{
+       struct ctlr_info *h;
+
+       h = kzalloc(sizeof(*h), GFP_KERNEL);
+       if (!h)
+               return NULL;
+
+       h->reply_map = kzalloc(sizeof(*h->reply_map) * nr_cpu_ids, GFP_KERNEL);
+       if (!h->reply_map) {
+               kfree(h);
+               return NULL;
+       }
+       return h;
+}
+
 static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
        int dac, rc;
@@ -8517,7 +8552,7 @@ reinit_after_soft_reset:
         * the driver.  See comments in hpsa.h for more info.
         */
        BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT);
-       h = kzalloc(sizeof(*h), GFP_KERNEL);
+       h = hpda_alloc_ctlr_info();
        if (!h) {
                dev_err(&pdev->dev, "Failed to allocate controller head\n");
                return -ENOMEM;
@@ -8916,7 +8951,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
        h->lockup_detected = NULL;                      /* init_one 2 */
        /* (void) pci_disable_pcie_error_reporting(pdev); */    /* init_one 1 */
 
-       kfree(h);                                       /* init_one 1 */
+       hpda_free_ctlr_info(h);                         /* init_one 1 */
 }
 
 static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev,
index 018f980..fb9f5e7 100644 (file)
@@ -158,6 +158,7 @@ struct bmic_controller_parameters {
 #pragma pack()
 
 struct ctlr_info {
+       unsigned int *reply_map;
        int     ctlr;
        char    devname[8];
        char    *product_name;
index b1b1d3a..daefe81 100644 (file)
@@ -3579,11 +3579,9 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
 static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad,
                                    struct ibmvfc_target *tgt)
 {
-       if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name,
-                  sizeof(tgt->ids.port_name)))
+       if (wwn_to_u64((u8 *)&mad->fc_iu.response[2]) != tgt->ids.port_name)
                return 1;
-       if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name,
-                  sizeof(tgt->ids.node_name)))
+       if (wwn_to_u64((u8 *)&mad->fc_iu.response[4]) != tgt->ids.node_name)
                return 1;
        if (be32_to_cpu(mad->fc_iu.response[6]) != tgt->scsi_id)
                return 1;
index 9a0696f..b81a53c 100644 (file)
@@ -367,7 +367,7 @@ enum ibmvfc_fcp_rsp_info_codes {
 };
 
 struct ibmvfc_fcp_rsp_info {
-       __be16 reserved;
+       u8 reserved[3];
        u8 rsp_code;
        u8 reserved2[4];
 }__attribute__((packed, aligned (2)));
index 6198559..dd66c11 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/kfifo.h>
 #include <linux/scatterlist.h>
 #include <linux/module.h>
+#include <linux/backing-dev.h>
 #include <net/tcp.h>
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
@@ -954,6 +955,13 @@ static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev)
 
 static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev)
 {
+       struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(sdev->host);
+       struct iscsi_session *session = tcp_sw_host->session;
+       struct iscsi_conn *conn = session->leadconn;
+
+       if (conn->datadgst_en)
+               sdev->request_queue->backing_dev_info->capabilities
+                       |= BDI_CAP_STABLE_WRITES;
        blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY);
        blk_queue_dma_alignment(sdev->request_queue, 0);
        return 0;
index 6de9681..ceab5e5 100644 (file)
@@ -223,6 +223,7 @@ out_done:
 static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
 {
        struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host);
+       struct domain_device *dev = cmd_to_domain_dev(cmd);
        struct sas_task *task = TO_SAS_TASK(cmd);
 
        /* At this point, we only get called following an actual abort
@@ -231,6 +232,14 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
         */
        sas_end_task(cmd, task);
 
+       if (dev_is_sata(dev)) {
+               /* defer commands to libata so that libata EH can
+                * handle ata qcs correctly
+                */
+               list_move_tail(&cmd->eh_entry, &sas_ha->eh_ata_q);
+               return;
+       }
+
        /* now finish the command and move it on to the error
         * handler done list, this also takes it off the
         * error handler pending list.
@@ -238,22 +247,6 @@ static void sas_eh_finish_cmd(struct scsi_cmnd *cmd)
        scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q);
 }
 
-static void sas_eh_defer_cmd(struct scsi_cmnd *cmd)
-{
-       struct domain_device *dev = cmd_to_domain_dev(cmd);
-       struct sas_ha_struct *ha = dev->port->ha;
-       struct sas_task *task = TO_SAS_TASK(cmd);
-
-       if (!dev_is_sata(dev)) {
-               sas_eh_finish_cmd(cmd);
-               return;
-       }
-
-       /* report the timeout to libata */
-       sas_end_task(cmd, task);
-       list_move_tail(&cmd->eh_entry, &ha->eh_ata_q);
-}
-
 static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
 {
        struct scsi_cmnd *cmd, *n;
@@ -261,7 +254,7 @@ static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd
        list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
                if (cmd->device->sdev_target == my_cmd->device->sdev_target &&
                    cmd->device->lun == my_cmd->device->lun)
-                       sas_eh_defer_cmd(cmd);
+                       sas_eh_finish_cmd(cmd);
        }
 }
 
@@ -631,12 +624,12 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
                case TASK_IS_DONE:
                        SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
                                    task);
-                       sas_eh_defer_cmd(cmd);
+                       sas_eh_finish_cmd(cmd);
                        continue;
                case TASK_IS_ABORTED:
                        SAS_DPRINTK("%s: task 0x%p is aborted\n",
                                    __func__, task);
-                       sas_eh_defer_cmd(cmd);
+                       sas_eh_finish_cmd(cmd);
                        continue;
                case TASK_IS_AT_LU:
                        SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
@@ -647,7 +640,7 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
                                            "recovered\n",
                                            SAS_ADDR(task->dev),
                                            cmd->device->lun);
-                               sas_eh_defer_cmd(cmd);
+                               sas_eh_finish_cmd(cmd);
                                sas_scsi_clear_queue_lu(work_q, cmd);
                                goto Again;
                        }
index ba6503f..27fab82 100644 (file)
@@ -2128,6 +2128,7 @@ enum MR_PD_TYPE {
 
 struct megasas_instance {
 
+       unsigned int *reply_map;
        __le32 *producer;
        dma_addr_t producer_h;
        __le32 *consumer;
index a71ee67..dde0798 100644 (file)
@@ -5165,6 +5165,26 @@ skip_alloc:
                instance->use_seqnum_jbod_fp = false;
 }
 
+static void megasas_setup_reply_map(struct megasas_instance *instance)
+{
+       const struct cpumask *mask;
+       unsigned int queue, cpu;
+
+       for (queue = 0; queue < instance->msix_vectors; queue++) {
+               mask = pci_irq_get_affinity(instance->pdev, queue);
+               if (!mask)
+                       goto fallback;
+
+               for_each_cpu(cpu, mask)
+                       instance->reply_map[cpu] = queue;
+       }
+       return;
+
+fallback:
+       for_each_possible_cpu(cpu)
+               instance->reply_map[cpu] = cpu % instance->msix_vectors;
+}
+
 /**
  * megasas_init_fw -   Initializes the FW
  * @instance:          Adapter soft state
@@ -5343,6 +5363,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
                        goto fail_setup_irqs;
        }
 
+       megasas_setup_reply_map(instance);
+
        dev_info(&instance->pdev->dev,
                "firmware supports msix\t: (%d)", fw_msix_count);
        dev_info(&instance->pdev->dev,
@@ -6123,20 +6145,29 @@ static inline int megasas_alloc_mfi_ctrl_mem(struct megasas_instance *instance)
  */
 static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
 {
+       instance->reply_map = kzalloc(sizeof(unsigned int) * nr_cpu_ids,
+                                     GFP_KERNEL);
+       if (!instance->reply_map)
+               return -ENOMEM;
+
        switch (instance->adapter_type) {
        case MFI_SERIES:
                if (megasas_alloc_mfi_ctrl_mem(instance))
-                       return -ENOMEM;
+                       goto fail;
                break;
        case VENTURA_SERIES:
        case THUNDERBOLT_SERIES:
        case INVADER_SERIES:
                if (megasas_alloc_fusion_context(instance))
-                       return -ENOMEM;
+                       goto fail;
                break;
        }
 
        return 0;
+ fail:
+       kfree(instance->reply_map);
+       instance->reply_map = NULL;
+       return -ENOMEM;
 }
 
 /*
@@ -6148,6 +6179,7 @@ static int megasas_alloc_ctrl_mem(struct megasas_instance *instance)
  */
 static inline void megasas_free_ctrl_mem(struct megasas_instance *instance)
 {
+       kfree(instance->reply_map);
        if (instance->adapter_type == MFI_SERIES) {
                if (instance->producer)
                        pci_free_consistent(instance->pdev, sizeof(u32),
@@ -6540,7 +6572,6 @@ fail_io_attach:
                pci_free_irq_vectors(instance->pdev);
 fail_init_mfi:
        scsi_host_put(host);
-
 fail_alloc_instance:
        pci_disable_device(pdev);
 
@@ -6746,6 +6777,8 @@ megasas_resume(struct pci_dev *pdev)
        if (rval < 0)
                goto fail_reenable_msix;
 
+       megasas_setup_reply_map(instance);
+
        if (instance->adapter_type != MFI_SERIES) {
                megasas_reset_reply_desc(instance);
                if (megasas_ioc_init_fusion(instance)) {
index 073ced0..5ec3b74 100644 (file)
@@ -216,36 +216,30 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
 /**
  * megasas_fire_cmd_fusion -   Sends command to the FW
  * @instance:                  Adapter soft state
- * @req_desc:                  32bit or 64bit Request descriptor
+ * @req_desc:                  64bit Request descriptor
  *
- * Perform PCI Write. Ventura supports 32 bit Descriptor.
- * Prior to Ventura (12G) MR controller supports 64 bit Descriptor.
+ * Perform PCI Write.
  */
 
 static void
 megasas_fire_cmd_fusion(struct megasas_instance *instance,
                union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc)
 {
-       if (instance->adapter_type == VENTURA_SERIES)
-               writel(le32_to_cpu(req_desc->u.low),
-                       &instance->reg_set->inbound_single_queue_port);
-       else {
 #if defined(writeq) && defined(CONFIG_64BIT)
-               u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
-                               le32_to_cpu(req_desc->u.low));
+       u64 req_data = (((u64)le32_to_cpu(req_desc->u.high) << 32) |
+               le32_to_cpu(req_desc->u.low));
 
-               writeq(req_data, &instance->reg_set->inbound_low_queue_port);
+       writeq(req_data, &instance->reg_set->inbound_low_queue_port);
 #else
-               unsigned long flags;
-               spin_lock_irqsave(&instance->hba_lock, flags);
-               writel(le32_to_cpu(req_desc->u.low),
-                       &instance->reg_set->inbound_low_queue_port);
-               writel(le32_to_cpu(req_desc->u.high),
-                       &instance->reg_set->inbound_high_queue_port);
-               mmiowb();
-               spin_unlock_irqrestore(&instance->hba_lock, flags);
+       unsigned long flags;
+       spin_lock_irqsave(&instance->hba_lock, flags);
+       writel(le32_to_cpu(req_desc->u.low),
+               &instance->reg_set->inbound_low_queue_port);
+       writel(le32_to_cpu(req_desc->u.high),
+               &instance->reg_set->inbound_high_queue_port);
+       mmiowb();
+       spin_unlock_irqrestore(&instance->hba_lock, flags);
 #endif
-       }
 }
 
 /**
@@ -982,7 +976,6 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
        const char *sys_info;
        MFI_CAPABILITIES *drv_ops;
        u32 scratch_pad_2;
-       unsigned long flags;
        ktime_t time;
        bool cur_fw_64bit_dma_capable;
 
@@ -1121,14 +1114,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                        break;
        }
 
-       /* For Ventura also IOC INIT required 64 bit Descriptor write. */
-       spin_lock_irqsave(&instance->hba_lock, flags);
-       writel(le32_to_cpu(req_desc.u.low),
-              &instance->reg_set->inbound_low_queue_port);
-       writel(le32_to_cpu(req_desc.u.high),
-              &instance->reg_set->inbound_high_queue_port);
-       mmiowb();
-       spin_unlock_irqrestore(&instance->hba_lock, flags);
+       megasas_fire_cmd_fusion(instance, &req_desc);
 
        wait_and_poll(instance, cmd, MFI_POLL_TIMEOUT_SECS);
 
@@ -2655,11 +2641,8 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        fp_possible = (io_info.fpOkForIo > 0) ? true : false;
        }
 
-       /* Use raw_smp_processor_id() for now until cmd->request->cpu is CPU
-          id by default, not CPU group id, otherwise all MSI-X queues won't
-          be utilized */
-       cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ?
-               raw_smp_processor_id() % instance->msix_vectors : 0;
+       cmd->request_desc->SCSIIO.MSIxIndex =
+               instance->reply_map[raw_smp_processor_id()];
 
        praid_context = &io_request->RaidContext;
 
@@ -2985,10 +2968,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
        }
 
        cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
-       cmd->request_desc->SCSIIO.MSIxIndex =
-               instance->msix_vectors ?
-               (raw_smp_processor_id() % instance->msix_vectors) : 0;
 
+       cmd->request_desc->SCSIIO.MSIxIndex =
+               instance->reply_map[raw_smp_processor_id()];
 
        if (!fp_possible) {
                /* system pd firmware path */
index 13d6e4e..0aafbfd 100644 (file)
@@ -2410,8 +2410,11 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
                                continue;
                        }
 
-                       for_each_cpu(cpu, mask)
+                       for_each_cpu_and(cpu, mask, cpu_online_mask) {
+                               if (cpu >= ioc->cpu_msix_table_sz)
+                                       break;
                                ioc->cpu_msix_table[cpu] = reply_q->msix_index;
+                       }
                }
                return;
        }
@@ -6294,14 +6297,14 @@ _base_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
 }
 
 /**
- * _wait_for_commands_to_complete - reset controller
+ * mpt3sas_wait_for_commands_to_complete - reset controller
  * @ioc: Pointer to MPT_ADAPTER structure
  *
  * This function is waiting 10s for all pending commands to complete
  * prior to putting controller in reset.
  */
-static void
-_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc)
+void
+mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc)
 {
        u32 ioc_state;
 
@@ -6374,7 +6377,7 @@ mpt3sas_base_hard_reset_handler(struct MPT3SAS_ADAPTER *ioc,
                        is_fault = 1;
        }
        _base_reset_handler(ioc, MPT3_IOC_PRE_RESET);
-       _wait_for_commands_to_complete(ioc);
+       mpt3sas_wait_for_commands_to_complete(ioc);
        _base_mask_interrupts(ioc);
        r = _base_make_ioc_ready(ioc, type);
        if (r)
index 789bc42..99ccf83 100644 (file)
@@ -1433,6 +1433,9 @@ void mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc,
 
 int mpt3sas_port_enable(struct MPT3SAS_ADAPTER *ioc);
 
+void
+mpt3sas_wait_for_commands_to_complete(struct MPT3SAS_ADAPTER *ioc);
+
 
 /* scsih shared API */
 struct scsi_cmnd *mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc,
index 74fca18..a1cb023 100644 (file)
@@ -2835,7 +2835,8 @@ scsih_abort(struct scsi_cmnd *scmd)
        _scsih_tm_display_info(ioc, scmd);
 
        sas_device_priv_data = scmd->device->hostdata;
-       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
+           ioc->remove_host) {
                sdev_printk(KERN_INFO, scmd->device,
                        "device been deleted! scmd(%p)\n", scmd);
                scmd->result = DID_NO_CONNECT << 16;
@@ -2898,7 +2899,8 @@ scsih_dev_reset(struct scsi_cmnd *scmd)
        _scsih_tm_display_info(ioc, scmd);
 
        sas_device_priv_data = scmd->device->hostdata;
-       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
+           ioc->remove_host) {
                sdev_printk(KERN_INFO, scmd->device,
                        "device been deleted! scmd(%p)\n", scmd);
                scmd->result = DID_NO_CONNECT << 16;
@@ -2961,7 +2963,8 @@ scsih_target_reset(struct scsi_cmnd *scmd)
        _scsih_tm_display_info(ioc, scmd);
 
        sas_device_priv_data = scmd->device->hostdata;
-       if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
+       if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
+           ioc->remove_host) {
                starget_printk(KERN_INFO, starget, "target been deleted! scmd(%p)\n",
                        scmd);
                scmd->result = DID_NO_CONNECT << 16;
@@ -3019,7 +3022,7 @@ scsih_host_reset(struct scsi_cmnd *scmd)
            ioc->name, scmd);
        scsi_print_command(scmd);
 
-       if (ioc->is_driver_loading) {
+       if (ioc->is_driver_loading || ioc->remove_host) {
                pr_info(MPT3SAS_FMT "Blocking the host reset\n",
                    ioc->name);
                r = FAILED;
@@ -4453,7 +4456,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc)
                st = scsi_cmd_priv(scmd);
                mpt3sas_base_clear_st(ioc, st);
                scsi_dma_unmap(scmd);
-               if (ioc->pci_error_recovery)
+               if (ioc->pci_error_recovery || ioc->remove_host)
                        scmd->result = DID_NO_CONNECT << 16;
                else
                        scmd->result = DID_RESET << 16;
@@ -9739,6 +9742,10 @@ static void scsih_remove(struct pci_dev *pdev)
        unsigned long flags;
 
        ioc->remove_host = 1;
+
+       mpt3sas_wait_for_commands_to_complete(ioc);
+       _scsih_flush_running_cmds(ioc);
+
        _scsih_fw_event_cleanup_queue(ioc);
 
        spin_lock_irqsave(&ioc->fw_event_lock, flags);
@@ -9815,6 +9822,10 @@ scsih_shutdown(struct pci_dev *pdev)
        unsigned long flags;
 
        ioc->remove_host = 1;
+
+       mpt3sas_wait_for_commands_to_complete(ioc);
+       _scsih_flush_running_cmds(ioc);
+
        _scsih_fw_event_cleanup_queue(ioc);
 
        spin_lock_irqsave(&ioc->fw_event_lock, flags);
@@ -10547,7 +10558,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
            "fw_event_%s%d", ioc->driver_name, ioc->id);
        ioc->firmware_event_thread = alloc_ordered_workqueue(
-           ioc->firmware_event_name, WQ_MEM_RECLAIM);
+           ioc->firmware_event_name, 0);
        if (!ioc->firmware_event_thread) {
                pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
                    ioc->name, __FILE__, __LINE__, __func__);
index 667d769..d09afe1 100644 (file)
@@ -762,6 +762,11 @@ static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi,
 
        iscsi_cid = cqe->conn_id;
        qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid];
+       if (!qedi_conn) {
+               QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
+                         "icid not found 0x%x\n", cqe->conn_id);
+               return;
+       }
 
        /* Based on this itt get the corresponding qedi_cmd */
        spin_lock_bh(&qedi_conn->tmf_work_lock);
index 029e2e6..f57a94b 100644 (file)
@@ -1724,7 +1724,6 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
 {
        struct qedi_ctx *qedi = data;
        struct nvm_iscsi_initiator *initiator;
-       char *str = buf;
        int rc = 1;
        u32 ipv6_en, dhcp_en, ip_len;
        struct nvm_iscsi_block *block;
@@ -1758,32 +1757,32 @@ static ssize_t qedi_show_boot_eth_info(void *data, int type, char *buf)
 
        switch (type) {
        case ISCSI_BOOT_ETH_IP_ADDR:
-               rc = snprintf(str, ip_len, fmt, ip);
+               rc = snprintf(buf, ip_len, fmt, ip);
                break;
        case ISCSI_BOOT_ETH_SUBNET_MASK:
-               rc = snprintf(str, ip_len, fmt, sub);
+               rc = snprintf(buf, ip_len, fmt, sub);
                break;
        case ISCSI_BOOT_ETH_GATEWAY:
-               rc = snprintf(str, ip_len, fmt, gw);
+               rc = snprintf(buf, ip_len, fmt, gw);
                break;
        case ISCSI_BOOT_ETH_FLAGS:
-               rc = snprintf(str, 3, "%hhd\n",
+               rc = snprintf(buf, 3, "%hhd\n",
                              SYSFS_FLAG_FW_SEL_BOOT);
                break;
        case ISCSI_BOOT_ETH_INDEX:
-               rc = snprintf(str, 3, "0\n");
+               rc = snprintf(buf, 3, "0\n");
                break;
        case ISCSI_BOOT_ETH_MAC:
-               rc = sysfs_format_mac(str, qedi->mac, ETH_ALEN);
+               rc = sysfs_format_mac(buf, qedi->mac, ETH_ALEN);
                break;
        case ISCSI_BOOT_ETH_VLAN:
-               rc = snprintf(str, 12, "%d\n",
+               rc = snprintf(buf, 12, "%d\n",
                              GET_FIELD2(initiator->generic_cont0,
                                         NVM_ISCSI_CFG_INITIATOR_VLAN));
                break;
        case ISCSI_BOOT_ETH_ORIGIN:
                if (dhcp_en)
-                       rc = snprintf(str, 3, "3\n");
+                       rc = snprintf(buf, 3, "3\n");
                break;
        default:
                rc = 0;
@@ -1819,7 +1818,6 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
 {
        struct qedi_ctx *qedi = data;
        struct nvm_iscsi_initiator *initiator;
-       char *str = buf;
        int rc;
        struct nvm_iscsi_block *block;
 
@@ -1831,8 +1829,8 @@ static ssize_t qedi_show_boot_ini_info(void *data, int type, char *buf)
 
        switch (type) {
        case ISCSI_BOOT_INI_INITIATOR_NAME:
-               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
-                             initiator->initiator_name.byte);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN,
+                            initiator->initiator_name.byte);
                break;
        default:
                rc = 0;
@@ -1860,7 +1858,6 @@ static ssize_t
 qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
                        char *buf, enum qedi_nvm_tgts idx)
 {
-       char *str = buf;
        int rc = 1;
        u32 ctrl_flags, ipv6_en, chap_en, mchap_en, ip_len;
        struct nvm_iscsi_block *block;
@@ -1899,48 +1896,48 @@ qedi_show_boot_tgt_info(struct qedi_ctx *qedi, int type,
 
        switch (type) {
        case ISCSI_BOOT_TGT_NAME:
-               rc = snprintf(str, NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN, "%s\n",
-                             block->target[idx].target_name.byte);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_ISCSI_NAME_MAX_LEN,
+                            block->target[idx].target_name.byte);
                break;
        case ISCSI_BOOT_TGT_IP_ADDR:
                if (ipv6_en)
-                       rc = snprintf(str, ip_len, "%pI6\n",
+                       rc = snprintf(buf, ip_len, "%pI6\n",
                                      block->target[idx].ipv6_addr.byte);
                else
-                       rc = snprintf(str, ip_len, "%pI4\n",
+                       rc = snprintf(buf, ip_len, "%pI4\n",
                                      block->target[idx].ipv4_addr.byte);
                break;
        case ISCSI_BOOT_TGT_PORT:
-               rc = snprintf(str, 12, "%d\n",
+               rc = snprintf(buf, 12, "%d\n",
                              GET_FIELD2(block->target[idx].generic_cont0,
                                         NVM_ISCSI_CFG_TARGET_TCP_PORT));
                break;
        case ISCSI_BOOT_TGT_LUN:
-               rc = snprintf(str, 22, "%.*d\n",
+               rc = snprintf(buf, 22, "%.*d\n",
                              block->target[idx].lun.value[1],
                              block->target[idx].lun.value[0]);
                break;
        case ISCSI_BOOT_TGT_CHAP_NAME:
-               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
-                             chap_name);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+                            chap_name);
                break;
        case ISCSI_BOOT_TGT_CHAP_SECRET:
-               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
-                             chap_secret);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+                            chap_secret);
                break;
        case ISCSI_BOOT_TGT_REV_CHAP_NAME:
-               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN, "%s\n",
-                             mchap_name);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+                            mchap_name);
                break;
        case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
-               rc = snprintf(str, NVM_ISCSI_CFG_CHAP_PWD_MAX_LEN, "%s\n",
-                             mchap_secret);
+               rc = sprintf(buf, "%.*s\n", NVM_ISCSI_CFG_CHAP_NAME_MAX_LEN,
+                            mchap_secret);
                break;
        case ISCSI_BOOT_TGT_FLAGS:
-               rc = snprintf(str, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
+               rc = snprintf(buf, 3, "%hhd\n", SYSFS_FLAG_FW_SEL_BOOT);
                break;
        case ISCSI_BOOT_TGT_NIC_ASSOC:
-               rc = snprintf(str, 3, "0\n");
+               rc = snprintf(buf, 3, "0\n");
                break;
        default:
                rc = 0;
index be7d682..c9689f9 100644 (file)
 struct name_list_extended {
        struct get_name_list_extended *l;
        dma_addr_t              ldma;
-       struct list_head        fcports;        /* protect by sess_list */
+       struct list_head        fcports;
+       spinlock_t              fcports_lock;
        u32                     size;
-       u8                      sent;
 };
 /*
  * Timeout timer counts in seconds
@@ -2217,6 +2217,7 @@ typedef struct {
 
 /* FCP-4 types */
 #define FC4_TYPE_FCP_SCSI      0x08
+#define FC4_TYPE_NVME          0x28
 #define FC4_TYPE_OTHER         0x0
 #define FC4_TYPE_UNKNOWN       0xff
 
index 5bf9a59..403fa09 100644 (file)
@@ -3179,6 +3179,7 @@ done_free_sp:
        sp->free(sp);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return rval;
 }
 
@@ -3370,6 +3371,7 @@ done_free_sp:
        sp->free(sp);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return rval;
 }
 
@@ -3971,6 +3973,9 @@ out:
        spin_lock_irqsave(&vha->work_lock, flags);
        vha->scan.scan_flags &= ~SF_SCANNING;
        spin_unlock_irqrestore(&vha->work_lock, flags);
+
+       if ((fc4type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled)
+               qla24xx_async_gpnft(vha, FC4_TYPE_NVME);
 }
 
 static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res)
index aececf6..8d7fab3 100644 (file)
@@ -59,8 +59,6 @@ qla2x00_sp_timeout(struct timer_list *t)
        req->outstanding_cmds[sp->handle] = NULL;
        iocb = &sp->u.iocb_cmd;
        iocb->timeout(sp);
-       if (sp->type != SRB_ELS_DCMD)
-               sp->free(sp);
        spin_unlock_irqrestore(&vha->hw->hardware_lock, flags);
 }
 
@@ -102,7 +100,6 @@ qla2x00_async_iocb_timeout(void *data)
        srb_t *sp = data;
        fc_port_t *fcport = sp->fcport;
        struct srb_iocb *lio = &sp->u.iocb_cmd;
-       struct event_arg ea;
 
        if (fcport) {
                ql_dbg(ql_dbg_disc, fcport->vha, 0x2071,
@@ -117,25 +114,13 @@ qla2x00_async_iocb_timeout(void *data)
 
        switch (sp->type) {
        case SRB_LOGIN_CMD:
-               if (!fcport)
-                       break;
                /* Retry as needed. */
                lio->u.logio.data[0] = MBS_COMMAND_ERROR;
                lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
                        QLA_LOGIO_LOGIN_RETRIED : 0;
-               memset(&ea, 0, sizeof(ea));
-               ea.event = FCME_PLOGI_DONE;
-               ea.fcport = sp->fcport;
-               ea.data[0] = lio->u.logio.data[0];
-               ea.data[1] = lio->u.logio.data[1];
-               ea.sp = sp;
-               qla24xx_handle_plogi_done_event(fcport->vha, &ea);
+               sp->done(sp, QLA_FUNCTION_TIMEOUT);
                break;
        case SRB_LOGOUT_CMD:
-               if (!fcport)
-                       break;
-               qlt_logo_completion_handler(fcport, QLA_FUNCTION_TIMEOUT);
-               break;
        case SRB_CT_PTHRU_CMD:
        case SRB_MB_IOCB:
        case SRB_NACK_PLOGI:
@@ -228,6 +213,7 @@ done_free_sp:
        sp->free(sp);
        fcport->flags &= ~FCF_ASYNC_SENT;
 done:
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return rval;
 }
 
@@ -235,12 +221,10 @@ static void
 qla2x00_async_logout_sp_done(void *ptr, int res)
 {
        srb_t *sp = ptr;
-       struct srb_iocb *lio = &sp->u.iocb_cmd;
 
        sp->fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
-       if (!test_bit(UNLOADING, &sp->vha->dpc_flags))
-               qla2x00_post_async_logout_done_work(sp->vha, sp->fcport,
-                   lio->u.logio.data);
+       sp->fcport->login_gen++;
+       qlt_logo_completion_handler(sp->fcport, res);
        sp->free(sp);
 }
 
@@ -280,7 +264,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
 done_free_sp:
        sp->free(sp);
 done:
-       fcport->flags &= ~FCF_ASYNC_SENT;
+       fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        return rval;
 }
 
@@ -288,6 +272,7 @@ void
 qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        /* Don't re-login in target mode */
        if (!fcport->tgt_session)
                qla2x00_mark_device_lost(vha, fcport, 1, 0);
@@ -301,6 +286,7 @@ qla2x00_async_prlo_sp_done(void *s, int res)
        struct srb_iocb *lio = &sp->u.iocb_cmd;
        struct scsi_qla_host *vha = sp->vha;
 
+       sp->fcport->flags &= ~FCF_ASYNC_ACTIVE;
        if (!test_bit(UNLOADING, &vha->dpc_flags))
                qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport,
                    lio->u.logio.data);
@@ -339,6 +325,7 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
 done_free_sp:
        sp->free(sp);
 done:
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return rval;
 }
 
@@ -392,6 +379,8 @@ qla2x00_async_adisc_sp_done(void *ptr, int res)
            "Async done-%s res %x %8phC\n",
            sp->name, res, sp->fcport->port_name);
 
+       sp->fcport->flags &= ~FCF_ASYNC_SENT;
+
        memset(&ea, 0, sizeof(ea));
        ea.event = FCME_ADISC_DONE;
        ea.rc = res;
@@ -442,7 +431,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
 done_free_sp:
        sp->free(sp);
 done:
-       fcport->flags &= ~FCF_ASYNC_SENT;
+       fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        qla2x00_post_async_adisc_work(vha, fcport, data);
        return rval;
 }
@@ -660,8 +649,7 @@ qla24xx_async_gnl_sp_done(void *s, int res)
                    (loop_id & 0x7fff));
        }
 
-       spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
-       vha->gnl.sent = 0;
+       spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
 
        INIT_LIST_HEAD(&h);
        fcport = tf = NULL;
@@ -670,12 +658,16 @@ qla24xx_async_gnl_sp_done(void *s, int res)
 
        list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
                list_del_init(&fcport->gnl_entry);
+               spin_lock(&vha->hw->tgt.sess_lock);
                fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+               spin_unlock(&vha->hw->tgt.sess_lock);
                ea.fcport = fcport;
 
                qla2x00_fcport_event_handler(vha, &ea);
        }
+       spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
 
+       spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
        /* create new fcport if fw has knowledge of new sessions */
        for (i = 0; i < n; i++) {
                port_id_t id;
@@ -727,18 +719,21 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport)
        ql_dbg(ql_dbg_disc, vha, 0x20d9,
            "Async-gnlist WWPN %8phC \n", fcport->port_name);
 
-       spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+       spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
+       if (!list_empty(&fcport->gnl_entry)) {
+               spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
+               rval = QLA_SUCCESS;
+               goto done;
+       }
+
+       spin_lock(&vha->hw->tgt.sess_lock);
        fcport->disc_state = DSC_GNL;
        fcport->last_rscn_gen = fcport->rscn_gen;
        fcport->last_login_gen = fcport->login_gen;
+       spin_unlock(&vha->hw->tgt.sess_lock);
 
        list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports);
-       if (vha->gnl.sent) {
-               spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
-               return QLA_SUCCESS;
-       }
-       vha->gnl.sent = 1;
-       spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+       spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
 
        sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
        if (!sp)
@@ -1066,6 +1061,7 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
        fc_port_t *fcport = ea->fcport;
        struct port_database_24xx *pd;
        struct srb *sp = ea->sp;
+       uint8_t ls;
 
        pd = (struct port_database_24xx *)sp->u.iocb_cmd.u.mbx.in;
 
@@ -1078,7 +1074,12 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea)
        if (fcport->disc_state == DSC_DELETE_PEND)
                return;
 
-       switch (pd->current_login_state) {
+       if (fcport->fc4f_nvme)
+               ls = pd->current_login_state >> 4;
+       else
+               ls = pd->current_login_state & 0xf;
+
+       switch (ls) {
        case PDS_PRLI_COMPLETE:
                __qla24xx_parse_gpdb(vha, fcport, pd);
                break;
@@ -1168,8 +1169,9 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport)
        if (fcport->scan_state != QLA_FCPORT_FOUND)
                return 0;
 
-       if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
-           (fcport->fw_login_state == DSC_LS_PRLI_PEND))
+       if ((fcport->loop_id != FC_NO_LOOP_ID) &&
+           ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) ||
+            (fcport->fw_login_state == DSC_LS_PRLI_PEND)))
                return 0;
 
        if (fcport->fw_login_state == DSC_LS_PLOGI_COMP) {
@@ -1544,6 +1546,7 @@ qla24xx_abort_sp_done(void *ptr, int res)
        srb_t *sp = ptr;
        struct srb_iocb *abt = &sp->u.iocb_cmd;
 
+       del_timer(&sp->u.iocb_cmd.timer);
        complete(&abt->u.abt.comp);
 }
 
@@ -1716,7 +1719,6 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea)
 
                        set_bit(ea->fcport->loop_id, vha->hw->loop_id_map);
                        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
-                       ea->fcport->loop_id = FC_NO_LOOP_ID;
                        ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset;
                        ea->fcport->logout_on_delete = 1;
                        ea->fcport->send_els_logo = 0;
@@ -1808,6 +1810,7 @@ qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
        qla2x00_mark_device_lost(vha, fcport, 1, 0);
        qlt_logo_completion_handler(fcport, data[0]);
        fcport->login_gen++;
+       fcport->flags &= ~FCF_ASYNC_ACTIVE;
        return;
 }
 
@@ -1815,6 +1818,7 @@ void
 qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
 {
+       fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
        if (data[0] == MBS_COMMAND_COMPLETE) {
                qla2x00_update_fcport(vha, fcport);
 
@@ -1822,7 +1826,6 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
        }
 
        /* Retry login. */
-       fcport->flags &= ~FCF_ASYNC_SENT;
        if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
                set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
        else
index 1b62e94..8d00d55 100644 (file)
@@ -3275,12 +3275,11 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb)
        memset(abt_iocb, 0, sizeof(struct abort_entry_24xx));
        abt_iocb->entry_type = ABORT_IOCB_TYPE;
        abt_iocb->entry_count = 1;
-       abt_iocb->handle =
-            cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no,
-                aio->u.abt.cmd_hndl));
+       abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle));
        abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
        abt_iocb->handle_to_abort =
-           cpu_to_le32(MAKE_HANDLE(req->id, aio->u.abt.cmd_hndl));
+           cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no,
+                                   aio->u.abt.cmd_hndl));
        abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
        abt_iocb->port_id[1] = sp->fcport->d_id.b.area;
        abt_iocb->port_id[2] = sp->fcport->d_id.b.domain;
index 14109d8..89f93eb 100644 (file)
@@ -272,7 +272,8 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
 
        /* Read all mbox registers? */
-       mboxes = (1 << ha->mbx_count) - 1;
+       WARN_ON_ONCE(ha->mbx_count > 32);
+       mboxes = (1ULL << ha->mbx_count) - 1;
        if (!ha->mcp)
                ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
        else
@@ -2880,7 +2881,8 @@ qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
 
        /* Read all mbox registers? */
-       mboxes = (1 << ha->mbx_count) - 1;
+       WARN_ON_ONCE(ha->mbx_count > 32);
+       mboxes = (1ULL << ha->mbx_count) - 1;
        if (!ha->mcp)
                ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
        else
index 12ee6e0..5c5dcca 100644 (file)
@@ -454,7 +454,7 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
        ha->req_q_map[0] = req;
        set_bit(0, ha->rsp_qid_map);
        set_bit(0, ha->req_qid_map);
-       return 1;
+       return 0;
 
 fail_qpair_map:
        kfree(ha->base_qpair);
@@ -471,6 +471,9 @@ fail_req_map:
 
 static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
 {
+       if (!ha->req_q_map)
+               return;
+
        if (IS_QLAFX00(ha)) {
                if (req && req->ring_fx00)
                        dma_free_coherent(&ha->pdev->dev,
@@ -481,14 +484,17 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
                (req->length + 1) * sizeof(request_t),
                req->ring, req->dma);
 
-       if (req)
+       if (req) {
                kfree(req->outstanding_cmds);
-
-       kfree(req);
+               kfree(req);
+       }
 }
 
 static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
 {
+       if (!ha->rsp_q_map)
+               return;
+
        if (IS_QLAFX00(ha)) {
                if (rsp && rsp->ring)
                        dma_free_coherent(&ha->pdev->dev,
@@ -499,7 +505,8 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
                (rsp->length + 1) * sizeof(response_t),
                rsp->ring, rsp->dma);
        }
-       kfree(rsp);
+       if (rsp)
+               kfree(rsp);
 }
 
 static void qla2x00_free_queues(struct qla_hw_data *ha)
@@ -1723,6 +1730,8 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res)
        struct qla_tgt_cmd *cmd;
        uint8_t trace = 0;
 
+       if (!ha->req_q_map)
+               return;
        spin_lock_irqsave(qp->qp_lock_ptr, flags);
        req = qp->req;
        for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
@@ -3095,14 +3104,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        /* Set up the irqs */
        ret = qla2x00_request_irqs(ha, rsp);
        if (ret)
-               goto probe_hw_failed;
+               goto probe_failed;
 
        /* Alloc arrays of request and response ring ptrs */
-       if (!qla2x00_alloc_queues(ha, req, rsp)) {
+       if (qla2x00_alloc_queues(ha, req, rsp)) {
                ql_log(ql_log_fatal, base_vha, 0x003d,
                    "Failed to allocate memory for queue pointers..."
                    "aborting.\n");
-               goto probe_init_failed;
+               goto probe_failed;
        }
 
        if (ha->mqenable && shost_use_blk_mq(host)) {
@@ -3387,15 +3396,6 @@ skip_dpc:
 
        return 0;
 
-probe_init_failed:
-       qla2x00_free_req_que(ha, req);
-       ha->req_q_map[0] = NULL;
-       clear_bit(0, ha->req_qid_map);
-       qla2x00_free_rsp_que(ha, rsp);
-       ha->rsp_q_map[0] = NULL;
-       clear_bit(0, ha->rsp_qid_map);
-       ha->max_req_queues = ha->max_rsp_queues = 0;
-
 probe_failed:
        if (base_vha->timer_active)
                qla2x00_stop_timer(base_vha);
@@ -3625,6 +3625,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
        }
        qla2x00_wait_for_hba_ready(base_vha);
 
+       qla2x00_wait_for_sess_deletion(base_vha);
+
        /*
         * if UNLOAD flag is already set, then continue unload,
         * where it was set first.
@@ -4506,11 +4508,17 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        if (ha->init_cb)
                dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
                        ha->init_cb, ha->init_cb_dma);
-       vfree(ha->optrom_buffer);
-       kfree(ha->nvram);
-       kfree(ha->npiv_info);
-       kfree(ha->swl);
-       kfree(ha->loop_id_map);
+
+       if (ha->optrom_buffer)
+               vfree(ha->optrom_buffer);
+       if (ha->nvram)
+               kfree(ha->nvram);
+       if (ha->npiv_info)
+               kfree(ha->npiv_info);
+       if (ha->swl)
+               kfree(ha->swl);
+       if (ha->loop_id_map)
+               kfree(ha->loop_id_map);
 
        ha->srb_mempool = NULL;
        ha->ctx_mempool = NULL;
@@ -4526,6 +4534,15 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        ha->ex_init_cb_dma = 0;
        ha->async_pd = NULL;
        ha->async_pd_dma = 0;
+       ha->loop_id_map = NULL;
+       ha->npiv_info = NULL;
+       ha->optrom_buffer = NULL;
+       ha->swl = NULL;
+       ha->nvram = NULL;
+       ha->mctp_dump = NULL;
+       ha->dcbx_tlv = NULL;
+       ha->xgmac_data = NULL;
+       ha->sfp_data = NULL;
 
        ha->s_dma_pool = NULL;
        ha->dl_dma_pool = NULL;
@@ -4575,6 +4592,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
 
        spin_lock_init(&vha->work_lock);
        spin_lock_init(&vha->cmd_list_lock);
+       spin_lock_init(&vha->gnl.fcports_lock);
        init_waitqueue_head(&vha->fcport_waitQ);
        init_waitqueue_head(&vha->vref_waitq);
 
@@ -4804,9 +4822,12 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        fcport->d_id = e->u.new_sess.id;
                        fcport->flags |= FCF_FABRIC_DEVICE;
                        fcport->fw_login_state = DSC_LS_PLOGI_PEND;
-                       if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI)
+                       if (e->u.new_sess.fc4_type == FC4_TYPE_FCP_SCSI) {
                                fcport->fc4_type = FC4_TYPE_FCP_SCSI;
-
+                       } else if (e->u.new_sess.fc4_type == FC4_TYPE_NVME) {
+                               fcport->fc4_type = FC4_TYPE_OTHER;
+                               fcport->fc4f_nvme = FC4_TYPE_NVME;
+                       }
                        memcpy(fcport->port_name, e->u.new_sess.port_name,
                            WWN_SIZE);
                } else {
@@ -4875,6 +4896,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                        }
                        qlt_plogi_ack_unref(vha, pla);
                } else {
+                       fc_port_t *dfcp = NULL;
+
                        spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
                        tfcp = qla2x00_find_fcport_by_nportid(vha,
                            &e->u.new_sess.id, 1);
@@ -4897,11 +4920,13 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e)
                                default:
                                        fcport->login_pause = 1;
                                        tfcp->conflict = fcport;
-                                       qlt_schedule_sess_for_deletion(tfcp);
+                                       dfcp = tfcp;
                                        break;
                                }
                        }
                        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+                       if (dfcp)
+                               qlt_schedule_sess_for_deletion(tfcp);
 
                        wwn = wwn_to_u64(fcport->node_name);
 
index fc89af8..b49ac85 100644 (file)
@@ -1224,10 +1224,10 @@ static void qla24xx_chk_fcp_state(struct fc_port *sess)
        }
 }
 
-/* ha->tgt.sess_lock supposed to be held on entry */
 void qlt_schedule_sess_for_deletion(struct fc_port *sess)
 {
        struct qla_tgt *tgt = sess->tgt;
+       struct qla_hw_data *ha = sess->vha->hw;
        unsigned long flags;
 
        if (sess->disc_state == DSC_DELETE_PEND)
@@ -1244,16 +1244,16 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
                        return;
        }
 
+       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
        if (sess->deleted == QLA_SESS_DELETED)
                sess->logout_on_delete = 0;
 
-       spin_lock_irqsave(&sess->vha->work_lock, flags);
        if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) {
-               spin_unlock_irqrestore(&sess->vha->work_lock, flags);
+               spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
                return;
        }
        sess->deleted = QLA_SESS_DELETION_IN_PROGRESS;
-       spin_unlock_irqrestore(&sess->vha->work_lock, flags);
+       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
 
        sess->disc_state = DSC_DELETE_PEND;
 
@@ -1262,13 +1262,10 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess)
        ql_dbg(ql_dbg_tgt, sess->vha, 0xe001,
            "Scheduling sess %p for deletion\n", sess);
 
-       /* use cancel to push work element through before re-queue */
-       cancel_work_sync(&sess->del_work);
        INIT_WORK(&sess->del_work, qla24xx_delete_sess_fn);
-       queue_work(sess->vha->hw->wq, &sess->del_work);
+       WARN_ON(!queue_work(sess->vha->hw->wq, &sess->del_work));
 }
 
-/* ha->tgt.sess_lock supposed to be held on entry */
 static void qlt_clear_tgt_db(struct qla_tgt *tgt)
 {
        struct fc_port *sess;
@@ -1451,8 +1448,8 @@ qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport, int max_gen)
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf008, "qla_tgt_fc_port_deleted %p", sess);
 
        sess->local = 1;
-       qlt_schedule_sess_for_deletion(sess);
        spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+       qlt_schedule_sess_for_deletion(sess);
 }
 
 static inline int test_tgt_sess_count(struct qla_tgt *tgt)
@@ -1512,10 +1509,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt)
         * Lock is needed, because we still can get an incoming packet.
         */
        mutex_lock(&vha->vha_tgt.tgt_mutex);
-       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
        tgt->tgt_stop = 1;
        qlt_clear_tgt_db(tgt);
-       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
        mutex_unlock(&vha->vha_tgt.tgt_mutex);
        mutex_unlock(&qla_tgt_mutex);
 
@@ -4871,8 +4866,6 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
                                    sess);
                                qlt_send_term_imm_notif(vha, iocb, 1);
                                res = 0;
-                               spin_lock_irqsave(&tgt->ha->tgt.sess_lock,
-                                   flags);
                                break;
                        }
 
index fc23371..817f312 100644 (file)
 #define DEV_DB_NON_PERSISTENT  0
 #define DEV_DB_PERSISTENT      1
 
+#define QL4_ISP_REG_DISCONNECT 0xffffffffU
+
 #define COPY_ISID(dst_isid, src_isid) {                        \
        int i, j;                                       \
        for (i = 0, j = ISID_SIZE - 1; i < ISID_SIZE;)  \
index 82e889b..fc2c97d 100644 (file)
@@ -262,6 +262,24 @@ static struct iscsi_transport qla4xxx_iscsi_transport = {
 
 static struct scsi_transport_template *qla4xxx_scsi_transport;
 
+static int qla4xxx_isp_check_reg(struct scsi_qla_host *ha)
+{
+       u32 reg_val = 0;
+       int rval = QLA_SUCCESS;
+
+       if (is_qla8022(ha))
+               reg_val = readl(&ha->qla4_82xx_reg->host_status);
+       else if (is_qla8032(ha) || is_qla8042(ha))
+               reg_val = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
+       else
+               reg_val = readw(&ha->reg->ctrl_status);
+
+       if (reg_val == QL4_ISP_REG_DISCONNECT)
+               rval = QLA_ERROR;
+
+       return rval;
+}
+
 static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num,
                             uint32_t iface_type, uint32_t payload_size,
                             uint32_t pid, struct sockaddr *dst_addr)
@@ -9186,10 +9204,17 @@ static int qla4xxx_eh_abort(struct scsi_cmnd *cmd)
        struct srb *srb = NULL;
        int ret = SUCCESS;
        int wait = 0;
+       int rval;
 
        ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%llu: Abort command issued cmd=%p, cdb=0x%x\n",
                   ha->host_no, id, lun, cmd, cmd->cmnd[0]);
 
+       rval = qla4xxx_isp_check_reg(ha);
+       if (rval != QLA_SUCCESS) {
+               ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
        srb = (struct srb *) CMD_SP(cmd);
        if (!srb) {
@@ -9241,6 +9266,7 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
        struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
        struct ddb_entry *ddb_entry = cmd->device->hostdata;
        int ret = FAILED, stat;
+       int rval;
 
        if (!ddb_entry)
                return ret;
@@ -9260,6 +9286,12 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
                      cmd, jiffies, cmd->request->timeout / HZ,
                      ha->dpc_flags, cmd->result, cmd->allowed));
 
+       rval = qla4xxx_isp_check_reg(ha);
+       if (rval != QLA_SUCCESS) {
+               ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        /* FIXME: wait for hba to go online */
        stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
        if (stat != QLA_SUCCESS) {
@@ -9303,6 +9335,7 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
        struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
        struct ddb_entry *ddb_entry = cmd->device->hostdata;
        int stat, ret;
+       int rval;
 
        if (!ddb_entry)
                return FAILED;
@@ -9320,6 +9353,12 @@ static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd)
                      ha->host_no, cmd, jiffies, cmd->request->timeout / HZ,
                      ha->dpc_flags, cmd->result, cmd->allowed));
 
+       rval = qla4xxx_isp_check_reg(ha);
+       if (rval != QLA_SUCCESS) {
+               ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        stat = qla4xxx_reset_target(ha, ddb_entry);
        if (stat != QLA_SUCCESS) {
                starget_printk(KERN_INFO, scsi_target(cmd->device),
@@ -9374,9 +9413,16 @@ static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
 {
        int return_status = FAILED;
        struct scsi_qla_host *ha;
+       int rval;
 
        ha = to_qla_host(cmd->device->host);
 
+       rval = qla4xxx_isp_check_reg(ha);
+       if (rval != QLA_SUCCESS) {
+               ql4_printk(KERN_INFO, ha, "PCI/Register disconnect, exiting.\n");
+               return FAILED;
+       }
+
        if ((is_qla8032(ha) || is_qla8042(ha)) && ql4xdontresethba)
                qla4_83xx_set_idc_dontreset(ha);
 
index d042915..ca53a5f 100644 (file)
@@ -223,7 +223,8 @@ static void scsi_eh_reset(struct scsi_cmnd *scmd)
 
 static void scsi_eh_inc_host_failed(struct rcu_head *head)
 {
-       struct Scsi_Host *shost = container_of(head, typeof(*shost), rcu);
+       struct scsi_cmnd *scmd = container_of(head, typeof(*scmd), rcu);
+       struct Scsi_Host *shost = scmd->device->host;
        unsigned long flags;
 
        spin_lock_irqsave(shost->host_lock, flags);
@@ -259,7 +260,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd)
         * Ensure that all tasks observe the host state change before the
         * host_failed change.
         */
-       call_rcu(&shost->rcu, scsi_eh_inc_host_failed);
+       call_rcu(&scmd->rcu, scsi_eh_inc_host_failed);
 }
 
 /**
index a86df9c..c84f931 100644 (file)
@@ -671,6 +671,7 @@ static bool scsi_end_request(struct request *req, blk_status_t error,
        if (!blk_rq_is_scsi(req)) {
                WARN_ON_ONCE(!(cmd->flags & SCMD_INITIALIZED));
                cmd->flags &= ~SCMD_INITIALIZED;
+               destroy_rcu_head(&cmd->rcu);
        }
 
        if (req->mq_ctx) {
@@ -720,6 +721,8 @@ static blk_status_t __scsi_error_from_host_byte(struct scsi_cmnd *cmd,
                int result)
 {
        switch (host_byte(result)) {
+       case DID_OK:
+               return BLK_STS_OK;
        case DID_TRANSPORT_FAILFAST:
                return BLK_STS_TRANSPORT;
        case DID_TARGET_FAILURE:
@@ -1151,6 +1154,7 @@ static void scsi_initialize_rq(struct request *rq)
        struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq);
 
        scsi_req_init(&cmd->req);
+       init_rcu_head(&cmd->rcu);
        cmd->jiffies_at_alloc = jiffies;
        cmd->retries = 0;
 }
index bff21e6..1fa84d6 100644 (file)
@@ -2484,6 +2484,8 @@ sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer)
                                sector_size = old_sector_size;
                                goto got_data;
                        }
+                       /* Remember that READ CAPACITY(16) succeeded */
+                       sdp->try_rc_10_first = 0;
                }
        }
 
@@ -2595,6 +2597,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
        int res;
        struct scsi_device *sdp = sdkp->device;
        struct scsi_mode_data data;
+       int disk_ro = get_disk_ro(sdkp->disk);
        int old_wp = sdkp->write_prot;
 
        set_disk_ro(sdkp->disk, 0);
@@ -2635,7 +2638,7 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer)
                          "Test WP failed, assume Write Enabled\n");
        } else {
                sdkp->write_prot = ((data.device_specific & 0x80) != 0);
-               set_disk_ro(sdkp->disk, sdkp->write_prot);
+               set_disk_ro(sdkp->disk, sdkp->write_prot || disk_ro);
                if (sdkp->first_scan || old_wp != sdkp->write_prot) {
                        sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n",
                                  sdkp->write_prot ? "on" : "off");
index 6c348a2..89cf449 100644 (file)
@@ -403,7 +403,7 @@ static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
  */
 static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 {
-       u64 zone_blocks;
+       u64 zone_blocks = 0;
        sector_t block = 0;
        unsigned char *buf;
        unsigned char *rec;
@@ -421,10 +421,8 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
 
        /* Do a report zone to get the same field */
        ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0);
-       if (ret) {
-               zone_blocks = 0;
-               goto out;
-       }
+       if (ret)
+               goto out_free;
 
        same = buf[4] & 0x0f;
        if (same > 0) {
@@ -464,7 +462,7 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
                        ret = sd_zbc_report_zones(sdkp, buf,
                                                  SD_ZBC_BUF_SIZE, block);
                        if (ret)
-                               return ret;
+                               goto out_free;
                }
 
        } while (block < sdkp->capacity);
@@ -472,35 +470,32 @@ static int sd_zbc_check_zone_size(struct scsi_disk *sdkp)
        zone_blocks = sdkp->zone_blocks;
 
 out:
-       kfree(buf);
-
        if (!zone_blocks) {
                if (sdkp->first_scan)
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Devices with non constant zone "
                                  "size are not supported\n");
-               return -ENODEV;
-       }
-
-       if (!is_power_of_2(zone_blocks)) {
+               ret = -ENODEV;
+       } else if (!is_power_of_2(zone_blocks)) {
                if (sdkp->first_scan)
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Devices with non power of 2 zone "
                                  "size are not supported\n");
-               return -ENODEV;
-       }
-
-       if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
+               ret = -ENODEV;
+       } else if (logical_to_sectors(sdkp->device, zone_blocks) > UINT_MAX) {
                if (sdkp->first_scan)
                        sd_printk(KERN_NOTICE, sdkp,
                                  "Zone size too large\n");
-               return -ENODEV;
+               ret = -ENODEV;
+       } else {
+               sdkp->zone_blocks = zone_blocks;
+               sdkp->zone_shift = ilog2(zone_blocks);
        }
 
-       sdkp->zone_blocks = zone_blocks;
-       sdkp->zone_shift = ilog2(zone_blocks);
+out_free:
+       kfree(buf);
 
-       return 0;
+       return ret;
 }
 
 /**
index 40fc7a5..8c51d62 100644 (file)
@@ -1311,7 +1311,8 @@ static int storvsc_do_io(struct hv_device *device,
                         */
                        cpumask_and(&alloced_mask, &stor_device->alloced_cpus,
                                    cpumask_of_node(cpu_to_node(q_num)));
-                       for_each_cpu(tgt_cpu, &alloced_mask) {
+                       for_each_cpu_wrap(tgt_cpu, &alloced_mask,
+                                       outgoing_channel->target_cpu + 1) {
                                if (tgt_cpu != outgoing_channel->target_cpu) {
                                        outgoing_channel =
                                        stor_device->stor_chns[tgt_cpu];
@@ -1657,7 +1658,7 @@ static struct scsi_host_template scsi_driver = {
        .eh_timed_out =         storvsc_eh_timed_out,
        .slave_alloc =          storvsc_device_alloc,
        .slave_configure =      storvsc_device_configure,
-       .cmd_per_lun =          255,
+       .cmd_per_lun =          2048,
        .this_id =              -1,
        .use_clustering =       ENABLE_CLUSTERING,
        /* Make sure we dont get a sg segment crosses a page boundary */
index ca360da..378af30 100644 (file)
@@ -536,7 +536,7 @@ sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fa
         *  Look for the greatest clock divisor that allows an 
         *  input speed faster than the period.
         */
-       while (div-- > 0)
+       while (--div > 0)
                if (kpc >= (div_10M[div] << 2)) break;
 
        /*
index a355d98..c7da2c1 100644 (file)
@@ -4352,6 +4352,8 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
        /* REPORT SUPPORTED OPERATION CODES is not supported */
        sdev->no_report_opcodes = 1;
 
+       /* WRITE_SAME command is not supported */
+       sdev->no_write_same = 1;
 
        ufshcd_set_queue_depth(sdev);
 
index 7c28e8d..45d0463 100644 (file)
@@ -91,9 +91,6 @@ struct virtio_scsi_vq {
 struct virtio_scsi_target_state {
        seqcount_t tgt_seq;
 
-       /* Count of outstanding requests. */
-       atomic_t reqs;
-
        /* Currently active virtqueue for requests sent to this target. */
        struct virtio_scsi_vq *req_vq;
 };
@@ -152,8 +149,6 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
        struct virtio_scsi_cmd *cmd = buf;
        struct scsi_cmnd *sc = cmd->sc;
        struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
-       struct virtio_scsi_target_state *tgt =
-                               scsi_target(sc->device)->hostdata;
 
        dev_dbg(&sc->device->sdev_gendev,
                "cmd %p response %u status %#02x sense_len %u\n",
@@ -210,8 +205,6 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
        }
 
        sc->scsi_done(sc);
-
-       atomic_dec(&tgt->reqs);
 }
 
 static void virtscsi_vq_done(struct virtio_scsi *vscsi,
@@ -529,11 +522,20 @@ static void virtio_scsi_init_hdr_pi(struct virtio_device *vdev,
 }
 #endif
 
-static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
-                                struct virtio_scsi_vq *req_vq,
+static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi,
+                                                 struct scsi_cmnd *sc)
+{
+       u32 tag = blk_mq_unique_tag(sc->request);
+       u16 hwq = blk_mq_unique_tag_to_hwq(tag);
+
+       return &vscsi->req_vqs[hwq];
+}
+
+static int virtscsi_queuecommand(struct Scsi_Host *shost,
                                 struct scsi_cmnd *sc)
 {
-       struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
+       struct virtio_scsi *vscsi = shost_priv(shost);
+       struct virtio_scsi_vq *req_vq = virtscsi_pick_vq_mq(vscsi, sc);
        struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc);
        unsigned long flags;
        int req_size;
@@ -576,79 +578,6 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
        return 0;
 }
 
-static int virtscsi_queuecommand_single(struct Scsi_Host *sh,
-                                       struct scsi_cmnd *sc)
-{
-       struct virtio_scsi *vscsi = shost_priv(sh);
-       struct virtio_scsi_target_state *tgt =
-                               scsi_target(sc->device)->hostdata;
-
-       atomic_inc(&tgt->reqs);
-       return virtscsi_queuecommand(vscsi, &vscsi->req_vqs[0], sc);
-}
-
-static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi,
-                                                 struct scsi_cmnd *sc)
-{
-       u32 tag = blk_mq_unique_tag(sc->request);
-       u16 hwq = blk_mq_unique_tag_to_hwq(tag);
-
-       return &vscsi->req_vqs[hwq];
-}
-
-static struct virtio_scsi_vq *virtscsi_pick_vq(struct virtio_scsi *vscsi,
-                                              struct virtio_scsi_target_state *tgt)
-{
-       struct virtio_scsi_vq *vq;
-       unsigned long flags;
-       u32 queue_num;
-
-       local_irq_save(flags);
-       if (atomic_inc_return(&tgt->reqs) > 1) {
-               unsigned long seq;
-
-               do {
-                       seq = read_seqcount_begin(&tgt->tgt_seq);
-                       vq = tgt->req_vq;
-               } while (read_seqcount_retry(&tgt->tgt_seq, seq));
-       } else {
-               /* no writes can be concurrent because of atomic_t */
-               write_seqcount_begin(&tgt->tgt_seq);
-
-               /* keep previous req_vq if a reader just arrived */
-               if (unlikely(atomic_read(&tgt->reqs) > 1)) {
-                       vq = tgt->req_vq;
-                       goto unlock;
-               }
-
-               queue_num = smp_processor_id();
-               while (unlikely(queue_num >= vscsi->num_queues))
-                       queue_num -= vscsi->num_queues;
-               tgt->req_vq = vq = &vscsi->req_vqs[queue_num];
- unlock:
-               write_seqcount_end(&tgt->tgt_seq);
-       }
-       local_irq_restore(flags);
-
-       return vq;
-}
-
-static int virtscsi_queuecommand_multi(struct Scsi_Host *sh,
-                                      struct scsi_cmnd *sc)
-{
-       struct virtio_scsi *vscsi = shost_priv(sh);
-       struct virtio_scsi_target_state *tgt =
-                               scsi_target(sc->device)->hostdata;
-       struct virtio_scsi_vq *req_vq;
-
-       if (shost_use_blk_mq(sh))
-               req_vq = virtscsi_pick_vq_mq(vscsi, sc);
-       else
-               req_vq = virtscsi_pick_vq(vscsi, tgt);
-
-       return virtscsi_queuecommand(vscsi, req_vq, sc);
-}
-
 static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd)
 {
        DECLARE_COMPLETION_ONSTACK(comp);
@@ -775,7 +704,6 @@ static int virtscsi_target_alloc(struct scsi_target *starget)
                return -ENOMEM;
 
        seqcount_init(&tgt->tgt_seq);
-       atomic_set(&tgt->reqs, 0);
        tgt->req_vq = &vscsi->req_vqs[0];
 
        starget->hostdata = tgt;
@@ -805,33 +733,13 @@ static enum blk_eh_timer_return virtscsi_eh_timed_out(struct scsi_cmnd *scmnd)
        return BLK_EH_RESET_TIMER;
 }
 
-static struct scsi_host_template virtscsi_host_template_single = {
-       .module = THIS_MODULE,
-       .name = "Virtio SCSI HBA",
-       .proc_name = "virtio_scsi",
-       .this_id = -1,
-       .cmd_size = sizeof(struct virtio_scsi_cmd),
-       .queuecommand = virtscsi_queuecommand_single,
-       .change_queue_depth = virtscsi_change_queue_depth,
-       .eh_abort_handler = virtscsi_abort,
-       .eh_device_reset_handler = virtscsi_device_reset,
-       .eh_timed_out = virtscsi_eh_timed_out,
-       .slave_alloc = virtscsi_device_alloc,
-
-       .dma_boundary = UINT_MAX,
-       .use_clustering = ENABLE_CLUSTERING,
-       .target_alloc = virtscsi_target_alloc,
-       .target_destroy = virtscsi_target_destroy,
-       .track_queue_depth = 1,
-};
-
-static struct scsi_host_template virtscsi_host_template_multi = {
+static struct scsi_host_template virtscsi_host_template = {
        .module = THIS_MODULE,
        .name = "Virtio SCSI HBA",
        .proc_name = "virtio_scsi",
        .this_id = -1,
        .cmd_size = sizeof(struct virtio_scsi_cmd),
-       .queuecommand = virtscsi_queuecommand_multi,
+       .queuecommand = virtscsi_queuecommand,
        .change_queue_depth = virtscsi_change_queue_depth,
        .eh_abort_handler = virtscsi_abort,
        .eh_device_reset_handler = virtscsi_device_reset,
@@ -844,6 +752,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
        .target_destroy = virtscsi_target_destroy,
        .map_queues = virtscsi_map_queues,
        .track_queue_depth = 1,
+       .force_blk_mq = 1,
 };
 
 #define virtscsi_config_get(vdev, fld) \
@@ -936,7 +845,6 @@ static int virtscsi_probe(struct virtio_device *vdev)
        u32 sg_elems, num_targets;
        u32 cmd_per_lun;
        u32 num_queues;
-       struct scsi_host_template *hostt;
 
        if (!vdev->config->get) {
                dev_err(&vdev->dev, "%s failure: config access disabled\n",
@@ -949,12 +857,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
 
        num_targets = virtscsi_config_get(vdev, max_target) + 1;
 
-       if (num_queues == 1)
-               hostt = &virtscsi_host_template_single;
-       else
-               hostt = &virtscsi_host_template_multi;
-
-       shost = scsi_host_alloc(hostt,
+       shost = scsi_host_alloc(&virtscsi_host_template,
                sizeof(*vscsi) + sizeof(vscsi->req_vqs[0]) * num_queues);
        if (!shost)
                return -ENOMEM;
index e4f5bb0..ba3cfa8 100644 (file)
@@ -2443,39 +2443,21 @@ struct cgr_comp {
        struct completion completion;
 };
 
-static int qman_delete_cgr_thread(void *p)
+static void qman_delete_cgr_smp_call(void *p)
 {
-       struct cgr_comp *cgr_comp = (struct cgr_comp *)p;
-       int ret;
-
-       ret = qman_delete_cgr(cgr_comp->cgr);
-       complete(&cgr_comp->completion);
-
-       return ret;
+       qman_delete_cgr((struct qman_cgr *)p);
 }
 
 void qman_delete_cgr_safe(struct qman_cgr *cgr)
 {
-       struct task_struct *thread;
-       struct cgr_comp cgr_comp;
-
        preempt_disable();
        if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) {
-               init_completion(&cgr_comp.completion);
-               cgr_comp.cgr = cgr;
-               thread = kthread_create(qman_delete_cgr_thread, &cgr_comp,
-                                       "cgr_del");
-
-               if (IS_ERR(thread))
-                       goto out;
-
-               kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]);
-               wake_up_process(thread);
-               wait_for_completion(&cgr_comp.completion);
+               smp_call_function_single(qman_cgr_cpus[cgr->cgrid],
+                                        qman_delete_cgr_smp_call, cgr, true);
                preempt_enable();
                return;
        }
-out:
+
        qman_delete_cgr(cgr);
        preempt_enable();
 }
index 53f7275..750f931 100644 (file)
@@ -348,7 +348,7 @@ static int imx_gpc_old_dt_init(struct device *dev, struct regmap *regmap,
                if (i == 1) {
                        domain->supply = devm_regulator_get(dev, "pu");
                        if (IS_ERR(domain->supply))
-                               return PTR_ERR(domain->supply);;
+                               return PTR_ERR(domain->supply);
 
                        ret = imx_pgc_get_clocks(dev, domain);
                        if (ret)
@@ -470,13 +470,21 @@ static int imx_gpc_probe(struct platform_device *pdev)
 
 static int imx_gpc_remove(struct platform_device *pdev)
 {
+       struct device_node *pgc_node;
        int ret;
 
+       pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc");
+
+       /* bail out if DT too old and doesn't provide the necessary info */
+       if (!of_property_read_bool(pdev->dev.of_node, "#power-domain-cells") &&
+           !pgc_node)
+               return 0;
+
        /*
         * If the old DT binding is used the toplevel driver needs to
         * de-register the power domains
         */
-       if (!of_get_child_by_name(pdev->dev.of_node, "pgc")) {
+       if (!pgc_node) {
                of_genpd_del_provider(pdev->dev.of_node);
 
                ret = pm_genpd_remove(&imx_gpc_domains[GPC_PGC_DOMAIN_PU].base);
index bbdc53b..86580b6 100644 (file)
@@ -326,24 +326,23 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin)
        mutex_lock(&ashmem_mutex);
 
        if (asma->size == 0) {
-               ret = -EINVAL;
-               goto out;
+               mutex_unlock(&ashmem_mutex);
+               return -EINVAL;
        }
 
        if (!asma->file) {
-               ret = -EBADF;
-               goto out;
+               mutex_unlock(&ashmem_mutex);
+               return -EBADF;
        }
 
+       mutex_unlock(&ashmem_mutex);
+
        ret = vfs_llseek(asma->file, offset, origin);
        if (ret < 0)
-               goto out;
+               return ret;
 
        /** Copy f_pos from backing file, since f_ops->llseek() sets it */
        file->f_pos = asma->file->f_pos;
-
-out:
-       mutex_unlock(&ashmem_mutex);
        return ret;
 }
 
@@ -702,30 +701,30 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
        size_t pgstart, pgend;
        int ret = -EINVAL;
 
-       if (unlikely(!asma->file))
-               return -EINVAL;
-
        if (unlikely(copy_from_user(&pin, p, sizeof(pin))))
                return -EFAULT;
 
+       mutex_lock(&ashmem_mutex);
+
+       if (unlikely(!asma->file))
+               goto out_unlock;
+
        /* per custom, you can pass zero for len to mean "everything onward" */
        if (!pin.len)
                pin.len = PAGE_ALIGN(asma->size) - pin.offset;
 
        if (unlikely((pin.offset | pin.len) & ~PAGE_MASK))
-               return -EINVAL;
+               goto out_unlock;
 
        if (unlikely(((__u32)-1) - pin.offset < pin.len))
-               return -EINVAL;
+               goto out_unlock;
 
        if (unlikely(PAGE_ALIGN(asma->size) < pin.offset + pin.len))
-               return -EINVAL;
+               goto out_unlock;
 
        pgstart = pin.offset / PAGE_SIZE;
        pgend = pgstart + (pin.len / PAGE_SIZE) - 1;
 
-       mutex_lock(&ashmem_mutex);
-
        switch (cmd) {
        case ASHMEM_PIN:
                ret = ashmem_pin(asma, pgstart, pgend);
@@ -738,6 +737,7 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd,
                break;
        }
 
+out_unlock:
        mutex_unlock(&ashmem_mutex);
 
        return ret;
index 94e0692..49718c9 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/err.h>
 #include <linux/cma.h>
 #include <linux/scatterlist.h>
+#include <linux/highmem.h>
 
 #include "ion.h"
 
@@ -42,6 +43,22 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
        if (!pages)
                return -ENOMEM;
 
+       if (PageHighMem(pages)) {
+               unsigned long nr_clear_pages = nr_pages;
+               struct page *page = pages;
+
+               while (nr_clear_pages > 0) {
+                       void *vaddr = kmap_atomic(page);
+
+                       memset(vaddr, 0, PAGE_SIZE);
+                       kunmap_atomic(vaddr);
+                       page++;
+                       nr_clear_pages--;
+               }
+       } else {
+               memset(page_address(pages), 0, size);
+       }
+
        table = kmalloc(sizeof(*table), GFP_KERNEL);
        if (!table)
                goto err;
index e618a87..9d73347 100644 (file)
@@ -475,8 +475,7 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s,
        struct comedi_cmd *cmd = &async->cmd;
 
        if (cmd->stop_src == TRIG_COUNT) {
-               unsigned int nscans = nsamples / cmd->scan_end_arg;
-               unsigned int scans_left = __comedi_nscans_left(s, nscans);
+               unsigned int scans_left = __comedi_nscans_left(s, cmd->stop_arg);
                unsigned int scan_pos =
                    comedi_bytes_to_samples(s, async->scan_progress);
                unsigned long long samples_left = 0;
index 1f91000..b35ef7e 100644 (file)
@@ -7,7 +7,7 @@
 
 config FSL_MC_BUS
        bool "QorIQ DPAA2 fsl-mc bus driver"
-       depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86 || PPC)))
+       depends on OF && (ARCH_LAYERSCAPE || (COMPILE_TEST && (ARM || ARM64 || X86_LOCAL_APIC || PPC)))
        select GENERIC_MSI_IRQ_DOMAIN
        help
          Driver to enable the bus infrastructure for the QorIQ DPAA2
index 5064d5d..fc2013a 100644 (file)
@@ -73,6 +73,8 @@ static int __init its_fsl_mc_msi_init(void)
 
        for (np = of_find_matching_node(NULL, its_device_id); np;
             np = of_find_matching_node(np, its_device_id)) {
+               if (!of_device_is_available(np))
+                       continue;
                if (!of_property_read_bool(np, "msi-controller"))
                        continue;
 
index f015955..425e8b8 100644 (file)
 #define AD7192_GPOCON_P1DAT    BIT(1) /* P1 state */
 #define AD7192_GPOCON_P0DAT    BIT(0) /* P0 state */
 
+#define AD7192_EXT_FREQ_MHZ_MIN        2457600
+#define AD7192_EXT_FREQ_MHZ_MAX        5120000
 #define AD7192_INT_FREQ_MHZ    4915200
 
 /* NOTE:
@@ -218,6 +220,12 @@ static int ad7192_calibrate_all(struct ad7192_state *st)
                                ARRAY_SIZE(ad7192_calib_arr));
 }
 
+static inline bool ad7192_valid_external_frequency(u32 freq)
+{
+       return (freq >= AD7192_EXT_FREQ_MHZ_MIN &&
+               freq <= AD7192_EXT_FREQ_MHZ_MAX);
+}
+
 static int ad7192_setup(struct ad7192_state *st,
                        const struct ad7192_platform_data *pdata)
 {
@@ -243,17 +251,20 @@ static int ad7192_setup(struct ad7192_state *st,
                         id);
 
        switch (pdata->clock_source_sel) {
-       case AD7192_CLK_EXT_MCLK1_2:
-       case AD7192_CLK_EXT_MCLK2:
-               st->mclk = AD7192_INT_FREQ_MHZ;
-               break;
        case AD7192_CLK_INT:
        case AD7192_CLK_INT_CO:
-               if (pdata->ext_clk_hz)
-                       st->mclk = pdata->ext_clk_hz;
-               else
-                       st->mclk = AD7192_INT_FREQ_MHZ;
+               st->mclk = AD7192_INT_FREQ_MHZ;
                break;
+       case AD7192_CLK_EXT_MCLK1_2:
+       case AD7192_CLK_EXT_MCLK2:
+               if (ad7192_valid_external_frequency(pdata->ext_clk_hz)) {
+                       st->mclk = pdata->ext_clk_hz;
+                       break;
+               }
+               dev_err(&st->sd.spi->dev, "Invalid frequency setting %u\n",
+                       pdata->ext_clk_hz);
+               ret = -EINVAL;
+               goto out;
        default:
                ret = -EINVAL;
                goto out;
index 2b28fb9..3bcf494 100644 (file)
@@ -648,8 +648,6 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
        /* Ring buffer functions - here trigger setup related */
        indio_dev->setup_ops = &ad5933_ring_setup_ops;
 
-       indio_dev->modes |= INDIO_BUFFER_HARDWARE;
-
        return 0;
 }
 
@@ -762,7 +760,7 @@ static int ad5933_probe(struct i2c_client *client,
        indio_dev->dev.parent = &client->dev;
        indio_dev->info = &ad5933_info;
        indio_dev->name = id->name;
-       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->modes = (INDIO_BUFFER_SOFTWARE | INDIO_DIRECT_MODE);
        indio_dev->channels = ad5933_channels;
        indio_dev->num_channels = ARRAY_SIZE(ad5933_channels);
 
index 804adfe..3e047eb 100644 (file)
@@ -981,6 +981,10 @@ ncp_read_kernel(struct ncp_server *server, const char *file_id,
                goto out;
        }
        *bytes_read = ncp_reply_be16(server, 0);
+       if (*bytes_read > to_read) {
+               result = -EINVAL;
+               goto out;
+       }
        source = ncp_reply_data(server, 2 + (offset & 1));
 
        memcpy(target, source, *bytes_read);
index 5c0e59e..cbe98bc 100644 (file)
@@ -2180,6 +2180,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                                }
                                if (tty_hung_up_p(file))
                                        break;
+                               /*
+                                * Abort readers for ttys which never actually
+                                * get hung up.  See __tty_hangup().
+                                */
+                               if (test_bit(TTY_HUPPING, &tty->flags))
+                                       break;
                                if (!timeout)
                                        break;
                                if (file->f_flags & O_NONBLOCK) {
index 54adf8d..a93f77a 100644 (file)
@@ -3387,11 +3387,9 @@ static int serial_pci_is_class_communication(struct pci_dev *dev)
        /*
         * If it is not a communications device or the programming
         * interface is greater than 6, give up.
-        *
-        * (Should we try to make guesses for multiport serial devices
-        * later?)
         */
        if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) &&
+            ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MULTISERIAL) &&
             ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) ||
            (dev->class & 0xff) > 6)
                return -ENODEV;
@@ -3428,6 +3426,12 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board)
 {
        int num_iomem, num_port, first_port = -1, i;
 
+       /*
+        * Should we try to make guesses for multiport serial devices later?
+        */
+       if ((dev->class >> 8) == PCI_CLASS_COMMUNICATION_MULTISERIAL)
+               return -ENODEV;
+
        num_iomem = num_port = 0;
        for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) {
                if (pci_resource_flags(dev, i) & IORESOURCE_IO) {
@@ -4699,6 +4703,17 @@ static const struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,    /* 135a.0dc0 */
                pbn_b2_4_115200 },
        /*
+        * BrainBoxes UC-260
+        */
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0D21,
+               PCI_ANY_ID, PCI_ANY_ID,
+               PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               pbn_b2_4_115200 },
+       {       PCI_VENDOR_ID_INTASHIELD, 0x0E34,
+               PCI_ANY_ID, PCI_ANY_ID,
+                PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00,
+               pbn_b2_4_115200 },
+       /*
         * Perle PCI-RAS cards
         */
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030,
index df46a9e..e287fe8 100644 (file)
@@ -1734,6 +1734,7 @@ static void atmel_get_ip_name(struct uart_port *port)
                switch (version) {
                case 0x302:
                case 0x10213:
+               case 0x10302:
                        dev_dbg(port->dev, "This version is usart\n");
                        atmel_port->has_frac_baudrate = true;
                        atmel_port->has_hw_timer = true;
index 870e84f..a242783 100644 (file)
@@ -245,11 +245,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match,
        }
        port->mapbase = addr;
        port->uartclk = BASE_BAUD * 16;
-       port->membase = earlycon_map(port->mapbase, SZ_4K);
 
        val = of_get_flat_dt_prop(node, "reg-offset", NULL);
        if (val)
                port->mapbase += be32_to_cpu(*val);
+       port->membase = earlycon_map(port->mapbase, SZ_4K);
+
        val = of_get_flat_dt_prop(node, "reg-shift", NULL);
        if (val)
                port->regshift = be32_to_cpu(*val);
index 1d7ca38..a33c685 100644 (file)
@@ -2093,7 +2093,7 @@ static int serial_imx_probe(struct platform_device *pdev)
        uart_get_rs485_mode(&pdev->dev, &sport->port.rs485);
 
        if (sport->port.rs485.flags & SER_RS485_ENABLED &&
-           (!sport->have_rtscts || !sport->have_rtsgpio))
+           (!sport->have_rtscts && !sport->have_rtsgpio))
                dev_err(&pdev->dev, "no RTS control, disabling rs485\n");
 
        imx_rs485_config(&sport->port, &sport->port.rs485);
index c8dde56..35b9201 100644 (file)
@@ -1144,6 +1144,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
                uport->ops->config_port(uport, flags);
 
                ret = uart_startup(tty, state, 1);
+               if (ret == 0)
+                       tty_port_set_initialized(port, true);
                if (ret > 0)
                        ret = 0;
        }
index 7257c07..44adf9d 100644 (file)
@@ -885,6 +885,8 @@ static void sci_receive_chars(struct uart_port *port)
                /* Tell the rest of the system the news. New characters! */
                tty_flip_buffer_push(tport);
        } else {
+               /* TTY buffers full; read from RX reg to prevent lockup */
+               serial_port_in(port, SCxRDR);
                serial_port_in(port, SCxSR); /* dummy read */
                sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port));
        }
index eb9133b..63114ea 100644 (file)
@@ -586,6 +586,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
                return;
        }
 
+       /*
+        * Some console devices aren't actually hung up for technical and
+        * historical reasons, which can lead to indefinite interruptible
+        * sleep in n_tty_read().  The following explicitly tells
+        * n_tty_read() to abort readers.
+        */
+       set_bit(TTY_HUPPING, &tty->flags);
+
        /* inuse_filps is protected by the single tty lock,
           this really needs to change if we want to flush the
           workqueue with the lock held */
@@ -640,6 +648,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session)
         * from the ldisc side, which is now guaranteed.
         */
        set_bit(TTY_HUPPED, &tty->flags);
+       clear_bit(TTY_HUPPING, &tty->flags);
        tty_unlock(tty);
 
        if (f)
index 88b902c..b4e57c5 100644 (file)
@@ -1727,7 +1727,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
        default_attr(vc);
        update_attr(vc);
 
-       vc->vc_tab_stop[0]      = 0x01010100;
+       vc->vc_tab_stop[0]      =
        vc->vc_tab_stop[1]      =
        vc->vc_tab_stop[2]      =
        vc->vc_tab_stop[3]      =
@@ -1771,7 +1771,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                vc->vc_pos -= (vc->vc_x << 1);
                while (vc->vc_x < vc->vc_cols - 1) {
                        vc->vc_x++;
-                       if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31)))
+                       if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31)))
                                break;
                }
                vc->vc_pos += (vc->vc_x << 1);
@@ -1831,7 +1831,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        lf(vc);
                        return;
                case 'H':
-                       vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31));
+                       vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31));
                        return;
                case 'Z':
                        respond_ID(tty);
@@ -2024,7 +2024,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                        return;
                case 'g':
                        if (!vc->vc_par[0])
-                               vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31));
+                               vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31));
                        else if (vc->vc_par[0] == 3) {
                                vc->vc_tab_stop[0] =
                                        vc->vc_tab_stop[1] =
index f699aba..148f3ee 100644 (file)
@@ -19,6 +19,12 @@ config USB_EHCI_BIG_ENDIAN_MMIO
 config USB_EHCI_BIG_ENDIAN_DESC
        bool
 
+config USB_UHCI_BIG_ENDIAN_MMIO
+       bool
+
+config USB_UHCI_BIG_ENDIAN_DESC
+       bool
+
 menuconfig USB_SUPPORT
        bool "USB support"
        depends on HAS_IOMEM
index 06b3b54..7b366a6 100644 (file)
@@ -174,6 +174,7 @@ static int acm_wb_alloc(struct acm *acm)
                wb = &acm->wb[wbn];
                if (!wb->use) {
                        wb->use = 1;
+                       wb->len = 0;
                        return wbn;
                }
                wbn = (wbn + 1) % ACM_NW;
@@ -805,16 +806,18 @@ static int acm_tty_write(struct tty_struct *tty,
 static void acm_tty_flush_chars(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
-       struct acm_wb *cur = acm->putbuffer;
+       struct acm_wb *cur;
        int err;
        unsigned long flags;
 
+       spin_lock_irqsave(&acm->write_lock, flags);
+
+       cur = acm->putbuffer;
        if (!cur) /* nothing to do */
-               return;
+               goto out;
 
        acm->putbuffer = NULL;
        err = usb_autopm_get_interface_async(acm->control);
-       spin_lock_irqsave(&acm->write_lock, flags);
        if (err < 0) {
                cur->use = 0;
                acm->putbuffer = cur;
index c64cf6c..0c11d40 100644 (file)
@@ -151,6 +151,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
 
        ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
+       /* Linger a bit, prior to the next control message. */
+       if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG)
+               msleep(200);
+
        kfree(dr);
 
        return ret;
index 4024926..54b019e 100644 (file)
@@ -226,8 +226,12 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
                        USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
 
+       /* Corsair K70 RGB */
+       { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT },
+
        /* Corsair Strafe RGB */
-       { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT },
+       { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT |
+         USB_QUIRK_DELAY_CTRL_MSG },
 
        /* Corsair K70 LUX */
        { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT },
index e4c3ce0..5bcad1d 100644 (file)
@@ -1917,7 +1917,9 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
                /* Not specific buffer needed for ep0 ZLP */
                dma_addr_t dma = hs_ep->desc_list_dma;
 
-               dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
+               if (!index)
+                       dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
+
                dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0);
        } else {
                dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
@@ -2974,9 +2976,13 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
        if (ints & DXEPINT_STSPHSERCVD) {
                dev_dbg(hsotg->dev, "%s: StsPhseRcvd\n", __func__);
 
-               /* Move to STATUS IN for DDMA */
-               if (using_desc_dma(hsotg))
-                       dwc2_hsotg_ep0_zlp(hsotg, true);
+               /* Safety check EP0 state when STSPHSERCVD asserted */
+               if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
+                       /* Move to STATUS IN for DDMA */
+                       if (using_desc_dma(hsotg))
+                               dwc2_hsotg_ep0_zlp(hsotg, true);
+               }
+
        }
 
        if (ints & DXEPINT_BACK2BACKSETUP)
@@ -3375,12 +3381,6 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
               DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
 
-       dwc2_hsotg_enqueue_setup(hsotg);
-
-       dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-               dwc2_readl(hsotg->regs + DIEPCTL0),
-               dwc2_readl(hsotg->regs + DOEPCTL0));
-
        /* clear global NAKs */
        val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
        if (!is_usb_reset)
@@ -3391,6 +3391,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        mdelay(3);
 
        hsotg->lx_state = DWC2_L0;
+
+       dwc2_hsotg_enqueue_setup(hsotg);
+
+       dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
+               dwc2_readl(hsotg->regs + DIEPCTL0),
+               dwc2_readl(hsotg->regs + DOEPCTL0));
 }
 
 static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
index 03fd20f..c4a4749 100644 (file)
@@ -137,7 +137,7 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
        p->activate_stm_fs_transceiver = true;
 }
 
-static void dwc2_set_stm32f7xx_hsotg_params(struct dwc2_hsotg *hsotg)
+static void dwc2_set_stm32f7_hsotg_params(struct dwc2_hsotg *hsotg)
 {
        struct dwc2_core_params *p = &hsotg->params;
 
@@ -164,8 +164,8 @@ const struct of_device_id dwc2_of_match_table[] = {
        { .compatible = "st,stm32f4x9-fsotg",
          .data = dwc2_set_stm32f4x9_fsotg_params },
        { .compatible = "st,stm32f4x9-hsotg" },
-       { .compatible = "st,stm32f7xx-hsotg",
-         .data = dwc2_set_stm32f7xx_hsotg_params },
+       { .compatible = "st,stm32f7-hsotg",
+         .data = dwc2_set_stm32f7_hsotg_params },
        {},
 };
 MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
index ade2ab0..e94bf91 100644 (file)
@@ -100,6 +100,8 @@ static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
        reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
        reg |= DWC3_GCTL_PRTCAPDIR(mode);
        dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+       dwc->current_dr_role = mode;
 }
 
 static void __dwc3_set_mode(struct work_struct *work)
@@ -133,8 +135,6 @@ static void __dwc3_set_mode(struct work_struct *work)
 
        dwc3_set_prtcap(dwc, dwc->desired_dr_role);
 
-       dwc->current_dr_role = dwc->desired_dr_role;
-
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        switch (dwc->desired_dr_role) {
@@ -175,7 +175,7 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
        dwc->desired_dr_role = mode;
        spin_unlock_irqrestore(&dwc->lock, flags);
 
-       queue_work(system_power_efficient_wq, &dwc->drd_work);
+       queue_work(system_freezable_wq, &dwc->drd_work);
 }
 
 u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
@@ -219,7 +219,7 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
         * XHCI driver will reset the host block. If dwc3 was configured for
         * host-only mode, then we can return early.
         */
-       if (dwc->dr_mode == USB_DR_MODE_HOST)
+       if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
                return 0;
 
        reg = dwc3_readl(dwc->regs, DWC3_DCTL);
@@ -234,6 +234,9 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
                udelay(1);
        } while (--retries);
 
+       phy_exit(dwc->usb3_generic_phy);
+       phy_exit(dwc->usb2_generic_phy);
+
        return -ETIMEDOUT;
 }
 
@@ -483,6 +486,22 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
        parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
 }
 
+static int dwc3_core_ulpi_init(struct dwc3 *dwc)
+{
+       int intf;
+       int ret = 0;
+
+       intf = DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3);
+
+       if (intf == DWC3_GHWPARAMS3_HSPHY_IFC_ULPI ||
+           (intf == DWC3_GHWPARAMS3_HSPHY_IFC_UTMI_ULPI &&
+            dwc->hsphy_interface &&
+            !strncmp(dwc->hsphy_interface, "ulpi", 4)))
+               ret = dwc3_ulpi_init(dwc);
+
+       return ret;
+}
+
 /**
  * dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
  * @dwc: Pointer to our controller context structure
@@ -494,7 +513,6 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 static int dwc3_phy_setup(struct dwc3 *dwc)
 {
        u32 reg;
-       int ret;
 
        reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
@@ -565,9 +583,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
                }
                /* FALLTHROUGH */
        case DWC3_GHWPARAMS3_HSPHY_IFC_ULPI:
-               ret = dwc3_ulpi_init(dwc);
-               if (ret)
-                       return ret;
                /* FALLTHROUGH */
        default:
                break;
@@ -724,6 +739,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
 }
 
 static int dwc3_core_get_phy(struct dwc3 *dwc);
+static int dwc3_core_ulpi_init(struct dwc3 *dwc);
 
 /**
  * dwc3_core_init - Low-level initialization of DWC3 Core
@@ -755,17 +771,27 @@ static int dwc3_core_init(struct dwc3 *dwc)
                        dwc->maximum_speed = USB_SPEED_HIGH;
        }
 
-       ret = dwc3_core_get_phy(dwc);
+       ret = dwc3_phy_setup(dwc);
        if (ret)
                goto err0;
 
-       ret = dwc3_core_soft_reset(dwc);
-       if (ret)
-               goto err0;
+       if (!dwc->ulpi_ready) {
+               ret = dwc3_core_ulpi_init(dwc);
+               if (ret)
+                       goto err0;
+               dwc->ulpi_ready = true;
+       }
 
-       ret = dwc3_phy_setup(dwc);
+       if (!dwc->phys_ready) {
+               ret = dwc3_core_get_phy(dwc);
+               if (ret)
+                       goto err0a;
+               dwc->phys_ready = true;
+       }
+
+       ret = dwc3_core_soft_reset(dwc);
        if (ret)
-               goto err0;
+               goto err0a;
 
        dwc3_core_setup_global_control(dwc);
        dwc3_core_num_eps(dwc);
@@ -838,6 +864,9 @@ err1:
        phy_exit(dwc->usb2_generic_phy);
        phy_exit(dwc->usb3_generic_phy);
 
+err0a:
+       dwc3_ulpi_exit(dwc);
+
 err0:
        return ret;
 }
@@ -916,7 +945,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
 
        switch (dwc->dr_mode) {
        case USB_DR_MODE_PERIPHERAL:
-               dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
                dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 
                if (dwc->usb2_phy)
@@ -932,7 +960,6 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
                }
                break;
        case USB_DR_MODE_HOST:
-               dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
                dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
 
                if (dwc->usb2_phy)
@@ -1234,7 +1261,6 @@ err4:
 
 err3:
        dwc3_free_event_buffers(dwc);
-       dwc3_ulpi_exit(dwc);
 
 err2:
        pm_runtime_allow(&pdev->dev);
@@ -1284,7 +1310,7 @@ static int dwc3_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
-static int dwc3_suspend_common(struct dwc3 *dwc)
+static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
 {
        unsigned long   flags;
 
@@ -1296,6 +1322,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
                dwc3_core_exit(dwc);
                break;
        case DWC3_GCTL_PRTCAP_HOST:
+               /* do nothing during host runtime_suspend */
+               if (!PMSG_IS_AUTO(msg))
+                       dwc3_core_exit(dwc);
+               break;
        default:
                /* do nothing */
                break;
@@ -1304,7 +1334,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
        return 0;
 }
 
-static int dwc3_resume_common(struct dwc3 *dwc)
+static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
 {
        unsigned long   flags;
        int             ret;
@@ -1320,6 +1350,13 @@ static int dwc3_resume_common(struct dwc3 *dwc)
                spin_unlock_irqrestore(&dwc->lock, flags);
                break;
        case DWC3_GCTL_PRTCAP_HOST:
+               /* nothing to do on host runtime_resume */
+               if (!PMSG_IS_AUTO(msg)) {
+                       ret = dwc3_core_init(dwc);
+                       if (ret)
+                               return ret;
+               }
+               break;
        default:
                /* do nothing */
                break;
@@ -1331,12 +1368,11 @@ static int dwc3_resume_common(struct dwc3 *dwc)
 static int dwc3_runtime_checks(struct dwc3 *dwc)
 {
        switch (dwc->current_dr_role) {
-       case USB_DR_MODE_PERIPHERAL:
-       case USB_DR_MODE_OTG:
+       case DWC3_GCTL_PRTCAP_DEVICE:
                if (dwc->connected)
                        return -EBUSY;
                break;
-       case USB_DR_MODE_HOST:
+       case DWC3_GCTL_PRTCAP_HOST:
        default:
                /* do nothing */
                break;
@@ -1353,7 +1389,7 @@ static int dwc3_runtime_suspend(struct device *dev)
        if (dwc3_runtime_checks(dwc))
                return -EBUSY;
 
-       ret = dwc3_suspend_common(dwc);
+       ret = dwc3_suspend_common(dwc, PMSG_AUTO_SUSPEND);
        if (ret)
                return ret;
 
@@ -1369,7 +1405,7 @@ static int dwc3_runtime_resume(struct device *dev)
 
        device_init_wakeup(dev, false);
 
-       ret = dwc3_resume_common(dwc);
+       ret = dwc3_resume_common(dwc, PMSG_AUTO_RESUME);
        if (ret)
                return ret;
 
@@ -1416,7 +1452,7 @@ static int dwc3_suspend(struct device *dev)
        struct dwc3     *dwc = dev_get_drvdata(dev);
        int             ret;
 
-       ret = dwc3_suspend_common(dwc);
+       ret = dwc3_suspend_common(dwc, PMSG_SUSPEND);
        if (ret)
                return ret;
 
@@ -1432,7 +1468,7 @@ static int dwc3_resume(struct device *dev)
 
        pinctrl_pm_select_default_state(dev);
 
-       ret = dwc3_resume_common(dwc);
+       ret = dwc3_resume_common(dwc, PMSG_RESUME);
        if (ret)
                return ret;
 
index 03c7aaa..860d2bc 100644 (file)
 #define DWC3_GDBGFIFOSPACE_TYPE(n)     (((n) << 5) & 0x1e0)
 #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff)
 
-#define DWC3_TXFIFOQ           1
-#define DWC3_RXFIFOQ           3
-#define DWC3_TXREQQ            5
-#define DWC3_RXREQQ            7
-#define DWC3_RXINFOQ           9
-#define DWC3_DESCFETCHQ                13
-#define DWC3_EVENTQ            15
+#define DWC3_TXFIFOQ           0
+#define DWC3_RXFIFOQ           1
+#define DWC3_TXREQQ            2
+#define DWC3_RXREQQ            3
+#define DWC3_RXINFOQ           4
+#define DWC3_PSTATQ            5
+#define DWC3_DESCFETCHQ                6
+#define DWC3_EVENTQ            7
+#define DWC3_AUXEVENTQ         8
 
 /* Global RX Threshold Configuration Register */
 #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
@@ -795,7 +797,9 @@ struct dwc3_scratchpad_array {
  * @usb3_phy: pointer to USB3 PHY
  * @usb2_generic_phy: pointer to USB2 PHY
  * @usb3_generic_phy: pointer to USB3 PHY
+ * @phys_ready: flag to indicate that PHYs are ready
  * @ulpi: pointer to ulpi interface
+ * @ulpi_ready: flag to indicate that ULPI is initialized
  * @u2sel: parameter from Set SEL request.
  * @u2pel: parameter from Set SEL request.
  * @u1sel: parameter from Set SEL request.
@@ -893,7 +897,10 @@ struct dwc3 {
        struct phy              *usb2_generic_phy;
        struct phy              *usb3_generic_phy;
 
+       bool                    phys_ready;
+
        struct ulpi             *ulpi;
+       bool                    ulpi_ready;
 
        void __iomem            *regs;
        size_t                  regs_size;
index 7ae0eef..e54c362 100644 (file)
@@ -143,6 +143,7 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
                clk_disable_unprepare(simple->clks[i]);
                clk_put(simple->clks[i]);
        }
+       simple->num_clocks = 0;
 
        reset_control_assert(simple->resets);
        reset_control_put(simple->resets);
index a4719e8..ed8b865 100644 (file)
@@ -582,9 +582,25 @@ static int dwc3_omap_resume(struct device *dev)
        return 0;
 }
 
+static void dwc3_omap_complete(struct device *dev)
+{
+       struct dwc3_omap        *omap = dev_get_drvdata(dev);
+
+       if (extcon_get_state(omap->edev, EXTCON_USB))
+               dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
+       else
+               dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_OFF);
+
+       if (extcon_get_state(omap->edev, EXTCON_USB_HOST))
+               dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
+       else
+               dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_FLOAT);
+}
+
 static const struct dev_pm_ops dwc3_omap_dev_pm_ops = {
 
        SET_SYSTEM_SLEEP_PM_OPS(dwc3_omap_suspend, dwc3_omap_resume)
+       .complete = dwc3_omap_complete,
 };
 
 #define DEV_PM_OPS     (&dwc3_omap_dev_pm_ops)
index 9c2e4a1..18be31d 100644 (file)
@@ -854,7 +854,12 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
                trb++;
                trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
                trace_dwc3_complete_trb(ep0, trb);
-               ep0->trb_enqueue = 0;
+
+               if (r->direction)
+                       dwc->eps[1]->trb_enqueue = 0;
+               else
+                       dwc->eps[0]->trb_enqueue = 0;
+
                dwc->ep0_bounced = false;
        }
 
index 616ef49..2bda4eb 100644 (file)
@@ -2745,6 +2745,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
                break;
        }
 
+       dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket;
+
        /* Enable USB2 LPM Capability */
 
        if ((dwc->revision > DWC3_REVISION_194A) &&
index 8f2cf3b..d2428a9 100644 (file)
@@ -1538,7 +1538,6 @@ ffs_fs_kill_sb(struct super_block *sb)
        if (sb->s_fs_info) {
                ffs_release_dev(sb->s_fs_info);
                ffs_data_closed(sb->s_fs_info);
-               ffs_data_put(sb->s_fs_info);
        }
 }
 
@@ -1855,44 +1854,20 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 
        spin_lock_irqsave(&func->ffs->eps_lock, flags);
        while(count--) {
-               struct usb_endpoint_descriptor *ds;
-               struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
-               int needs_comp_desc = false;
-               int desc_idx;
-
-               if (ffs->gadget->speed == USB_SPEED_SUPER) {
-                       desc_idx = 2;
-                       needs_comp_desc = true;
-               } else if (ffs->gadget->speed == USB_SPEED_HIGH)
-                       desc_idx = 1;
-               else
-                       desc_idx = 0;
-
-               /* fall-back to lower speed if desc missing for current speed */
-               do {
-                       ds = ep->descs[desc_idx];
-               } while (!ds && --desc_idx >= 0);
-
-               if (!ds) {
-                       ret = -EINVAL;
-                       break;
-               }
-
                ep->ep->driver_data = ep;
-               ep->ep->desc = ds;
 
-               if (needs_comp_desc) {
-                       comp_desc = (struct usb_ss_ep_comp_descriptor *)(ds +
-                                       USB_DT_ENDPOINT_SIZE);
-                       ep->ep->maxburst = comp_desc->bMaxBurst + 1;
-                       ep->ep->comp_desc = comp_desc;
+               ret = config_ep_by_speed(func->gadget, &func->function, ep->ep);
+               if (ret) {
+                       pr_err("%s: config_ep_by_speed(%s) returned %d\n",
+                                       __func__, ep->ep->name, ret);
+                       break;
                }
 
                ret = usb_ep_enable(ep->ep);
                if (likely(!ret)) {
                        epfile->ep = ep;
-                       epfile->in = usb_endpoint_dir_in(ds);
-                       epfile->isoc = usb_endpoint_xfer_isoc(ds);
+                       epfile->in = usb_endpoint_dir_in(ep->ep->desc);
+                       epfile->isoc = usb_endpoint_xfer_isoc(ep->ep->desc);
                } else {
                        break;
                }
@@ -2979,10 +2954,8 @@ static int _ffs_func_bind(struct usb_configuration *c,
        struct ffs_data *ffs = func->ffs;
 
        const int full = !!func->ffs->fs_descs_count;
-       const int high = gadget_is_dualspeed(func->gadget) &&
-               func->ffs->hs_descs_count;
-       const int super = gadget_is_superspeed(func->gadget) &&
-               func->ffs->ss_descs_count;
+       const int high = !!func->ffs->hs_descs_count;
+       const int super = !!func->ffs->ss_descs_count;
 
        int fs_len, hs_len, ss_len, ret, i;
        struct ffs_ep *eps_ptr;
index 11fe788..d2dc1f0 100644 (file)
@@ -524,6 +524,8 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
                dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
                return ret;
        }
+       iad_desc.bFirstInterface = ret;
+
        std_ac_if_desc.bInterfaceNumber = ret;
        uac2->ac_intf = ret;
        uac2->ac_alt = 0;
index 1e95670..0875d38 100644 (file)
@@ -274,7 +274,6 @@ config USB_SNP_UDC_PLAT
        tristate "Synopsys USB 2.0 Device controller"
        depends on USB_GADGET && OF && HAS_DMA
        depends on EXTCON || EXTCON=n
-       select USB_GADGET_DUALSPEED
        select USB_SNP_CORE
        default ARCH_BCM_IPROC
        help
index 1e940f0..6dbc489 100644 (file)
@@ -77,6 +77,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
        if (ret) {
                dev_err(&pci->dev,
                        "couldn't add resources to bdc device\n");
+               platform_device_put(bdc);
                return ret;
        }
 
index 859d5b1..1f8b19d 100644 (file)
@@ -180,8 +180,8 @@ EXPORT_SYMBOL_GPL(usb_ep_alloc_request);
 void usb_ep_free_request(struct usb_ep *ep,
                                       struct usb_request *req)
 {
-       ep->ops->free_request(ep, req);
        trace_usb_ep_free_request(ep, req, 0);
+       ep->ops->free_request(ep, req);
 }
 EXPORT_SYMBOL_GPL(usb_ep_free_request);
 
index e5b4ee9..56b517a 100644 (file)
@@ -1305,7 +1305,7 @@ static void udc_reset_ep_queue(struct fsl_udc *udc, u8 pipe)
 {
        struct fsl_ep *ep = get_ep_by_pipe(udc, pipe);
 
-       if (ep->name)
+       if (ep->ep.name)
                nuke(ep, -ESHUTDOWN);
 }
 
@@ -1693,7 +1693,7 @@ static void dtd_complete_irq(struct fsl_udc *udc)
                curr_ep = get_ep_by_pipe(udc, i);
 
                /* If the ep is configured */
-               if (curr_ep->name == NULL) {
+               if (!curr_ep->ep.name) {
                        WARNING("Invalid EP?");
                        continue;
                }
index 6e87af2..409cde4 100644 (file)
@@ -2410,7 +2410,7 @@ static int renesas_usb3_remove(struct platform_device *pdev)
        __renesas_usb3_ep_free_request(usb3->ep0_req);
        if (usb3->phy)
                phy_put(usb3->phy);
-       pm_runtime_disable(usb3_to_dev(usb3));
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index 6150bed..4fcfb30 100644 (file)
@@ -633,14 +633,6 @@ config USB_UHCI_ASPEED
        bool
        default y if ARCH_ASPEED
 
-config USB_UHCI_BIG_ENDIAN_MMIO
-       bool
-       default y if SPARC_LEON
-
-config USB_UHCI_BIG_ENDIAN_DESC
-       bool
-       default y if SPARC_LEON
-
 config USB_FHCI_HCD
        tristate "Freescale QE USB Host Controller support"
        depends on OF_GPIO && QE_GPIO && QUICC_ENGINE
index facafdf..d7641cb 100644 (file)
@@ -774,12 +774,12 @@ static struct urb *request_single_step_set_feature_urb(
        atomic_inc(&urb->use_count);
        atomic_inc(&urb->dev->urbnum);
        urb->setup_dma = dma_map_single(
-                       hcd->self.controller,
+                       hcd->self.sysdev,
                        urb->setup_packet,
                        sizeof(struct usb_ctrlrequest),
                        DMA_TO_DEVICE);
        urb->transfer_dma = dma_map_single(
-                       hcd->self.controller,
+                       hcd->self.sysdev,
                        urb->transfer_buffer,
                        urb->transfer_buffer_length,
                        DMA_FROM_DEVICE);
index 8815832..3276304 100644 (file)
@@ -1188,10 +1188,10 @@ static int submit_single_step_set_feature(
         * 15 secs after the setup
         */
        if (is_setup) {
-               /* SETUP pid */
+               /* SETUP pid, and interrupt after SETUP completion */
                qtd_fill(ehci, qtd, urb->setup_dma,
                                sizeof(struct usb_ctrlrequest),
-                               token | (2 /* "setup" */ << 8), 8);
+                               QTD_IOC | token | (2 /* "setup" */ << 8), 8);
 
                submit_async(ehci, urb, &qtd_list, GFP_ATOMIC);
                return 0; /*Return now; we shall come back after 15 seconds*/
@@ -1228,12 +1228,8 @@ static int submit_single_step_set_feature(
        qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
        list_add_tail(&qtd->qtd_list, head);
 
-       /* dont fill any data in such packets */
-       qtd_fill(ehci, qtd, 0, 0, token, 0);
-
-       /* by default, enable interrupt on urb completion */
-       if (likely(!(urb->transfer_flags & URB_NO_INTERRUPT)))
-               qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
+       /* Interrupt after STATUS completion */
+       qtd_fill(ehci, qtd, 0, 0, token | QTD_IOC, 0);
 
        submit_async(ehci, urb, &qtd_list, GFP_KERNEL);
 
index ee96763..d088c34 100644 (file)
@@ -74,6 +74,7 @@ static const char     hcd_name [] = "ohci_hcd";
 
 #define        STATECHANGE_DELAY       msecs_to_jiffies(300)
 #define        IO_WATCHDOG_DELAY       msecs_to_jiffies(275)
+#define        IO_WATCHDOG_OFF         0xffffff00
 
 #include "ohci.h"
 #include "pci-quirks.h"
@@ -231,7 +232,7 @@ static int ohci_urb_enqueue (
                }
 
                /* Start up the I/O watchdog timer, if it's not running */
-               if (!timer_pending(&ohci->io_watchdog) &&
+               if (ohci->prev_frame_no == IO_WATCHDOG_OFF &&
                                list_empty(&ohci->eds_in_use) &&
                                !(ohci->flags & OHCI_QUIRK_QEMU)) {
                        ohci->prev_frame_no = ohci_frame_no(ohci);
@@ -446,7 +447,8 @@ static int ohci_init (struct ohci_hcd *ohci)
        struct usb_hcd *hcd = ohci_to_hcd(ohci);
 
        /* Accept arbitrarily long scatter-gather lists */
-       hcd->self.sg_tablesize = ~0;
+       if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+               hcd->self.sg_tablesize = ~0;
 
        if (distrust_firmware)
                ohci->flags |= OHCI_QUIRK_HUB_POWER;
@@ -501,6 +503,7 @@ static int ohci_init (struct ohci_hcd *ohci)
                return 0;
 
        timer_setup(&ohci->io_watchdog, io_watchdog_func, 0);
+       ohci->prev_frame_no = IO_WATCHDOG_OFF;
 
        ohci->hcca = dma_alloc_coherent (hcd->self.controller,
                        sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL);
@@ -730,7 +733,7 @@ static void io_watchdog_func(struct timer_list *t)
        u32             head;
        struct ed       *ed;
        struct td       *td, *td_start, *td_next;
-       unsigned        frame_no;
+       unsigned        frame_no, prev_frame_no = IO_WATCHDOG_OFF;
        unsigned long   flags;
 
        spin_lock_irqsave(&ohci->lock, flags);
@@ -835,7 +838,7 @@ static void io_watchdog_func(struct timer_list *t)
                        }
                }
                if (!list_empty(&ohci->eds_in_use)) {
-                       ohci->prev_frame_no = frame_no;
+                       prev_frame_no = frame_no;
                        ohci->prev_wdh_cnt = ohci->wdh_cnt;
                        ohci->prev_donehead = ohci_readl(ohci,
                                        &ohci->regs->donehead);
@@ -845,6 +848,7 @@ static void io_watchdog_func(struct timer_list *t)
        }
 
  done:
+       ohci->prev_frame_no = prev_frame_no;
        spin_unlock_irqrestore(&ohci->lock, flags);
 }
 
@@ -973,6 +977,7 @@ static void ohci_stop (struct usb_hcd *hcd)
        if (quirk_nec(ohci))
                flush_work(&ohci->nec_work);
        del_timer_sync(&ohci->io_watchdog);
+       ohci->prev_frame_no = IO_WATCHDOG_OFF;
 
        ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
        ohci_usb_reset(ohci);
index fb7aaa3..634f3c7 100644 (file)
@@ -311,8 +311,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
                rc = ohci_rh_suspend (ohci, 0);
        spin_unlock_irq (&ohci->lock);
 
-       if (rc == 0)
+       if (rc == 0) {
                del_timer_sync(&ohci->io_watchdog);
+               ohci->prev_frame_no = IO_WATCHDOG_OFF;
+       }
        return rc;
 }
 
index b2ec8c3..4ccb85a 100644 (file)
@@ -1019,6 +1019,8 @@ skip_ed:
                 * have modified this list.  normally it's just prepending
                 * entries (which we'd ignore), but paranoia won't hurt.
                 */
+               *last = ed->ed_next;
+               ed->ed_next = NULL;
                modified = 0;
 
                /* unlink urbs as requested, but rescan the list after
@@ -1077,21 +1079,22 @@ rescan_this:
                        goto rescan_this;
 
                /*
-                * If no TDs are queued, take ED off the ed_rm_list.
+                * If no TDs are queued, ED is now idle.
                 * Otherwise, if the HC is running, reschedule.
-                * If not, leave it on the list for further dequeues.
+                * If the HC isn't running, add ED back to the
+                * start of the list for later processing.
                 */
                if (list_empty(&ed->td_list)) {
-                       *last = ed->ed_next;
-                       ed->ed_next = NULL;
                        ed->state = ED_IDLE;
                        list_del(&ed->in_use_list);
                } else if (ohci->rh_state == OHCI_RH_RUNNING) {
-                       *last = ed->ed_next;
-                       ed->ed_next = NULL;
                        ed_schedule(ohci, ed);
                } else {
-                       last = &ed->ed_next;
+                       ed->ed_next = ohci->ed_rm_list;
+                       ohci->ed_rm_list = ed;
+                       /* Don't loop on the same ED */
+                       if (last == &ohci->ed_rm_list)
+                               last = &ed->ed_next;
                }
 
                if (modified)
index 1615367..67ad4bb 100644 (file)
 #define        AX_INDXC                0x30
 #define        AX_DATAC                0x34
 
+#define PT_ADDR_INDX           0xE8
+#define PT_READ_INDX           0xE4
+#define PT_SIG_1_ADDR          0xA520
+#define PT_SIG_2_ADDR          0xA521
+#define PT_SIG_3_ADDR          0xA522
+#define PT_SIG_4_ADDR          0xA523
+#define PT_SIG_1_DATA          0x78
+#define PT_SIG_2_DATA          0x56
+#define PT_SIG_3_DATA          0x34
+#define PT_SIG_4_DATA          0x12
+#define PT4_P1_REG             0xB521
+#define PT4_P2_REG             0xB522
+#define PT2_P1_REG             0xD520
+#define PT2_P2_REG             0xD521
+#define PT1_P1_REG             0xD522
+#define PT1_P2_REG             0xD523
+
 #define        NB_PCIE_INDX_ADDR       0xe0
 #define        NB_PCIE_INDX_DATA       0xe4
 #define        PCIE_P_CNTL             0x10040
@@ -513,6 +530,98 @@ void usb_amd_dev_put(void)
 EXPORT_SYMBOL_GPL(usb_amd_dev_put);
 
 /*
+ * Check if port is disabled in BIOS on AMD Promontory host.
+ * BIOS Disabled ports may wake on connect/disconnect and need
+ * driver workaround to keep them disabled.
+ * Returns true if port is marked disabled.
+ */
+bool usb_amd_pt_check_port(struct device *device, int port)
+{
+       unsigned char value, port_shift;
+       struct pci_dev *pdev;
+       u16 reg;
+
+       pdev = to_pci_dev(device);
+       pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_1_ADDR);
+
+       pci_read_config_byte(pdev, PT_READ_INDX, &value);
+       if (value != PT_SIG_1_DATA)
+               return false;
+
+       pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_2_ADDR);
+
+       pci_read_config_byte(pdev, PT_READ_INDX, &value);
+       if (value != PT_SIG_2_DATA)
+               return false;
+
+       pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_3_ADDR);
+
+       pci_read_config_byte(pdev, PT_READ_INDX, &value);
+       if (value != PT_SIG_3_DATA)
+               return false;
+
+       pci_write_config_word(pdev, PT_ADDR_INDX, PT_SIG_4_ADDR);
+
+       pci_read_config_byte(pdev, PT_READ_INDX, &value);
+       if (value != PT_SIG_4_DATA)
+               return false;
+
+       /* Check disabled port setting, if bit is set port is enabled */
+       switch (pdev->device) {
+       case 0x43b9:
+       case 0x43ba:
+       /*
+        * device is AMD_PROMONTORYA_4(0x43b9) or PROMONTORYA_3(0x43ba)
+        * PT4_P1_REG bits[7..1] represents USB2.0 ports 6 to 0
+        * PT4_P2_REG bits[6..0] represents ports 13 to 7
+        */
+               if (port > 6) {
+                       reg = PT4_P2_REG;
+                       port_shift = port - 7;
+               } else {
+                       reg = PT4_P1_REG;
+                       port_shift = port + 1;
+               }
+               break;
+       case 0x43bb:
+       /*
+        * device is AMD_PROMONTORYA_2(0x43bb)
+        * PT2_P1_REG bits[7..5] represents USB2.0 ports 2 to 0
+        * PT2_P2_REG bits[5..0] represents ports 9 to 3
+        */
+               if (port > 2) {
+                       reg = PT2_P2_REG;
+                       port_shift = port - 3;
+               } else {
+                       reg = PT2_P1_REG;
+                       port_shift = port + 5;
+               }
+               break;
+       case 0x43bc:
+       /*
+        * device is AMD_PROMONTORYA_1(0x43bc)
+        * PT1_P1_REG[7..4] represents USB2.0 ports 3 to 0
+        * PT1_P2_REG[5..0] represents ports 9 to 4
+        */
+               if (port > 3) {
+                       reg = PT1_P2_REG;
+                       port_shift = port - 4;
+               } else {
+                       reg = PT1_P1_REG;
+                       port_shift = port + 4;
+               }
+               break;
+       default:
+               return false;
+       }
+       pci_write_config_word(pdev, PT_ADDR_INDX, reg);
+       pci_read_config_byte(pdev, PT_READ_INDX, &value);
+
+       return !(value & BIT(port_shift));
+}
+EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
+
+/*
  * Make sure the controller is completely inactive, unable to
  * generate interrupts or do DMA.
  */
index b68dcb5..4ca0d9b 100644 (file)
@@ -17,6 +17,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev);
 void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 void sb800_prefetch(struct device *dev, int on);
 bool usb_xhci_needs_pci_reset(struct pci_dev *pdev);
+bool usb_amd_pt_check_port(struct device *device, int port);
 #else
 struct pci_dev;
 static inline void usb_amd_quirk_pll_disable(void) {}
@@ -25,6 +26,10 @@ static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
 static inline void usb_amd_dev_put(void) {}
 static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
 static inline void sb800_prefetch(struct device *dev, int on) {}
+static inline bool usb_amd_pt_check_port(struct device *device, int port)
+{
+       return false;
+}
 #endif  /* CONFIG_USB_PCI */
 
 #endif  /*  __LINUX_USB_PCI_QUIRKS_H  */
index a1ab8ac..c359bae 100644 (file)
@@ -328,13 +328,14 @@ dbc_ep_do_queue(struct dbc_ep *dep, struct dbc_request *req)
 int dbc_ep_queue(struct dbc_ep *dep, struct dbc_request *req,
                 gfp_t gfp_flags)
 {
+       unsigned long           flags;
        struct xhci_dbc         *dbc = dep->dbc;
        int                     ret = -ESHUTDOWN;
 
-       spin_lock(&dbc->lock);
+       spin_lock_irqsave(&dbc->lock, flags);
        if (dbc->state == DS_CONFIGURED)
                ret = dbc_ep_do_queue(dep, req);
-       spin_unlock(&dbc->lock);
+       spin_unlock_irqrestore(&dbc->lock, flags);
 
        mod_delayed_work(system_wq, &dbc->event_work, 0);
 
@@ -521,15 +522,16 @@ static void xhci_do_dbc_stop(struct xhci_hcd *xhci)
 static int xhci_dbc_start(struct xhci_hcd *xhci)
 {
        int                     ret;
+       unsigned long           flags;
        struct xhci_dbc         *dbc = xhci->dbc;
 
        WARN_ON(!dbc);
 
        pm_runtime_get_sync(xhci_to_hcd(xhci)->self.controller);
 
-       spin_lock(&dbc->lock);
+       spin_lock_irqsave(&dbc->lock, flags);
        ret = xhci_do_dbc_start(xhci);
-       spin_unlock(&dbc->lock);
+       spin_unlock_irqrestore(&dbc->lock, flags);
 
        if (ret) {
                pm_runtime_put(xhci_to_hcd(xhci)->self.controller);
@@ -541,6 +543,7 @@ static int xhci_dbc_start(struct xhci_hcd *xhci)
 
 static void xhci_dbc_stop(struct xhci_hcd *xhci)
 {
+       unsigned long           flags;
        struct xhci_dbc         *dbc = xhci->dbc;
        struct dbc_port         *port = &dbc->port;
 
@@ -551,9 +554,9 @@ static void xhci_dbc_stop(struct xhci_hcd *xhci)
        if (port->registered)
                xhci_dbc_tty_unregister_device(xhci);
 
-       spin_lock(&dbc->lock);
+       spin_lock_irqsave(&dbc->lock, flags);
        xhci_do_dbc_stop(xhci);
-       spin_unlock(&dbc->lock);
+       spin_unlock_irqrestore(&dbc->lock, flags);
 
        pm_runtime_put_sync(xhci_to_hcd(xhci)->self.controller);
 }
@@ -779,14 +782,15 @@ static void xhci_dbc_handle_events(struct work_struct *work)
        int                     ret;
        enum evtreturn          evtr;
        struct xhci_dbc         *dbc;
+       unsigned long           flags;
        struct xhci_hcd         *xhci;
 
        dbc = container_of(to_delayed_work(work), struct xhci_dbc, event_work);
        xhci = dbc->xhci;
 
-       spin_lock(&dbc->lock);
+       spin_lock_irqsave(&dbc->lock, flags);
        evtr = xhci_dbc_do_handle_events(dbc);
-       spin_unlock(&dbc->lock);
+       spin_unlock_irqrestore(&dbc->lock, flags);
 
        switch (evtr) {
        case EVT_GSER:
index 8d47b6f..75f0b92 100644 (file)
@@ -92,21 +92,23 @@ static void dbc_start_rx(struct dbc_port *port)
 static void
 dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
 {
+       unsigned long           flags;
        struct xhci_dbc         *dbc = xhci->dbc;
        struct dbc_port         *port = &dbc->port;
 
-       spin_lock(&port->port_lock);
+       spin_lock_irqsave(&port->port_lock, flags);
        list_add_tail(&req->list_pool, &port->read_queue);
        tasklet_schedule(&port->push);
-       spin_unlock(&port->port_lock);
+       spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
 static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
 {
+       unsigned long           flags;
        struct xhci_dbc         *dbc = xhci->dbc;
        struct dbc_port         *port = &dbc->port;
 
-       spin_lock(&port->port_lock);
+       spin_lock_irqsave(&port->port_lock, flags);
        list_add(&req->list_pool, &port->write_pool);
        switch (req->status) {
        case 0:
@@ -119,7 +121,7 @@ static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
                          req->status);
                break;
        }
-       spin_unlock(&port->port_lock);
+       spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
 static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
@@ -327,12 +329,13 @@ static void dbc_rx_push(unsigned long _port)
 {
        struct dbc_request      *req;
        struct tty_struct       *tty;
+       unsigned long           flags;
        bool                    do_push = false;
        bool                    disconnect = false;
        struct dbc_port         *port = (void *)_port;
        struct list_head        *queue = &port->read_queue;
 
-       spin_lock_irq(&port->port_lock);
+       spin_lock_irqsave(&port->port_lock, flags);
        tty = port->port.tty;
        while (!list_empty(queue)) {
                req = list_first_entry(queue, struct dbc_request, list_pool);
@@ -392,16 +395,17 @@ static void dbc_rx_push(unsigned long _port)
        if (!disconnect)
                dbc_start_rx(port);
 
-       spin_unlock_irq(&port->port_lock);
+       spin_unlock_irqrestore(&port->port_lock, flags);
 }
 
 static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
 {
+       unsigned long   flags;
        struct dbc_port *port = container_of(_port, struct dbc_port, port);
 
-       spin_lock_irq(&port->port_lock);
+       spin_lock_irqsave(&port->port_lock, flags);
        dbc_start_rx(port);
-       spin_unlock_irq(&port->port_lock);
+       spin_unlock_irqrestore(&port->port_lock, flags);
 
        return 0;
 }
index e26e685..5851052 100644 (file)
@@ -211,7 +211,7 @@ static void xhci_ring_dump_segment(struct seq_file *s,
 static int xhci_ring_trb_show(struct seq_file *s, void *unused)
 {
        int                     i;
-       struct xhci_ring        *ring = s->private;
+       struct xhci_ring        *ring = *(struct xhci_ring **)s->private;
        struct xhci_segment     *seg = ring->first_seg;
 
        for (i = 0; i < ring->num_segs; i++) {
@@ -387,7 +387,7 @@ void xhci_debugfs_create_endpoint(struct xhci_hcd *xhci,
 
        snprintf(epriv->name, sizeof(epriv->name), "ep%02d", ep_index);
        epriv->root = xhci_debugfs_create_ring_dir(xhci,
-                                                  &dev->eps[ep_index].new_ring,
+                                                  &dev->eps[ep_index].ring,
                                                   epriv->name,
                                                   spriv->root);
        spriv->eps[ep_index] = epriv;
index 46d5e08..72ebbc9 100644 (file)
@@ -1224,17 +1224,17 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                                temp = readl(port_array[wIndex]);
                                break;
                        }
-
-                       /* Software should not attempt to set
-                        * port link state above '3' (U3) and the port
-                        * must be enabled.
-                        */
-                       if ((temp & PORT_PE) == 0 ||
-                               (link_state > USB_SS_PORT_LS_U3)) {
-                               xhci_warn(xhci, "Cannot set link state.\n");
+                       /* Port must be enabled */
+                       if (!(temp & PORT_PE)) {
+                               retval = -ENODEV;
+                               break;
+                       }
+                       /* Can't set port link state above '3' (U3) */
+                       if (link_state > USB_SS_PORT_LS_U3) {
+                               xhci_warn(xhci, "Cannot set port %d link state %d\n",
+                                        wIndex, link_state);
                                goto error;
                        }
-
                        if (link_state == USB_SS_PORT_LS_U3) {
                                slot_id = xhci_find_slot_id_by_port(hcd, xhci,
                                                wIndex + 1);
@@ -1522,6 +1522,13 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
                                t2 |= PORT_WKOC_E | PORT_WKCONN_E;
                                t2 &= ~PORT_WKDISC_E;
                        }
+
+                       if ((xhci->quirks & XHCI_U2_DISABLE_WAKE) &&
+                           (hcd->speed < HCD_USB3)) {
+                               if (usb_amd_pt_check_port(hcd->self.controller,
+                                                         port_index))
+                                       t2 &= ~PORT_WAKE_BITS;
+                       }
                } else
                        t2 &= ~PORT_WAKE_BITS;
 
index 6c79037..d9f831b 100644 (file)
 #define PCI_DEVICE_ID_INTEL_APL_XHCI                   0x5aa8
 #define PCI_DEVICE_ID_INTEL_DNV_XHCI                   0x19d0
 
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_4                        0x43b9
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_3                        0x43ba
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_2                        0x43bb
+#define PCI_DEVICE_ID_AMD_PROMONTORYA_1                        0x43bc
 #define PCI_DEVICE_ID_ASMEDIA_1042A_XHCI               0x1142
 
 static const char hcd_name[] = "xhci_hcd";
@@ -122,9 +126,19 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
        if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info())
                xhci->quirks |= XHCI_AMD_PLL_FIX;
 
+       if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == 0x43bb)
+               xhci->quirks |= XHCI_SUSPEND_DELAY;
+
        if (pdev->vendor == PCI_VENDOR_ID_AMD)
                xhci->quirks |= XHCI_TRUST_TX_LENGTH;
 
+       if ((pdev->vendor == PCI_VENDOR_ID_AMD) &&
+               ((pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_4) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_3) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_2) ||
+               (pdev->device == PCI_DEVICE_ID_AMD_PROMONTORYA_1)))
+               xhci->quirks |= XHCI_U2_DISABLE_WAKE;
+
        if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                xhci->quirks |= XHCI_LPM_SUPPORT;
                xhci->quirks |= XHCI_INTEL_HOST;
index 6f03830..6652e2d 100644 (file)
@@ -360,7 +360,6 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
 {
        struct usb_hcd  *hcd = dev_get_drvdata(dev);
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-       int ret;
 
        /*
         * xhci_suspend() needs `do_wakeup` to know whether host is allowed
@@ -370,12 +369,7 @@ static int __maybe_unused xhci_plat_suspend(struct device *dev)
         * reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
         * also applies to runtime suspend.
         */
-       ret = xhci_suspend(xhci, device_may_wakeup(dev));
-
-       if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
-               clk_disable_unprepare(xhci->clk);
-
-       return ret;
+       return xhci_suspend(xhci, device_may_wakeup(dev));
 }
 
 static int __maybe_unused xhci_plat_resume(struct device *dev)
@@ -384,9 +378,6 @@ static int __maybe_unused xhci_plat_resume(struct device *dev)
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
        int ret;
 
-       if (!device_may_wakeup(dev) && !IS_ERR(xhci->clk))
-               clk_prepare_enable(xhci->clk);
-
        ret = xhci_priv_resume_quirk(hcd);
        if (ret)
                return ret;
index f0b5596..f33ffc2 100644 (file)
@@ -83,6 +83,10 @@ static const struct soc_device_attribute rcar_quirks_match[]  = {
                .soc_id = "r8a7796",
                .data = (void *)RCAR_XHCI_FIRMWARE_V3,
        },
+       {
+               .soc_id = "r8a77965",
+               .data = (void *)RCAR_XHCI_FIRMWARE_V3,
+       },
        { /* sentinel */ },
 };
 
index 1eeb339..5d37700 100644 (file)
@@ -646,8 +646,6 @@ static void xhci_stop(struct usb_hcd *hcd)
                return;
        }
 
-       xhci_debugfs_exit(xhci);
-
        xhci_dbc_exit(xhci);
 
        spin_lock_irq(&xhci->lock);
@@ -680,6 +678,7 @@ static void xhci_stop(struct usb_hcd *hcd)
 
        xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
        xhci_mem_cleanup(xhci);
+       xhci_debugfs_exit(xhci);
        xhci_dbg_trace(xhci, trace_xhci_dbg_init,
                        "xhci_stop completed - status = %x",
                        readl(&xhci->op_regs->status));
@@ -878,6 +877,9 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
        clear_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
        del_timer_sync(&xhci->shared_hcd->rh_timer);
 
+       if (xhci->quirks & XHCI_SUSPEND_DELAY)
+               usleep_range(1000, 1500);
+
        spin_lock_irq(&xhci->lock);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        clear_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags);
@@ -1014,6 +1016,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
 
                xhci_dbg(xhci, "cleaning up memory\n");
                xhci_mem_cleanup(xhci);
+               xhci_debugfs_exit(xhci);
                xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
                            readl(&xhci->op_regs->status));
 
@@ -3544,12 +3547,10 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
                virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING;
                del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);
        }
-
+       xhci_debugfs_remove_slot(xhci, udev->slot_id);
        ret = xhci_disable_slot(xhci, udev->slot_id);
-       if (ret) {
-               xhci_debugfs_remove_slot(xhci, udev->slot_id);
+       if (ret)
                xhci_free_virt_device(xhci, udev->slot_id);
-       }
 }
 
 int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
index 96099a2..866e141 100644 (file)
@@ -718,11 +718,12 @@ struct xhci_ep_ctx {
 /* bits 10:14 are Max Primary Streams */
 /* bit 15 is Linear Stream Array */
 /* Interval - period between requests to an endpoint - 125u increments. */
-#define EP_INTERVAL(p)         (((p) & 0xff) << 16)
-#define EP_INTERVAL_TO_UFRAMES(p)              (1 << (((p) >> 16) & 0xff))
-#define CTX_TO_EP_INTERVAL(p)  (((p) >> 16) & 0xff)
-#define EP_MAXPSTREAMS_MASK    (0x1f << 10)
-#define EP_MAXPSTREAMS(p)      (((p) << 10) & EP_MAXPSTREAMS_MASK)
+#define EP_INTERVAL(p)                 (((p) & 0xff) << 16)
+#define EP_INTERVAL_TO_UFRAMES(p)      (1 << (((p) >> 16) & 0xff))
+#define CTX_TO_EP_INTERVAL(p)          (((p) >> 16) & 0xff)
+#define EP_MAXPSTREAMS_MASK            (0x1f << 10)
+#define EP_MAXPSTREAMS(p)              (((p) << 10) & EP_MAXPSTREAMS_MASK)
+#define CTX_TO_EP_MAXPSTREAMS(p)       (((p) & EP_MAXPSTREAMS_MASK) >> 10)
 /* Endpoint is set up with a Linear Stream Array (vs. Secondary Stream Array) */
 #define        EP_HAS_LSA              (1 << 15)
 /* hosts with LEC=1 use bits 31:24 as ESIT high bits. */
@@ -1822,9 +1823,10 @@ struct xhci_hcd {
 /* For controller with a broken Port Disable implementation */
 #define XHCI_BROKEN_PORT_PED   (1 << 25)
 #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26)
-/* Reserved. It was XHCI_U2_DISABLE_WAKE */
+#define XHCI_U2_DISABLE_WAKE   (1 << 27)
 #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL        (1 << 28)
 #define XHCI_HW_LPM_DISABLE    (1 << 29)
+#define XHCI_SUSPEND_DELAY     (1 << 30)
 
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
@@ -2549,21 +2551,22 @@ static inline const char *xhci_decode_ep_context(u32 info, u32 info2, u64 deq,
        u8 burst;
        u8 cerr;
        u8 mult;
-       u8 lsa;
-       u8 hid;
+
+       bool lsa;
+       bool hid;
 
        esit = CTX_TO_MAX_ESIT_PAYLOAD_HI(info) << 16 |
                CTX_TO_MAX_ESIT_PAYLOAD(tx_info);
 
        ep_state = info & EP_STATE_MASK;
-       max_pstr = info & EP_MAXPSTREAMS_MASK;
+       max_pstr = CTX_TO_EP_MAXPSTREAMS(info);
        interval = CTX_TO_EP_INTERVAL(info);
        mult = CTX_TO_EP_MULT(info) + 1;
-       lsa = info & EP_HAS_LSA;
+       lsa = !!(info & EP_HAS_LSA);
 
        cerr = (info2 & (3 << 1)) >> 1;
        ep_type = CTX_TO_EP_TYPE(info2);
-       hid = info2 & (1 << 7);
+       hid = !!(info2 & (1 << 7));
        burst = CTX_TO_MAX_BURST(info2);
        maxp = MAX_PACKET_DECODED(info2);
 
index 63b9e85..236a60f 100644 (file)
@@ -42,6 +42,9 @@
 #define USB_DEVICE_ID_LD_MICROCASSYTIME                0x1033  /* USB Product ID of Micro-CASSY Time (reserved) */
 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035  /* USB Product ID of Micro-CASSY Temperature */
 #define USB_DEVICE_ID_LD_MICROCASSYPH          0x1038  /* USB Product ID of Micro-CASSY pH */
+#define USB_DEVICE_ID_LD_POWERANALYSERCASSY    0x1040  /* USB Product ID of Power Analyser CASSY */
+#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY      0x1042  /* USB Product ID of Converter Controller CASSY */
+#define USB_DEVICE_ID_LD_MACHINETESTCASSY      0x1043  /* USB Product ID of Machine Test CASSY */
 #define USB_DEVICE_ID_LD_JWM           0x1080  /* USB Product ID of Joule and Wattmeter */
 #define USB_DEVICE_ID_LD_DMMP          0x1081  /* USB Product ID of Digital Multimeter P (reserved) */
 #define USB_DEVICE_ID_LD_UMIP          0x1090  /* USB Product ID of UMI P */
@@ -84,6 +87,9 @@ static const struct usb_device_id ld_usb_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) },
+       { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
index f5e1bb5..984f7e1 100644 (file)
@@ -85,6 +85,8 @@ struct mon_reader_text {
 
        wait_queue_head_t wait;
        int printf_size;
+       size_t printf_offset;
+       size_t printf_togo;
        char *printf_buf;
        struct mutex printf_lock;
 
@@ -376,75 +378,103 @@ err_alloc:
        return rc;
 }
 
-/*
- * For simplicity, we read one record in one system call and throw out
- * what does not fit. This means that the following does not work:
- *   dd if=/dbg/usbmon/0t bs=10
- * Also, we do not allow seeks and do not bother advancing the offset.
- */
+static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp,
+    char __user * const buf, const size_t nbytes)
+{
+       const size_t togo = min(nbytes, rp->printf_togo);
+
+       if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo))
+               return -EFAULT;
+       rp->printf_togo -= togo;
+       rp->printf_offset += togo;
+       return togo;
+}
+
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_t(struct file *file, char __user *buf,
-                               size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
        struct mon_reader_text *rp = file->private_data;
        struct mon_event_text *ep;
        struct mon_text_ptr ptr;
+       ssize_t ret;
 
-       ep = mon_text_read_wait(rp, file);
-       if (IS_ERR(ep))
-               return PTR_ERR(ep);
        mutex_lock(&rp->printf_lock);
-       ptr.cnt = 0;
-       ptr.pbuf = rp->printf_buf;
-       ptr.limit = rp->printf_size;
-
-       mon_text_read_head_t(rp, &ptr, ep);
-       mon_text_read_statset(rp, &ptr, ep);
-       ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-           " %d", ep->length);
-       mon_text_read_data(rp, &ptr, ep);
-
-       if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-               ptr.cnt = -EFAULT;
+
+       if (rp->printf_togo == 0) {
+
+               ep = mon_text_read_wait(rp, file);
+               if (IS_ERR(ep)) {
+                       mutex_unlock(&rp->printf_lock);
+                       return PTR_ERR(ep);
+               }
+               ptr.cnt = 0;
+               ptr.pbuf = rp->printf_buf;
+               ptr.limit = rp->printf_size;
+
+               mon_text_read_head_t(rp, &ptr, ep);
+               mon_text_read_statset(rp, &ptr, ep);
+               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+                   " %d", ep->length);
+               mon_text_read_data(rp, &ptr, ep);
+
+               rp->printf_togo = ptr.cnt;
+               rp->printf_offset = 0;
+
+               kmem_cache_free(rp->e_slab, ep);
+       }
+
+       ret = mon_text_copy_to_user(rp, buf, nbytes);
        mutex_unlock(&rp->printf_lock);
-       kmem_cache_free(rp->e_slab, ep);
-       return ptr.cnt;
+       return ret;
 }
 
+/* ppos is not advanced since the llseek operation is not permitted. */
 static ssize_t mon_text_read_u(struct file *file, char __user *buf,
-                               size_t nbytes, loff_t *ppos)
+    size_t nbytes, loff_t *ppos)
 {
        struct mon_reader_text *rp = file->private_data;
        struct mon_event_text *ep;
        struct mon_text_ptr ptr;
+       ssize_t ret;
 
-       ep = mon_text_read_wait(rp, file);
-       if (IS_ERR(ep))
-               return PTR_ERR(ep);
        mutex_lock(&rp->printf_lock);
-       ptr.cnt = 0;
-       ptr.pbuf = rp->printf_buf;
-       ptr.limit = rp->printf_size;
 
-       mon_text_read_head_u(rp, &ptr, ep);
-       if (ep->type == 'E') {
-               mon_text_read_statset(rp, &ptr, ep);
-       } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
-               mon_text_read_isostat(rp, &ptr, ep);
-               mon_text_read_isodesc(rp, &ptr, ep);
-       } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
-               mon_text_read_intstat(rp, &ptr, ep);
-       } else {
-               mon_text_read_statset(rp, &ptr, ep);
+       if (rp->printf_togo == 0) {
+
+               ep = mon_text_read_wait(rp, file);
+               if (IS_ERR(ep)) {
+                       mutex_unlock(&rp->printf_lock);
+                       return PTR_ERR(ep);
+               }
+               ptr.cnt = 0;
+               ptr.pbuf = rp->printf_buf;
+               ptr.limit = rp->printf_size;
+
+               mon_text_read_head_u(rp, &ptr, ep);
+               if (ep->type == 'E') {
+                       mon_text_read_statset(rp, &ptr, ep);
+               } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
+                       mon_text_read_isostat(rp, &ptr, ep);
+                       mon_text_read_isodesc(rp, &ptr, ep);
+               } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
+                       mon_text_read_intstat(rp, &ptr, ep);
+               } else {
+                       mon_text_read_statset(rp, &ptr, ep);
+               }
+               ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
+                   " %d", ep->length);
+               mon_text_read_data(rp, &ptr, ep);
+
+               rp->printf_togo = ptr.cnt;
+               rp->printf_offset = 0;
+
+               kmem_cache_free(rp->e_slab, ep);
        }
-       ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt,
-           " %d", ep->length);
-       mon_text_read_data(rp, &ptr, ep);
 
-       if (copy_to_user(buf, rp->printf_buf, ptr.cnt))
-               ptr.cnt = -EFAULT;
+       ret = mon_text_copy_to_user(rp, buf, nbytes);
        mutex_unlock(&rp->printf_lock);
-       kmem_cache_free(rp->e_slab, ep);
-       return ptr.cnt;
+       return ret;
 }
 
 static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp,
index 968bf1e..4d72307 100644 (file)
@@ -1756,6 +1756,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
        int             vbus;
        u8              devctl;
 
+       pm_runtime_get_sync(dev);
        spin_lock_irqsave(&musb->lock, flags);
        val = musb->a_wait_bcon;
        vbus = musb_platform_get_vbus_status(musb);
@@ -1769,6 +1770,7 @@ vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
                        vbus = 0;
        }
        spin_unlock_irqrestore(&musb->lock, flags);
+       pm_runtime_put_sync(dev);
 
        return sprintf(buf, "Vbus %s, timeout %lu msec\n",
                        vbus ? "on" : "off", val);
@@ -2471,11 +2473,11 @@ static int musb_remove(struct platform_device *pdev)
        musb_disable_interrupts(musb);
        musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
        spin_unlock_irqrestore(&musb->lock, flags);
+       musb_platform_exit(musb);
 
        pm_runtime_dont_use_autosuspend(musb->controller);
        pm_runtime_put_sync(musb->controller);
        pm_runtime_disable(musb->controller);
-       musb_platform_exit(musb);
        musb_phy_callback = NULL;
        if (musb->dma_controller)
                musb_dma_controller_destroy(musb->dma_controller);
@@ -2708,7 +2710,8 @@ static int musb_resume(struct device *dev)
        if ((devctl & mask) != (musb->context.devctl & mask))
                musb->port1_status = 0;
 
-       musb_start(musb);
+       musb_enable_interrupts(musb);
+       musb_platform_enable(musb);
 
        spin_lock_irqsave(&musb->lock, flags);
        error = musb_run_resume_work(musb);
index 394b4ac..45ed32c 100644 (file)
@@ -391,13 +391,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
                }
        }
 
-       /*
-        * The pipe must be broken if current urb->status is set, so don't
-        * start next urb.
-        * TODO: to minimize the risk of regression, only check urb->status
-        * for RX, until we have a test case to understand the behavior of TX.
-        */
-       if ((!status || !is_in) && qh && qh->is_ready) {
+       if (qh != NULL && qh->is_ready) {
                musb_dbg(musb, "... next ep%d %cX urb %p",
                    hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
                musb_start_urb(musb, is_in, qh);
index da031c4..fbec863 100644 (file)
@@ -602,6 +602,9 @@ static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
        void __iomem *base = phy->io_priv;
        enum usb_charger_type chgr_type = UNKNOWN_TYPE;
 
+       if (!regmap)
+               return UNKNOWN_TYPE;
+
        if (mxs_charger_data_contact_detect(mxs_phy))
                return chgr_type;
 
index 5925d11..39fa2fc 100644 (file)
@@ -982,6 +982,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt,
        if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1))
                goto usbhsf_pio_prepare_pop;
 
+       /* return at this time if the pipe is running */
+       if (usbhs_pipe_is_running(pipe))
+               return 0;
+
        usbhs_pipe_config_change_bfre(pipe, 1);
 
        ret = usbhsf_fifo_select(pipe, fifo, 0);
@@ -1172,6 +1176,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt,
        usbhsf_fifo_clear(pipe, fifo);
        pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len);
 
+       usbhs_pipe_running(pipe, 0);
        usbhsf_dma_stop(pipe, fifo);
        usbhsf_dma_unmap(pkt);
        usbhsf_fifo_unselect(pipe, pipe->fifo);
index 5db8ed5..2d8d915 100644 (file)
@@ -241,6 +241,7 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_PRODUCT_EC21                   0x0121
 #define QUECTEL_PRODUCT_EC25                   0x0125
 #define QUECTEL_PRODUCT_BG96                   0x0296
+#define QUECTEL_PRODUCT_EP06                   0x0306
 
 #define CMOTECH_VENDOR_ID                      0x16d8
 #define CMOTECH_PRODUCT_6001                   0x6001
@@ -689,6 +690,10 @@ static const struct option_blacklist_info yuga_clm920_nc5_blacklist = {
        .reserved = BIT(1) | BIT(4),
 };
 
+static const struct option_blacklist_info quectel_ep06_blacklist = {
+       .reserved = BIT(4) | BIT(5),
+};
+
 static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
@@ -1203,6 +1208,8 @@ static const struct usb_device_id option_ids[] = {
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06),
+         .driver_info = (kernel_ulong_t)&quectel_ep06_blacklist },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) },
        { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003),
index 3b1b969..6034c39 100644 (file)
@@ -1076,7 +1076,7 @@ static int uas_post_reset(struct usb_interface *intf)
                return 0;
 
        err = uas_configure_endpoints(devinfo);
-       if (err && err != ENODEV)
+       if (err && err != -ENODEV)
                shost_printk(KERN_ERR, shost,
                             "%s: alloc streams error %d after reset",
                             __func__, err);
index 264af19..747d3a9 100644 (file)
@@ -2118,6 +2118,13 @@ UNUSUAL_DEV(  0x152d, 0x2566, 0x0114, 0x0114,
                USB_SC_DEVICE, USB_PR_DEVICE, NULL,
                US_FL_BROKEN_FUA ),
 
+/* Reported by Teijo Kinnunen <teijo.kinnunen@code-q.fi> */
+UNUSUAL_DEV(  0x152d, 0x2567, 0x0117, 0x0117,
+               "JMicron",
+               "USB to ATA/ATAPI Bridge",
+               USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+               US_FL_BROKEN_FUA ),
+
 /* Reported-by George Cherian <george.cherian@cavium.com> */
 UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999,
                "JMicron",
index 9ce4756..dcd8ef0 100644 (file)
@@ -1857,7 +1857,8 @@ static int fusb302_probe(struct i2c_client *client,
        chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
        if (IS_ERR(chip->tcpm_port)) {
                ret = PTR_ERR(chip->tcpm_port);
-               dev_err(dev, "cannot register tcpm port, ret=%d", ret);
+               if (ret != -EPROBE_DEFER)
+                       dev_err(dev, "cannot register tcpm port, ret=%d", ret);
                goto destroy_workqueue;
        }
 
index f4d563e..8b637a4 100644 (file)
@@ -252,9 +252,6 @@ struct tcpm_port {
        unsigned int nr_src_pdo;
        u32 snk_pdo[PDO_MAX_OBJECTS];
        unsigned int nr_snk_pdo;
-       unsigned int nr_fixed; /* number of fixed sink PDOs */
-       unsigned int nr_var; /* number of variable sink PDOs */
-       unsigned int nr_batt; /* number of battery sink PDOs */
        u32 snk_vdo[VDO_MAX_OBJECTS];
        unsigned int nr_snk_vdo;
 
@@ -1770,90 +1767,39 @@ static int tcpm_pd_check_request(struct tcpm_port *port)
        return 0;
 }
 
-#define min_power(x, y) min(pdo_max_power(x), pdo_max_power(y))
-#define min_current(x, y) min(pdo_max_current(x), pdo_max_current(y))
-
-static int tcpm_pd_select_pdo(struct tcpm_port *port, int *sink_pdo,
-                             int *src_pdo)
+static int tcpm_pd_select_pdo(struct tcpm_port *port)
 {
-       unsigned int i, j, max_mw = 0, max_mv = 0, mw = 0, mv = 0, ma = 0;
+       unsigned int i, max_mw = 0, max_mv = 0;
        int ret = -EINVAL;
 
        /*
-        * Select the source PDO providing the most power which has a
-        * matchig sink cap.
+        * Select the source PDO providing the most power while staying within
+        * the board's voltage limits. Prefer PDO providing exp
         */
        for (i = 0; i < port->nr_source_caps; i++) {
                u32 pdo = port->source_caps[i];
                enum pd_pdo_type type = pdo_type(pdo);
+               unsigned int mv, ma, mw;
 
-               if (type == PDO_TYPE_FIXED) {
-                       for (j = 0; j < port->nr_fixed; j++) {
-                               if (pdo_fixed_voltage(pdo) ==
-                                   pdo_fixed_voltage(port->snk_pdo[j])) {
-                                       ma = min_current(pdo, port->snk_pdo[j]);
-                                       mv = pdo_fixed_voltage(pdo);
-                                       mw = ma * mv / 1000;
-                                       if (mw > max_mw ||
-                                           (mw == max_mw && mv > max_mv)) {
-                                               ret = 0;
-                                               *src_pdo = i;
-                                               *sink_pdo = j;
-                                               max_mw = mw;
-                                               max_mv = mv;
-                                       }
-                                       /* There could only be one fixed pdo
-                                        * at a specific voltage level.
-                                        * So breaking here.
-                                        */
-                                       break;
-                               }
-                       }
-               } else if (type == PDO_TYPE_BATT) {
-                       for (j = port->nr_fixed;
-                            j < port->nr_fixed +
-                                port->nr_batt;
-                            j++) {
-                               if (pdo_min_voltage(pdo) >=
-                                    pdo_min_voltage(port->snk_pdo[j]) &&
-                                    pdo_max_voltage(pdo) <=
-                                    pdo_max_voltage(port->snk_pdo[j])) {
-                                       mw = min_power(pdo, port->snk_pdo[j]);
-                                       mv = pdo_min_voltage(pdo);
-                                       if (mw > max_mw ||
-                                           (mw == max_mw && mv > max_mv)) {
-                                               ret = 0;
-                                               *src_pdo = i;
-                                               *sink_pdo = j;
-                                               max_mw = mw;
-                                               max_mv = mv;
-                                       }
-                               }
-                       }
-               } else if (type == PDO_TYPE_VAR) {
-                       for (j = port->nr_fixed +
-                                port->nr_batt;
-                            j < port->nr_fixed +
-                                port->nr_batt +
-                                port->nr_var;
-                            j++) {
-                               if (pdo_min_voltage(pdo) >=
-                                    pdo_min_voltage(port->snk_pdo[j]) &&
-                                    pdo_max_voltage(pdo) <=
-                                    pdo_max_voltage(port->snk_pdo[j])) {
-                                       ma = min_current(pdo, port->snk_pdo[j]);
-                                       mv = pdo_min_voltage(pdo);
-                                       mw = ma * mv / 1000;
-                                       if (mw > max_mw ||
-                                           (mw == max_mw && mv > max_mv)) {
-                                               ret = 0;
-                                               *src_pdo = i;
-                                               *sink_pdo = j;
-                                               max_mw = mw;
-                                               max_mv = mv;
-                                       }
-                               }
-                       }
+               if (type == PDO_TYPE_FIXED)
+                       mv = pdo_fixed_voltage(pdo);
+               else
+                       mv = pdo_min_voltage(pdo);
+
+               if (type == PDO_TYPE_BATT) {
+                       mw = pdo_max_power(pdo);
+               } else {
+                       ma = min(pdo_max_current(pdo),
+                                port->max_snk_ma);
+                       mw = ma * mv / 1000;
+               }
+
+               /* Perfer higher voltages if available */
+               if ((mw > max_mw || (mw == max_mw && mv > max_mv)) &&
+                   mv <= port->max_snk_mv) {
+                       ret = i;
+                       max_mw = mw;
+                       max_mv = mv;
                }
        }
 
@@ -1865,14 +1811,13 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
        unsigned int mv, ma, mw, flags;
        unsigned int max_ma, max_mw;
        enum pd_pdo_type type;
-       int src_pdo_index, snk_pdo_index;
-       u32 pdo, matching_snk_pdo;
+       int index;
+       u32 pdo;
 
-       if (tcpm_pd_select_pdo(port, &snk_pdo_index, &src_pdo_index) < 0)
+       index = tcpm_pd_select_pdo(port);
+       if (index < 0)
                return -EINVAL;
-
-       pdo = port->source_caps[src_pdo_index];
-       matching_snk_pdo = port->snk_pdo[snk_pdo_index];
+       pdo = port->source_caps[index];
        type = pdo_type(pdo);
 
        if (type == PDO_TYPE_FIXED)
@@ -1880,28 +1825,26 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
        else
                mv = pdo_min_voltage(pdo);
 
-       /* Select maximum available current within the sink pdo's limit */
+       /* Select maximum available current within the board's power limit */
        if (type == PDO_TYPE_BATT) {
-               mw = min_power(pdo, matching_snk_pdo);
-               ma = 1000 * mw / mv;
+               mw = pdo_max_power(pdo);
+               ma = 1000 * min(mw, port->max_snk_mw) / mv;
        } else {
-               ma = min_current(pdo, matching_snk_pdo);
-               mw = ma * mv / 1000;
+               ma = min(pdo_max_current(pdo),
+                        1000 * port->max_snk_mw / mv);
        }
+       ma = min(ma, port->max_snk_ma);
 
        flags = RDO_USB_COMM | RDO_NO_SUSPEND;
 
        /* Set mismatch bit if offered power is less than operating power */
+       mw = ma * mv / 1000;
        max_ma = ma;
        max_mw = mw;
        if (mw < port->operating_snk_mw) {
                flags |= RDO_CAP_MISMATCH;
-               if (type == PDO_TYPE_BATT &&
-                   (pdo_max_power(matching_snk_pdo) > pdo_max_power(pdo)))
-                       max_mw = pdo_max_power(matching_snk_pdo);
-               else if (pdo_max_current(matching_snk_pdo) >
-                        pdo_max_current(pdo))
-                       max_ma = pdo_max_current(matching_snk_pdo);
+               max_mw = port->operating_snk_mw;
+               max_ma = max_mw * 1000 / mv;
        }
 
        tcpm_log(port, "cc=%d cc1=%d cc2=%d vbus=%d vconn=%s polarity=%d",
@@ -1910,16 +1853,16 @@ static int tcpm_pd_build_request(struct tcpm_port *port, u32 *rdo)
                 port->polarity);
 
        if (type == PDO_TYPE_BATT) {
-               *rdo = RDO_BATT(src_pdo_index + 1, mw, max_mw, flags);
+               *rdo = RDO_BATT(index + 1, mw, max_mw, flags);
 
                tcpm_log(port, "Requesting PDO %d: %u mV, %u mW%s",
-                        src_pdo_index, mv, mw,
+                        index, mv, mw,
                         flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
        } else {
-               *rdo = RDO_FIXED(src_pdo_index + 1, ma, max_ma, flags);
+               *rdo = RDO_FIXED(index + 1, ma, max_ma, flags);
 
                tcpm_log(port, "Requesting PDO %d: %u mV, %u mA%s",
-                        src_pdo_index, mv, ma,
+                        index, mv, ma,
                         flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
        }
 
@@ -3650,19 +3593,6 @@ int tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
 }
 EXPORT_SYMBOL_GPL(tcpm_update_sink_capabilities);
 
-static int nr_type_pdos(const u32 *pdo, unsigned int nr_pdo,
-                       enum pd_pdo_type type)
-{
-       int count = 0;
-       int i;
-
-       for (i = 0; i < nr_pdo; i++) {
-               if (pdo_type(pdo[i]) == type)
-                       count++;
-       }
-       return count;
-}
-
 struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
 {
        struct tcpm_port *port;
@@ -3708,15 +3638,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
                                          tcpc->config->nr_src_pdo);
        port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
                                          tcpc->config->nr_snk_pdo);
-       port->nr_fixed =  nr_type_pdos(port->snk_pdo,
-                                      port->nr_snk_pdo,
-                                      PDO_TYPE_FIXED);
-       port->nr_var = nr_type_pdos(port->snk_pdo,
-                                   port->nr_snk_pdo,
-                                   PDO_TYPE_VAR);
-       port->nr_batt = nr_type_pdos(port->snk_pdo,
-                                    port->nr_snk_pdo,
-                                    PDO_TYPE_BATT);
        port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo,
                                          tcpc->config->nr_snk_vdo);
 
index 49e5524..dd8ef36 100644 (file)
@@ -73,6 +73,7 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
                        goto err;
 
                sdev->ud.tcp_socket = socket;
+               sdev->ud.sockfd = sockfd;
 
                spin_unlock_irq(&sdev->ud.lock);
 
@@ -172,6 +173,7 @@ static void stub_shutdown_connection(struct usbip_device *ud)
        if (ud->tcp_socket) {
                sockfd_put(ud->tcp_socket);
                ud->tcp_socket = NULL;
+               ud->sockfd = -1;
        }
 
        /* 3. free used data */
@@ -266,6 +268,7 @@ static struct stub_device *stub_device_alloc(struct usb_device *udev)
        sdev->ud.status         = SDEV_ST_AVAILABLE;
        spin_lock_init(&sdev->ud.lock);
        sdev->ud.tcp_socket     = NULL;
+       sdev->ud.sockfd         = -1;
 
        INIT_LIST_HEAD(&sdev->priv_init);
        INIT_LIST_HEAD(&sdev->priv_tx);
index c3e1008..20e3d46 100644 (file)
@@ -984,6 +984,7 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
        if (vdev->ud.tcp_socket) {
                sockfd_put(vdev->ud.tcp_socket);
                vdev->ud.tcp_socket = NULL;
+               vdev->ud.sockfd = -1;
        }
        pr_info("release socket\n");
 
@@ -1030,6 +1031,7 @@ static void vhci_device_reset(struct usbip_device *ud)
        if (ud->tcp_socket) {
                sockfd_put(ud->tcp_socket);
                ud->tcp_socket = NULL;
+               ud->sockfd = -1;
        }
        ud->status = VDEV_ST_NULL;
 
index d86f72b..6dcd3ff 100644 (file)
@@ -105,10 +105,14 @@ static ssize_t usbip_sockfd_store(struct device *dev, struct device_attribute *a
        if (rv != 0)
                return -EINVAL;
 
+       if (!udc) {
+               dev_err(dev, "no device");
+               return -ENODEV;
+       }
        spin_lock_irqsave(&udc->lock, flags);
        /* Don't export what we don't have */
-       if (!udc || !udc->driver || !udc->pullup) {
-               dev_err(dev, "no device or gadget not bound");
+       if (!udc->driver || !udc->pullup) {
+               dev_err(dev, "gadget not bound");
                ret = -ENODEV;
                goto unlock;
        }
index b0f7594..8a1508a 100644 (file)
@@ -207,9 +207,6 @@ static bool vfio_pci_nointx(struct pci_dev *pdev)
                }
        }
 
-       if (!pdev->irq)
-               return true;
-
        return false;
 }
 
index e30e29a..45657e2 100644 (file)
@@ -338,11 +338,12 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
 {
        struct page *page[1];
        struct vm_area_struct *vma;
+       struct vm_area_struct *vmas[1];
        int ret;
 
        if (mm == current->mm) {
-               ret = get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE),
-                                         page);
+               ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE),
+                                             page, vmas);
        } else {
                unsigned int flags = 0;
 
@@ -351,7 +352,18 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
 
                down_read(&mm->mmap_sem);
                ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page,
-                                           NULL, NULL);
+                                           vmas, NULL);
+               /*
+                * The lifetime of a vaddr_get_pfn() page pin is
+                * userspace-controlled. In the fs-dax case this could
+                * lead to indefinite stalls in filesystem operations.
+                * Disallow attempts to pin fs-dax pages via this
+                * interface.
+                */
+               if (ret > 0 && vma_is_fsdax(vmas[0])) {
+                       ret = -EOPNOTSUPP;
+                       put_page(page[0]);
+               }
                up_read(&mm->mmap_sem);
        }
 
index 610cba2..12bcfba 100644 (file)
@@ -170,7 +170,7 @@ static void vhost_net_buf_unproduce(struct vhost_net_virtqueue *nvq)
        if (nvq->rx_ring && !vhost_net_buf_is_empty(rxq)) {
                ptr_ring_unconsume(nvq->rx_ring, rxq->queue + rxq->head,
                                   vhost_net_buf_get_size(rxq),
-                                  __skb_array_destroy_skb);
+                                  tun_ptr_free);
                rxq->head = rxq->tail = 0;
        }
 }
@@ -630,7 +630,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk)
 
        if (!len && vq->busyloop_timeout) {
                /* Both tx vq and rx socket were polled here */
-               mutex_lock(&vq->mutex);
+               mutex_lock_nested(&vq->mutex, 1);
                vhost_disable_notify(&net->dev, vq);
 
                preempt_disable();
@@ -763,7 +763,7 @@ static void handle_rx(struct vhost_net *net)
        struct iov_iter fixup;
        __virtio16 num_buffers;
 
-       mutex_lock(&vq->mutex);
+       mutex_lock_nested(&vq->mutex, 0);
        sock = vq->private_data;
        if (!sock)
                goto out;
@@ -948,6 +948,7 @@ static int vhost_net_open(struct inode *inode, struct file *f)
                n->vqs[i].done_idx = 0;
                n->vqs[i].vhost_hlen = 0;
                n->vqs[i].sock_hlen = 0;
+               n->vqs[i].rx_ring = NULL;
                vhost_net_buf_init(&n->vqs[i].rxq);
        }
        vhost_dev_init(dev, vqs, VHOST_NET_VQ_MAX);
@@ -972,6 +973,7 @@ static struct socket *vhost_net_stop_vq(struct vhost_net *n,
        vhost_net_disable_vq(n, vq);
        vq->private_data = NULL;
        vhost_net_buf_unproduce(nvq);
+       nvq->rx_ring = NULL;
        mutex_unlock(&vq->mutex);
        return sock;
 }
@@ -1161,14 +1163,14 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
                vhost_net_disable_vq(n, vq);
                vq->private_data = sock;
                vhost_net_buf_unproduce(nvq);
-               if (index == VHOST_NET_VQ_RX)
-                       nvq->rx_ring = get_tap_ptr_ring(fd);
                r = vhost_vq_init_access(vq);
                if (r)
                        goto err_used;
                r = vhost_net_enable_vq(n, vq);
                if (r)
                        goto err_used;
+               if (index == VHOST_NET_VQ_RX)
+                       nvq->rx_ring = get_tap_ptr_ring(fd);
 
                oldubufs = nvq->ubufs;
                nvq->ubufs = ubufs;
index 1b3e8d2..5320039 100644 (file)
@@ -212,8 +212,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file)
        if (mask)
                vhost_poll_wakeup(&poll->wait, 0, 0, poll_to_key(mask));
        if (mask & EPOLLERR) {
-               if (poll->wqh)
-                       remove_wait_queue(poll->wqh, &poll->wait);
+               vhost_poll_stop(poll);
                ret = -EINVAL;
        }
 
@@ -1245,14 +1244,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq,
 /* Caller should have vq mutex and device mutex */
 int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 {
-       if (vq->iotlb) {
-               /* When device IOTLB was used, the access validation
-                * will be validated during prefetching.
-                */
-               return 1;
-       }
-       return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) &&
-               vq_log_access_ok(vq, vq->log_base);
+       int ret = vq_log_access_ok(vq, vq->log_base);
+
+       if (ret || vq->iotlb)
+               return ret;
+
+       return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used);
 }
 EXPORT_SYMBOL_GPL(vhost_vq_access_ok);
 
index af6fc97..a436d44 100644 (file)
@@ -122,7 +122,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                unsigned char __user *ured;
                unsigned char __user *ugreen;
                unsigned char __user *ublue;
-               int index, count, i;
+               unsigned int index, count, i;
 
                if (get_user(index, &c->index) ||
                    __get_user(count, &c->count) ||
@@ -161,7 +161,7 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg,
                unsigned char __user *ugreen;
                unsigned char __user *ublue;
                struct fb_cmap *cmap = &info->cmap;
-               int index, count, i;
+               unsigned int index, count, i;
                u8 red, green, blue;
 
                if (get_user(index, &c->index) ||
index eb30f3e..71458f4 100644 (file)
@@ -428,8 +428,6 @@ unmap_release:
                i = virtio16_to_cpu(_vq->vdev, vq->vring.desc[i].next);
        }
 
-       vq->vq.num_free += total_sg;
-
        if (indirect)
                kfree(desc);
 
index aff773b..37460cd 100644 (file)
@@ -226,6 +226,7 @@ config ZIIRAVE_WATCHDOG
 config RAVE_SP_WATCHDOG
        tristate "RAVE SP Watchdog timer"
        depends on RAVE_SP_CORE
+       depends on NVMEM || !NVMEM
        select WATCHDOG_CORE
        help
          Support for the watchdog on RAVE SP device.
@@ -903,6 +904,7 @@ config F71808E_WDT
 config SP5100_TCO
        tristate "AMD/ATI SP5100 TCO Timer/Watchdog"
        depends on X86 && PCI
+       select WATCHDOG_CORE
        ---help---
          Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO
          (Total Cost of Ownership) timer is a watchdog timer that will reboot
@@ -1008,6 +1010,7 @@ config WAFER_WDT
 config I6300ESB_WDT
        tristate "Intel 6300ESB Timer/Watchdog"
        depends on PCI
+       select WATCHDOG_CORE
        ---help---
          Hardware driver for the watchdog timer built into the Intel
          6300ESB controller hub.
@@ -1837,6 +1840,7 @@ config WATCHDOG_SUN4V
 config XEN_WDT
        tristate "Xen Watchdog support"
        depends on XEN
+       select WATCHDOG_CORE
        help
          Say Y here to support the hypervisor watchdog capability provided
          by Xen 4.0 and newer.  The watchdog timeout period is normally one
index e0678c1..3a33c53 100644 (file)
@@ -566,7 +566,8 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf,
                                char c;
                                if (get_user(c, buf + i))
                                        return -EFAULT;
-                               expect_close = (c == 'V');
+                               if (c == 'V')
+                                       expect_close = true;
                        }
 
                        /* Properly order writes across fork()ed processes */
index f1f00df..b0a1580 100644 (file)
 #include <linux/types.h>
 #include <linux/uaccess.h>
 #include <linux/watchdog.h>
-#ifdef CONFIG_HPWDT_NMI_DECODING
-#include <linux/dmi.h>
-#include <linux/spinlock.h>
-#include <linux/nmi.h>
-#include <linux/kdebug.h>
-#include <linux/notifier.h>
-#include <asm/set_memory.h>
-#endif /* CONFIG_HPWDT_NMI_DECODING */
 #include <asm/nmi.h>
-#include <asm/frame.h>
 
 #define HPWDT_VERSION                  "1.4.0"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
@@ -48,6 +39,9 @@
 static unsigned int soft_margin = DEFAULT_MARGIN;      /* in seconds */
 static unsigned int reload;                    /* the computed soft_margin */
 static bool nowayout = WATCHDOG_NOWAYOUT;
+#ifdef CONFIG_HPWDT_NMI_DECODING
+static unsigned int allow_kdump = 1;
+#endif
 static char expect_release;
 static unsigned long hpwdt_is_open;
 
@@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = {
 };
 MODULE_DEVICE_TABLE(pci, hpwdt_devices);
 
-#ifdef CONFIG_HPWDT_NMI_DECODING
-#define PCI_BIOS32_SD_VALUE            0x5F32335F      /* "_32_" */
-#define CRU_BIOS_SIGNATURE_VALUE       0x55524324
-#define PCI_BIOS32_PARAGRAPH_LEN       16
-#define PCI_ROM_BASE1                  0x000F0000
-#define ROM_SIZE                       0x10000
-
-struct bios32_service_dir {
-       u32 signature;
-       u32 entry_point;
-       u8 revision;
-       u8 length;
-       u8 checksum;
-       u8 reserved[5];
-};
-
-/* type 212 */
-struct smbios_cru64_info {
-       u8 type;
-       u8 byte_length;
-       u16 handle;
-       u32 signature;
-       u64 physical_address;
-       u32 double_length;
-       u32 double_offset;
-};
-#define SMBIOS_CRU64_INFORMATION       212
-
-/* type 219 */
-struct smbios_proliant_info {
-       u8 type;
-       u8 byte_length;
-       u16 handle;
-       u32 power_features;
-       u32 omega_features;
-       u32 reserved;
-       u32 misc_features;
-};
-#define SMBIOS_ICRU_INFORMATION                219
-
-
-struct cmn_registers {
-       union {
-               struct {
-                       u8 ral;
-                       u8 rah;
-                       u16 rea2;
-               };
-               u32 reax;
-       } u1;
-       union {
-               struct {
-                       u8 rbl;
-                       u8 rbh;
-                       u8 reb2l;
-                       u8 reb2h;
-               };
-               u32 rebx;
-       } u2;
-       union {
-               struct {
-                       u8 rcl;
-                       u8 rch;
-                       u16 rec2;
-               };
-               u32 recx;
-       } u3;
-       union {
-               struct {
-                       u8 rdl;
-                       u8 rdh;
-                       u16 red2;
-               };
-               u32 redx;
-       } u4;
-
-       u32 resi;
-       u32 redi;
-       u16 rds;
-       u16 res;
-       u32 reflags;
-}  __attribute__((packed));
-
-static unsigned int hpwdt_nmi_decoding;
-static unsigned int allow_kdump = 1;
-static unsigned int is_icru;
-static unsigned int is_uefi;
-static DEFINE_SPINLOCK(rom_lock);
-static void *cru_rom_addr;
-static struct cmn_registers cmn_regs;
-
-extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
-                                               unsigned long *pRomEntry);
-
-#ifdef CONFIG_X86_32
-/* --32 Bit Bios------------------------------------------------------------ */
-
-#define HPWDT_ARCH     32
-
-asm(".text                          \n\t"
-    ".align 4                       \n\t"
-    ".globl asminline_call         \n"
-    "asminline_call:                \n\t"
-    "pushl       %ebp               \n\t"
-    "movl        %esp, %ebp         \n\t"
-    "pusha                          \n\t"
-    "pushf                          \n\t"
-    "push        %es                \n\t"
-    "push        %ds                \n\t"
-    "pop         %es                \n\t"
-    "movl        8(%ebp),%eax       \n\t"
-    "movl        4(%eax),%ebx       \n\t"
-    "movl        8(%eax),%ecx       \n\t"
-    "movl        12(%eax),%edx      \n\t"
-    "movl        16(%eax),%esi      \n\t"
-    "movl        20(%eax),%edi      \n\t"
-    "movl        (%eax),%eax        \n\t"
-    "push        %cs                \n\t"
-    "call        *12(%ebp)          \n\t"
-    "pushf                          \n\t"
-    "pushl       %eax               \n\t"
-    "movl        8(%ebp),%eax       \n\t"
-    "movl        %ebx,4(%eax)       \n\t"
-    "movl        %ecx,8(%eax)       \n\t"
-    "movl        %edx,12(%eax)      \n\t"
-    "movl        %esi,16(%eax)      \n\t"
-    "movl        %edi,20(%eax)      \n\t"
-    "movw        %ds,24(%eax)       \n\t"
-    "movw        %es,26(%eax)       \n\t"
-    "popl        %ebx               \n\t"
-    "movl        %ebx,(%eax)        \n\t"
-    "popl        %ebx               \n\t"
-    "movl        %ebx,28(%eax)      \n\t"
-    "pop         %es                \n\t"
-    "popf                           \n\t"
-    "popa                           \n\t"
-    "leave                          \n\t"
-    "ret                            \n\t"
-    ".previous");
-
-
-/*
- *     cru_detect
- *
- *     Routine Description:
- *     This function uses the 32-bit BIOS Service Directory record to
- *     search for a $CRU record.
- *
- *     Return Value:
- *     0        :  SUCCESS
- *     <0       :  FAILURE
- */
-static int cru_detect(unsigned long map_entry,
-       unsigned long map_offset)
-{
-       void *bios32_map;
-       unsigned long *bios32_entrypoint;
-       unsigned long cru_physical_address;
-       unsigned long cru_length;
-       unsigned long physical_bios_base = 0;
-       unsigned long physical_bios_offset = 0;
-       int retval = -ENODEV;
-
-       bios32_map = ioremap(map_entry, (2 * PAGE_SIZE));
-
-       if (bios32_map == NULL)
-               return -ENODEV;
-
-       bios32_entrypoint = bios32_map + map_offset;
-
-       cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE;
-
-       set_memory_x((unsigned long)bios32_map, 2);
-       asminline_call(&cmn_regs, bios32_entrypoint);
-
-       if (cmn_regs.u1.ral != 0) {
-               pr_warn("Call succeeded but with an error: 0x%x\n",
-                       cmn_regs.u1.ral);
-       } else {
-               physical_bios_base = cmn_regs.u2.rebx;
-               physical_bios_offset = cmn_regs.u4.redx;
-               cru_length = cmn_regs.u3.recx;
-               cru_physical_address =
-                       physical_bios_base + physical_bios_offset;
-
-               /* If the values look OK, then map it in. */
-               if ((physical_bios_base + physical_bios_offset)) {
-                       cru_rom_addr =
-                               ioremap(cru_physical_address, cru_length);
-                       if (cru_rom_addr) {
-                               set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK,
-                                       (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT);
-                               retval = 0;
-                       }
-               }
-
-               pr_debug("CRU Base Address:   0x%lx\n", physical_bios_base);
-               pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset);
-               pr_debug("CRU Length:         0x%lx\n", cru_length);
-               pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr);
-       }
-       iounmap(bios32_map);
-       return retval;
-}
-
-/*
- *     bios_checksum
- */
-static int bios_checksum(const char __iomem *ptr, int len)
-{
-       char sum = 0;
-       int i;
-
-       /*
-        * calculate checksum of size bytes. This should add up
-        * to zero if we have a valid header.
-        */
-       for (i = 0; i < len; i++)
-               sum += ptr[i];
-
-       return ((sum == 0) && (len > 0));
-}
-
-/*
- *     bios32_present
- *
- *     Routine Description:
- *     This function finds the 32-bit BIOS Service Directory
- *
- *     Return Value:
- *     0        :  SUCCESS
- *     <0       :  FAILURE
- */
-static int bios32_present(const char __iomem *p)
-{
-       struct bios32_service_dir *bios_32_ptr;
-       int length;
-       unsigned long map_entry, map_offset;
-
-       bios_32_ptr = (struct bios32_service_dir *) p;
-
-       /*
-        * Search for signature by checking equal to the swizzled value
-        * instead of calling another routine to perform a strcmp.
-        */
-       if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) {
-               length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN;
-               if (bios_checksum(p, length)) {
-                       /*
-                        * According to the spec, we're looking for the
-                        * first 4KB-aligned address below the entrypoint
-                        * listed in the header. The Service Directory code
-                        * is guaranteed to occupy no more than 2 4KB pages.
-                        */
-                       map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1);
-                       map_offset = bios_32_ptr->entry_point - map_entry;
-
-                       return cru_detect(map_entry, map_offset);
-               }
-       }
-       return -ENODEV;
-}
-
-static int detect_cru_service(void)
-{
-       char __iomem *p, *q;
-       int rc = -1;
-
-       /*
-        * Search from 0x0f0000 through 0x0fffff, inclusive.
-        */
-       p = ioremap(PCI_ROM_BASE1, ROM_SIZE);
-       if (p == NULL)
-               return -ENOMEM;
-
-       for (q = p; q < p + ROM_SIZE; q += 16) {
-               rc = bios32_present(q);
-               if (!rc)
-                       break;
-       }
-       iounmap(p);
-       return rc;
-}
-/* ------------------------------------------------------------------------- */
-#endif /* CONFIG_X86_32 */
-#ifdef CONFIG_X86_64
-/* --64 Bit Bios------------------------------------------------------------ */
-
-#define HPWDT_ARCH     64
-
-asm(".text                      \n\t"
-    ".align 4                   \n\t"
-    ".globl asminline_call     \n\t"
-    ".type asminline_call, @function \n\t"
-    "asminline_call:            \n\t"
-    FRAME_BEGIN
-    "pushq      %rax            \n\t"
-    "pushq      %rbx            \n\t"
-    "pushq      %rdx            \n\t"
-    "pushq      %r12            \n\t"
-    "pushq      %r9             \n\t"
-    "movq       %rsi, %r12      \n\t"
-    "movq       %rdi, %r9       \n\t"
-    "movl       4(%r9),%ebx     \n\t"
-    "movl       8(%r9),%ecx     \n\t"
-    "movl       12(%r9),%edx    \n\t"
-    "movl       16(%r9),%esi    \n\t"
-    "movl       20(%r9),%edi    \n\t"
-    "movl       (%r9),%eax      \n\t"
-    "call       *%r12           \n\t"
-    "pushfq                     \n\t"
-    "popq        %r12           \n\t"
-    "movl       %eax, (%r9)     \n\t"
-    "movl       %ebx, 4(%r9)    \n\t"
-    "movl       %ecx, 8(%r9)    \n\t"
-    "movl       %edx, 12(%r9)   \n\t"
-    "movl       %esi, 16(%r9)   \n\t"
-    "movl       %edi, 20(%r9)   \n\t"
-    "movq       %r12, %rax      \n\t"
-    "movl       %eax, 28(%r9)   \n\t"
-    "popq       %r9             \n\t"
-    "popq       %r12            \n\t"
-    "popq       %rdx            \n\t"
-    "popq       %rbx            \n\t"
-    "popq       %rax            \n\t"
-    FRAME_END
-    "ret                        \n\t"
-    ".previous");
-
-/*
- *     dmi_find_cru
- *
- *     Routine Description:
- *     This function checks whether or not a SMBIOS/DMI record is
- *     the 64bit CRU info or not
- */
-static void dmi_find_cru(const struct dmi_header *dm, void *dummy)
-{
-       struct smbios_cru64_info *smbios_cru64_ptr;
-       unsigned long cru_physical_address;
-
-       if (dm->type == SMBIOS_CRU64_INFORMATION) {
-               smbios_cru64_ptr = (struct smbios_cru64_info *) dm;
-               if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) {
-                       cru_physical_address =
-                               smbios_cru64_ptr->physical_address +
-                               smbios_cru64_ptr->double_offset;
-                       cru_rom_addr = ioremap(cru_physical_address,
-                               smbios_cru64_ptr->double_length);
-                       set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK,
-                               smbios_cru64_ptr->double_length >> PAGE_SHIFT);
-               }
-       }
-}
-
-static int detect_cru_service(void)
-{
-       cru_rom_addr = NULL;
-
-       dmi_walk(dmi_find_cru, NULL);
-
-       /* if cru_rom_addr has been set then we found a CRU service */
-       return ((cru_rom_addr != NULL) ? 0 : -ENODEV);
-}
-/* ------------------------------------------------------------------------- */
-#endif /* CONFIG_X86_64 */
-#endif /* CONFIG_HPWDT_NMI_DECODING */
 
 /*
  *     Watchdog operations
@@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void)
  */
 static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
 {
-       unsigned long rom_pl;
-       static int die_nmi_called;
-
-       if (!hpwdt_nmi_decoding)
-               return NMI_DONE;
-
        if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi())
                return NMI_DONE;
 
-       spin_lock_irqsave(&rom_lock, rom_pl);
-       if (!die_nmi_called && !is_icru && !is_uefi)
-               asminline_call(&cmn_regs, cru_rom_addr);
-       die_nmi_called = 1;
-       spin_unlock_irqrestore(&rom_lock, rom_pl);
-
        if (allow_kdump)
                hpwdt_stop();
 
-       if (!is_icru && !is_uefi) {
-               if (cmn_regs.u1.ral == 0) {
-                       nmi_panic(regs, "An NMI occurred, but unable to determine source.\n");
-                       return NMI_HANDLED;
-               }
-       }
        nmi_panic(regs, "An NMI occurred. Depending on your system the reason "
                "for the NMI is logged in any one of the following "
                "resources:\n"
@@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = {
  *     Init & Exit
  */
 
-#ifdef CONFIG_HPWDT_NMI_DECODING
-#ifdef CONFIG_X86_LOCAL_APIC
-static void hpwdt_check_nmi_decoding(struct pci_dev *dev)
-{
-       /*
-        * If nmi_watchdog is turned off then we can turn on
-        * our nmi decoding capability.
-        */
-       hpwdt_nmi_decoding = 1;
-}
-#else
-static void hpwdt_check_nmi_decoding(struct pci_dev *dev)
-{
-       dev_warn(&dev->dev, "NMI decoding is disabled. "
-               "Your kernel does not support a NMI Watchdog.\n");
-}
-#endif /* CONFIG_X86_LOCAL_APIC */
-
-/*
- *     dmi_find_icru
- *
- *     Routine Description:
- *     This function checks whether or not we are on an iCRU-based server.
- *     This check is independent of architecture and needs to be made for
- *     any ProLiant system.
- */
-static void dmi_find_icru(const struct dmi_header *dm, void *dummy)
-{
-       struct smbios_proliant_info *smbios_proliant_ptr;
-
-       if (dm->type == SMBIOS_ICRU_INFORMATION) {
-               smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
-               if (smbios_proliant_ptr->misc_features & 0x01)
-                       is_icru = 1;
-               if (smbios_proliant_ptr->misc_features & 0x1400)
-                       is_uefi = 1;
-       }
-}
 
 static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
 {
+#ifdef CONFIG_HPWDT_NMI_DECODING
        int retval;
-
-       /*
-        * On typical CRU-based systems we need to map that service in
-        * the BIOS. For 32 bit Operating Systems we need to go through
-        * the 32 Bit BIOS Service Directory. For 64 bit Operating
-        * Systems we get that service through SMBIOS.
-        *
-        * On systems that support the new iCRU service all we need to
-        * do is call dmi_walk to get the supported flag value and skip
-        * the old cru detect code.
-        */
-       dmi_walk(dmi_find_icru, NULL);
-       if (!is_icru && !is_uefi) {
-
-               /*
-               * We need to map the ROM to get the CRU service.
-               * For 32 bit Operating Systems we need to go through the 32 Bit
-               * BIOS Service Directory
-               * For 64 bit Operating Systems we get that service through SMBIOS.
-               */
-               retval = detect_cru_service();
-               if (retval < 0) {
-                       dev_warn(&dev->dev,
-                               "Unable to detect the %d Bit CRU Service.\n",
-                               HPWDT_ARCH);
-                       return retval;
-               }
-
-               /*
-               * We know this is the only CRU call we need to make so lets keep as
-               * few instructions as possible once the NMI comes in.
-               */
-               cmn_regs.u1.rah = 0x0D;
-               cmn_regs.u1.ral = 0x02;
-       }
-
        /*
         * Only one function can register for NMI_UNKNOWN
         */
@@ -780,45 +316,26 @@ error:
        dev_warn(&dev->dev,
                "Unable to register a die notifier (err=%d).\n",
                retval);
-       if (cru_rom_addr)
-               iounmap(cru_rom_addr);
        return retval;
+#endif /* CONFIG_HPWDT_NMI_DECODING */
+       return 0;
 }
 
 static void hpwdt_exit_nmi_decoding(void)
 {
+#ifdef CONFIG_HPWDT_NMI_DECODING
        unregister_nmi_handler(NMI_UNKNOWN, "hpwdt");
        unregister_nmi_handler(NMI_SERR, "hpwdt");
        unregister_nmi_handler(NMI_IO_CHECK, "hpwdt");
-       if (cru_rom_addr)
-               iounmap(cru_rom_addr);
-}
-#else /* !CONFIG_HPWDT_NMI_DECODING */
-static void hpwdt_check_nmi_decoding(struct pci_dev *dev)
-{
-}
-
-static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
-{
-       return 0;
+#endif
 }
 
-static void hpwdt_exit_nmi_decoding(void)
-{
-}
-#endif /* CONFIG_HPWDT_NMI_DECODING */
-
 static int hpwdt_init_one(struct pci_dev *dev,
                                        const struct pci_device_id *ent)
 {
        int retval;
 
        /*
-        * Check if we can do NMI decoding or not
-        */
-       hpwdt_check_nmi_decoding(dev);
-
-       /*
         * First let's find out if we are on an iLO2+ server. We will
         * not run on a legacy ASM box.
         * So we only support the G5 ProLiant servers and higher.
@@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
 #ifdef CONFIG_HPWDT_NMI_DECODING
 module_param(allow_kdump, int, 0);
 MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
-#endif /* !CONFIG_HPWDT_NMI_DECODING */
+#endif /* CONFIG_HPWDT_NMI_DECODING */
 
 module_pci_driver(hpwdt_driver);
index 316c2eb..e8bd988 100644 (file)
@@ -50,6 +50,7 @@
  */
 
 #include <linux/io.h>
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -159,7 +160,7 @@ static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd)
            !(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0))
                timeleft += readl(gwdt->control_base + SBSA_GWDT_WOR);
 
-       timeleft += readq(gwdt->control_base + SBSA_GWDT_WCV) -
+       timeleft += lo_hi_readq(gwdt->control_base + SBSA_GWDT_WCV) -
                    arch_counter_get_cntvct();
 
        do_div(timeleft, gwdt->clk);
index 6d1fbda..0da9943 100644 (file)
@@ -392,7 +392,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
 
                memset(&r, 0, sizeof(r));
                r.start = gas->address;
-               r.end = r.start + gas->access_width;
+               r.end = r.start + gas->access_width - 1;
                if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                        r.flags = IORESOURCE_MEM;
                } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
index 1ab4bd1..762378f 100644 (file)
@@ -755,8 +755,8 @@ out:
        mutex_unlock(&irq_mapping_update_lock);
        return irq;
 error_irq:
-       for (; i >= 0; i--)
-               __unbind_from_irq(irq + i);
+       while (nvec--)
+               __unbind_from_irq(irq + nvec);
        mutex_unlock(&irq_mapping_update_lock);
        return ret;
 }
index 156e5ae..b1092fb 100644 (file)
@@ -416,7 +416,7 @@ static int pvcalls_back_connect(struct xenbus_device *dev,
                                        sock);
        if (!map) {
                ret = -EFAULT;
-               sock_release(map->sock);
+               sock_release(sock);
        }
 
 out:
index 753d9cb..2f11ca7 100644 (file)
@@ -60,6 +60,7 @@ struct sock_mapping {
        bool active_socket;
        struct list_head list;
        struct socket *sock;
+       atomic_t refcount;
        union {
                struct {
                        int irq;
@@ -72,20 +73,25 @@ struct sock_mapping {
                        wait_queue_head_t inflight_conn_req;
                } active;
                struct {
-               /* Socket status */
+               /*
+                * Socket status, needs to be 64-bit aligned due to the
+                * test_and_* functions which have this requirement on arm64.
+                */
 #define PVCALLS_STATUS_UNINITALIZED  0
 #define PVCALLS_STATUS_BIND          1
 #define PVCALLS_STATUS_LISTEN        2
-                       uint8_t status;
+                       uint8_t status __attribute__((aligned(8)));
                /*
                 * Internal state-machine flags.
                 * Only one accept operation can be inflight for a socket.
                 * Only one poll operation can be inflight for a given socket.
+                * flags needs to be 64-bit aligned due to the test_and_*
+                * functions which have this requirement on arm64.
                 */
 #define PVCALLS_FLAG_ACCEPT_INFLIGHT 0
 #define PVCALLS_FLAG_POLL_INFLIGHT   1
 #define PVCALLS_FLAG_POLL_RET        2
-                       uint8_t flags;
+                       uint8_t flags __attribute__((aligned(8)));
                        uint32_t inflight_req_id;
                        struct sock_mapping *accept_map;
                        wait_queue_head_t inflight_accept_req;
@@ -93,6 +99,32 @@ struct sock_mapping {
        };
 };
 
+static inline struct sock_mapping *pvcalls_enter_sock(struct socket *sock)
+{
+       struct sock_mapping *map;
+
+       if (!pvcalls_front_dev ||
+               dev_get_drvdata(&pvcalls_front_dev->dev) == NULL)
+               return ERR_PTR(-ENOTCONN);
+
+       map = (struct sock_mapping *)sock->sk->sk_send_head;
+       if (map == NULL)
+               return ERR_PTR(-ENOTSOCK);
+
+       pvcalls_enter();
+       atomic_inc(&map->refcount);
+       return map;
+}
+
+static inline void pvcalls_exit_sock(struct socket *sock)
+{
+       struct sock_mapping *map;
+
+       map = (struct sock_mapping *)sock->sk->sk_send_head;
+       atomic_dec(&map->refcount);
+       pvcalls_exit();
+}
+
 static inline int get_request(struct pvcalls_bedata *bedata, int *req_id)
 {
        *req_id = bedata->ring.req_prod_pvt & (RING_SIZE(&bedata->ring) - 1);
@@ -369,31 +401,23 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
                return -EOPNOTSUPP;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
 
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *)sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        spin_lock(&bedata->socket_lock);
        ret = get_request(bedata, &req_id);
        if (ret < 0) {
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        ret = create_active(map, &evtchn);
        if (ret < 0) {
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
 
@@ -423,7 +447,7 @@ int pvcalls_front_connect(struct socket *sock, struct sockaddr *addr,
        smp_rmb();
        ret = bedata->rsp[req_id].ret;
        bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return ret;
 }
 
@@ -488,23 +512,15 @@ int pvcalls_front_sendmsg(struct socket *sock, struct msghdr *msg,
        if (flags & (MSG_CONFIRM|MSG_DONTROUTE|MSG_EOR|MSG_OOB))
                return -EOPNOTSUPP;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        mutex_lock(&map->active.out_mutex);
        if ((flags & MSG_DONTWAIT) && !pvcalls_front_write_todo(map)) {
                mutex_unlock(&map->active.out_mutex);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -EAGAIN;
        }
        if (len > INT_MAX)
@@ -526,7 +542,7 @@ again:
                tot_sent = sent;
 
        mutex_unlock(&map->active.out_mutex);
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return tot_sent;
 }
 
@@ -591,19 +607,11 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
        if (flags & (MSG_CMSG_CLOEXEC|MSG_ERRQUEUE|MSG_OOB|MSG_TRUNC))
                return -EOPNOTSUPP;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        mutex_lock(&map->active.in_mutex);
        if (len > XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER))
                len = XEN_FLEX_RING_SIZE(PVCALLS_RING_ORDER);
@@ -623,7 +631,7 @@ int pvcalls_front_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
                ret = 0;
 
        mutex_unlock(&map->active.in_mutex);
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return ret;
 }
 
@@ -637,24 +645,16 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
        if (addr->sa_family != AF_INET || sock->type != SOCK_STREAM)
                return -EOPNOTSUPP;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (map == NULL) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        spin_lock(&bedata->socket_lock);
        ret = get_request(bedata, &req_id);
        if (ret < 0) {
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        req = RING_GET_REQUEST(&bedata->ring, req_id);
@@ -684,7 +684,7 @@ int pvcalls_front_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
        bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
 
        map->passive.status = PVCALLS_STATUS_BIND;
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return 0;
 }
 
@@ -695,21 +695,13 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
        struct xen_pvcalls_request *req;
        int notify, req_id, ret;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        if (map->passive.status != PVCALLS_STATUS_BIND) {
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -EOPNOTSUPP;
        }
 
@@ -717,7 +709,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
        ret = get_request(bedata, &req_id);
        if (ret < 0) {
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        req = RING_GET_REQUEST(&bedata->ring, req_id);
@@ -741,7 +733,7 @@ int pvcalls_front_listen(struct socket *sock, int backlog)
        bedata->rsp[req_id].req_id = PVCALLS_INVALID_ID;
 
        map->passive.status = PVCALLS_STATUS_LISTEN;
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return ret;
 }
 
@@ -753,21 +745,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
        struct xen_pvcalls_request *req;
        int notify, req_id, ret, evtchn, nonblock;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -ENOTCONN;
-       }
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
+               return PTR_ERR(map);
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return -ENOTSOCK;
-       }
-
        if (map->passive.status != PVCALLS_STATUS_LISTEN) {
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -EINVAL;
        }
 
@@ -785,13 +769,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
                        goto received;
                }
                if (nonblock) {
-                       pvcalls_exit();
+                       pvcalls_exit_sock(sock);
                        return -EAGAIN;
                }
                if (wait_event_interruptible(map->passive.inflight_accept_req,
                        !test_and_set_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                                          (void *)&map->passive.flags))) {
-                       pvcalls_exit();
+                       pvcalls_exit_sock(sock);
                        return -EINTR;
                }
        }
@@ -802,7 +786,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
                clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                          (void *)&map->passive.flags);
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        map2 = kzalloc(sizeof(*map2), GFP_ATOMIC);
@@ -810,7 +794,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
                clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                          (void *)&map->passive.flags);
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -ENOMEM;
        }
        ret = create_active(map2, &evtchn);
@@ -819,7 +803,7 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
                clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                          (void *)&map->passive.flags);
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        list_add_tail(&map2->list, &bedata->socket_mappings);
@@ -841,13 +825,13 @@ int pvcalls_front_accept(struct socket *sock, struct socket *newsock, int flags)
        /* We could check if we have received a response before returning. */
        if (nonblock) {
                WRITE_ONCE(map->passive.inflight_req_id, req_id);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -EAGAIN;
        }
 
        if (wait_event_interruptible(bedata->inflight_req,
                READ_ONCE(bedata->rsp[req_id].req_id) == req_id)) {
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -EINTR;
        }
        /* read req_id, then the content */
@@ -862,7 +846,7 @@ received:
                clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT,
                          (void *)&map->passive.flags);
                pvcalls_front_free_map(bedata, map2);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return -ENOMEM;
        }
        newsock->sk->sk_send_head = (void *)map2;
@@ -874,7 +858,7 @@ received:
        clear_bit(PVCALLS_FLAG_ACCEPT_INFLIGHT, (void *)&map->passive.flags);
        wake_up(&map->passive.inflight_accept_req);
 
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return ret;
 }
 
@@ -965,23 +949,16 @@ __poll_t pvcalls_front_poll(struct file *file, struct socket *sock,
        struct sock_mapping *map;
        __poll_t ret;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map))
                return EPOLLNVAL;
-       }
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (!map) {
-               pvcalls_exit();
-               return EPOLLNVAL;
-       }
        if (map->active_socket)
                ret = pvcalls_front_poll_active(file, bedata, map, wait);
        else
                ret = pvcalls_front_poll_passive(file, bedata, map, wait);
-       pvcalls_exit();
+       pvcalls_exit_sock(sock);
        return ret;
 }
 
@@ -995,25 +972,20 @@ int pvcalls_front_release(struct socket *sock)
        if (sock->sk == NULL)
                return 0;
 
-       pvcalls_enter();
-       if (!pvcalls_front_dev) {
-               pvcalls_exit();
-               return -EIO;
+       map = pvcalls_enter_sock(sock);
+       if (IS_ERR(map)) {
+               if (PTR_ERR(map) == -ENOTCONN)
+                       return -EIO;
+               else
+                       return 0;
        }
-
        bedata = dev_get_drvdata(&pvcalls_front_dev->dev);
 
-       map = (struct sock_mapping *) sock->sk->sk_send_head;
-       if (map == NULL) {
-               pvcalls_exit();
-               return 0;
-       }
-
        spin_lock(&bedata->socket_lock);
        ret = get_request(bedata, &req_id);
        if (ret < 0) {
                spin_unlock(&bedata->socket_lock);
-               pvcalls_exit();
+               pvcalls_exit_sock(sock);
                return ret;
        }
        sock->sk->sk_send_head = NULL;
@@ -1043,14 +1015,20 @@ int pvcalls_front_release(struct socket *sock)
                /*
                 * We need to make sure that sendmsg/recvmsg on this socket have
                 * not started before we've cleared sk_send_head here. The
-                * easiest (though not optimal) way to guarantee this is to see
-                * that no pvcall (other than us) is in progress.
+                * easiest way to guarantee this is to see that no pvcalls
+                * (other than us) is in progress on this socket.
                 */
-               while (atomic_read(&pvcalls_refcount) > 1)
+               while (atomic_read(&map->refcount) > 1)
                        cpu_relax();
 
                pvcalls_front_free_map(bedata, map);
        } else {
+               wake_up(&bedata->inflight_req);
+               wake_up(&map->passive.inflight_accept_req);
+
+               while (atomic_read(&map->refcount) > 1)
+                       cpu_relax();
+
                spin_lock(&bedata->socket_lock);
                list_del(&map->list);
                spin_unlock(&bedata->socket_lock);
index bf13d1e..04e7b3b 100644 (file)
@@ -284,6 +284,10 @@ static int tmem_frontswap_store(unsigned type, pgoff_t offset,
        int pool = tmem_frontswap_poolid;
        int ret;
 
+       /* THP isn't supported */
+       if (PageTransHuge(page))
+               return -1;
+
        if (pool < 0)
                return -1;
        if (ind64 != ind)
index 149c5e7..0929811 100644 (file)
@@ -76,6 +76,7 @@ struct xb_req_data {
        struct list_head list;
        wait_queue_head_t wq;
        struct xsd_sockmsg msg;
+       uint32_t caller_req_id;
        enum xsd_sockmsg_type type;
        char *body;
        const struct kvec *vec;
index 5b081a0..d239fc3 100644 (file)
@@ -309,6 +309,7 @@ static int process_msg(void)
                        goto out;
 
                if (req->state == xb_req_state_wait_reply) {
+                       req->msg.req_id = req->caller_req_id;
                        req->msg.type = state.msg.type;
                        req->msg.len = state.msg.len;
                        req->body = state.body;
index 74888ca..ec9eb4f 100644 (file)
@@ -466,8 +466,11 @@ int xenbus_probe_node(struct xen_bus_type *bus,
 
        /* Register with generic device framework. */
        err = device_register(&xendev->dev);
-       if (err)
+       if (err) {
+               put_device(&xendev->dev);
+               xendev = NULL;
                goto fail;
+       }
 
        return 0;
 fail:
index 3e59590..3f3b293 100644 (file)
@@ -227,6 +227,8 @@ static void xs_send(struct xb_req_data *req, struct xsd_sockmsg *msg)
        req->state = xb_req_state_queued;
        init_waitqueue_head(&req->wq);
 
+       /* Save the caller req_id and restore it later in the reply */
+       req->caller_req_id = req->msg.req_id;
        req->msg.req_id = xs_request_enter(req);
 
        mutex_lock(&xb_write_mutex);
@@ -310,6 +312,7 @@ static void *xs_talkv(struct xenbus_transaction t,
        req->num_vecs = num_vecs;
        req->cb = xs_wake_up;
 
+       msg.req_id = 0;
        msg.tx_id = t.id;
        msg.type = type;
        msg.len = 0;
index a062d75..6bcd3fb 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -68,9 +68,9 @@ struct aio_ring {
 #define AIO_RING_PAGES 8
 
 struct kioctx_table {
-       struct rcu_head rcu;
-       unsigned        nr;
-       struct kioctx   *table[];
+       struct rcu_head         rcu;
+       unsigned                nr;
+       struct kioctx __rcu     *table[];
 };
 
 struct kioctx_cpu {
@@ -115,7 +115,8 @@ struct kioctx {
        struct page             **ring_pages;
        long                    nr_pages;
 
-       struct work_struct      free_work;
+       struct rcu_head         free_rcu;
+       struct work_struct      free_work;      /* see free_ioctx() */
 
        /*
         * signals when all in-flight requests are done
@@ -329,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma)
        for (i = 0; i < table->nr; i++) {
                struct kioctx *ctx;
 
-               ctx = table->table[i];
+               ctx = rcu_dereference(table->table[i]);
                if (ctx && ctx->aio_ring_file == file) {
                        if (!atomic_read(&ctx->dead)) {
                                ctx->user_id = ctx->mmap_base = vma->vm_start;
@@ -588,6 +589,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb)
        return cancel(&kiocb->common);
 }
 
+/*
+ * free_ioctx() should be RCU delayed to synchronize against the RCU
+ * protected lookup_ioctx() and also needs process context to call
+ * aio_free_ring(), so the double bouncing through kioctx->free_rcu and
+ * ->free_work.
+ */
 static void free_ioctx(struct work_struct *work)
 {
        struct kioctx *ctx = container_of(work, struct kioctx, free_work);
@@ -601,6 +608,14 @@ static void free_ioctx(struct work_struct *work)
        kmem_cache_free(kioctx_cachep, ctx);
 }
 
+static void free_ioctx_rcufn(struct rcu_head *head)
+{
+       struct kioctx *ctx = container_of(head, struct kioctx, free_rcu);
+
+       INIT_WORK(&ctx->free_work, free_ioctx);
+       schedule_work(&ctx->free_work);
+}
+
 static void free_ioctx_reqs(struct percpu_ref *ref)
 {
        struct kioctx *ctx = container_of(ref, struct kioctx, reqs);
@@ -609,8 +624,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref)
        if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count))
                complete(&ctx->rq_wait->comp);
 
-       INIT_WORK(&ctx->free_work, free_ioctx);
-       schedule_work(&ctx->free_work);
+       /* Synchronize against RCU protected table->table[] dereferences */
+       call_rcu(&ctx->free_rcu, free_ioctx_rcufn);
 }
 
 /*
@@ -651,9 +666,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
        while (1) {
                if (table)
                        for (i = 0; i < table->nr; i++)
-                               if (!table->table[i]) {
+                               if (!rcu_access_pointer(table->table[i])) {
                                        ctx->id = i;
-                                       table->table[i] = ctx;
+                                       rcu_assign_pointer(table->table[i], ctx);
                                        spin_unlock(&mm->ioctx_lock);
 
                                        /* While kioctx setup is in progress,
@@ -834,11 +849,11 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx,
        }
 
        table = rcu_dereference_raw(mm->ioctx_table);
-       WARN_ON(ctx != table->table[ctx->id]);
-       table->table[ctx->id] = NULL;
+       WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id]));
+       RCU_INIT_POINTER(table->table[ctx->id], NULL);
        spin_unlock(&mm->ioctx_lock);
 
-       /* percpu_ref_kill() will do the necessary call_rcu() */
+       /* free_ioctx_reqs() will do the necessary RCU synchronization */
        wake_up_all(&ctx->wait);
 
        /*
@@ -880,7 +895,8 @@ void exit_aio(struct mm_struct *mm)
 
        skipped = 0;
        for (i = 0; i < table->nr; ++i) {
-               struct kioctx *ctx = table->table[i];
+               struct kioctx *ctx =
+                       rcu_dereference_protected(table->table[i], true);
 
                if (!ctx) {
                        skipped++;
@@ -1069,7 +1085,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
        if (!table || id >= table->nr)
                goto out;
 
-       ctx = table->table[id];
+       ctx = rcu_dereference(table->table[id]);
        if (ctx && ctx->user_id == ctx_id) {
                percpu_ref_get(&ctx->users);
                ret = ctx;
index 4a181fc..fe09ef9 100644 (file)
@@ -1058,6 +1058,27 @@ retry:
        return 0;
 }
 
+static struct gendisk *bdev_get_gendisk(struct block_device *bdev, int *partno)
+{
+       struct gendisk *disk = get_gendisk(bdev->bd_dev, partno);
+
+       if (!disk)
+               return NULL;
+       /*
+        * Now that we hold gendisk reference we make sure bdev we looked up is
+        * not stale. If it is, it means device got removed and created before
+        * we looked up gendisk and we fail open in such case. Associating
+        * unhashed bdev with newly created gendisk could lead to two bdevs
+        * (and thus two independent caches) being associated with one device
+        * which is bad.
+        */
+       if (inode_unhashed(bdev->bd_inode)) {
+               put_disk_and_module(disk);
+               return NULL;
+       }
+       return disk;
+}
+
 /**
  * bd_start_claiming - start claiming a block device
  * @bdev: block device of interest
@@ -1094,7 +1115,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
         * @bdev might not have been initialized properly yet, look up
         * and grab the outer block device the hard way.
         */
-       disk = get_gendisk(bdev->bd_dev, &partno);
+       disk = bdev_get_gendisk(bdev, &partno);
        if (!disk)
                return ERR_PTR(-ENXIO);
 
@@ -1111,8 +1132,7 @@ static struct block_device *bd_start_claiming(struct block_device *bdev,
        else
                whole = bdgrab(bdev);
 
-       module_put(disk->fops->owner);
-       put_disk(disk);
+       put_disk_and_module(disk);
        if (!whole)
                return ERR_PTR(-ENOMEM);
 
@@ -1407,10 +1427,10 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part);
 static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
 {
        struct gendisk *disk;
-       struct module *owner;
        int ret;
        int partno;
        int perm = 0;
+       bool first_open = false;
 
        if (mode & FMODE_READ)
                perm |= MAY_READ;
@@ -1430,14 +1450,14 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
  restart:
 
        ret = -ENXIO;
-       disk = get_gendisk(bdev->bd_dev, &partno);
+       disk = bdev_get_gendisk(bdev, &partno);
        if (!disk)
                goto out;
-       owner = disk->fops->owner;
 
        disk_block_events(disk);
        mutex_lock_nested(&bdev->bd_mutex, for_part);
        if (!bdev->bd_openers) {
+               first_open = true;
                bdev->bd_disk = disk;
                bdev->bd_queue = disk->queue;
                bdev->bd_contains = bdev;
@@ -1463,8 +1483,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                                        bdev->bd_queue = NULL;
                                        mutex_unlock(&bdev->bd_mutex);
                                        disk_unblock_events(disk);
-                                       put_disk(disk);
-                                       module_put(owner);
+                                       put_disk_and_module(disk);
                                        goto restart;
                                }
                        }
@@ -1524,15 +1543,15 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
                        if (ret)
                                goto out_unlock_bdev;
                }
-               /* only one opener holds refs to the module and disk */
-               put_disk(disk);
-               module_put(owner);
        }
        bdev->bd_openers++;
        if (for_part)
                bdev->bd_part_count++;
        mutex_unlock(&bdev->bd_mutex);
        disk_unblock_events(disk);
+       /* only one opener holds refs to the module and disk */
+       if (!first_open)
+               put_disk_and_module(disk);
        return 0;
 
  out_clear:
@@ -1546,8 +1565,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part)
  out_unlock_bdev:
        mutex_unlock(&bdev->bd_mutex);
        disk_unblock_events(disk);
-       put_disk(disk);
-       module_put(owner);
+       put_disk_and_module(disk);
  out:
        bdput(bdev);
 
@@ -1770,8 +1788,6 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
                        disk->fops->release(disk, mode);
        }
        if (!bdev->bd_openers) {
-               struct module *owner = disk->fops->owner;
-
                disk_put_part(bdev->bd_part);
                bdev->bd_part = NULL;
                bdev->bd_disk = NULL;
@@ -1779,8 +1795,7 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
                        victim = bdev->bd_contains;
                bdev->bd_contains = NULL;
 
-               put_disk(disk);
-               module_put(owner);
+               put_disk_and_module(disk);
        }
        mutex_unlock(&bdev->bd_mutex);
        bdput(bdev);
index e4054e5..2648464 100644 (file)
@@ -1264,7 +1264,16 @@ again:
        while (node) {
                ref = rb_entry(node, struct prelim_ref, rbnode);
                node = rb_next(&ref->rbnode);
-               WARN_ON(ref->count < 0);
+               /*
+                * ref->count < 0 can happen here if there are delayed
+                * refs with a node->action of BTRFS_DROP_DELAYED_REF.
+                * prelim_ref_insert() relies on this when merging
+                * identical refs to keep the overall count correct.
+                * prelim_ref_insert() will merge only those refs
+                * which compare identically.  Any refs having
+                * e.g. different offsets would not be merged,
+                * and would retain their original ref->count < 0.
+                */
                if (roots && ref->count && ref->root_id && ref->parent == 0) {
                        if (sc && sc->root_objectid &&
                            ref->root_id != sc->root_objectid) {
@@ -1510,6 +1519,7 @@ int btrfs_check_shared(struct btrfs_root *root, u64 inum, u64 bytenr)
                if (!node)
                        break;
                bytenr = node->val;
+               shared.share_count = 0;
                cond_resched();
        }
 
index 1a462ab..da30877 100644 (file)
@@ -2974,7 +2974,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
        kfree(fs_info->super_copy);
        kfree(fs_info->super_for_commit);
        security_free_mnt_opts(&fs_info->security_opts);
-       kfree(fs_info);
+       kvfree(fs_info);
 }
 
 /* tree mod log functions from ctree.c */
@@ -3095,7 +3095,10 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
                          u64 inode_objectid, u64 ref_objectid, int ins_len,
                          int cow);
 
-int btrfs_find_name_in_ext_backref(struct btrfs_path *path,
+int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,
+                              const char *name,
+                              int name_len, struct btrfs_inode_ref **ref_ret);
+int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
                                   u64 ref_objectid, const char *name,
                                   int name_len,
                                   struct btrfs_inode_extref **extref_ret);
index a1a40cf..7ab5e01 100644 (file)
@@ -821,7 +821,8 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
        spin_unlock(&delayed_refs->lock);
 
        if (qrecord_inserted)
-               return btrfs_qgroup_trace_extent_post(fs_info, record);
+               btrfs_qgroup_trace_extent_post(fs_info, record);
+
        return 0;
 
 free_head_ref:
index 05751a6..c1618ab 100644 (file)
@@ -2147,6 +2147,10 @@ int btrfs_discard_extent(struct btrfs_fs_info *fs_info, u64 bytenr,
                        u64 bytes;
                        struct request_queue *req_q;
 
+                       if (!stripe->dev->bdev) {
+                               ASSERT(btrfs_test_opt(fs_info, DEGRADED));
+                               continue;
+                       }
                        req_q = bdev_get_queue(stripe->dev->bdev);
                        if (!blk_queue_discard(req_q))
                                continue;
index 39c968f..65e1a76 100644 (file)
 #include "transaction.h"
 #include "print-tree.h"
 
-static int find_name_in_backref(struct btrfs_path *path, const char *name,
-                        int name_len, struct btrfs_inode_ref **ref_ret)
+int btrfs_find_name_in_backref(struct extent_buffer *leaf, int slot,
+                              const char *name,
+                              int name_len, struct btrfs_inode_ref **ref_ret)
 {
-       struct extent_buffer *leaf;
        struct btrfs_inode_ref *ref;
        unsigned long ptr;
        unsigned long name_ptr;
@@ -33,9 +33,8 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
        u32 cur_offset = 0;
        int len;
 
-       leaf = path->nodes[0];
-       item_size = btrfs_item_size_nr(leaf, path->slots[0]);
-       ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+       item_size = btrfs_item_size_nr(leaf, slot);
+       ptr = btrfs_item_ptr_offset(leaf, slot);
        while (cur_offset < item_size) {
                ref = (struct btrfs_inode_ref *)(ptr + cur_offset);
                len = btrfs_inode_ref_name_len(leaf, ref);
@@ -44,18 +43,19 @@ static int find_name_in_backref(struct btrfs_path *path, const char *name,
                if (len != name_len)
                        continue;
                if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) {
-                       *ref_ret = ref;
+                       if (ref_ret)
+                               *ref_ret = ref;
                        return 1;
                }
        }
        return 0;
 }
 
-int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
+int btrfs_find_name_in_ext_backref(struct extent_buffer *leaf, int slot,
+                                  u64 ref_objectid,
                                   const char *name, int name_len,
                                   struct btrfs_inode_extref **extref_ret)
 {
-       struct extent_buffer *leaf;
        struct btrfs_inode_extref *extref;
        unsigned long ptr;
        unsigned long name_ptr;
@@ -63,9 +63,8 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
        u32 cur_offset = 0;
        int ref_name_len;
 
-       leaf = path->nodes[0];
-       item_size = btrfs_item_size_nr(leaf, path->slots[0]);
-       ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+       item_size = btrfs_item_size_nr(leaf, slot);
+       ptr = btrfs_item_ptr_offset(leaf, slot);
 
        /*
         * Search all extended backrefs in this item. We're only
@@ -113,7 +112,9 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
                return ERR_PTR(ret);
        if (ret > 0)
                return NULL;
-       if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref))
+       if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
+                                           ref_objectid, name, name_len,
+                                           &extref))
                return NULL;
        return extref;
 }
@@ -155,7 +156,8 @@ static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
         * This should always succeed so error here will make the FS
         * readonly.
         */
-       if (!btrfs_find_name_in_ext_backref(path, ref_objectid,
+       if (!btrfs_find_name_in_ext_backref(path->nodes[0], path->slots[0],
+                                           ref_objectid,
                                            name, name_len, &extref)) {
                btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL);
                ret = -EROFS;
@@ -225,7 +227,8 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
        } else if (ret < 0) {
                goto out;
        }
-       if (!find_name_in_backref(path, name, name_len, &ref)) {
+       if (!btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
+                                       name, name_len, &ref)) {
                ret = -ENOENT;
                search_ext_refs = 1;
                goto out;
@@ -293,7 +296,9 @@ static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans,
        ret = btrfs_insert_empty_item(trans, root, path, &key,
                                      ins_len);
        if (ret == -EEXIST) {
-               if (btrfs_find_name_in_ext_backref(path, ref_objectid,
+               if (btrfs_find_name_in_ext_backref(path->nodes[0],
+                                                  path->slots[0],
+                                                  ref_objectid,
                                                   name, name_len, NULL))
                        goto out;
 
@@ -351,7 +356,8 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
        if (ret == -EEXIST) {
                u32 old_size;
 
-               if (find_name_in_backref(path, name, name_len, &ref))
+               if (btrfs_find_name_in_backref(path->nodes[0], path->slots[0],
+                                              name, name_len, &ref))
                        goto out;
 
                old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]);
@@ -365,7 +371,9 @@ int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans,
                ret = 0;
        } else if (ret < 0) {
                if (ret == -EOVERFLOW) {
-                       if (find_name_in_backref(path, name, name_len, &ref))
+                       if (btrfs_find_name_in_backref(path->nodes[0],
+                                                      path->slots[0],
+                                                      name, name_len, &ref))
                                ret = -EEXIST;
                        else
                                ret = -EMLINK;
index 53ca025..f534701 100644 (file)
@@ -1335,8 +1335,11 @@ next_slot:
                leaf = path->nodes[0];
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
                        ret = btrfs_next_leaf(root, path);
-                       if (ret < 0)
+                       if (ret < 0) {
+                               if (cow_start != (u64)-1)
+                                       cur_offset = cow_start;
                                goto error;
+                       }
                        if (ret > 0)
                                break;
                        leaf = path->nodes[0];
@@ -2040,12 +2043,15 @@ static noinline int add_pending_csums(struct btrfs_trans_handle *trans,
                             struct inode *inode, struct list_head *list)
 {
        struct btrfs_ordered_sum *sum;
+       int ret;
 
        list_for_each_entry(sum, list, list) {
                trans->adding_csums = true;
-               btrfs_csum_file_blocks(trans,
+               ret = btrfs_csum_file_blocks(trans,
                       BTRFS_I(inode)->root->fs_info->csum_root, sum);
                trans->adding_csums = false;
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -3059,7 +3065,11 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                goto out;
        }
 
-       add_pending_csums(trans, inode, &ordered_extent->list);
+       ret = add_pending_csums(trans, inode, &ordered_extent->list);
+       if (ret) {
+               btrfs_abort_transaction(trans, ret);
+               goto out;
+       }
 
        btrfs_ordered_update_i_size(inode, 0, ordered_extent);
        ret = btrfs_update_inode_fallback(trans, root, inode);
@@ -3385,6 +3395,11 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
                ret = btrfs_orphan_reserve_metadata(trans, inode);
                ASSERT(!ret);
                if (ret) {
+                       /*
+                        * dec doesn't need spin_lock as ->orphan_block_rsv
+                        * would be released only if ->orphan_inodes is
+                        * zero.
+                        */
                        atomic_dec(&root->orphan_inodes);
                        clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                                  &inode->runtime_flags);
@@ -3399,12 +3414,17 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans,
        if (insert >= 1) {
                ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
                if (ret) {
-                       atomic_dec(&root->orphan_inodes);
                        if (reserve) {
                                clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                                          &inode->runtime_flags);
                                btrfs_orphan_release_metadata(inode);
                        }
+                       /*
+                        * btrfs_orphan_commit_root may race with us and set
+                        * ->orphan_block_rsv to zero, in order to avoid that,
+                        * decrease ->orphan_inodes after everything is done.
+                        */
+                       atomic_dec(&root->orphan_inodes);
                        if (ret != -EEXIST) {
                                clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                                          &inode->runtime_flags);
@@ -3436,28 +3456,26 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,
 {
        struct btrfs_root *root = inode->root;
        int delete_item = 0;
-       int release_rsv = 0;
        int ret = 0;
 
-       spin_lock(&root->orphan_lock);
        if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                               &inode->runtime_flags))
                delete_item = 1;
 
+       if (delete_item && trans)
+               ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
+
        if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
                               &inode->runtime_flags))
-               release_rsv = 1;
-       spin_unlock(&root->orphan_lock);
+               btrfs_orphan_release_metadata(inode);
 
-       if (delete_item) {
+       /*
+        * btrfs_orphan_commit_root may race with us and set ->orphan_block_rsv
+        * to zero, in order to avoid that, decrease ->orphan_inodes after
+        * everything is done.
+        */
+       if (delete_item)
                atomic_dec(&root->orphan_inodes);
-               if (trans)
-                       ret = btrfs_del_orphan_item(trans, root,
-                                                   btrfs_ino(inode));
-       }
-
-       if (release_rsv)
-               btrfs_orphan_release_metadata(inode);
 
        return ret;
 }
@@ -5281,7 +5299,7 @@ void btrfs_evict_inode(struct inode *inode)
        trace_btrfs_inode_evict(inode);
 
        if (!root) {
-               kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
+               clear_inode(inode);
                return;
        }
 
index 9e61dd6..aa259d6 100644 (file)
@@ -1442,8 +1442,13 @@ int btrfs_qgroup_trace_extent_post(struct btrfs_fs_info *fs_info,
        int ret;
 
        ret = btrfs_find_all_roots(NULL, fs_info, bytenr, 0, &old_root, false);
-       if (ret < 0)
-               return ret;
+       if (ret < 0) {
+               fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
+               btrfs_warn(fs_info,
+"error accounting new delayed refs extent (err code: %d), quota inconsistent",
+                       ret);
+               return 0;
+       }
 
        /*
         * Here we don't need to get the lock of
index dec0907..fcfc20d 100644 (file)
@@ -1370,6 +1370,7 @@ static int find_bio_stripe(struct btrfs_raid_bio *rbio,
                stripe_start = stripe->physical;
                if (physical >= stripe_start &&
                    physical < stripe_start + rbio->stripe_len &&
+                   stripe->dev->bdev &&
                    bio->bi_disk == stripe->dev->bdev->bd_disk &&
                    bio->bi_partno == stripe->dev->bdev->bd_partno) {
                        return i;
index f0c3f00..cd2298d 100644 (file)
@@ -3268,8 +3268,22 @@ static int relocate_file_extent_cluster(struct inode *inode,
                        nr++;
                }
 
-               btrfs_set_extent_delalloc(inode, page_start, page_end, 0, NULL,
-                                         0);
+               ret = btrfs_set_extent_delalloc(inode, page_start, page_end, 0,
+                                               NULL, 0);
+               if (ret) {
+                       unlock_page(page);
+                       put_page(page);
+                       btrfs_delalloc_release_metadata(BTRFS_I(inode),
+                                                        PAGE_SIZE);
+                       btrfs_delalloc_release_extents(BTRFS_I(inode),
+                                                      PAGE_SIZE);
+
+                       clear_extent_bits(&BTRFS_I(inode)->io_tree,
+                                         page_start, page_end,
+                                         EXTENT_LOCKED | EXTENT_BOUNDARY);
+                       goto out;
+
+               }
                set_page_dirty(page);
 
                unlock_extent(&BTRFS_I(inode)->io_tree,
index f306c60..484e2af 100644 (file)
@@ -5005,6 +5005,9 @@ static int send_hole(struct send_ctx *sctx, u64 end)
        u64 len;
        int ret = 0;
 
+       if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA)
+               return send_update_extent(sctx, offset, end - offset);
+
        p = fs_path_alloc();
        if (!p)
                return -ENOMEM;
index 6e71a2a..4b81794 100644 (file)
@@ -1545,7 +1545,7 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
         * it for searching for existing supers, so this lets us do that and
         * then open_ctree will properly initialize everything later.
         */
-       fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
+       fs_info = kvzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
        if (!fs_info) {
                error = -ENOMEM;
                goto error_sec_opts;
index afadaad..4344577 100644 (file)
@@ -29,6 +29,7 @@
 #include "hash.h"
 #include "compression.h"
 #include "qgroup.h"
+#include "inode-map.h"
 
 /* magic values for the inode_only field in btrfs_log_inode:
  *
@@ -966,7 +967,9 @@ static noinline int backref_in_log(struct btrfs_root *log,
        ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]);
 
        if (key->type == BTRFS_INODE_EXTREF_KEY) {
-               if (btrfs_find_name_in_ext_backref(path, ref_objectid,
+               if (btrfs_find_name_in_ext_backref(path->nodes[0],
+                                                  path->slots[0],
+                                                  ref_objectid,
                                                   name, namelen, NULL))
                        match = 1;
 
@@ -1190,7 +1193,8 @@ static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
        read_extent_buffer(eb, *name, (unsigned long)&extref->name,
                           *namelen);
 
-       *index = btrfs_inode_extref_index(eb, extref);
+       if (index)
+               *index = btrfs_inode_extref_index(eb, extref);
        if (parent_objectid)
                *parent_objectid = btrfs_inode_extref_parent(eb, extref);
 
@@ -1211,12 +1215,102 @@ static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr,
 
        read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen);
 
-       *index = btrfs_inode_ref_index(eb, ref);
+       if (index)
+               *index = btrfs_inode_ref_index(eb, ref);
 
        return 0;
 }
 
 /*
+ * Take an inode reference item from the log tree and iterate all names from the
+ * inode reference item in the subvolume tree with the same key (if it exists).
+ * For any name that is not in the inode reference item from the log tree, do a
+ * proper unlink of that name (that is, remove its entry from the inode
+ * reference item and both dir index keys).
+ */
+static int unlink_old_inode_refs(struct btrfs_trans_handle *trans,
+                                struct btrfs_root *root,
+                                struct btrfs_path *path,
+                                struct btrfs_inode *inode,
+                                struct extent_buffer *log_eb,
+                                int log_slot,
+                                struct btrfs_key *key)
+{
+       int ret;
+       unsigned long ref_ptr;
+       unsigned long ref_end;
+       struct extent_buffer *eb;
+
+again:
+       btrfs_release_path(path);
+       ret = btrfs_search_slot(NULL, root, key, path, 0, 0);
+       if (ret > 0) {
+               ret = 0;
+               goto out;
+       }
+       if (ret < 0)
+               goto out;
+
+       eb = path->nodes[0];
+       ref_ptr = btrfs_item_ptr_offset(eb, path->slots[0]);
+       ref_end = ref_ptr + btrfs_item_size_nr(eb, path->slots[0]);
+       while (ref_ptr < ref_end) {
+               char *name = NULL;
+               int namelen;
+               u64 parent_id;
+
+               if (key->type == BTRFS_INODE_EXTREF_KEY) {
+                       ret = extref_get_fields(eb, ref_ptr, &namelen, &name,
+                                               NULL, &parent_id);
+               } else {
+                       parent_id = key->offset;
+                       ret = ref_get_fields(eb, ref_ptr, &namelen, &name,
+                                            NULL);
+               }
+               if (ret)
+                       goto out;
+
+               if (key->type == BTRFS_INODE_EXTREF_KEY)
+                       ret = btrfs_find_name_in_ext_backref(log_eb, log_slot,
+                                                            parent_id, name,
+                                                            namelen, NULL);
+               else
+                       ret = btrfs_find_name_in_backref(log_eb, log_slot, name,
+                                                        namelen, NULL);
+
+               if (!ret) {
+                       struct inode *dir;
+
+                       btrfs_release_path(path);
+                       dir = read_one_inode(root, parent_id);
+                       if (!dir) {
+                               ret = -ENOENT;
+                               kfree(name);
+                               goto out;
+                       }
+                       ret = btrfs_unlink_inode(trans, root, BTRFS_I(dir),
+                                                inode, name, namelen);
+                       kfree(name);
+                       iput(dir);
+                       if (ret)
+                               goto out;
+                       goto again;
+               }
+
+               kfree(name);
+               ref_ptr += namelen;
+               if (key->type == BTRFS_INODE_EXTREF_KEY)
+                       ref_ptr += sizeof(struct btrfs_inode_extref);
+               else
+                       ref_ptr += sizeof(struct btrfs_inode_ref);
+       }
+       ret = 0;
+ out:
+       btrfs_release_path(path);
+       return ret;
+}
+
+/*
  * replay one inode back reference item found in the log tree.
  * eb, slot and key refer to the buffer and key found in the log tree.
  * root is the destination we are replaying into, and path is for temp
@@ -1344,6 +1438,19 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                }
        }
 
+       /*
+        * Before we overwrite the inode reference item in the subvolume tree
+        * with the item from the log tree, we must unlink all names from the
+        * parent directory that are in the subvolume's tree inode reference
+        * item, otherwise we end up with an inconsistent subvolume tree where
+        * dir index entries exist for a name but there is no inode reference
+        * item with the same name.
+        */
+       ret = unlink_old_inode_refs(trans, root, path, BTRFS_I(inode), eb, slot,
+                                   key);
+       if (ret)
+               goto out;
+
        /* finally write the back reference in the inode */
        ret = overwrite_item(trans, root, path, eb, slot, key);
 out:
@@ -2472,6 +2579,9 @@ static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans,
                                        clean_tree_block(fs_info, next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
 
                                WARN_ON(root_owner !=
@@ -2552,6 +2662,9 @@ static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans,
                                        clean_tree_block(fs_info, next);
                                        btrfs_wait_tree_block_writeback(next);
                                        btrfs_tree_unlock(next);
+                               } else {
+                                       if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                               clear_extent_buffer_dirty(next);
                                }
 
                                WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID);
@@ -2630,6 +2743,9 @@ static int walk_log_tree(struct btrfs_trans_handle *trans,
                                clean_tree_block(fs_info, next);
                                btrfs_wait_tree_block_writeback(next);
                                btrfs_tree_unlock(next);
+                       } else {
+                               if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &next->bflags))
+                                       clear_extent_buffer_dirty(next);
                        }
 
                        WARN_ON(log->root_key.objectid !=
@@ -3018,13 +3134,14 @@ static void free_log_tree(struct btrfs_trans_handle *trans,
 
        while (1) {
                ret = find_first_extent_bit(&log->dirty_log_pages,
-                               0, &start, &end, EXTENT_DIRTY | EXTENT_NEW,
+                               0, &start, &end,
+                               EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT,
                                NULL);
                if (ret)
                        break;
 
                clear_extent_bits(&log->dirty_log_pages, start, end,
-                                 EXTENT_DIRTY | EXTENT_NEW);
+                                 EXTENT_DIRTY | EXTENT_NEW | EXTENT_NEED_WAIT);
        }
 
        /*
@@ -5677,6 +5794,23 @@ again:
                                                      path);
                }
 
+               if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) {
+                       struct btrfs_root *root = wc.replay_dest;
+
+                       btrfs_release_path(path);
+
+                       /*
+                        * We have just replayed everything, and the highest
+                        * objectid of fs roots probably has changed in case
+                        * some inode_item's got replayed.
+                        *
+                        * root->objectid_mutex is not acquired as log replay
+                        * could only happen during mount.
+                        */
+                       ret = btrfs_find_highest_objectid(root,
+                                                 &root->highest_objectid);
+               }
+
                key.offset = found_key.offset - 1;
                wc.replay_dest->log_root = NULL;
                free_extent_buffer(log->node);
@@ -5825,7 +5959,7 @@ int btrfs_log_new_name(struct btrfs_trans_handle *trans,
         * this will force the logging code to walk the dentry chain
         * up for the file
         */
-       if (S_ISREG(inode->vfs_inode.i_mode))
+       if (!S_ISDIR(inode->vfs_inode.i_mode))
                inode->last_unlink_trans = trans->transid;
 
        /*
index b5036bd..b2d05c6 100644 (file)
@@ -645,6 +645,7 @@ static void btrfs_free_stale_devices(const char *path,
                                btrfs_sysfs_remove_fsid(fs_devs);
                                list_del(&fs_devs->list);
                                free_fs_devices(fs_devs);
+                               break;
                        } else {
                                fs_devs->num_devices--;
                                list_del(&dev->dev_list);
@@ -4828,10 +4829,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
        ndevs = min(ndevs, devs_max);
 
        /*
-        * the primary goal is to maximize the number of stripes, so use as many
-        * devices as possible, even if the stripes are not maximum sized.
+        * The primary goal is to maximize the number of stripes, so use as
+        * many devices as possible, even if the stripes are not maximum sized.
+        *
+        * The DUP profile stores more than one stripe per device, the
+        * max_avail is the total size so we have to adjust.
         */
-       stripe_size = devices_info[ndevs-1].max_avail;
+       stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes);
        num_stripes = ndevs * dev_stripes;
 
        /*
@@ -4866,8 +4870,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                        stripe_size = devices_info[ndevs-1].max_avail;
        }
 
-       stripe_size = div_u64(stripe_size, dev_stripes);
-
        /* align to BTRFS_STRIPE_LEN */
        stripe_size = round_down(stripe_size, BTRFS_STRIPE_LEN);
 
index 6582c45..0e5bd3e 100644 (file)
@@ -3965,6 +3965,32 @@ void ceph_put_fmode(struct ceph_inode_info *ci, int fmode)
 }
 
 /*
+ * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps. If it
+ * looks like the link count will hit 0, drop any other caps (other
+ * than PIN) we don't specifically want (due to the file still being
+ * open).
+ */
+int ceph_drop_caps_for_unlink(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
+
+       spin_lock(&ci->i_ceph_lock);
+       if (inode->i_nlink == 1) {
+               drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
+
+               ci->i_ceph_flags |= CEPH_I_NODELAY;
+               if (__ceph_caps_dirty(ci)) {
+                       struct ceph_mds_client *mdsc =
+                               ceph_inode_to_client(inode)->mdsc;
+                       __cap_delay_requeue_front(mdsc, ci);
+               }
+       }
+       spin_unlock(&ci->i_ceph_lock);
+       return drop;
+}
+
+/*
  * Helpers for embedding cap and dentry lease releases into mds
  * requests.
  *
index 0c43468..f1d9c6c 100644 (file)
@@ -1003,26 +1003,6 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
 }
 
 /*
- * For a soon-to-be unlinked file, drop the AUTH_RDCACHE caps.  If it
- * looks like the link count will hit 0, drop any other caps (other
- * than PIN) we don't specifically want (due to the file still being
- * open).
- */
-static int drop_caps_for_unlink(struct inode *inode)
-{
-       struct ceph_inode_info *ci = ceph_inode(inode);
-       int drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
-
-       spin_lock(&ci->i_ceph_lock);
-       if (inode->i_nlink == 1) {
-               drop |= ~(__ceph_caps_wanted(ci) | CEPH_CAP_PIN);
-               ci->i_ceph_flags |= CEPH_I_NODELAY;
-       }
-       spin_unlock(&ci->i_ceph_lock);
-       return drop;
-}
-
-/*
  * rmdir and unlink are differ only by the metadata op code
  */
 static int ceph_unlink(struct inode *dir, struct dentry *dentry)
@@ -1056,7 +1036,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
        set_bit(CEPH_MDS_R_PARENT_LOCKED, &req->r_req_flags);
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
-       req->r_inode_drop = drop_caps_for_unlink(inode);
+       req->r_inode_drop = ceph_drop_caps_for_unlink(inode);
        err = ceph_mdsc_do_request(mdsc, dir, req);
        if (!err && !req->r_reply_info.head->is_dentry)
                d_delete(dentry);
@@ -1104,8 +1084,10 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
        /* release LINK_RDCACHE on source inode (mds will lock it) */
        req->r_old_inode_drop = CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL;
-       if (d_really_is_positive(new_dentry))
-               req->r_inode_drop = drop_caps_for_unlink(d_inode(new_dentry));
+       if (d_really_is_positive(new_dentry)) {
+               req->r_inode_drop =
+                       ceph_drop_caps_for_unlink(d_inode(new_dentry));
+       }
        err = ceph_mdsc_do_request(mdsc, old_dir, req);
        if (!err && !req->r_reply_info.head->is_dentry) {
                /*
index 6639926..b67eec3 100644 (file)
@@ -640,7 +640,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *to,
 struct ceph_aio_request {
        struct kiocb *iocb;
        size_t total_len;
-       int write;
+       bool write;
+       bool should_dirty;
        int error;
        struct list_head osd_reqs;
        unsigned num_reqs;
@@ -750,7 +751,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req)
                }
        }
 
-       ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write);
+       ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty);
        ceph_osdc_put_request(req);
 
        if (rc < 0)
@@ -847,6 +848,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
        size_t count = iov_iter_count(iter);
        loff_t pos = iocb->ki_pos;
        bool write = iov_iter_rw(iter) == WRITE;
+       bool should_dirty = !write && iter_is_iovec(iter);
 
        if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
@@ -914,6 +916,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                        if (aio_req) {
                                aio_req->iocb = iocb;
                                aio_req->write = write;
+                               aio_req->should_dirty = should_dirty;
                                INIT_LIST_HEAD(&aio_req->osd_reqs);
                                if (write) {
                                        aio_req->mtime = mtime;
@@ -971,7 +974,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter,
                                len = ret;
                }
 
-               ceph_put_page_vector(pages, num_pages, !write);
+               ceph_put_page_vector(pages, num_pages, should_dirty);
 
                ceph_osdc_put_request(req);
                if (ret < 0)
index a62d2a9..fb2bc9c 100644 (file)
@@ -225,6 +225,7 @@ static int parse_fsopt_token(char *c, void *private)
                        return -ENOMEM;
                break;
        case Opt_mds_namespace:
+               kfree(fsopt->mds_namespace);
                fsopt->mds_namespace = kstrndup(argstr[0].from,
                                                argstr[0].to-argstr[0].from,
                                                GFP_KERNEL);
@@ -232,6 +233,7 @@ static int parse_fsopt_token(char *c, void *private)
                        return -ENOMEM;
                break;
        case Opt_fscache_uniq:
+               kfree(fsopt->fscache_uniq);
                fsopt->fscache_uniq = kstrndup(argstr[0].from,
                                               argstr[0].to-argstr[0].from,
                                               GFP_KERNEL);
@@ -711,14 +713,17 @@ static int __init init_caches(void)
                goto bad_dentry;
 
        ceph_file_cachep = KMEM_CACHE(ceph_file_info, SLAB_MEM_SPREAD);
-
        if (!ceph_file_cachep)
                goto bad_file;
 
-       if ((error = ceph_fscache_register()))
-               goto bad_file;
+       error = ceph_fscache_register();
+       if (error)
+               goto bad_fscache;
 
        return 0;
+
+bad_fscache:
+       kmem_cache_destroy(ceph_file_cachep);
 bad_file:
        kmem_cache_destroy(ceph_dentry_cachep);
 bad_dentry:
@@ -836,7 +841,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
        int err;
        unsigned long started = jiffies;  /* note the start time */
        struct dentry *root;
-       int first = 0;   /* first vfsmount for this super_block */
 
        dout("mount start %p\n", fsc);
        mutex_lock(&fsc->client->mount_mutex);
@@ -861,17 +865,17 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
                        path = fsc->mount_options->server_path + 1;
                        dout("mount opening path %s\n", path);
                }
+
+               err = ceph_fs_debugfs_init(fsc);
+               if (err < 0)
+                       goto out;
+
                root = open_root_dentry(fsc, path, started);
                if (IS_ERR(root)) {
                        err = PTR_ERR(root);
                        goto out;
                }
                fsc->sb->s_root = dget(root);
-               first = 1;
-
-               err = ceph_fs_debugfs_init(fsc);
-               if (err < 0)
-                       goto fail;
        } else {
                root = dget(fsc->sb->s_root);
        }
@@ -881,11 +885,6 @@ static struct dentry *ceph_real_mount(struct ceph_fs_client *fsc)
        mutex_unlock(&fsc->client->mount_mutex);
        return root;
 
-fail:
-       if (first) {
-               dput(fsc->sb->s_root);
-               fsc->sb->s_root = NULL;
-       }
 out:
        mutex_unlock(&fsc->client->mount_mutex);
        return ERR_PTR(err);
index 21b2e5b..1c2086e 100644 (file)
@@ -987,7 +987,7 @@ extern void ceph_check_caps(struct ceph_inode_info *ci, int flags,
                            struct ceph_mds_session *session);
 extern void ceph_check_delayed_caps(struct ceph_mds_client *mdsc);
 extern void ceph_flush_dirty_caps(struct ceph_mds_client *mdsc);
-
+extern int  ceph_drop_caps_for_unlink(struct inode *inode);
 extern int ceph_encode_inode_release(void **p, struct inode *inode,
                                     int mds, int drop, int unless, int force);
 extern int ceph_encode_dentry_release(void **p, struct dentry *dn,
index 7c38f39..8945e6c 100644 (file)
@@ -647,11 +647,16 @@ again:
                spin_unlock(&parent->d_lock);
                goto again;
        }
-       rcu_read_unlock();
-       if (parent != dentry)
+       if (parent != dentry) {
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-       else
+               if (unlikely(dentry->d_lockref.count < 0)) {
+                       spin_unlock(&parent->d_lock);
+                       parent = NULL;
+               }
+       } else {
                parent = NULL;
+       }
+       rcu_read_unlock();
        return parent;
 }
 
@@ -2474,7 +2479,7 @@ struct dentry *d_alloc_parallel(struct dentry *parent,
 
 retry:
        rcu_read_lock();
-       seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1;
+       seq = smp_load_acquire(&parent->d_inode->i_dir_seq);
        r_seq = read_seqbegin(&rename_lock);
        dentry = __d_lookup_rcu(parent, name, &d_seq);
        if (unlikely(dentry)) {
@@ -2495,8 +2500,14 @@ retry:
                rcu_read_unlock();
                goto retry;
        }
+
+       if (unlikely(seq & 1)) {
+               rcu_read_unlock();
+               goto retry;
+       }
+
        hlist_bl_lock(b);
-       if (unlikely(parent->d_inode->i_dir_seq != seq)) {
+       if (unlikely(READ_ONCE(parent->d_inode->i_dir_seq) != seq)) {
                hlist_bl_unlock(b);
                rcu_read_unlock();
                goto retry;
index a0ca9e4..1357ef5 100644 (file)
@@ -1274,8 +1274,7 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
         */
        if (dio->is_async && iov_iter_rw(iter) == WRITE) {
                retval = 0;
-               if ((iocb->ki_filp->f_flags & O_DSYNC) ||
-                   IS_SYNC(iocb->ki_filp->f_mapping->host))
+               if (iocb->ki_flags & IOCB_DSYNC)
                        retval = dio_set_defer_completion(dio);
                else if (!dio->inode->i_sb->s_dio_done_wq) {
                        /*
index 5f22e74..8e56842 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/efi.h>
+#include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/slab.h>
 #include <linux/mount.h>
@@ -74,6 +75,11 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf,
        ssize_t size = 0;
        int err;
 
+       while (!__ratelimit(&file->f_cred->user->ratelimit)) {
+               if (!msleep_interruptible(50))
+                       return -EINTR;
+       }
+
        err = efivar_entry_size(var, &datasize);
 
        /*
index 86d6a44..51f940e 100644 (file)
@@ -807,9 +807,6 @@ do_alloc:
                        iomap->length = hole_size(inode, lblock, &mp);
                else
                        iomap->length = size - pos;
-       } else {
-               if (height <= ip->i_height)
-                       iomap->length = hole_size(inode, lblock, &mp);
        }
        goto out_release;
 }
index 8fe1b0a..b9a254d 100644 (file)
@@ -108,6 +108,16 @@ static void huge_pagevec_release(struct pagevec *pvec)
        pagevec_reinit(pvec);
 }
 
+/*
+ * Mask used when checking the page offset value passed in via system
+ * calls.  This value will be converted to a loff_t which is signed.
+ * Therefore, we want to check the upper PAGE_SHIFT + 1 bits of the
+ * value.  The extra bit (- 1 in the shift value) is to take the sign
+ * bit into account.
+ */
+#define PGOFF_LOFFT_MAX \
+       (((1UL << (PAGE_SHIFT + 1)) - 1) <<  (BITS_PER_LONG - (PAGE_SHIFT + 1)))
+
 static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file_inode(file);
@@ -127,12 +137,13 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
        vma->vm_ops = &hugetlb_vm_ops;
 
        /*
-        * Offset passed to mmap (before page shift) could have been
-        * negative when represented as a (l)off_t.
+        * page based offset in vm_pgoff could be sufficiently large to
+        * overflow a (l)off_t when converted to byte offset.
         */
-       if (((loff_t)vma->vm_pgoff << PAGE_SHIFT) < 0)
+       if (vma->vm_pgoff & PGOFF_LOFFT_MAX)
                return -EINVAL;
 
+       /* must be huge page aligned */
        if (vma->vm_pgoff & (~huge_page_mask(h) >> PAGE_SHIFT))
                return -EINVAL;
 
index 921ae32..cafa365 100644 (file)
@@ -559,9 +559,10 @@ static int __nd_alloc_stack(struct nameidata *nd)
 static bool path_connected(const struct path *path)
 {
        struct vfsmount *mnt = path->mnt;
+       struct super_block *sb = mnt->mnt_sb;
 
-       /* Only bind mounts can have disconnected paths */
-       if (mnt->mnt_root == mnt->mnt_sb->s_root)
+       /* Bind mounts and multi-root filesystems can have disconnected paths */
+       if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root))
                return true;
 
        return is_subdir(path->dentry, mnt->mnt_root);
index 2435af5..a50d781 100644 (file)
@@ -572,7 +572,7 @@ out:
 }
 
 static bool
-validate_bitmap_values(unsigned long mask)
+validate_bitmap_values(unsigned int mask)
 {
        return (mask & ~RCA4_TYPE_MASK_ALL) == 0;
 }
@@ -596,17 +596,15 @@ __be32 nfs4_callback_recallany(void *argp, void *resp,
                goto out;
 
        status = cpu_to_be32(NFS4_OK);
-       if (test_bit(RCA4_TYPE_MASK_RDATA_DLG, (const unsigned long *)
-                    &args->craa_type_mask))
+       if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_RDATA_DLG))
                flags = FMODE_READ;
-       if (test_bit(RCA4_TYPE_MASK_WDATA_DLG, (const unsigned long *)
-                    &args->craa_type_mask))
+       if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_WDATA_DLG))
                flags |= FMODE_WRITE;
-       if (test_bit(RCA4_TYPE_MASK_FILE_LAYOUT, (const unsigned long *)
-                    &args->craa_type_mask))
-               pnfs_recall_all_layouts(cps->clp);
        if (flags)
                nfs_expire_unused_delegation_types(cps->clp, flags);
+
+       if (args->craa_type_mask & BIT(RCA4_TYPE_MASK_FILE_LAYOUT))
+               pnfs_recall_all_layouts(cps->clp);
 out:
        dprintk("%s: exit with status = %d\n", __func__, ntohl(status));
        return status;
index 8c10b05..621c517 100644 (file)
@@ -86,10 +86,10 @@ struct nfs_direct_req {
        struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX];
        int                     mirror_count;
 
+       loff_t                  io_start;       /* Start offset for I/O */
        ssize_t                 count,          /* bytes actually processed */
                                max_count,      /* max expected count */
                                bytes_left,     /* bytes left to be sent */
-                               io_start,       /* start of IO */
                                error;          /* any reported error */
        struct completion       completion;     /* wait for i/o completion */
 
index 49f848f..7327930 100644 (file)
@@ -873,7 +873,7 @@ static void nfs3_nlm_release_call(void *data)
        }
 }
 
-const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = {
+static const struct nlmclnt_operations nlmclnt_fl_close_lock_ops = {
        .nlmclnt_alloc_call = nfs3_nlm_alloc_call,
        .nlmclnt_unlock_prepare = nfs3_nlm_unlock_prepare,
        .nlmclnt_release_call = nfs3_nlm_release_call,
index 04612c2..9796314 100644 (file)
@@ -868,8 +868,10 @@ static int nfs4_set_client(struct nfs_server *server,
        if (IS_ERR(clp))
                return PTR_ERR(clp);
 
-       if (server->nfs_client == clp)
+       if (server->nfs_client == clp) {
+               nfs_put_client(clp);
                return -ELOOP;
+       }
 
        /*
         * Query for the lease time on clientid setup or renewal
@@ -1244,11 +1246,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname,
                                clp->cl_proto, clnt->cl_timeout,
                                clp->cl_minorversion, net);
        clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
-       nfs_put_client(clp);
        if (error != 0) {
                nfs_server_insert_lists(server);
                return error;
        }
+       nfs_put_client(clp);
 
        if (server->nfs_client->cl_hostname == NULL)
                server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
index c13e826..ee723aa 100644 (file)
@@ -292,8 +292,11 @@ pnfs_detach_layout_hdr(struct pnfs_layout_hdr *lo)
 void
 pnfs_put_layout_hdr(struct pnfs_layout_hdr *lo)
 {
-       struct inode *inode = lo->plh_inode;
+       struct inode *inode;
 
+       if (!lo)
+               return;
+       inode = lo->plh_inode;
        pnfs_layoutreturn_before_put_layout_hdr(lo);
 
        if (refcount_dec_and_lock(&lo->plh_refcount, &inode->i_lock)) {
@@ -1241,10 +1244,12 @@ retry:
        spin_lock(&ino->i_lock);
        lo = nfsi->layout;
        if (!lo || !pnfs_layout_is_valid(lo) ||
-           test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags))
+           test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) {
+               lo = NULL;
                goto out_noroc;
+       }
+       pnfs_get_layout_hdr(lo);
        if (test_bit(NFS_LAYOUT_RETURN_LOCK, &lo->plh_flags)) {
-               pnfs_get_layout_hdr(lo);
                spin_unlock(&ino->i_lock);
                wait_on_bit(&lo->plh_flags, NFS_LAYOUT_RETURN,
                                TASK_UNINTERRUPTIBLE);
@@ -1312,10 +1317,12 @@ out_noroc:
                struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld;
                if (ld->prepare_layoutreturn)
                        ld->prepare_layoutreturn(args);
+               pnfs_put_layout_hdr(lo);
                return true;
        }
        if (layoutreturn)
                pnfs_send_layoutreturn(lo, &stateid, iomode, true);
+       pnfs_put_layout_hdr(lo);
        return false;
 }
 
index 29bacdc..5e470e2 100644 (file)
@@ -2631,6 +2631,8 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
                /* initial superblock/root creation */
                mount_info->fill_super(s, mount_info);
                nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
+               if (!(server->flags & NFS_MOUNT_UNSHARED))
+                       s->s_iflags |= SB_I_MULTIROOT;
        }
 
        mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
index 7428a66..e7d8cea 100644 (file)
@@ -1876,40 +1876,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head,
        return status;
 }
 
-int nfs_commit_inode(struct inode *inode, int how)
+static int __nfs_commit_inode(struct inode *inode, int how,
+               struct writeback_control *wbc)
 {
        LIST_HEAD(head);
        struct nfs_commit_info cinfo;
        int may_wait = how & FLUSH_SYNC;
-       int error = 0;
-       int res;
+       int ret, nscan;
 
        nfs_init_cinfo_from_inode(&cinfo, inode);
        nfs_commit_begin(cinfo.mds);
-       res = nfs_scan_commit(inode, &head, &cinfo);
-       if (res)
-               error = nfs_generic_commit_list(inode, &head, how, &cinfo);
+       for (;;) {
+               ret = nscan = nfs_scan_commit(inode, &head, &cinfo);
+               if (ret <= 0)
+                       break;
+               ret = nfs_generic_commit_list(inode, &head, how, &cinfo);
+               if (ret < 0)
+                       break;
+               ret = 0;
+               if (wbc && wbc->sync_mode == WB_SYNC_NONE) {
+                       if (nscan < wbc->nr_to_write)
+                               wbc->nr_to_write -= nscan;
+                       else
+                               wbc->nr_to_write = 0;
+               }
+               if (nscan < INT_MAX)
+                       break;
+               cond_resched();
+       }
        nfs_commit_end(cinfo.mds);
-       if (res == 0)
-               return res;
-       if (error < 0)
-               goto out_error;
-       if (!may_wait)
-               goto out_mark_dirty;
-       error = wait_on_commit(cinfo.mds);
-       if (error < 0)
-               return error;
-       return res;
-out_error:
-       res = error;
-       /* Note: If we exit without ensuring that the commit is complete,
-        * we must mark the inode as dirty. Otherwise, future calls to
-        * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure
-        * that the data is on the disk.
-        */
-out_mark_dirty:
-       __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
-       return res;
+       if (ret || !may_wait)
+               return ret;
+       return wait_on_commit(cinfo.mds);
+}
+
+int nfs_commit_inode(struct inode *inode, int how)
+{
+       return __nfs_commit_inode(inode, how, NULL);
 }
 EXPORT_SYMBOL_GPL(nfs_commit_inode);
 
@@ -1919,11 +1922,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
        int flags = FLUSH_SYNC;
        int ret = 0;
 
-       /* no commits means nothing needs to be done */
-       if (!atomic_long_read(&nfsi->commit_info.ncommit))
-               return ret;
-
        if (wbc->sync_mode == WB_SYNC_NONE) {
+               /* no commits means nothing needs to be done */
+               if (!atomic_long_read(&nfsi->commit_info.ncommit))
+                       goto check_requests_outstanding;
+
                /* Don't commit yet if this is a non-blocking flush and there
                 * are a lot of outstanding writes for this mapping.
                 */
@@ -1934,16 +1937,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc)
                flags = 0;
        }
 
-       ret = nfs_commit_inode(inode, flags);
-       if (ret >= 0) {
-               if (wbc->sync_mode == WB_SYNC_NONE) {
-                       if (ret < wbc->nr_to_write)
-                               wbc->nr_to_write -= ret;
-                       else
-                               wbc->nr_to_write = 0;
-               }
-               return 0;
-       }
+       ret = __nfs_commit_inode(inode, flags, wbc);
+       if (!ret) {
+               if (flags & FLUSH_SYNC)
+                       return 0;
+       } else if (atomic_long_read(&nfsi->commit_info.ncommit))
+               goto out_mark_dirty;
+
+check_requests_outstanding:
+       if (!atomic_read(&nfsi->commit_info.rpcs_out))
+               return ret;
 out_mark_dirty:
        __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
        return ret;
index 150521c..61b770e 100644 (file)
@@ -268,6 +268,35 @@ free_blocked_lock(struct nfsd4_blocked_lock *nbl)
        kfree(nbl);
 }
 
+static void
+remove_blocked_locks(struct nfs4_lockowner *lo)
+{
+       struct nfs4_client *clp = lo->lo_owner.so_client;
+       struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
+       struct nfsd4_blocked_lock *nbl;
+       LIST_HEAD(reaplist);
+
+       /* Dequeue all blocked locks */
+       spin_lock(&nn->blocked_locks_lock);
+       while (!list_empty(&lo->lo_blocked)) {
+               nbl = list_first_entry(&lo->lo_blocked,
+                                       struct nfsd4_blocked_lock,
+                                       nbl_list);
+               list_del_init(&nbl->nbl_list);
+               list_move(&nbl->nbl_lru, &reaplist);
+       }
+       spin_unlock(&nn->blocked_locks_lock);
+
+       /* Now free them */
+       while (!list_empty(&reaplist)) {
+               nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock,
+                                       nbl_lru);
+               list_del_init(&nbl->nbl_lru);
+               posix_unblock_lock(&nbl->nbl_lock);
+               free_blocked_lock(nbl);
+       }
+}
+
 static int
 nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task)
 {
@@ -1866,6 +1895,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp)
 static void
 __destroy_client(struct nfs4_client *clp)
 {
+       int i;
        struct nfs4_openowner *oo;
        struct nfs4_delegation *dp;
        struct list_head reaplist;
@@ -1895,6 +1925,16 @@ __destroy_client(struct nfs4_client *clp)
                nfs4_get_stateowner(&oo->oo_owner);
                release_openowner(oo);
        }
+       for (i = 0; i < OWNER_HASH_SIZE; i++) {
+               struct nfs4_stateowner *so, *tmp;
+
+               list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i],
+                                        so_strhash) {
+                       /* Should be no openowners at this point */
+                       WARN_ON_ONCE(so->so_is_open_owner);
+                       remove_blocked_locks(lockowner(so));
+               }
+       }
        nfsd4_return_all_client_layouts(clp);
        nfsd4_shutdown_callback(clp);
        if (clp->cl_cb_conn.cb_xprt)
@@ -6355,6 +6395,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
        }
        spin_unlock(&clp->cl_lock);
        free_ol_stateid_reaplist(&reaplist);
+       remove_blocked_locks(lo);
        nfs4_put_stateowner(&lo->lo_owner);
 
        return status;
@@ -7140,6 +7181,8 @@ nfs4_state_destroy_net(struct net *net)
                }
        }
 
+       WARN_ON(!list_empty(&nn->blocked_locks_lru));
+
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                while (!list_empty(&nn->unconf_id_hashtbl[i])) {
                        clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
@@ -7206,7 +7249,6 @@ nfs4_state_shutdown_net(struct net *net)
        struct nfs4_delegation *dp = NULL;
        struct list_head *pos, *next, reaplist;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
-       struct nfsd4_blocked_lock *nbl;
 
        cancel_delayed_work_sync(&nn->laundromat_work);
        locks_end_grace(&nn->nfsd4_manager);
@@ -7227,24 +7269,6 @@ nfs4_state_shutdown_net(struct net *net)
                nfs4_put_stid(&dp->dl_stid);
        }
 
-       BUG_ON(!list_empty(&reaplist));
-       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->blocked_locks_lock);
-
-       while (!list_empty(&reaplist)) {
-               nbl = list_first_entry(&reaplist,
-                                       struct nfsd4_blocked_lock, nbl_lru);
-               list_del_init(&nbl->nbl_lru);
-               posix_unblock_lock(&nbl->nbl_lock);
-               free_blocked_lock(nbl);
-       }
-
        nfsd4_client_tracking_exit(net);
        nfs4_state_destroy_net(net);
 }
index 406e72d..ce6ff5a 100644 (file)
@@ -24,6 +24,8 @@ config OVERLAY_FS_REDIRECT_DIR
          an overlay which has redirects on a kernel that doesn't support this
          feature will have unexpected results.
 
+         If unsure, say N.
+
 config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW
        bool "Overlayfs: follow redirects even if redirects are turned off"
        default y
@@ -32,8 +34,13 @@ config OVERLAY_FS_REDIRECT_ALWAYS_FOLLOW
          Disable this to get a possibly more secure configuration, but that
          might not be backward compatible with previous kernels.
 
+         If backward compatibility is not an issue, then it is safe and
+         recommended to say N here.
+
          For more information, see Documentation/filesystems/overlayfs.txt
 
+         If unsure, say Y.
+
 config OVERLAY_FS_INDEX
        bool "Overlayfs: turn on inodes index feature by default"
        depends on OVERLAY_FS
@@ -51,6 +58,8 @@ config OVERLAY_FS_INDEX
          That is, mounting an overlay which has an inodes index on a kernel
          that doesn't support this feature will have unexpected results.
 
+         If unsure, say N.
+
 config OVERLAY_FS_NFS_EXPORT
        bool "Overlayfs: turn on NFS export feature by default"
        depends on OVERLAY_FS
@@ -72,3 +81,8 @@ config OVERLAY_FS_NFS_EXPORT
          Note, that the NFS export feature is not backward compatible.
          That is, mounting an overlay which has a full index on a kernel
          that doesn't support this feature will have unexpected results.
+
+         Most users should say N here and enable this feature on a case-by-
+         case basis with the "nfs_export=on" mount option.
+
+         Say N unless you fully understand the consequences.
index bb94ce9..87bd414 100644 (file)
 #include <linux/ratelimit.h>
 #include "overlayfs.h"
 
+static int ovl_encode_maybe_copy_up(struct dentry *dentry)
+{
+       int err;
+
+       if (ovl_dentry_upper(dentry))
+               return 0;
+
+       err = ovl_want_write(dentry);
+       if (!err) {
+               err = ovl_copy_up(dentry);
+               ovl_drop_write(dentry);
+       }
+
+       if (err) {
+               pr_warn_ratelimited("overlayfs: failed to copy up on encode (%pd2, err=%i)\n",
+                                   dentry, err);
+       }
+
+       return err;
+}
+
+/*
+ * Before encoding a non-upper directory file handle from real layer N, we need
+ * to check if it will be possible to reconnect an overlay dentry from the real
+ * lower decoded dentry. This is done by following the overlay ancestry up to a
+ * "layer N connected" ancestor and verifying that all parents along the way are
+ * "layer N connectable". If an ancestor that is NOT "layer N connectable" is
+ * found, we need to copy up an ancestor, which is "layer N connectable", thus
+ * making that ancestor "layer N connected". For example:
+ *
+ * layer 1: /a
+ * layer 2: /a/b/c
+ *
+ * The overlay dentry /a is NOT "layer 2 connectable", because if dir /a is
+ * copied up and renamed, upper dir /a will be indexed by lower dir /a from
+ * layer 1. The dir /a from layer 2 will never be indexed, so the algorithm (*)
+ * in ovl_lookup_real_ancestor() will not be able to lookup a connected overlay
+ * dentry from the connected lower dentry /a/b/c.
+ *
+ * To avoid this problem on decode time, we need to copy up an ancestor of
+ * /a/b/c, which is "layer 2 connectable", on encode time. That ancestor is
+ * /a/b. After copy up (and index) of /a/b, it will become "layer 2 connected"
+ * and when the time comes to decode the file handle from lower dentry /a/b/c,
+ * ovl_lookup_real_ancestor() will find the indexed ancestor /a/b and decoding
+ * a connected overlay dentry will be accomplished.
+ *
+ * (*) the algorithm in ovl_lookup_real_ancestor() can be improved to lookup an
+ * entry /a in the lower layers above layer N and find the indexed dir /a from
+ * layer 1. If that improvement is made, then the check for "layer N connected"
+ * will need to verify there are no redirects in lower layers above N. In the
+ * example above, /a will be "layer 2 connectable". However, if layer 2 dir /a
+ * is a target of a layer 1 redirect, then /a will NOT be "layer 2 connectable":
+ *
+ * layer 1: /A (redirect = /a)
+ * layer 2: /a/b/c
+ */
+
+/* Return the lowest layer for encoding a connectable file handle */
+static int ovl_connectable_layer(struct dentry *dentry)
+{
+       struct ovl_entry *oe = OVL_E(dentry);
+
+       /* We can get overlay root from root of any layer */
+       if (dentry == dentry->d_sb->s_root)
+               return oe->numlower;
+
+       /*
+        * If it's an unindexed merge dir, then it's not connectable with any
+        * lower layer
+        */
+       if (ovl_dentry_upper(dentry) &&
+           !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
+               return 0;
+
+       /* We can get upper/overlay path from indexed/lower dentry */
+       return oe->lowerstack[0].layer->idx;
+}
+
+/*
+ * @dentry is "connected" if all ancestors up to root or a "connected" ancestor
+ * have the same uppermost lower layer as the origin's layer. We may need to
+ * copy up a "connectable" ancestor to make it "connected". A "connected" dentry
+ * cannot become non "connected", so cache positive result in dentry flags.
+ *
+ * Return the connected origin layer or < 0 on error.
+ */
+static int ovl_connect_layer(struct dentry *dentry)
+{
+       struct dentry *next, *parent = NULL;
+       int origin_layer;
+       int err = 0;
+
+       if (WARN_ON(dentry == dentry->d_sb->s_root) ||
+           WARN_ON(!ovl_dentry_lower(dentry)))
+               return -EIO;
+
+       origin_layer = OVL_E(dentry)->lowerstack[0].layer->idx;
+       if (ovl_dentry_test_flag(OVL_E_CONNECTED, dentry))
+               return origin_layer;
+
+       /* Find the topmost origin layer connectable ancestor of @dentry */
+       next = dget(dentry);
+       for (;;) {
+               parent = dget_parent(next);
+               if (WARN_ON(parent == next)) {
+                       err = -EIO;
+                       break;
+               }
+
+               /*
+                * If @parent is not origin layer connectable, then copy up
+                * @next which is origin layer connectable and we are done.
+                */
+               if (ovl_connectable_layer(parent) < origin_layer) {
+                       err = ovl_encode_maybe_copy_up(next);
+                       break;
+               }
+
+               /* If @parent is connected or indexed we are done */
+               if (ovl_dentry_test_flag(OVL_E_CONNECTED, parent) ||
+                   ovl_test_flag(OVL_INDEX, d_inode(parent)))
+                       break;
+
+               dput(next);
+               next = parent;
+       }
+
+       dput(parent);
+       dput(next);
+
+       if (!err)
+               ovl_dentry_set_flag(OVL_E_CONNECTED, dentry);
+
+       return err ?: origin_layer;
+}
+
 /*
  * We only need to encode origin if there is a chance that the same object was
  * encoded pre copy up and then we need to stay consistent with the same
  * L = lower file handle
  *
  * (*) Connecting an overlay dir from real lower dentry is not always
- * possible when there are redirects in lower layers. To mitigate this case,
- * we copy up the lower dir first and then encode an upper dir file handle.
+ * possible when there are redirects in lower layers and non-indexed merge dirs.
+ * To mitigate those case, we may copy up the lower dir ancestor before encode
+ * a lower dir file handle.
+ *
+ * Return 0 for upper file handle, > 0 for lower file handle or < 0 on error.
  */
-static bool ovl_should_encode_origin(struct dentry *dentry)
+static int ovl_check_encode_origin(struct dentry *dentry)
 {
        struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
 
+       /* Upper file handle for pure upper */
        if (!ovl_dentry_lower(dentry))
-               return false;
+               return 0;
 
        /*
-        * Decoding a merge dir, whose origin's parent is under a redirected
-        * lower dir is not always possible. As a simple aproximation, we do
-        * not encode lower dir file handles when overlay has multiple lower
-        * layers and origin is below the topmost lower layer.
+        * Upper file handle for non-indexed upper.
         *
-        * TODO: copy up only the parent that is under redirected lower.
+        * Root is never indexed, so if there's an upper layer, encode upper for
+        * root.
         */
-       if (d_is_dir(dentry) && ofs->upper_mnt &&
-           OVL_E(dentry)->lowerstack[0].layer->idx > 1)
-               return false;
-
-       /* Decoding a non-indexed upper from origin is not implemented */
        if (ovl_dentry_upper(dentry) &&
            !ovl_test_flag(OVL_INDEX, d_inode(dentry)))
-               return false;
-
-       return true;
-}
-
-static int ovl_encode_maybe_copy_up(struct dentry *dentry)
-{
-       int err;
-
-       if (ovl_dentry_upper(dentry))
                return 0;
 
-       err = ovl_want_write(dentry);
-       if (err)
-               return err;
-
-       err = ovl_copy_up(dentry);
+       /*
+        * Decoding a merge dir, whose origin's ancestor is under a redirected
+        * lower dir or under a non-indexed upper is not always possible.
+        * ovl_connect_layer() will try to make origin's layer "connected" by
+        * copying up a "connectable" ancestor.
+        */
+       if (d_is_dir(dentry) && ofs->upper_mnt)
+               return ovl_connect_layer(dentry);
 
-       ovl_drop_write(dentry);
-       return err;
+       /* Lower file handle for indexed and non-upper dir/non-dir */
+       return 1;
 }
 
 static int ovl_d_to_fh(struct dentry *dentry, char *buf, int buflen)
 {
-       struct dentry *origin = ovl_dentry_lower(dentry);
        struct ovl_fh *fh = NULL;
-       int err;
+       int err, enc_lower;
 
        /*
-        * If we should not encode a lower dir file handle, copy up and encode
-        * an upper dir file handle.
+        * Check if we should encode a lower or upper file handle and maybe
+        * copy up an ancestor to make lower file handle connectable.
         */
-       if (!ovl_should_encode_origin(dentry)) {
-               err = ovl_encode_maybe_copy_up(dentry);
-               if (err)
-                       goto fail;
-
-               origin = NULL;
-       }
+       err = enc_lower = ovl_check_encode_origin(dentry);
+       if (enc_lower < 0)
+               goto fail;
 
-       /* Encode an upper or origin file handle */
-       fh = ovl_encode_fh(origin ?: ovl_dentry_upper(dentry), !origin);
+       /* Encode an upper or lower file handle */
+       fh = ovl_encode_fh(enc_lower ? ovl_dentry_lower(dentry) :
+                                      ovl_dentry_upper(dentry), !enc_lower);
        err = PTR_ERR(fh);
        if (IS_ERR(fh))
                goto fail;
@@ -355,8 +477,8 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
                dput(upper);
        }
 
-       if (!this)
-               return NULL;
+       if (IS_ERR_OR_NULL(this))
+               return this;
 
        if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) {
                dput(this);
@@ -498,7 +620,7 @@ static struct dentry *ovl_lookup_real(struct super_block *sb,
                        if (err == -ECHILD) {
                                this = ovl_lookup_real_ancestor(sb, real,
                                                                layer);
-                               err = IS_ERR(this) ? PTR_ERR(this) : 0;
+                               err = PTR_ERR_OR_ZERO(this);
                        }
                        if (!err) {
                                dput(connected);
index fcd97b7..3b1bd46 100644 (file)
@@ -669,38 +669,59 @@ struct inode *ovl_lookup_inode(struct super_block *sb, struct dentry *real,
        return inode;
 }
 
+/*
+ * Does overlay inode need to be hashed by lower inode?
+ */
+static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
+                            struct dentry *lower, struct dentry *index)
+{
+       struct ovl_fs *ofs = sb->s_fs_info;
+
+       /* No, if pure upper */
+       if (!lower)
+               return false;
+
+       /* Yes, if already indexed */
+       if (index)
+               return true;
+
+       /* Yes, if won't be copied up */
+       if (!ofs->upper_mnt)
+               return true;
+
+       /* No, if lower hardlink is or will be broken on copy up */
+       if ((upper || !ovl_indexdir(sb)) &&
+           !d_is_dir(lower) && d_inode(lower)->i_nlink > 1)
+               return false;
+
+       /* No, if non-indexed upper with NFS export */
+       if (sb->s_export_op && upper)
+               return false;
+
+       /* Otherwise, hash by lower inode for fsnotify */
+       return true;
+}
+
 struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
                            struct dentry *lowerdentry, struct dentry *index,
                            unsigned int numlower)
 {
-       struct ovl_fs *ofs = sb->s_fs_info;
        struct inode *realinode = upperdentry ? d_inode(upperdentry) : NULL;
        struct inode *inode;
-       /* Already indexed or could be indexed on copy up? */
-       bool indexed = (index || (ovl_indexdir(sb) && !upperdentry));
-       struct dentry *origin = indexed ? lowerdentry : NULL;
+       bool bylower = ovl_hash_bylower(sb, upperdentry, lowerdentry, index);
        bool is_dir;
 
-       if (WARN_ON(upperdentry && indexed && !lowerdentry))
-               return ERR_PTR(-EIO);
-
        if (!realinode)
                realinode = d_inode(lowerdentry);
 
        /*
-        * Copy up origin (lower) may exist for non-indexed non-dir upper, but
-        * we must not use lower as hash key in that case.
-        * Hash non-dir that is or could be indexed by origin inode.
-        * Hash dir that is or could be merged by origin inode.
-        * Hash pure upper and non-indexed non-dir by upper inode.
-        * Hash non-indexed dir by upper inode for NFS export.
+        * Copy up origin (lower) may exist for non-indexed upper, but we must
+        * not use lower as hash key if this is a broken hardlink.
         */
        is_dir = S_ISDIR(realinode->i_mode);
-       if (is_dir && (indexed || !sb->s_export_op || !ofs->upper_mnt))
-               origin = lowerdentry;
-
-       if (upperdentry || origin) {
-               struct inode *key = d_inode(origin ?: upperdentry);
+       if (upperdentry || bylower) {
+               struct inode *key = d_inode(bylower ? lowerdentry :
+                                                     upperdentry);
                unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
 
                inode = iget5_locked(sb, (unsigned long) key,
@@ -728,6 +749,7 @@ struct inode *ovl_get_inode(struct super_block *sb, struct dentry *upperdentry,
                        nlink = ovl_get_nlink(lowerdentry, upperdentry, nlink);
                set_nlink(inode, nlink);
        } else {
+               /* Lower hardlink that will be broken on copy up */
                inode = new_inode(sb);
                if (!inode)
                        goto out_nomem;
index de3e6da..70fcfcc 100644 (file)
@@ -913,9 +913,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                stack[ctr].layer = lower.layer;
                ctr++;
 
-               if (d.stop)
-                       break;
-
                /*
                 * Following redirects can have security consequences: it's like
                 * a symlink into the lower layer without the permission checks.
@@ -933,6 +930,9 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
                        goto out_put;
                }
 
+               if (d.stop)
+                       break;
+
                if (d.redirect && d.redirect[0] == '/' && poe != roe) {
                        poe = roe;
                        /* Find the current layer on the root dentry */
index 0df25a9..225ff11 100644 (file)
@@ -40,6 +40,7 @@ enum ovl_inode_flag {
 enum ovl_entry_flag {
        OVL_E_UPPER_ALIAS,
        OVL_E_OPAQUE,
+       OVL_E_CONNECTED,
 };
 
 /*
index 9ee37c7..7c24619 100644 (file)
@@ -1359,6 +1359,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
        /* Root is always merge -> can have whiteouts */
        ovl_set_flag(OVL_WHITEOUTS, d_inode(root_dentry));
+       ovl_dentry_set_flag(OVL_E_CONNECTED, root_dentry);
        ovl_inode_init(d_inode(root_dentry), upperpath.dentry,
                       ovl_dentry_lower(root_dentry));
 
index e8a93bc..d1e8276 100644 (file)
@@ -510,6 +510,10 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
                        /* we have to zero-fill user buffer even if no read */
                        if (copy_to_user(buffer, buf, tsz))
                                return -EFAULT;
+               } else if (m->type == KCORE_USER) {
+                       /* User page is handled prior to normal kernel page: */
+                       if (copy_to_user(buffer, (char *)start, tsz))
+                               return -EFAULT;
                } else {
                        if (kern_addr_valid(start)) {
                                /*
index 9990957..76bf9cc 100644 (file)
@@ -118,13 +118,22 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
                err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
 #endif
 #ifdef BUS_MCEERR_AO
-               /* 
+               /*
+                * Other callers might not initialize the si_lsb field,
+                * so check explicitly for the right codes here.
+                */
+               if (kinfo->si_signo == SIGBUS &&
+                    kinfo->si_code == BUS_MCEERR_AO)
+                       err |= __put_user((short) kinfo->si_addr_lsb,
+                                         &uinfo->ssi_addr_lsb);
+#endif
+#ifdef BUS_MCEERR_AR
+               /*
                 * Other callers might not initialize the si_lsb field,
                 * so check explicitly for the right codes here.
                 */
                if (kinfo->si_signo == SIGBUS &&
-                   (kinfo->si_code == BUS_MCEERR_AR ||
-                    kinfo->si_code == BUS_MCEERR_AO))
+                   kinfo->si_code == BUS_MCEERR_AR)
                        err |= __put_user((short) kinfo->si_addr_lsb,
                                          &uinfo->ssi_addr_lsb);
 #endif
index 8664db2..215c225 100644 (file)
@@ -106,6 +106,7 @@ int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
 {
        return sysfs_do_create_link(kobj, target, name, 0);
 }
+EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn);
 
 /**
  *     sysfs_delete_link - remove symlink in object's directory.
index fd97552..05c66e0 100644 (file)
@@ -767,7 +767,7 @@ int
 xfs_scrub_agfl(
        struct xfs_scrub_context        *sc)
 {
-       struct xfs_scrub_agfl_info      sai = { 0 };
+       struct xfs_scrub_agfl_info      sai;
        struct xfs_agf                  *agf;
        xfs_agnumber_t                  agno;
        unsigned int                    agflcount;
@@ -795,6 +795,7 @@ xfs_scrub_agfl(
                xfs_scrub_block_set_corrupt(sc, sc->sa.agf_bp);
                goto out;
        }
+       memset(&sai, 0, sizeof(sai));
        sai.sz_entries = agflcount;
        sai.entries = kmem_zalloc(sizeof(xfs_agblock_t) * agflcount, KM_NOFS);
        if (!sai.entries) {
index 66e1edb..046469f 100644 (file)
@@ -955,15 +955,29 @@ static inline bool imap_needs_alloc(struct inode *inode,
                (IS_DAX(inode) && imap->br_state == XFS_EXT_UNWRITTEN);
 }
 
+static inline bool needs_cow_for_zeroing(struct xfs_bmbt_irec *imap, int nimaps)
+{
+       return nimaps &&
+               imap->br_startblock != HOLESTARTBLOCK &&
+               imap->br_state != XFS_EXT_UNWRITTEN;
+}
+
 static inline bool need_excl_ilock(struct xfs_inode *ip, unsigned flags)
 {
        /*
-        * COW writes will allocate delalloc space, so we need to make sure
-        * to take the lock exclusively here.
+        * COW writes may allocate delalloc space or convert unwritten COW
+        * extents, so we need to make sure to take the lock exclusively here.
         */
        if (xfs_is_reflink_inode(ip) && (flags & (IOMAP_WRITE | IOMAP_ZERO)))
                return true;
-       if ((flags & IOMAP_DIRECT) && (flags & IOMAP_WRITE))
+
+       /*
+        * Extents not yet cached requires exclusive access, don't block.
+        * This is an opencoded xfs_ilock_data_map_shared() to cater for the
+        * non-blocking behaviour.
+        */
+       if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE &&
+           !(ip->i_df.if_flags & XFS_IFEXTENTS))
                return true;
        return false;
 }
@@ -993,16 +1007,18 @@ xfs_file_iomap_begin(
                return xfs_file_iomap_begin_delay(inode, offset, length, iomap);
        }
 
-       if (need_excl_ilock(ip, flags)) {
+       if (need_excl_ilock(ip, flags))
                lockmode = XFS_ILOCK_EXCL;
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-       } else {
-               lockmode = xfs_ilock_data_map_shared(ip);
-       }
+       else
+               lockmode = XFS_ILOCK_SHARED;
 
-       if ((flags & IOMAP_NOWAIT) && !(ip->i_df.if_flags & XFS_IFEXTENTS)) {
-               error = -EAGAIN;
-               goto out_unlock;
+       if (flags & IOMAP_NOWAIT) {
+               if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
+                       return -EAGAIN;
+               if (!xfs_ilock_nowait(ip, lockmode))
+                       return -EAGAIN;
+       } else {
+               xfs_ilock(ip, lockmode);
        }
 
        ASSERT(offset <= mp->m_super->s_maxbytes);
@@ -1024,7 +1040,9 @@ xfs_file_iomap_begin(
                        goto out_unlock;
        }
 
-       if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) {
+       if (xfs_is_reflink_inode(ip) &&
+           ((flags & IOMAP_WRITE) ||
+            ((flags & IOMAP_ZERO) && needs_cow_for_zeroing(&imap, nimaps)))) {
                if (flags & IOMAP_DIRECT) {
                        /*
                         * A reflinked inode will result in CoW alloc.
index 3a55d6f..7a39f40 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
+#include "xfs_shared.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_trans.h"
@@ -456,10 +457,12 @@ xfs_cui_recover(
         * transaction.  Normally, any work that needs to be deferred
         * gets attached to the same defer_ops that scheduled the
         * refcount update.  However, we're in log recovery here, so we
-        * we create our own defer_ops and use that to finish up any
-        * work that doesn't fit.
+        * we use the passed in defer_ops and to finish up any work that
+        * doesn't fit.  We need to reserve enough blocks to handle a
+        * full btree split on either end of the refcount range.
         */
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
+                       mp->m_refc_maxlevels * 2, 0, XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
        cudp = xfs_trans_get_cud(tp, cuip);
index f3b139c..49d3124 100644 (file)
@@ -23,6 +23,7 @@
 #include "xfs_log_format.h"
 #include "xfs_trans_resv.h"
 #include "xfs_bit.h"
+#include "xfs_shared.h"
 #include "xfs_mount.h"
 #include "xfs_defer.h"
 #include "xfs_trans.h"
@@ -470,7 +471,8 @@ xfs_rui_recover(
                }
        }
 
-       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
+       error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
+                       mp->m_rmap_maxlevels, 0, XFS_TRANS_RESERVE, &tp);
        if (error)
                return error;
        rudp = xfs_trans_get_rud(tp, ruip);
index 7aba628..93588ea 100644 (file)
@@ -250,6 +250,7 @@ xfs_parseargs(
                                return -EINVAL;
                        break;
                case Opt_logdev:
+                       kfree(mp->m_logname);
                        mp->m_logname = match_strdup(args);
                        if (!mp->m_logname)
                                return -ENOMEM;
@@ -258,6 +259,7 @@ xfs_parseargs(
                        xfs_warn(mp, "%s option not allowed on this system", p);
                        return -EINVAL;
                case Opt_rtdev:
+                       kfree(mp->m_rtname);
                        mp->m_rtname = match_strdup(args);
                        if (!mp->m_rtname)
                                return -ENOMEM;
index bc39757..67ab280 100644 (file)
@@ -7,7 +7,8 @@
  * @nr: Bit to set
  * @addr: Address to count from
  *
- * This operation is atomic and provides acquire barrier semantics.
+ * This operation is atomic and provides acquire barrier semantics if
+ * the returned value is 0.
  * It can be used to implement bit locks.
  */
 #define test_and_set_bit_lock(nr, addr)        test_and_set_bit(nr, addr)
index 963b755..a7613e1 100644 (file)
@@ -52,6 +52,7 @@ struct bug_entry {
 #ifndef HAVE_ARCH_BUG
 #define BUG() do { \
        printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
+       barrier_before_unreachable(); \
        panic("BUG!"); \
 } while (0)
 #endif
index 2cfa307..bfbb44a 100644 (file)
@@ -983,6 +983,8 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot);
 int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot);
 int pud_clear_huge(pud_t *pud);
 int pmd_clear_huge(pmd_t *pmd);
+int pud_free_pmd_page(pud_t *pud);
+int pmd_free_pte_page(pmd_t *pmd);
 #else  /* !CONFIG_HAVE_ARCH_HUGE_VMAP */
 static inline int p4d_set_huge(p4d_t *p4d, phys_addr_t addr, pgprot_t prot)
 {
@@ -1008,6 +1010,14 @@ static inline int pmd_clear_huge(pmd_t *pmd)
 {
        return 0;
 }
+static inline int pud_free_pmd_page(pud_t *pud)
+{
+       return 0;
+}
+static inline int pmd_free_pte_page(pmd_t *pmd)
+{
+       return 0;
+}
 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
 
 #ifndef __HAVE_ARCH_FLUSH_PMD_TLB_RANGE
index 1c27526..cf13842 100644 (file)
@@ -134,6 +134,15 @@ struct drm_crtc_commit {
         * &drm_pending_vblank_event pointer to clean up private events.
         */
        struct drm_pending_vblank_event *event;
+
+       /**
+        * @abort_completion:
+        *
+        * A flag that's set after drm_atomic_helper_setup_commit takes a second
+        * reference for the completion of $drm_crtc_state.event. It's used by
+        * the free code to remove the second reference if commit fails.
+        */
+       bool abort_completion;
 };
 
 struct __drm_planes_state {
index 76e237b..6914633 100644 (file)
@@ -77,5 +77,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev);
 
 void drm_kms_helper_poll_disable(struct drm_device *dev);
 void drm_kms_helper_poll_enable(struct drm_device *dev);
+bool drm_kms_helper_is_poll_worker(void);
 
 #endif
index d32b688..d23dcdd 100644 (file)
@@ -56,6 +56,7 @@ struct drm_printer;
 #define DRIVER_ATOMIC                  0x10000
 #define DRIVER_KMS_LEGACY_CONTEXT      0x20000
 #define DRIVER_SYNCOBJ                  0x40000
+#define DRIVER_PREFER_XBGR_30BPP        0x80000
 
 /**
  * struct drm_driver - DRM driver structure
index cdbd142..02924ae 100644 (file)
@@ -360,6 +360,7 @@ void kvm_vgic_put(struct kvm_vcpu *vcpu);
 bool kvm_vcpu_has_pending_irqs(struct kvm_vcpu *vcpu);
 void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu);
 void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu);
+void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid);
 
 void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
 
index 64e1074..968173e 100644 (file)
@@ -587,7 +587,7 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
 const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
                                               const struct device *dev);
 
-void *acpi_get_match_data(const struct device *dev);
+const void *acpi_device_get_match_data(const struct device *dev);
 extern bool acpi_driver_match_device(struct device *dev,
                                     const struct device_driver *drv);
 int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
@@ -766,7 +766,7 @@ static inline const struct acpi_device_id *acpi_match_device(
        return NULL;
 }
 
-static inline void *acpi_get_match_data(const struct device *dev)
+static inline const void *acpi_device_get_match_data(const struct device *dev)
 {
        return NULL;
 }
index d0eb659..ce547a2 100644 (file)
@@ -511,6 +511,7 @@ void zero_fill_bio(struct bio *bio);
 extern struct bio_vec *bvec_alloc(gfp_t, int, unsigned long *, mempool_t *);
 extern void bvec_free(mempool_t *, struct bio_vec *, unsigned int);
 extern unsigned int bvec_nr_vecs(unsigned short idx);
+extern const char *bio_devname(struct bio *bio, char *buffer);
 
 #define bio_set_dev(bio, bdev)                         \
 do {                                           \
@@ -529,9 +530,6 @@ do {                                                \
 #define bio_dev(bio) \
        disk_devt((bio)->bi_disk)
 
-#define bio_devname(bio, buf) \
-       __bdevname(bio_dev(bio), (buf))
-
 #ifdef CONFIG_BLK_CGROUP
 int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css);
 void bio_disassociate_task(struct bio *bio);
index 4f3df80..ed63f3b 100644 (file)
@@ -49,7 +49,7 @@ struct blk_stat_callback;
 #define BLKDEV_MIN_RQ  4
 #define BLKDEV_MAX_RQ  128     /* Default maximum */
 
-/* Must be consisitent with blk_mq_poll_stats_bkt() */
+/* Must be consistent with blk_mq_poll_stats_bkt() */
 #define BLK_MQ_POLL_STATS_BKTS 16
 
 /*
index 9f242b8..f8e76d0 100644 (file)
@@ -755,13 +755,13 @@ struct sock_cgroup_data {
  * updaters and return part of the previous pointer as the prioidx or
  * classid.  Such races are short-lived and the result isn't critical.
  */
-static inline u16 sock_cgroup_prioidx(struct sock_cgroup_data *skcd)
+static inline u16 sock_cgroup_prioidx(const struct sock_cgroup_data *skcd)
 {
        /* fallback to 1 which is always the ID of the root cgroup */
        return (skcd->is_data & 1) ? skcd->prioidx : 1;
 }
 
-static inline u32 sock_cgroup_classid(struct sock_cgroup_data *skcd)
+static inline u32 sock_cgroup_classid(const struct sock_cgroup_data *skcd)
 {
        /* fallback to 0 which is the unconfigured default classid */
        return (skcd->is_data & 1) ? skcd->classid : 0;
index 8a96438..16c3027 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/if.h>
 #include <linux/fs.h>
 #include <linux/aio_abi.h>     /* for aio_context_t */
+#include <linux/uaccess.h>
 #include <linux/unistd.h>
 
 #include <asm/compat.h>
@@ -229,13 +230,13 @@ typedef struct compat_siginfo {
                                short int _addr_lsb;    /* Valid LSB of the reported address. */
                                /* used when si_code=SEGV_BNDERR */
                                struct {
-                                       short _dummy_bnd;
+                                       compat_uptr_t _dummy_bnd;
                                        compat_uptr_t _lower;
                                        compat_uptr_t _upper;
                                } _addr_bnd;
                                /* used when si_code=SEGV_PKUERR */
                                struct {
-                                       short _dummy_pkey;
+                                       compat_uptr_t _dummy_pkey;
                                        u32 _pkey;
                                } _addr_pkey;
                        };
@@ -550,8 +551,29 @@ asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
 asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
 
 extern int get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat);
-extern int put_compat_sigset(compat_sigset_t __user *compat,
-                            const sigset_t *set, unsigned int size);
+
+/*
+ * Defined inline such that size can be compile time constant, which avoids
+ * CONFIG_HARDENED_USERCOPY complaining about copies from task_struct
+ */
+static inline int
+put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set,
+                 unsigned int size)
+{
+       /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */
+#ifdef __BIG_ENDIAN
+       compat_sigset_t v;
+       switch (_NSIG_WORDS) {
+       case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3];
+       case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2];
+       case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1];
+       case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0];
+       }
+       return copy_to_user(compat, &v, size) ? -EFAULT : 0;
+#else
+       return copy_to_user(compat, set, size) ? -EFAULT : 0;
+#endif
+}
 
 asmlinkage long compat_sys_migrate_pages(compat_pid_t pid,
                compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes,
index 673fbf9..e2c7f43 100644 (file)
 #endif
 
 /*
+ * calling noreturn functions, __builtin_unreachable() and __builtin_trap()
+ * confuse the stack allocation in gcc, leading to overly large stack
+ * frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
+ *
+ * Adding an empty inline assembly before it works around the problem
+ */
+#define barrier_before_unreachable() asm volatile("")
+
+/*
  * Mark a position in code as unreachable.  This can be used to
  * suppress control flow warnings after asm blocks that transfer
  * control elsewhere.
  * unreleased.  Really, we need to have autoconf for the kernel.
  */
 #define unreachable() \
-       do { annotate_unreachable(); __builtin_unreachable(); } while (0)
+       do {                                    \
+               annotate_unreachable();         \
+               barrier_before_unreachable();   \
+               __builtin_unreachable();        \
+       } while (0)
 
 /* Mark a function definition as prohibited from being cloned. */
 #define __noclone      __attribute__((__noclone__, __optimize__("no-tracer")))
index e835fc0..ab4711c 100644 (file)
@@ -86,6 +86,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val,
 # define barrier_data(ptr) barrier()
 #endif
 
+/* workaround for GCC PR82365 if needed */
+#ifndef barrier_before_unreachable
+# define barrier_before_unreachable() do { } while (0)
+#endif
+
 /* Unreachable code */
 #ifdef CONFIG_STACK_VALIDATION
 /*
index 871f9e2..0b3fc22 100644 (file)
@@ -225,7 +225,7 @@ static inline void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev,
 }
 #endif
 
-#ifdef CONFIG_ARCH_HAS_CPU_RELAX
+#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_ARCH_HAS_CPU_RELAX)
 void cpuidle_poll_state_init(struct cpuidle_driver *drv);
 #else
 static inline void cpuidle_poll_state_init(struct cpuidle_driver *drv) {}
index d4a2a7d..bf53d89 100644 (file)
@@ -170,6 +170,8 @@ static inline unsigned int cpumask_local_spread(unsigned int i, int node)
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 #define for_each_cpu_not(cpu, mask)            \
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
+#define for_each_cpu_wrap(cpu, mask, start)    \
+       for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)(start))
 #define for_each_cpu_and(cpu, mask, and)       \
        for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and)
 #else
index 34fe846..eb9eab4 100644 (file)
@@ -578,7 +578,7 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
 
 /*
  * This is a hack for the legacy x86 forbid_dac and iommu_sac_force. Please
- * don't use this is new code.
+ * don't use this in new code.
  */
 #ifndef arch_dma_supported
 #define arch_dma_supported(dev, mask)  (1)
index 2a81556..c6baf76 100644 (file)
@@ -1317,6 +1317,7 @@ extern int send_sigurg(struct fown_struct *fown);
 #define SB_I_CGROUPWB  0x00000001      /* cgroup-aware writeback enabled */
 #define SB_I_NOEXEC    0x00000002      /* Ignore executables on this fs */
 #define SB_I_NODEV     0x00000004      /* Ignore devices on this fs */
+#define SB_I_MULTIROOT 0x00000008      /* Multiple roots to the dentry tree */
 
 /* sb->s_iflags to limit user namespace mounts */
 #define SB_I_USERNS_VISIBLE            0x00000010 /* fstype already mounted */
@@ -3198,7 +3199,7 @@ static inline bool vma_is_fsdax(struct vm_area_struct *vma)
        if (!vma_is_dax(vma))
                return false;
        inode = file_inode(vma->vm_file);
-       if (inode->i_mode == S_IFCHR)
+       if (S_ISCHR(inode->i_mode))
                return false; /* device-dax */
        return true;
 }
index c332f0a..3fdfede 100644 (file)
@@ -734,11 +734,7 @@ struct fsl_ifc_nand {
        u32 res19[0x10];
        __be32 nand_fsr;
        u32 res20;
-       /* The V1 nand_eccstat is actually 4 words that overlaps the
-        * V2 nand_eccstat.
-        */
-       __be32 v1_nand_eccstat[2];
-       __be32 v2_nand_eccstat[6];
+       __be32 nand_eccstat[8];
        u32 res21[0x1c];
        __be32 nanndcr;
        u32 res22[0x2];
index 4fa1a48..4fe8f28 100644 (file)
@@ -73,8 +73,8 @@ struct fwnode_operations {
        struct fwnode_handle *(*get)(struct fwnode_handle *fwnode);
        void (*put)(struct fwnode_handle *fwnode);
        bool (*device_is_available)(const struct fwnode_handle *fwnode);
-       void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
-                                      const struct device *dev);
+       const void *(*device_get_match_data)(const struct fwnode_handle *fwnode,
+                                            const struct device *dev);
        bool (*property_present)(const struct fwnode_handle *fwnode,
                                 const char *propname);
        int (*property_read_int_array)(const struct fwnode_handle *fwnode,
index 5e35310..c826b0b 100644 (file)
@@ -198,6 +198,7 @@ struct gendisk {
        void *private_data;
 
        int flags;
+       struct rw_semaphore lookup_sem;
        struct kobject *slave_dir;
 
        struct timer_rand_state *random;
@@ -600,8 +601,9 @@ extern void delete_partition(struct gendisk *, int);
 extern void printk_all_partitions(void);
 
 extern struct gendisk *__alloc_disk_node(int minors, int node_id);
-extern struct kobject *get_disk(struct gendisk *disk);
+extern struct kobject *get_disk_and_module(struct gendisk *disk);
 extern void put_disk(struct gendisk *disk);
+extern void put_disk_and_module(struct gendisk *disk);
 extern void blk_register_region(dev_t devt, unsigned long range,
                        struct module *module,
                        struct kobject *(*probe)(dev_t, int *, void *),
index c5b0a75..fd00170 100644 (file)
@@ -25,6 +25,7 @@ struct ptr_ring *tun_get_tx_ring(struct file *file);
 bool tun_is_xdp_buff(void *ptr);
 void *tun_xdp_to_ptr(void *ptr);
 void *tun_ptr_to_xdp(void *ptr);
+void tun_ptr_free(void *ptr);
 #else
 #include <linux/err.h>
 #include <linux/errno.h>
@@ -50,5 +51,8 @@ static inline void *tun_ptr_to_xdp(void *ptr)
 {
        return NULL;
 }
+static inline void tun_ptr_free(void *ptr)
+{
+}
 #endif /* CONFIG_TUN */
 #endif /* __IF_TUN_H */
index 5e6a2d4..7d30892 100644 (file)
@@ -300,32 +300,47 @@ static inline bool vlan_hw_offload_capable(netdev_features_t features,
 }
 
 /**
- * __vlan_insert_tag - regular VLAN tag inserting
+ * __vlan_insert_inner_tag - inner VLAN tag inserting
  * @skb: skbuff to tag
  * @vlan_proto: VLAN encapsulation protocol
  * @vlan_tci: VLAN TCI to insert
+ * @mac_len: MAC header length including outer vlan headers
  *
- * Inserts the VLAN tag into @skb as part of the payload
+ * Inserts the VLAN tag into @skb as part of the payload at offset mac_len
  * Returns error if skb_cow_head failes.
  *
  * Does not change skb->protocol so this function can be used during receive.
  */
-static inline int __vlan_insert_tag(struct sk_buff *skb,
-                                   __be16 vlan_proto, u16 vlan_tci)
+static inline int __vlan_insert_inner_tag(struct sk_buff *skb,
+                                         __be16 vlan_proto, u16 vlan_tci,
+                                         unsigned int mac_len)
 {
        struct vlan_ethhdr *veth;
 
        if (skb_cow_head(skb, VLAN_HLEN) < 0)
                return -ENOMEM;
 
-       veth = skb_push(skb, VLAN_HLEN);
+       skb_push(skb, VLAN_HLEN);
 
-       /* Move the mac addresses to the beginning of the new header. */
-       memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN);
+       /* Move the mac header sans proto to the beginning of the new header. */
+       if (likely(mac_len > ETH_TLEN))
+               memmove(skb->data, skb->data + VLAN_HLEN, mac_len - ETH_TLEN);
        skb->mac_header -= VLAN_HLEN;
 
+       veth = (struct vlan_ethhdr *)(skb->data + mac_len - ETH_HLEN);
+
        /* first, the ethernet type */
-       veth->h_vlan_proto = vlan_proto;
+       if (likely(mac_len >= ETH_TLEN)) {
+               /* h_vlan_encapsulated_proto should already be populated, and
+                * skb->data has space for h_vlan_proto
+                */
+               veth->h_vlan_proto = vlan_proto;
+       } else {
+               /* h_vlan_encapsulated_proto should not be populated, and
+                * skb->data has no space for h_vlan_proto
+                */
+               veth->h_vlan_encapsulated_proto = skb->protocol;
+       }
 
        /* now, the TCI */
        veth->h_vlan_TCI = htons(vlan_tci);
@@ -334,12 +349,30 @@ static inline int __vlan_insert_tag(struct sk_buff *skb,
 }
 
 /**
- * vlan_insert_tag - regular VLAN tag inserting
+ * __vlan_insert_tag - regular VLAN tag inserting
  * @skb: skbuff to tag
  * @vlan_proto: VLAN encapsulation protocol
  * @vlan_tci: VLAN TCI to insert
  *
  * Inserts the VLAN tag into @skb as part of the payload
+ * Returns error if skb_cow_head failes.
+ *
+ * Does not change skb->protocol so this function can be used during receive.
+ */
+static inline int __vlan_insert_tag(struct sk_buff *skb,
+                                   __be16 vlan_proto, u16 vlan_tci)
+{
+       return __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN);
+}
+
+/**
+ * vlan_insert_inner_tag - inner VLAN tag inserting
+ * @skb: skbuff to tag
+ * @vlan_proto: VLAN encapsulation protocol
+ * @vlan_tci: VLAN TCI to insert
+ * @mac_len: MAC header length including outer vlan headers
+ *
+ * Inserts the VLAN tag into @skb as part of the payload at offset mac_len
  * Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
  *
  * Following the skb_unshare() example, in case of error, the calling function
@@ -347,12 +380,14 @@ static inline int __vlan_insert_tag(struct sk_buff *skb,
  *
  * Does not change skb->protocol so this function can be used during receive.
  */
-static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
-                                             __be16 vlan_proto, u16 vlan_tci)
+static inline struct sk_buff *vlan_insert_inner_tag(struct sk_buff *skb,
+                                                   __be16 vlan_proto,
+                                                   u16 vlan_tci,
+                                                   unsigned int mac_len)
 {
        int err;
 
-       err = __vlan_insert_tag(skb, vlan_proto, vlan_tci);
+       err = __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, mac_len);
        if (err) {
                dev_kfree_skb_any(skb);
                return NULL;
@@ -361,6 +396,26 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
 }
 
 /**
+ * vlan_insert_tag - regular VLAN tag inserting
+ * @skb: skbuff to tag
+ * @vlan_proto: VLAN encapsulation protocol
+ * @vlan_tci: VLAN TCI to insert
+ *
+ * Inserts the VLAN tag into @skb as part of the payload
+ * Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
+ *
+ * Following the skb_unshare() example, in case of error, the calling function
+ * doesn't have to worry about freeing the original skb.
+ *
+ * Does not change skb->protocol so this function can be used during receive.
+ */
+static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
+                                             __be16 vlan_proto, u16 vlan_tci)
+{
+       return vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN);
+}
+
+/**
  * vlan_insert_tag_set_proto - regular VLAN tag inserting
  * @skb: skbuff to tag
  * @vlan_proto: VLAN encapsulation protocol
index c00c4c3..b26eccc 100644 (file)
 
 #define ICH_HCR_EN                     (1 << 0)
 #define ICH_HCR_UIE                    (1 << 1)
+#define ICH_HCR_NPIE                   (1 << 3)
 #define ICH_HCR_TC                     (1 << 10)
 #define ICH_HCR_TALL0                  (1 << 11)
 #define ICH_HCR_TALL1                  (1 << 12)
index d3453ee..68d8b1f 100644 (file)
@@ -84,6 +84,7 @@
 
 #define GICH_HCR_EN                    (1 << 0)
 #define GICH_HCR_UIE                   (1 << 1)
+#define GICH_HCR_NPIE                  (1 << 3)
 
 #define GICH_LR_VIRTUALID              (0x3ff << 0)
 #define GICH_LR_PHYSID_CPUID_SHIFT     (10)
index 2168cc6..b46b541 100644 (file)
@@ -151,7 +151,7 @@ extern struct jump_entry __start___jump_table[];
 extern struct jump_entry __stop___jump_table[];
 
 extern void jump_label_init(void);
-extern void jump_label_invalidate_init(void);
+extern void jump_label_invalidate_initmem(void);
 extern void jump_label_lock(void);
 extern void jump_label_unlock(void);
 extern void arch_jump_label_transform(struct jump_entry *entry,
@@ -199,7 +199,7 @@ static __always_inline void jump_label_init(void)
        static_key_initialized = true;
 }
 
-static inline void jump_label_invalidate_init(void) {}
+static inline void jump_label_invalidate_initmem(void) {}
 
 static __always_inline bool static_key_false(struct static_key *key)
 {
index fec5076..dcde947 100644 (file)
@@ -4,6 +4,12 @@
 
 #include <generated/autoconf.h>
 
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define __BIG_ENDIAN 4321
+#else
+#define __LITTLE_ENDIAN 1234
+#endif
+
 #define __ARG_PLACEHOLDER_1 0,
 #define __take_second_arg(__ignored, val, ...) val
 
@@ -64,4 +70,7 @@
  */
 #define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
 
+/* Make sure we always have all types and struct attributes defined. */
+#include <linux/compiler_types.h>
+
 #endif /* __LINUX_KCONFIG_H */
index 7ff25a8..80db19d 100644 (file)
@@ -10,6 +10,7 @@ enum kcore_type {
        KCORE_VMALLOC,
        KCORE_RAM,
        KCORE_VMEMMAP,
+       KCORE_USER,
        KCORE_OTHER,
 };
 
index ac0062b..6930c63 100644 (file)
@@ -1105,7 +1105,6 @@ static inline void kvm_irq_routing_update(struct kvm *kvm)
 {
 }
 #endif
-void kvm_arch_irq_routing_update(struct kvm *kvm);
 
 static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 {
@@ -1114,6 +1113,8 @@ static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
 
 #endif /* CONFIG_HAVE_KVM_EVENTFD */
 
+void kvm_arch_irq_routing_update(struct kvm *kvm);
+
 static inline void kvm_make_request(int req, struct kvm_vcpu *vcpu)
 {
        /*
@@ -1272,4 +1273,7 @@ static inline long kvm_arch_vcpu_async_ioctl(struct file *filp,
 }
 #endif /* CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL */
 
+void kvm_arch_mmu_notifier_invalidate_range(struct kvm *kvm,
+               unsigned long start, unsigned long end);
+
 #endif
index 8be5077..f92ea77 100644 (file)
@@ -187,7 +187,6 @@ int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
                            unsigned long  *end_pfn);
 void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
                          unsigned long *out_end_pfn, int *out_nid);
-unsigned long memblock_next_valid_pfn(unsigned long pfn, unsigned long max_pfn);
 
 /**
  * for_each_mem_pfn_range - early memory pfn range iterator
index 8820468..c46016b 100644 (file)
@@ -523,9 +523,11 @@ static inline void __mod_memcg_state(struct mem_cgroup *memcg,
 static inline void mod_memcg_state(struct mem_cgroup *memcg,
                                   int idx, int val)
 {
-       preempt_disable();
+       unsigned long flags;
+
+       local_irq_save(flags);
        __mod_memcg_state(memcg, idx, val);
-       preempt_enable();
+       local_irq_restore(flags);
 }
 
 /**
@@ -606,9 +608,11 @@ static inline void __mod_lruvec_state(struct lruvec *lruvec,
 static inline void mod_lruvec_state(struct lruvec *lruvec,
                                    enum node_stat_item idx, int val)
 {
-       preempt_disable();
+       unsigned long flags;
+
+       local_irq_save(flags);
        __mod_lruvec_state(lruvec, idx, val);
-       preempt_enable();
+       local_irq_restore(flags);
 }
 
 static inline void __mod_lruvec_page_state(struct page *page,
@@ -630,9 +634,11 @@ static inline void __mod_lruvec_page_state(struct page *page,
 static inline void mod_lruvec_page_state(struct page *page,
                                         enum node_stat_item idx, int val)
 {
-       preempt_disable();
+       unsigned long flags;
+
+       local_irq_save(flags);
        __mod_lruvec_page_state(page, idx, val);
-       preempt_enable();
+       local_irq_restore(flags);
 }
 
 unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order,
@@ -659,9 +665,11 @@ static inline void __count_memcg_events(struct mem_cgroup *memcg,
 static inline void count_memcg_events(struct mem_cgroup *memcg,
                                      int idx, unsigned long count)
 {
-       preempt_disable();
+       unsigned long flags;
+
+       local_irq_save(flags);
        __count_memcg_events(memcg, idx, count);
-       preempt_enable();
+       local_irq_restore(flags);
 }
 
 /* idx can be of type enum memcg_event_item or vm_event_item */
index 6ed79a8..9d3a033 100644 (file)
@@ -453,8 +453,8 @@ struct mlx5_core_srq {
        struct mlx5_core_rsc_common     common; /* must be first */
        u32             srqn;
        int             max;
-       int             max_gs;
-       int             max_avail_gather;
+       size_t          max_gs;
+       size_t          max_avail_gather;
        int             wqe_shift;
        void (*event)   (struct mlx5_core_srq *, enum mlx5_event);
 
index c30b32e..10191c2 100644 (file)
@@ -127,10 +127,4 @@ static __always_inline enum lru_list page_lru(struct page *page)
 
 #define lru_to_page(head) (list_entry((head)->prev, struct page, lru))
 
-#ifdef arch_unmap_kpfn
-extern void arch_unmap_kpfn(unsigned long pfn);
-#else
-static __always_inline void arch_unmap_kpfn(unsigned long pfn) { }
-#endif
-
 #endif
index f25c134..cb3bbed 100644 (file)
@@ -66,6 +66,11 @@ struct mutex {
 #endif
 };
 
+/*
+ * Internal helper function; C doesn't allow us to hide it :/
+ *
+ * DO NOT USE (outside of mutex code).
+ */
 static inline struct task_struct *__mutex_owner(struct mutex *lock)
 {
        return (struct task_struct *)(atomic_long_read(&lock->owner) & ~0x07);
index 91216b1..2a0391e 100644 (file)
@@ -222,6 +222,7 @@ enum {
 int sock_wake_async(struct socket_wq *sk_wq, int how, int band);
 int sock_register(const struct net_proto_family *fam);
 void sock_unregister(int family);
+bool sock_is_registered(int family);
 int __sock_create(struct net *net, int family, int type, int proto,
                  struct socket **res, int kern);
 int sock_create(int family, int type, int proto, struct socket **res);
index bebeaad..29ed8fd 100644 (file)
@@ -231,7 +231,7 @@ static inline void net_dim_exit_parking(struct net_dim *dim)
 }
 
 #define IS_SIGNIFICANT_DIFF(val, ref) \
-       (((100 * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */
+       (((100UL * abs((val) - (ref))) / (ref)) > 10) /* more than 10% difference */
 
 static inline int net_dim_stats_compare(struct net_dim_stats *curr,
                                        struct net_dim_stats *prev)
index 1313b35..1452951 100644 (file)
@@ -285,6 +285,8 @@ unsigned int *xt_alloc_entry_offsets(unsigned int size);
 bool xt_find_jump_offset(const unsigned int *offsets,
                         unsigned int target, unsigned int size);
 
+int xt_check_proc_name(const char *name, unsigned int size);
+
 int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto,
                   bool inv_proto);
 int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto,
index 88865e0..091033a 100644 (file)
@@ -13,7 +13,6 @@ struct device_node;
 struct device_node *of_pci_find_child_device(struct device_node *parent,
                                             unsigned int devfn);
 int of_pci_get_devfn(struct device_node *np);
-int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
 int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
 int of_get_pci_domain_nr(struct device_node *node);
 int of_pci_get_max_link_speed(struct device_node *node);
@@ -34,12 +33,6 @@ static inline int of_pci_get_devfn(struct device_node *np)
 }
 
 static inline int
-of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
-{
-       return 0;
-}
-
-static inline int
 of_pci_parse_bus_range(struct device_node *node, struct resource *res)
 {
        return -EINVAL;
@@ -67,6 +60,16 @@ of_pci_get_max_link_speed(struct device_node *node)
 static inline void of_pci_check_probe_only(void) { }
 #endif
 
+#if IS_ENABLED(CONFIG_OF_IRQ)
+int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
+#else
+static inline int
+of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       return 0;
+}
+#endif
+
 #if defined(CONFIG_OF_ADDRESS)
 int of_pci_get_host_bridge_resources(struct device_node *dev,
                        unsigned char busno, unsigned char bus_max,
index 864d167..009cdf3 100644 (file)
  * calls io_destroy() or the process exits.
  *
  * In the aio code, kill_ioctx() is called when we wish to destroy a kioctx; it
- * calls percpu_ref_kill(), then hlist_del_rcu() and synchronize_rcu() to remove
- * the kioctx from the proccess's list of kioctxs - after that, there can't be
- * any new users of the kioctx (from lookup_ioctx()) and it's then safe to drop
- * the initial ref with percpu_ref_put().
+ * removes the kioctx from the proccess's table of kioctxs and kills percpu_ref.
+ * After that, there can't be any new users of the kioctx (from lookup_ioctx())
+ * and it's then safe to drop the initial ref with percpu_ref_put().
+ *
+ * Note that the free path, free_ioctx(), needs to go through explicit call_rcu()
+ * to synchronize with RCU protected lookup_ioctx().  percpu_ref operations don't
+ * imply RCU grace periods of any kind and if a user wants to combine percpu_ref
+ * with RCU protection, it must be done explicitly.
  *
  * Code that does a two stage shutdown like this often needs some kind of
  * explicit synchronization to ensure the initial refcount can only be dropped
@@ -113,8 +117,10 @@ void percpu_ref_reinit(struct percpu_ref *ref);
  * Must be used to drop the initial ref on a percpu refcount; must be called
  * precisely once before shutdown.
  *
- * Puts @ref in non percpu mode, then does a call_rcu() before gathering up the
- * percpu counters and dropping the initial ref.
+ * Switches @ref into atomic mode before gathering up the percpu counters
+ * and dropping the initial ref.
+ *
+ * There are no implied RCU grace periods between kill and release.
  */
 static inline void percpu_ref_kill(struct percpu_ref *ref)
 {
index af0f44e..40036a5 100644 (file)
 
 #include <linux/interrupt.h>
 #include <linux/perf_event.h>
+#include <linux/platform_device.h>
 #include <linux/sysfs.h>
 #include <asm/cputype.h>
 
-/*
- * struct arm_pmu_platdata - ARM PMU platform data
- *
- * @handle_irq: an optional handler which will be called from the
- *     interrupt and passed the address of the low level handler,
- *     and can be used to implement any platform specific handling
- *     before or after calling it.
- *
- * @irq_flags: if non-zero, these flags will be passed to request_irq
- *             when requesting interrupts for this PMU device.
- */
-struct arm_pmu_platdata {
-       irqreturn_t (*handle_irq)(int irq, void *dev,
-                                 irq_handler_t pmu_handler);
-       unsigned long irq_flags;
-};
-
 #ifdef CONFIG_ARM_PMU
 
 /*
@@ -92,7 +76,6 @@ enum armpmu_attr_groups {
 
 struct arm_pmu {
        struct pmu      pmu;
-       cpumask_t       active_irqs;
        cpumask_t       supported_cpus;
        char            *name;
        irqreturn_t     (*handle_irq)(int irq_num, void *dev);
@@ -174,12 +157,11 @@ static inline int arm_pmu_acpi_probe(armpmu_init_fn init_fn) { return 0; }
 
 /* Internal functions only for core arm_pmu code */
 struct arm_pmu *armpmu_alloc(void);
+struct arm_pmu *armpmu_alloc_atomic(void);
 void armpmu_free(struct arm_pmu *pmu);
 int armpmu_register(struct arm_pmu *pmu);
-int armpmu_request_irqs(struct arm_pmu *armpmu);
-void armpmu_free_irqs(struct arm_pmu *armpmu);
-int armpmu_request_irq(struct arm_pmu *armpmu, int cpu);
-void armpmu_free_irq(struct arm_pmu *armpmu, int cpu);
+int armpmu_request_irq(int irq, int cpu);
+void armpmu_free_irq(int irq, int cpu);
 
 #define ARMV8_PMU_PDEV_NAME "armv8-pmu"
 
index 5a0c3e5..7c4c237 100644 (file)
@@ -924,6 +924,7 @@ void phy_device_remove(struct phy_device *phydev);
 int phy_init_hw(struct phy_device *phydev);
 int phy_suspend(struct phy_device *phydev);
 int phy_resume(struct phy_device *phydev);
+int __phy_resume(struct phy_device *phydev);
 int phy_loopback(struct phy_device *phydev, bool enable);
 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
                              phy_interface_t interface);
@@ -983,6 +984,10 @@ static inline int genphy_no_soft_reset(struct phy_device *phydev)
 {
        return 0;
 }
+int genphy_read_mmd_unsupported(struct phy_device *phdev, int devad,
+                               u16 regnum);
+int genphy_write_mmd_unsupported(struct phy_device *phdev, int devnum,
+                                u16 regnum, u16 val);
 
 /* Clause 45 PHY */
 int genphy_c45_restart_aneg(struct phy_device *phydev);
@@ -1011,7 +1016,6 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner);
 int phy_drivers_register(struct phy_driver *new_driver, int n,
                         struct module *owner);
 void phy_state_machine(struct work_struct *work);
-void phy_change(struct phy_device *phydev);
 void phy_change_work(struct work_struct *work);
 void phy_mac_interrupt(struct phy_device *phydev);
 void phy_start_machine(struct phy_device *phydev);
index 769d372..2eea4b3 100644 (file)
@@ -283,7 +283,7 @@ bool device_dma_supported(struct device *dev);
 
 enum dev_dma_attr device_get_dma_attr(struct device *dev);
 
-void *device_get_match_data(struct device *dev);
+const void *device_get_match_data(struct device *dev);
 
 int device_get_phy_mode(struct device *dev);
 
index b884b77..e633522 100644 (file)
@@ -469,7 +469,7 @@ static inline int ptr_ring_consume_batched_bh(struct ptr_ring *r,
  */
 static inline void **__ptr_ring_init_queue_alloc(unsigned int size, gfp_t gfp)
 {
-       if (size * sizeof(void *) > KMALLOC_MAX_SIZE)
+       if (size > KMALLOC_MAX_SIZE / sizeof(void *))
                return NULL;
        return kvmalloc_array(size, sizeof(void *), gfp | __GFP_ZERO);
 }
index c9df252..668a21f 100644 (file)
@@ -766,8 +766,10 @@ slow_path:
                if (!key ||
                    (params.obj_cmpfn ?
                     params.obj_cmpfn(&arg, rht_obj(ht, head)) :
-                    rhashtable_compare(&arg, rht_obj(ht, head))))
+                    rhashtable_compare(&arg, rht_obj(ht, head)))) {
+                       pprev = &head->next;
                        continue;
+               }
 
                data = rht_obj(ht, head);
 
index 1149533..9806184 100644 (file)
@@ -36,7 +36,18 @@ static inline void mmgrab(struct mm_struct *mm)
        atomic_inc(&mm->mm_count);
 }
 
-extern void mmdrop(struct mm_struct *mm);
+extern void __mmdrop(struct mm_struct *mm);
+
+static inline void mmdrop(struct mm_struct *mm)
+{
+       /*
+        * The implicit full barrier implied by atomic_dec_and_test() is
+        * required by the membarrier system call before returning to
+        * user-space, after storing to rq->curr.
+        */
+       if (unlikely(atomic_dec_and_test(&mm->mm_count)))
+               __mmdrop(mm);
+}
 
 /**
  * mmget() - Pin the address space associated with a &struct mm_struct.
index 0dcf4e4..96fe289 100644 (file)
@@ -4,6 +4,7 @@
 
 #include <linux/uidgid.h>
 #include <linux/atomic.h>
+#include <linux/ratelimit.h>
 
 struct key;
 
@@ -41,6 +42,9 @@ struct user_struct {
     defined(CONFIG_NET)
        atomic_long_t locked_vm;
 #endif
+
+       /* Miscellaneous per-user rate limit */
+       struct ratelimit_state ratelimit;
 };
 
 extern int uids_sysfs_init(void);
index dc368b8..11c86fb 100644 (file)
@@ -4,7 +4,7 @@
  *
  * Distributed under the terms of the GNU GPL, version 2
  *
- * Please see kernel/semaphore.c for documentation of these functions
+ * Please see kernel/locking/semaphore.c for documentation of these functions
  */
 #ifndef __LINUX_SEMAPHORE_H
 #define __LINUX_SEMAPHORE_H
index 5ebc0f8..99df171 100644 (file)
@@ -3285,8 +3285,7 @@ int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu);
+bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu);
 bool skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len);
 struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
 struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
@@ -3646,7 +3645,7 @@ static inline bool __skb_checksum_validate_needed(struct sk_buff *skb,
        return true;
 }
 
-/* For small packets <= CHECKSUM_BREAK peform checksum complete directly
+/* For small packets <= CHECKSUM_BREAK perform checksum complete directly
  * in checksum_init.
  */
 #define CHECKSUM_BREAK 76
@@ -4038,6 +4037,12 @@ static inline bool skb_is_gso_v6(const struct sk_buff *skb)
        return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6;
 }
 
+/* Note: Should be called only if skb_is_gso(skb) is true */
+static inline bool skb_is_gso_sctp(const struct sk_buff *skb)
+{
+       return skb_shinfo(skb)->gso_type & SKB_GSO_SCTP;
+}
+
 static inline void skb_gso_reset(struct sk_buff *skb)
 {
        skb_shinfo(skb)->gso_size = 0;
@@ -4045,6 +4050,22 @@ static inline void skb_gso_reset(struct sk_buff *skb)
        skb_shinfo(skb)->gso_type = 0;
 }
 
+static inline void skb_increase_gso_size(struct skb_shared_info *shinfo,
+                                        u16 increment)
+{
+       if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS))
+               return;
+       shinfo->gso_size += increment;
+}
+
+static inline void skb_decrease_gso_size(struct skb_shared_info *shinfo,
+                                        u16 decrement)
+{
+       if (WARN_ON_ONCE(shinfo->gso_size == GSO_BY_FRAGS))
+               return;
+       shinfo->gso_size -= decrement;
+}
+
 void __skb_warn_lro_forwarding(const struct sk_buff *skb);
 
 static inline bool skb_warn_if_lro(const struct sk_buff *skb)
@@ -4104,38 +4125,6 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb)
        return !skb->head_frag || skb_cloned(skb);
 }
 
-/**
- * skb_gso_network_seglen - Return length of individual segments of a gso packet
- *
- * @skb: GSO skb
- *
- * skb_gso_network_seglen is used to determine the real size of the
- * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
- *
- * The MAC/L2 header is not accounted for.
- */
-static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
-{
-       unsigned int hdr_len = skb_transport_header(skb) -
-                              skb_network_header(skb);
-       return hdr_len + skb_gso_transport_seglen(skb);
-}
-
-/**
- * skb_gso_mac_seglen - Return length of individual segments of a gso packet
- *
- * @skb: GSO skb
- *
- * skb_gso_mac_seglen is used to determine the real size of the
- * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
- * headers (TCP/UDP).
- */
-static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
-{
-       unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
-       return hdr_len + skb_gso_transport_seglen(skb);
-}
-
 /* Local Checksum Offload.
  * Compute outer checksum based on the assumption that the
  * inner checksum will be offloaded later.
index 7b6a59f..a1a3f4e 100644 (file)
@@ -337,8 +337,6 @@ extern void deactivate_file_page(struct page *page);
 extern void mark_page_lazyfree(struct page *page);
 extern void swap_setup(void);
 
-extern void add_page_to_unevictable_list(struct page *page);
-
 extern void lru_cache_add_active_or_unevictable(struct page *page,
                                                struct vm_area_struct *vma);
 
index 0a6c71e..47f8af2 100644 (file)
@@ -364,6 +364,7 @@ struct tty_file_private {
 #define TTY_PTY_LOCK           16      /* pty private */
 #define TTY_NO_WRITE_SPLIT     17      /* Preserve write boundaries to driver */
 #define TTY_HUPPED             18      /* Post driver->hangup() */
+#define TTY_HUPPING            19      /* Hangup in progress */
 #define TTY_LDISC_HALTED       22      /* Line discipline is halted */
 
 /* Values for tty->flow_change */
index 5bdbd9f..07ee0f8 100644 (file)
@@ -90,6 +90,28 @@ static inline void u64_stats_update_end(struct u64_stats_sync *syncp)
 #endif
 }
 
+static inline unsigned long
+u64_stats_update_begin_irqsave(struct u64_stats_sync *syncp)
+{
+       unsigned long flags = 0;
+
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+       local_irq_save(flags);
+       write_seqcount_begin(&syncp->seq);
+#endif
+       return flags;
+}
+
+static inline void
+u64_stats_update_end_irqrestore(struct u64_stats_sync *syncp,
+                               unsigned long flags)
+{
+#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
+       write_seqcount_end(&syncp->seq);
+       local_irq_restore(flags);
+#endif
+}
+
 static inline void u64_stats_update_begin_raw(struct u64_stats_sync *syncp)
 {
 #if BITS_PER_LONG==32 && defined(CONFIG_SMP)
index f1fcec2..b7a99ce 100644 (file)
@@ -63,4 +63,7 @@
  */
 #define USB_QUIRK_DISCONNECT_SUSPEND           BIT(12)
 
+/* Device needs a pause after every control message. */
+#define USB_QUIRK_DELAY_CTRL_MSG               BIT(13)
+
 #endif /* __LINUX_USB_QUIRKS_H */
index 4a54ef9..0c33014 100644 (file)
@@ -456,7 +456,6 @@ extern int schedule_on_each_cpu(work_func_t func);
 int execute_in_process_context(work_func_t fn, struct execute_work *);
 
 extern bool flush_work(struct work_struct *work);
-extern bool cancel_work(struct work_struct *work);
 extern bool cancel_work_sync(struct work_struct *work);
 
 extern bool flush_delayed_work(struct delayed_work *dwork);
@@ -465,6 +464,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
 
 extern void workqueue_set_max_active(struct workqueue_struct *wq,
                                     int max_active);
+extern struct work_struct *current_work(void);
 extern bool current_is_workqueue_rescuer(void);
 extern bool workqueue_congested(int cpu, struct workqueue_struct *wq);
 extern unsigned int work_busy(struct work_struct *work);
index c4df6ce..bf00a5a 100644 (file)
@@ -117,7 +117,7 @@ struct dmx_ts_feed {
  *               specified by @filter_value that will be used on the filter
  *               match logic.
  * @filter_mode:  Contains a 16 bytes (128 bits) filter mode.
- * @parent:      Pointer to struct dmx_section_feed.
+ * @parent:      Back-pointer to struct dmx_section_feed.
  * @priv:        Pointer to private data of the API client.
  *
  *
@@ -130,8 +130,9 @@ struct dmx_section_filter {
        u8 filter_value[DMX_MAX_FILTER_SIZE];
        u8 filter_mask[DMX_MAX_FILTER_SIZE];
        u8 filter_mode[DMX_MAX_FILTER_SIZE];
-       struct dmx_section_feed *parent; /* Back-pointer */
-       void *priv; /* Pointer to private data of the API client */
+       struct dmx_section_feed *parent;
+
+       void *priv;
 };
 
 /**
@@ -193,6 +194,10 @@ struct dmx_section_feed {
  * @buffer2:           Pointer to the tail of the filtered TS packets, or NULL.
  * @buffer2_length:    Length of the TS data in buffer2.
  * @source:            Indicates which TS feed is the source of the callback.
+ * @buffer_flags:      Address where buffer flags are stored. Those are
+ *                     used to report discontinuity users via DVB
+ *                     memory mapped API, as defined by
+ *                     &enum dmx_buffer_flags.
  *
  * This function callback prototype, provided by the client of the demux API,
  * is called from the demux code. The function is only called when filtering
@@ -245,7 +250,8 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
                         size_t buffer1_length,
                         const u8 *buffer2,
                         size_t buffer2_length,
-                        struct dmx_ts_feed *source);
+                        struct dmx_ts_feed *source,
+                        u32 *buffer_flags);
 
 /**
  * typedef dmx_section_cb - DVB demux TS filter callback function prototype
@@ -261,6 +267,10 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
  *                     including headers and CRC.
  * @source:            Indicates which section feed is the source of the
  *                     callback.
+ * @buffer_flags:      Address where buffer flags are stored. Those are
+ *                     used to report discontinuity users via DVB
+ *                     memory mapped API, as defined by
+ *                     &enum dmx_buffer_flags.
  *
  * This function callback prototype, provided by the client of the demux API,
  * is called from the demux code. The function is only called when
@@ -286,7 +296,8 @@ typedef int (*dmx_section_cb)(const u8 *buffer1,
                              size_t buffer1_len,
                              const u8 *buffer2,
                              size_t buffer2_len,
-                             struct dmx_section_filter *source);
+                             struct dmx_section_filter *source,
+                             u32 *buffer_flags);
 
 /*
  * DVB Front-End
index 2f5cb2c..baafa3b 100644 (file)
@@ -163,6 +163,7 @@ struct dmxdev_filter {
  * @demux:             pointer to &struct dmx_demux.
  * @filternum:         number of filters.
  * @capabilities:      demux capabilities as defined by &enum dmx_demux_caps.
+ * @may_do_mmap:       flag used to indicate if the device may do mmap.
  * @exit:              flag to indicate that the demux is being released.
  * @dvr_orig_fe:       pointer to &struct dmx_frontend.
  * @dvr_buffer:                embedded &struct dvb_ringbuffer for DVB output.
@@ -180,6 +181,7 @@ struct dmxdev {
        int filternum;
        int capabilities;
 
+       unsigned int may_do_mmap:1;
        unsigned int exit:1;
 #define DMXDEV_CAP_DUPLEX 1
        struct dmx_frontend *dvr_orig_fe;
index b070920..3b6aeca 100644 (file)
@@ -115,6 +115,8 @@ struct dvb_demux_filter {
  * @pid:       PID to be filtered.
  * @timeout:   feed timeout.
  * @filter:    pointer to &struct dvb_demux_filter.
+ * @buffer_flags: Buffer flags used to report discontinuity users via DVB
+ *               memory mapped API, as defined by &enum dmx_buffer_flags.
  * @ts_type:   type of TS, as defined by &enum ts_filter_type.
  * @pes_type:  type of PES, as defined by &enum dmx_ts_pes.
  * @cc:                MPEG-TS packet continuity counter
@@ -145,6 +147,8 @@ struct dvb_demux_feed {
        ktime_t timeout;
        struct dvb_demux_filter *filter;
 
+       u32 buffer_flags;
+
        enum ts_filter_type ts_type;
        enum dmx_ts_pes pes_type;
 
index 01d1202..8cb8845 100644 (file)
@@ -85,6 +85,12 @@ struct dvb_buffer {
  * @nonblocking:
  *             If different than zero, device is operating on non-blocking
  *             mode.
+ * @flags:     buffer flags as defined by &enum dmx_buffer_flags.
+ *             Filled only at &DMX_DQBUF. &DMX_QBUF should zero this field.
+ * @count:     monotonic counter for filled buffers. Helps to identify
+ *             data stream loses. Filled only at &DMX_DQBUF. &DMX_QBUF should
+ *             zero this field.
+ *
  * @name:      name of the device type. Currently, it can either be
  *             "dvr" or "demux_filter".
  */
@@ -100,10 +106,14 @@ struct dvb_vb2_ctx {
        int     buf_siz;
        int     buf_cnt;
        int     nonblocking;
+
+       enum dmx_buffer_flags flags;
+       u32     count;
+
        char    name[DVB_VB2_NAME_MAX + 1];
 };
 
-#ifndef DVB_MMAP
+#ifndef CONFIG_DVB_MMAP
 static inline int dvb_vb2_init(struct dvb_vb2_ctx *ctx,
                               const char *name, int non_blocking)
 {
@@ -114,7 +124,7 @@ static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
        return 0;
 };
 #define dvb_vb2_is_streaming(ctx) (0)
-#define dvb_vb2_fill_buffer(ctx, file, wait) (0)
+#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0)
 
 static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
                                    struct file *file,
@@ -153,9 +163,13 @@ int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx);
  * @ctx:       control struct for VB2 handler
  * @src:       place where the data is stored
  * @len:       number of bytes to be copied from @src
+ * @buffer_flags:
+ *             pointer to buffer flags as defined by &enum dmx_buffer_flags.
+ *             can be NULL.
  */
 int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
-                       const unsigned char *src, int len);
+                       const unsigned char *src, int len,
+                       enum dmx_buffer_flags *buffer_flags);
 
 /**
  * dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV
index 6545b03..4de35ed 100644 (file)
@@ -257,6 +257,18 @@ struct devlink_resource_size_params {
        enum devlink_resource_unit unit;
 };
 
+static inline void
+devlink_resource_size_params_init(struct devlink_resource_size_params *size_params,
+                                 u64 size_min, u64 size_max,
+                                 u64 size_granularity,
+                                 enum devlink_resource_unit unit)
+{
+       size_params->size_min = size_min;
+       size_params->size_max = size_max;
+       size_params->size_granularity = size_granularity;
+       size_params->unit = unit;
+}
+
 /**
  * struct devlink_resource - devlink resource
  * @name: name of the resource
@@ -278,7 +290,7 @@ struct devlink_resource {
        u64 size_new;
        bool size_valid;
        struct devlink_resource *parent;
-       struct devlink_resource_size_params *size_params;
+       struct devlink_resource_size_params size_params;
        struct list_head list;
        struct list_head resource_list;
        const struct devlink_resource_ops *resource_ops;
@@ -402,7 +414,7 @@ int devlink_resource_register(struct devlink *devlink,
                              u64 resource_size,
                              u64 resource_id,
                              u64 parent_resource_id,
-                             struct devlink_resource_size_params *size_params,
+                             const struct devlink_resource_size_params *size_params,
                              const struct devlink_resource_ops *resource_ops);
 void devlink_resources_unregister(struct devlink *devlink,
                                  struct devlink_resource *resource);
@@ -556,7 +568,7 @@ devlink_resource_register(struct devlink *devlink,
                          u64 resource_size,
                          u64 resource_id,
                          u64 parent_resource_id,
-                         struct devlink_resource_size_params *size_params,
+                         const struct devlink_resource_size_params *size_params,
                          const struct devlink_resource_ops *resource_ops)
 {
        return 0;
index 746abff..f49b3a5 100644 (file)
@@ -328,6 +328,13 @@ int ip_decrease_ttl(struct iphdr *iph)
        return --iph->ttl;
 }
 
+static inline int ip_mtu_locked(const struct dst_entry *dst)
+{
+       const struct rtable *rt = (const struct rtable *)dst;
+
+       return rt->rt_mtu_locked || dst_metric_locked(dst, RTAX_MTU);
+}
+
 static inline
 int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst)
 {
@@ -335,7 +342,7 @@ int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst)
 
        return  pmtudisc == IP_PMTUDISC_DO ||
                (pmtudisc == IP_PMTUDISC_WANT &&
-                !(dst_metric_locked(dst, RTAX_MTU)));
+                !ip_mtu_locked(dst));
 }
 
 static inline bool ip_sk_accept_pmtu(const struct sock *sk)
@@ -361,7 +368,7 @@ static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst,
        struct net *net = dev_net(dst->dev);
 
        if (net->ipv4.sysctl_ip_fwd_use_pmtu ||
-           dst_metric_locked(dst, RTAX_MTU) ||
+           ip_mtu_locked(dst) ||
            !forwarding)
                return dst_mtu(dst);
 
index 27d23a6..ac0866b 100644 (file)
@@ -179,6 +179,9 @@ void rt6_disable_ip(struct net_device *dev, unsigned long event);
 void rt6_sync_down_dev(struct net_device *dev, unsigned long event);
 void rt6_multipath_rebalance(struct rt6_info *rt);
 
+void rt6_uncached_list_add(struct rt6_info *rt);
+void rt6_uncached_list_del(struct rt6_info *rt);
+
 static inline const struct rt6_info *skb_rt6_info(const struct sk_buff *skb)
 {
        const struct dst_entry *dst = skb_dst(skb);
index f805243..77d0a78 100644 (file)
@@ -59,6 +59,7 @@ struct fib_nh_exception {
        int                             fnhe_genid;
        __be32                          fnhe_daddr;
        u32                             fnhe_pmtu;
+       bool                            fnhe_mtu_locked;
        __be32                          fnhe_gw;
        unsigned long                   fnhe_expires;
        struct rtable __rcu             *fnhe_rth_input;
index fe994d2..5c40f11 100644 (file)
@@ -103,7 +103,7 @@ void llc_sk_reset(struct sock *sk);
 
 /* Access to a connection */
 int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
-void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
+int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
 void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb);
 void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit);
 void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit);
index 906e902..2b581bd 100644 (file)
@@ -2063,6 +2063,9 @@ struct ieee80211_txq {
  * @IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA: Hardware supports buffer STA on
  *     TDLS links.
  *
+ * @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't
+ *     support QoS NDP for AP probing - that's most likely a driver bug.
+ *
  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
  */
 enum ieee80211_hw_flags {
@@ -2106,6 +2109,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_REPORTS_LOW_ACK,
        IEEE80211_HW_SUPPORTS_TX_FRAG,
        IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
+       IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
 
        /* keep last, obviously */
        NUM_IEEE80211_HW_FLAGS
@@ -4149,7 +4153,7 @@ void ieee80211_sta_uapsd_trigger(struct ieee80211_sta *sta, u8 tid);
  * The TX headroom reserved by mac80211 for its own tx_status functions.
  * This is enough for the radiotap header.
  */
-#define IEEE80211_TX_STATUS_HEADROOM   14
+#define IEEE80211_TX_STATUS_HEADROOM   ALIGN(14, 4)
 
 /**
  * ieee80211_sta_set_buffered - inform mac80211 about driver-buffered frames
index 663b015..30eb065 100644 (file)
@@ -1068,6 +1068,8 @@ struct nft_object_ops {
 int nft_register_obj(struct nft_object_type *obj_type);
 void nft_unregister_obj(struct nft_object_type *obj_type);
 
+#define NFT_FLOWTABLE_DEVICE_MAX       8
+
 /**
  *     struct nft_flowtable - nf_tables flow table
  *
@@ -1080,6 +1082,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type);
  *     @genmask: generation mask
  *     @use: number of references to this flow table
  *     @handle: unique object handle
+ *     @dev_name: array of device names
  *     @data: rhashtable and garbage collector
  *     @ops: array of hooks
  */
@@ -1093,6 +1096,7 @@ struct nft_flowtable {
        u32                             genmask:2,
                                        use:30;
        u64                             handle;
+       char                            *dev_name[NFT_FLOWTABLE_DEVICE_MAX];
        /* runtime data below here */
        struct nf_hook_ops              *ops ____cacheline_aligned;
        struct nf_flowtable             data;
index ebc5a2e..f83cacc 100644 (file)
@@ -78,7 +78,7 @@ struct regulatory_request {
        int wiphy_idx;
        enum nl80211_reg_initiator initiator;
        enum nl80211_user_reg_hint_type user_reg_hint_type;
-       char alpha2[2];
+       char alpha2[3];
        enum nl80211_dfs_regions dfs_region;
        bool intersect;
        bool processed;
index 1eb9ce4..20a92ca 100644 (file)
@@ -63,7 +63,8 @@ struct rtable {
        __be32                  rt_gateway;
 
        /* Miscellaneous cached information */
-       u32                     rt_pmtu;
+       u32                     rt_mtu_locked:1,
+                               rt_pmtu:31;
 
        u32                     rt_table_id;
 
@@ -227,6 +228,9 @@ struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
 void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
 
+void rt_add_uncached_list(struct rtable *rt);
+void rt_del_uncached_list(struct rtable *rt);
+
 static inline void ip_rt_put(struct rtable *rt)
 {
        /* dst_release() accepts a NULL parameter.
index e2ab136..8da3267 100644 (file)
@@ -30,6 +30,7 @@ struct qdisc_rate_table {
 enum qdisc_state_t {
        __QDISC_STATE_SCHED,
        __QDISC_STATE_DEACTIVATED,
+       __QDISC_STATE_RUNNING,
 };
 
 struct qdisc_size_table {
@@ -824,6 +825,16 @@ static inline void __qdisc_drop(struct sk_buff *skb, struct sk_buff **to_free)
        *to_free = skb;
 }
 
+static inline void __qdisc_drop_all(struct sk_buff *skb,
+                                   struct sk_buff **to_free)
+{
+       if (skb->prev)
+               skb->prev->next = *to_free;
+       else
+               skb->next = *to_free;
+       *to_free = skb;
+}
+
 static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch,
                                                   struct qdisc_skb_head *qh,
                                                   struct sk_buff **to_free)
@@ -956,6 +967,15 @@ static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch,
        return NET_XMIT_DROP;
 }
 
+static inline int qdisc_drop_all(struct sk_buff *skb, struct Qdisc *sch,
+                                struct sk_buff **to_free)
+{
+       __qdisc_drop_all(skb, to_free);
+       qdisc_qstats_drop(sch);
+
+       return NET_XMIT_DROP;
+}
+
 /* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how
    long it will take to send a packet given its size.
  */
index 169c92a..ae23f3b 100644 (file)
@@ -1137,6 +1137,7 @@ struct proto {
 
 int proto_register(struct proto *prot, int alloc_slab);
 void proto_unregister(struct proto *prot);
+int sock_load_diag_module(int family, int protocol);
 
 #ifdef SOCK_REFCNT_DEBUG
 static inline void sk_refcnt_debug_inc(struct sock *sk)
index 81bdbf9..9185e45 100644 (file)
@@ -64,6 +64,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh)
                UDP_SKB_CB(skb)->cscov = cscov;
                if (skb->ip_summed == CHECKSUM_COMPLETE)
                        skb->ip_summed = CHECKSUM_NONE;
+               skb->csum_valid = 0;
         }
 
        return 0;
index d656809..415e099 100644 (file)
@@ -130,6 +130,8 @@ void rdma_copy_addr(struct rdma_dev_addr *dev_addr,
                    const unsigned char *dst_dev_addr);
 
 int rdma_addr_size(struct sockaddr *addr);
+int rdma_addr_size_in6(struct sockaddr_in6 *addr);
+int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr);
 
 int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid,
                                 const union ib_gid *dgid,
index 73b2387..ff3ed43 100644 (file)
@@ -1537,10 +1537,6 @@ struct ib_xrcd {
 
        struct mutex            tgt_qp_mutex;
        struct list_head        tgt_qp_list;
-       /*
-        * Implementation details of the RDMA core, don't use in drivers:
-        */
-       struct rdma_restrack_entry res;
 };
 
 struct ib_ah {
index c2d8116..2cdf8dc 100644 (file)
@@ -29,10 +29,6 @@ enum rdma_restrack_type {
         */
        RDMA_RESTRACK_QP,
        /**
-        * @RDMA_RESTRACK_XRCD: XRC domain (XRCD)
-        */
-       RDMA_RESTRACK_XRCD,
-       /**
         * @RDMA_RESTRACK_MAX: Last entry, used for array dclarations
         */
        RDMA_RESTRACK_MAX
index 6da4407..38287d9 100644 (file)
@@ -276,10 +276,7 @@ struct uverbs_object_tree_def {
  */
 
 struct uverbs_ptr_attr {
-       union {
-               u64             data;
-               void    __user *ptr;
-       };
+       u64             data;
        u16             len;
        /* Combination of bits from enum UVERBS_ATTR_F_XXXX */
        u16             flags;
@@ -351,38 +348,60 @@ static inline const struct uverbs_attr *uverbs_attr_get(const struct uverbs_attr
 }
 
 static inline int uverbs_copy_to(const struct uverbs_attr_bundle *attrs_bundle,
-                                size_t idx, const void *from)
+                                size_t idx, const void *from, size_t size)
 {
        const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
        u16 flags;
+       size_t min_size;
 
        if (IS_ERR(attr))
                return PTR_ERR(attr);
 
+       min_size = min_t(size_t, attr->ptr_attr.len, size);
+       if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
+               return -EFAULT;
+
        flags = attr->ptr_attr.flags | UVERBS_ATTR_F_VALID_OUTPUT;
-       return (!copy_to_user(attr->ptr_attr.ptr, from, attr->ptr_attr.len) &&
-               !put_user(flags, &attr->uattr->flags)) ? 0 : -EFAULT;
+       if (put_user(flags, &attr->uattr->flags))
+               return -EFAULT;
+
+       return 0;
 }
 
-static inline int _uverbs_copy_from(void *to, size_t to_size,
+static inline bool uverbs_attr_ptr_is_inline(const struct uverbs_attr *attr)
+{
+       return attr->ptr_attr.len <= sizeof(attr->ptr_attr.data);
+}
+
+static inline int _uverbs_copy_from(void *to,
                                    const struct uverbs_attr_bundle *attrs_bundle,
-                                   size_t idx)
+                                   size_t idx,
+                                   size_t size)
 {
        const struct uverbs_attr *attr = uverbs_attr_get(attrs_bundle, idx);
 
        if (IS_ERR(attr))
                return PTR_ERR(attr);
 
-       if (to_size <= sizeof(((struct ib_uverbs_attr *)0)->data))
+       /*
+        * Validation ensures attr->ptr_attr.len >= size. If the caller is
+        * using UVERBS_ATTR_SPEC_F_MIN_SZ then it must call copy_from with
+        * the right size.
+        */
+       if (unlikely(size < attr->ptr_attr.len))
+               return -EINVAL;
+
+       if (uverbs_attr_ptr_is_inline(attr))
                memcpy(to, &attr->ptr_attr.data, attr->ptr_attr.len);
-       else if (copy_from_user(to, attr->ptr_attr.ptr, attr->ptr_attr.len))
+       else if (copy_from_user(to, u64_to_user_ptr(attr->ptr_attr.data),
+                               attr->ptr_attr.len))
                return -EFAULT;
 
        return 0;
 }
 
 #define uverbs_copy_from(to, attrs_bundle, idx)                                      \
-       _uverbs_copy_from(to, sizeof(*(to)), attrs_bundle, idx)
+       _uverbs_copy_from(to, attrs_bundle, idx, sizeof(*to))
 
 /* =================================================
  *      Definitions -> Specs infrastructure
index d8d4a90..2280b23 100644 (file)
@@ -68,6 +68,9 @@ struct scsi_cmnd {
        struct list_head list;  /* scsi_cmnd participates in queue lists */
        struct list_head eh_entry; /* entry for the host eh_cmd_q */
        struct delayed_work abort_work;
+
+       struct rcu_head rcu;
+
        int eh_eflags;          /* Used by error handlr */
 
        /*
index 1a1df0d..9c1e4ba 100644 (file)
@@ -452,6 +452,9 @@ struct scsi_host_template {
        /* True if the controller does not support WRITE SAME */
        unsigned no_write_same:1;
 
+       /* True if the low-level driver supports blk-mq only */
+       unsigned force_blk_mq:1;
+
        /*
         * Countdown for host blocking with no commands outstanding.
         */
@@ -571,8 +574,6 @@ struct Scsi_Host {
                struct blk_mq_tag_set   tag_set;
        };
 
-       struct rcu_head rcu;
-
        atomic_t host_busy;                /* commands actually active on low-level */
        atomic_t host_blocked;
 
index c2d1b15..a91f251 100644 (file)
@@ -15,6 +15,7 @@
 
 #define ARC_REG_MCIP_BCR       0x0d0
 #define ARC_REG_MCIP_IDU_BCR   0x0D5
+#define ARC_REG_GFRC_BUILD     0x0D6
 #define ARC_REG_MCIP_CMD       0x600
 #define ARC_REG_MCIP_WDATA     0x601
 #define ARC_REG_MCIP_READBACK  0x602
@@ -36,10 +37,14 @@ struct mcip_cmd {
 #define CMD_SEMA_RELEASE               0x12
 
 #define CMD_DEBUG_SET_MASK             0x34
+#define CMD_DEBUG_READ_MASK            0x35
 #define CMD_DEBUG_SET_SELECT           0x36
+#define CMD_DEBUG_READ_SELECT          0x37
 
 #define CMD_GFRC_READ_LO               0x42
 #define CMD_GFRC_READ_HI               0x43
+#define CMD_GFRC_SET_CORE              0x47
+#define CMD_GFRC_READ_CORE             0x48
 
 #define CMD_IDU_ENABLE                 0x71
 #define CMD_IDU_DISABLE                        0x72
index 4bb86d3..9a4fa0c 100644 (file)
@@ -31,7 +31,7 @@
 #define AC97_HEADPHONE         0x04    /* Headphone Volume (optional) */
 #define AC97_MASTER_MONO       0x06    /* Master Volume Mono (optional) */
 #define AC97_MASTER_TONE       0x08    /* Master Tone (Bass & Treble) (optional) */
-#define AC97_PC_BEEP           0x0a    /* PC Beep Volume (optinal) */
+#define AC97_PC_BEEP           0x0a    /* PC Beep Volume (optional) */
 #define AC97_PHONE             0x0c    /* Phone Volume (optional) */
 #define AC97_MIC               0x0e    /* MIC Volume */
 #define AC97_LINE              0x10    /* Line In Volume */
index 200f731..7b706ff 100644 (file)
@@ -86,8 +86,8 @@ TRACE_EVENT(mmc_request_start,
                  __entry->stop_flags, __entry->stop_retries,
                  __entry->sbc_opcode, __entry->sbc_arg,
                  __entry->sbc_flags, __entry->sbc_retries,
-                 __entry->blocks, __entry->blk_addr,
-                 __entry->blksz, __entry->data_flags, __entry->tag,
+                 __entry->blocks, __entry->blksz,
+                 __entry->blk_addr, __entry->data_flags, __entry->tag,
                  __entry->can_retune, __entry->doing_retune,
                  __entry->retune_now, __entry->need_retune,
                  __entry->hold_retune, __entry->retune_period)
index 85dc965..99c902e 100644 (file)
@@ -102,13 +102,13 @@ typedef struct siginfo {
                                short _addr_lsb; /* LSB of the reported address */
                                /* used when si_code=SEGV_BNDERR */
                                struct {
-                                       short _dummy_bnd;
+                                       void *_dummy_bnd;
                                        void __user *_lower;
                                        void __user *_upper;
                                } _addr_bnd;
                                /* used when si_code=SEGV_PKUERR */
                                struct {
-                                       short _dummy_pkey;
+                                       void *_dummy_pkey;
                                        __u32 _pkey;
                                } _addr_pkey;
                        };
index 91a31ff..9a781f0 100644 (file)
@@ -63,6 +63,7 @@ struct drm_virtgpu_execbuffer {
 };
 
 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */
+#define VIRTGPU_PARAM_CAPSET_QUERY_FIX 2 /* do we have the capset fix */
 
 struct drm_virtgpu_getparam {
        __u64 param;
index 20d1490..3c50e07 100644 (file)
@@ -131,7 +131,7 @@ enum {
 #define BLKTRACE_BDEV_SIZE     32
 
 /*
- * User setup structure passed with BLKTRACESTART
+ * User setup structure passed with BLKTRACESETUP
  */
 struct blk_user_trace_setup {
        char name[BLKTRACE_BDEV_SIZE];  /* output */
index 5f3c5a9..b4112f0 100644 (file)
@@ -212,6 +212,32 @@ struct dmx_stc {
 };
 
 /**
+ * enum dmx_buffer_flags - DMX memory-mapped buffer flags
+ *
+ * @DMX_BUFFER_FLAG_HAD_CRC32_DISCARD:
+ *     Indicates that the Kernel discarded one or more frames due to wrong
+ *     CRC32 checksum.
+ * @DMX_BUFFER_FLAG_TEI:
+ *     Indicates that the Kernel has detected a Transport Error indicator
+ *     (TEI) on a filtered pid.
+ * @DMX_BUFFER_PKT_COUNTER_MISMATCH:
+ *     Indicates that the Kernel has detected a packet counter mismatch
+ *     on a filtered pid.
+ * @DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED:
+ *     Indicates that the Kernel has detected one or more frame discontinuity.
+ * @DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR:
+ *     Received at least one packet with a frame discontinuity indicator.
+ */
+
+enum dmx_buffer_flags {
+       DMX_BUFFER_FLAG_HAD_CRC32_DISCARD               = 1 << 0,
+       DMX_BUFFER_FLAG_TEI                             = 1 << 1,
+       DMX_BUFFER_PKT_COUNTER_MISMATCH                 = 1 << 2,
+       DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED          = 1 << 3,
+       DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR         = 1 << 4,
+};
+
+/**
  * struct dmx_buffer - dmx buffer info
  *
  * @index:     id number of the buffer
@@ -220,15 +246,24 @@ struct dmx_stc {
  *             offset from the start of the device memory for this plane,
  *             (or a "cookie" that should be passed to mmap() as offset)
  * @length:    size in bytes of the buffer
+ * @flags:     bit array of buffer flags as defined by &enum dmx_buffer_flags.
+ *             Filled only at &DMX_DQBUF.
+ * @count:     monotonic counter for filled buffers. Helps to identify
+ *             data stream loses. Filled only at &DMX_DQBUF.
  *
  * Contains data exchanged by application and driver using one of the streaming
  * I/O methods.
+ *
+ * Please notice that, for &DMX_QBUF, only @index should be filled.
+ * On &DMX_DQBUF calls, all fields will be filled by the Kernel.
  */
 struct dmx_buffer {
        __u32                   index;
        __u32                   bytesused;
        __u32                   offset;
        __u32                   length;
+       __u32                   flags;
+       __u32                   count;
 };
 
 /**
index f8cb576..820de5d 100644 (file)
@@ -23,7 +23,6 @@
 #define _UAPI_LINUX_IF_ETHER_H
 
 #include <linux/types.h>
-#include <linux/libc-compat.h>
 
 /*
  *     IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
@@ -31,6 +30,7 @@
  */
 
 #define ETH_ALEN       6               /* Octets in one ethernet addr   */
+#define ETH_TLEN       2               /* Octets in ethernet type field */
 #define ETH_HLEN       14              /* Total octets in header.       */
 #define ETH_ZLEN       60              /* Min. octets in frame sans FCS */
 #define ETH_DATA_LEN   1500            /* Max. octets in payload        */
  *     This is an Ethernet frame header.
  */
 
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR              1
+#endif
+
 #if __UAPI_DEF_ETHHDR
 struct ethhdr {
        unsigned char   h_dest[ETH_ALEN];       /* destination eth addr */
index 0fb5ef9..7b26d4b 100644 (file)
@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
 #define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
 #define KVM_GET_EMULATED_CPUID   _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
+#define KVM_GET_MSR_FEATURE_INDEX_LIST    _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
 
 /*
  * Extension capability list.
@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_AIS_MIGRATION 150
 #define KVM_CAP_PPC_GET_CPU_CHAR 151
 #define KVM_CAP_S390_BPB 152
+#define KVM_CAP_GET_MSR_FEATURES 153
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index fc29efa..8254c93 100644 (file)
 
 #endif /* __GLIBC__ */
 
-/* Definitions for if_ether.h */
-/* allow libcs like musl to deactivate this, glibc does not implement this. */
-#ifndef __UAPI_DEF_ETHHDR
-#define __UAPI_DEF_ETHHDR              1
-#endif
-
 #endif /* _UAPI_LIBC_COMPAT_H */
index 4fe580d..f5bf06e 100644 (file)
@@ -54,7 +54,6 @@
 #define LIRC_CAN_SEND_RAW              LIRC_MODE2SEND(LIRC_MODE_RAW)
 #define LIRC_CAN_SEND_PULSE            LIRC_MODE2SEND(LIRC_MODE_PULSE)
 #define LIRC_CAN_SEND_MODE2            LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_SCANCODE         LIRC_MODE2SEND(LIRC_MODE_SCANCODE)
 #define LIRC_CAN_SEND_LIRCCODE         LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
 
 #define LIRC_CAN_SEND_MASK             0x0000003f
index 3d77fe9..9008f31 100644 (file)
@@ -42,7 +42,7 @@ typedef enum {
        SEV_RET_INVALID_PLATFORM_STATE,
        SEV_RET_INVALID_GUEST_STATE,
        SEV_RET_INAVLID_CONFIG,
-       SEV_RET_INVALID_len,
+       SEV_RET_INVALID_LEN,
        SEV_RET_ALREADY_OWNED,
        SEV_RET_INVALID_CERTIFICATE,
        SEV_RET_POLICY_FAILURE,
index e46d82b..d5a1b8a 100644 (file)
@@ -69,8 +69,8 @@ struct ptrace_peeksiginfo_args {
 #define PTRACE_SECCOMP_GET_METADATA    0x420d
 
 struct seccomp_metadata {
-       unsigned long filter_off;       /* Input: which filter */
-       unsigned int flags;             /* Output: filter's flags */
+       __u64 filter_off;       /* Input: which filter */
+       __u64 flags;            /* Output: filter's flags */
 };
 
 /* Read signals from a shared (process wide) queue */
index 17a022c..da3315e 100644 (file)
@@ -370,7 +370,7 @@ static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_d
 {
        return (protocol == UAC_VERSION_1) ?
                desc->baSourceID[desc->bNrInPins + 4] :
-               desc->baSourceID[desc->bNrInPins + 6];
+               2; /* in UAC2, this value is constant */
 }
 
 static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
@@ -378,7 +378,7 @@ static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_de
 {
        return (protocol == UAC_VERSION_1) ?
                &desc->baSourceID[desc->bNrInPins + 5] :
-               &desc->baSourceID[desc->bNrInPins + 7];
+               &desc->baSourceID[desc->bNrInPins + 6];
 }
 
 static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
index 4b0b0b7..0af83d8 100644 (file)
@@ -32,6 +32,22 @@ struct ocxl_ioctl_attach {
        __u64 reserved3;
 };
 
+struct ocxl_ioctl_metadata {
+       __u16 version; // struct version, always backwards compatible
+
+       // Version 0 fields
+       __u8  afu_version_major;
+       __u8  afu_version_minor;
+       __u32 pasid;            // PASID assigned to the current context
+
+       __u64 pp_mmio_size;     // Per PASID MMIO size
+       __u64 global_mmio_size;
+
+       // End version 0 fields
+
+       __u64 reserved[13]; // Total of 16*u64
+};
+
 struct ocxl_ioctl_irq_fd {
        __u64 irq_offset;
        __s32 eventfd;
@@ -45,5 +61,6 @@ struct ocxl_ioctl_irq_fd {
 #define OCXL_IOCTL_IRQ_ALLOC   _IOR(OCXL_MAGIC, 0x11, __u64)
 #define OCXL_IOCTL_IRQ_FREE    _IOW(OCXL_MAGIC, 0x12, __u64)
 #define OCXL_IOCTL_IRQ_SET_FD  _IOW(OCXL_MAGIC, 0x13, struct ocxl_ioctl_irq_fd)
+#define OCXL_IOCTL_GET_METADATA _IOR(OCXL_MAGIC, 0x14, struct ocxl_ioctl_metadata)
 
 #endif /* _UAPI_MISC_OCXL_H */
index 03557b5..46de088 100644 (file)
@@ -65,7 +65,7 @@ struct ib_uverbs_attr {
        __u16 len;              /* only for pointers */
        __u16 flags;            /* combination of UVERBS_ATTR_F_XXXX */
        __u16 reserved;
-       __u64 data;             /* ptr to command, inline data or idr/fd */
+       __aligned_u64 data;     /* ptr to command, inline data or idr/fd */
 };
 
 struct ib_uverbs_ioctl_hdr {
@@ -73,7 +73,7 @@ struct ib_uverbs_ioctl_hdr {
        __u16 object_id;
        __u16 method_id;
        __u16 num_attrs;
-       __u64 reserved;
+       __aligned_u64 reserved;
        struct ib_uverbs_attr  attrs[0];
 };
 
index 969eaf1..21efbf6 100644 (file)
@@ -1001,7 +1001,7 @@ static int __ref kernel_init(void *unused)
        /* need to finish all async __init code before freeing the memory */
        async_synchronize_full();
        ftrace_free_init_mem();
-       jump_label_invalidate_init();
+       jump_label_invalidate_initmem();
        free_initmem();
        mark_readonly();
        system_state = SYSTEM_RUNNING;
index d7f309f..a808f29 100644 (file)
@@ -325,9 +325,8 @@ err:
 static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
-       struct ipc_namespace *ns = data;
+       struct ipc_namespace *ns = sb->s_fs_info;
 
-       sb->s_fs_info = ns;
        sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV;
        sb->s_blocksize = PAGE_SIZE;
        sb->s_blocksize_bits = PAGE_SHIFT;
@@ -344,44 +343,18 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 }
 
-static struct file_system_type mqueue_fs_type;
-/*
- * Return value is pinned only by reference in ->mq_mnt; it will
- * live until ipcns dies.  Caller does not need to drop it.
- */
-static struct vfsmount *mq_internal_mount(void)
-{
-       struct ipc_namespace *ns = current->nsproxy->ipc_ns;
-       struct vfsmount *m = ns->mq_mnt;
-       if (m)
-               return m;
-       m = kern_mount_data(&mqueue_fs_type, ns);
-       spin_lock(&mq_lock);
-       if (unlikely(ns->mq_mnt)) {
-               spin_unlock(&mq_lock);
-               if (!IS_ERR(m))
-                       kern_unmount(m);
-               return ns->mq_mnt;
-       }
-       if (!IS_ERR(m))
-               ns->mq_mnt = m;
-       spin_unlock(&mq_lock);
-       return m;
-}
-
 static struct dentry *mqueue_mount(struct file_system_type *fs_type,
                         int flags, const char *dev_name,
                         void *data)
 {
-       struct vfsmount *m;
-       if (flags & SB_KERNMOUNT)
-               return mount_nodev(fs_type, flags, data, mqueue_fill_super);
-       m = mq_internal_mount();
-       if (IS_ERR(m))
-               return ERR_CAST(m);
-       atomic_inc(&m->mnt_sb->s_active);
-       down_write(&m->mnt_sb->s_umount);
-       return dget(m->mnt_root);
+       struct ipc_namespace *ns;
+       if (flags & SB_KERNMOUNT) {
+               ns = data;
+               data = NULL;
+       } else {
+               ns = current->nsproxy->ipc_ns;
+       }
+       return mount_ns(fs_type, flags, data, ns, ns->user_ns, mqueue_fill_super);
 }
 
 static void init_once(void *foo)
@@ -771,16 +744,13 @@ static int prepare_open(struct dentry *dentry, int oflag, int ro,
 static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
                      struct mq_attr *attr)
 {
-       struct vfsmount *mnt = mq_internal_mount();
-       struct dentry *root;
+       struct vfsmount *mnt = current->nsproxy->ipc_ns->mq_mnt;
+       struct dentry *root = mnt->mnt_root;
        struct filename *name;
        struct path path;
        int fd, error;
        int ro;
 
-       if (IS_ERR(mnt))
-               return PTR_ERR(mnt);
-
        audit_mq_open(oflag, mode, attr);
 
        if (IS_ERR(name = getname(u_name)))
@@ -791,7 +761,6 @@ static int do_mq_open(const char __user *u_name, int oflag, umode_t mode,
                goto out_putname;
 
        ro = mnt_want_write(mnt);       /* we'll drop it in any case */
-       root = mnt->mnt_root;
        inode_lock(d_inode(root));
        path.dentry = lookup_one_len(name->name, root, strlen(name->name));
        if (IS_ERR(path.dentry)) {
@@ -840,9 +809,6 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
        struct ipc_namespace *ipc_ns = current->nsproxy->ipc_ns;
        struct vfsmount *mnt = ipc_ns->mq_mnt;
 
-       if (!mnt)
-               return -ENOENT;
-
        name = getname(u_name);
        if (IS_ERR(name))
                return PTR_ERR(name);
@@ -1569,26 +1535,28 @@ int mq_init_ns(struct ipc_namespace *ns)
        ns->mq_msgsize_max   = DFLT_MSGSIZEMAX;
        ns->mq_msg_default   = DFLT_MSG;
        ns->mq_msgsize_default  = DFLT_MSGSIZE;
-       ns->mq_mnt = NULL;
 
+       ns->mq_mnt = kern_mount_data(&mqueue_fs_type, ns);
+       if (IS_ERR(ns->mq_mnt)) {
+               int err = PTR_ERR(ns->mq_mnt);
+               ns->mq_mnt = NULL;
+               return err;
+       }
        return 0;
 }
 
 void mq_clear_sbinfo(struct ipc_namespace *ns)
 {
-       if (ns->mq_mnt)
-               ns->mq_mnt->mnt_sb->s_fs_info = NULL;
+       ns->mq_mnt->mnt_sb->s_fs_info = NULL;
 }
 
 void mq_put_mnt(struct ipc_namespace *ns)
 {
-       if (ns->mq_mnt)
-               kern_unmount(ns->mq_mnt);
+       kern_unmount(ns->mq_mnt);
 }
 
 static int __init init_mqueue_fs(void)
 {
-       struct vfsmount *m;
        int error;
 
        mqueue_inode_cachep = kmem_cache_create("mqueue_inode_cache",
@@ -1610,10 +1578,6 @@ static int __init init_mqueue_fs(void)
        if (error)
                goto out_filesystem;
 
-       m = kern_mount_data(&mqueue_fs_type, &init_ipc_ns);
-       if (IS_ERR(m))
-               goto out_filesystem;
-       init_ipc_ns.mq_mnt = m;
        return 0;
 
 out_filesystem:
index 4643865..93e0e3a 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -386,6 +386,17 @@ static int shm_fault(struct vm_fault *vmf)
        return sfd->vm_ops->fault(vmf);
 }
 
+static int shm_split(struct vm_area_struct *vma, unsigned long addr)
+{
+       struct file *file = vma->vm_file;
+       struct shm_file_data *sfd = shm_file_data(file);
+
+       if (sfd->vm_ops && sfd->vm_ops->split)
+               return sfd->vm_ops->split(vma, addr);
+
+       return 0;
+}
+
 #ifdef CONFIG_NUMA
 static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
 {
@@ -510,6 +521,7 @@ static const struct vm_operations_struct shm_vm_ops = {
        .open   = shm_open,     /* callback for a new vm-area open */
        .close  = shm_close,    /* callback for when the vm-area is released */
        .fault  = shm_fault,
+       .split  = shm_split,
 #if defined(CONFIG_NUMA)
        .set_policy = shm_set_policy,
        .get_policy = shm_get_policy,
index b1f6648..14750e7 100644 (file)
@@ -26,8 +26,10 @@ static void bpf_array_free_percpu(struct bpf_array *array)
 {
        int i;
 
-       for (i = 0; i < array->map.max_entries; i++)
+       for (i = 0; i < array->map.max_entries; i++) {
                free_percpu(array->pptrs[i]);
+               cond_resched();
+       }
 }
 
 static int bpf_array_alloc_percpu(struct bpf_array *array)
@@ -43,6 +45,7 @@ static int bpf_array_alloc_percpu(struct bpf_array *array)
                        return -ENOMEM;
                }
                array->pptrs[i] = ptr;
+               cond_resched();
        }
 
        return 0;
@@ -73,11 +76,11 @@ static int array_map_alloc_check(union bpf_attr *attr)
 static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 {
        bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY;
-       int numa_node = bpf_map_attr_numa_node(attr);
+       int ret, numa_node = bpf_map_attr_numa_node(attr);
        u32 elem_size, index_mask, max_entries;
        bool unpriv = !capable(CAP_SYS_ADMIN);
+       u64 cost, array_size, mask64;
        struct bpf_array *array;
-       u64 array_size, mask64;
 
        elem_size = round_up(attr->value_size, 8);
 
@@ -109,8 +112,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
                array_size += (u64) max_entries * elem_size;
 
        /* make sure there is no u32 overflow later in round_up() */
-       if (array_size >= U32_MAX - PAGE_SIZE)
+       cost = array_size;
+       if (cost >= U32_MAX - PAGE_SIZE)
                return ERR_PTR(-ENOMEM);
+       if (percpu) {
+               cost += (u64)attr->max_entries * elem_size * num_possible_cpus();
+               if (cost >= U32_MAX - PAGE_SIZE)
+                       return ERR_PTR(-ENOMEM);
+       }
+       cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT;
+
+       ret = bpf_map_precharge_memlock(cost);
+       if (ret < 0)
+               return ERR_PTR(ret);
 
        /* allocate all map elements and zero-initialize them */
        array = bpf_map_area_alloc(array_size, numa_node);
@@ -121,20 +135,13 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
 
        /* copy mandatory map attributes */
        bpf_map_init_from_attr(&array->map, attr);
+       array->map.pages = cost;
        array->elem_size = elem_size;
 
-       if (!percpu)
-               goto out;
-
-       array_size += (u64) attr->max_entries * elem_size * num_possible_cpus();
-
-       if (array_size >= U32_MAX - PAGE_SIZE ||
-           bpf_array_alloc_percpu(array)) {
+       if (percpu && bpf_array_alloc_percpu(array)) {
                bpf_map_area_free(array);
                return ERR_PTR(-ENOMEM);
        }
-out:
-       array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT;
 
        return &array->map;
 }
index 29ca920..d315b39 100644 (file)
@@ -1590,7 +1590,7 @@ int bpf_prog_array_copy_to_user(struct bpf_prog_array __rcu *progs,
         * so always copy 'cnt' prog_ids to the user.
         * In a rare race the user will see zero prog_ids
         */
-       ids = kcalloc(cnt, sizeof(u32), GFP_USER);
+       ids = kcalloc(cnt, sizeof(u32), GFP_USER | __GFP_NOWARN);
        if (!ids)
                return -ENOMEM;
        rcu_read_lock();
index fbfdada..a4bb0b3 100644 (file)
@@ -334,7 +334,7 @@ static int cpu_map_kthread_run(void *data)
 static struct bpf_cpu_map_entry *__cpu_map_entry_alloc(u32 qsize, u32 cpu,
                                                       int map_id)
 {
-       gfp_t gfp = GFP_ATOMIC|__GFP_NOWARN;
+       gfp_t gfp = GFP_KERNEL | __GFP_NOWARN;
        struct bpf_cpu_map_entry *rcpu;
        int numa, err;
 
index 7b469d1..b4b5b81 100644 (file)
@@ -555,7 +555,10 @@ static void trie_free(struct bpf_map *map)
        struct lpm_trie_node __rcu **slot;
        struct lpm_trie_node *node;
 
-       raw_spin_lock(&trie->lock);
+       /* Wait for outstanding programs to complete
+        * update/lookup/delete/get_next_key and free the trie.
+        */
+       synchronize_rcu();
 
        /* Always start at the root and walk down to a node that has no
         * children. Then free that node, nullify its reference in the parent
@@ -566,10 +569,9 @@ static void trie_free(struct bpf_map *map)
                slot = &trie->root;
 
                for (;;) {
-                       node = rcu_dereference_protected(*slot,
-                                       lockdep_is_held(&trie->lock));
+                       node = rcu_dereference_protected(*slot, 1);
                        if (!node)
-                               goto unlock;
+                               goto out;
 
                        if (rcu_access_pointer(node->child[0])) {
                                slot = &node->child[0];
@@ -587,8 +589,8 @@ static void trie_free(struct bpf_map *map)
                }
        }
 
-unlock:
-       raw_spin_unlock(&trie->lock);
+out:
+       kfree(trie);
 }
 
 static int trie_get_next_key(struct bpf_map *map, void *_key, void *_next_key)
index 48c3341..a927e89 100644 (file)
@@ -521,8 +521,8 @@ static struct smap_psock *smap_init_psock(struct sock *sock,
 static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 {
        struct bpf_stab *stab;
-       int err = -EINVAL;
        u64 cost;
+       int err;
 
        if (!capable(CAP_NET_ADMIN))
                return ERR_PTR(-EPERM);
@@ -547,6 +547,7 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
 
        /* make sure page count doesn't overflow */
        cost = (u64) stab->map.max_entries * sizeof(struct sock *);
+       err = -EINVAL;
        if (cost >= U32_MAX - PAGE_SIZE)
                goto free_stab;
 
index e24aa32..43f95d1 100644 (file)
@@ -1845,7 +1845,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz
        union bpf_attr attr = {};
        int err;
 
-       if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled)
+       if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN))
                return -EPERM;
 
        err = check_uarg_tail_zero(uattr, sizeof(attr), size);
index 5fb69a8..c6eff10 100644 (file)
@@ -1356,6 +1356,13 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno)
        return reg->type == PTR_TO_CTX;
 }
 
+static bool is_pkt_reg(struct bpf_verifier_env *env, int regno)
+{
+       const struct bpf_reg_state *reg = cur_regs(env) + regno;
+
+       return type_is_pkt_pointer(reg->type);
+}
+
 static int check_pkt_ptr_alignment(struct bpf_verifier_env *env,
                                   const struct bpf_reg_state *reg,
                                   int off, int size, bool strict)
@@ -1416,10 +1423,10 @@ static int check_generic_ptr_alignment(struct bpf_verifier_env *env,
 }
 
 static int check_ptr_alignment(struct bpf_verifier_env *env,
-                              const struct bpf_reg_state *reg,
-                              int off, int size)
+                              const struct bpf_reg_state *reg, int off,
+                              int size, bool strict_alignment_once)
 {
-       bool strict = env->strict_alignment;
+       bool strict = env->strict_alignment || strict_alignment_once;
        const char *pointer_desc = "";
 
        switch (reg->type) {
@@ -1576,9 +1583,9 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size)
  * if t==write && value_regno==-1, some unknown value is stored into memory
  * if t==read && value_regno==-1, don't care what we read from memory
  */
-static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off,
-                           int bpf_size, enum bpf_access_type t,
-                           int value_regno)
+static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno,
+                           int off, int bpf_size, enum bpf_access_type t,
+                           int value_regno, bool strict_alignment_once)
 {
        struct bpf_reg_state *regs = cur_regs(env);
        struct bpf_reg_state *reg = regs + regno;
@@ -1590,7 +1597,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                return size;
 
        /* alignment checks will add in reg->off themselves */
-       err = check_ptr_alignment(env, reg, off, size);
+       err = check_ptr_alignment(env, reg, off, size, strict_alignment_once);
        if (err)
                return err;
 
@@ -1735,21 +1742,23 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins
                return -EACCES;
        }
 
-       if (is_ctx_reg(env, insn->dst_reg)) {
-               verbose(env, "BPF_XADD stores into R%d context is not allowed\n",
-                       insn->dst_reg);
+       if (is_ctx_reg(env, insn->dst_reg) ||
+           is_pkt_reg(env, insn->dst_reg)) {
+               verbose(env, "BPF_XADD stores into R%d %s is not allowed\n",
+                       insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ?
+                       "context" : "packet");
                return -EACCES;
        }
 
        /* check whether atomic_add can read the memory */
        err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
-                              BPF_SIZE(insn->code), BPF_READ, -1);
+                              BPF_SIZE(insn->code), BPF_READ, -1, true);
        if (err)
                return err;
 
        /* check whether atomic_add can write into the same memory */
        return check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
-                               BPF_SIZE(insn->code), BPF_WRITE, -1);
+                               BPF_SIZE(insn->code), BPF_WRITE, -1, true);
 }
 
 /* when register 'regno' is passed into function that will read 'access_size'
@@ -2388,7 +2397,8 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn
         * is inferred from register state.
         */
        for (i = 0; i < meta.access_size; i++) {
-               err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1);
+               err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B,
+                                      BPF_WRITE, -1, false);
                if (err)
                        return err;
        }
@@ -4632,7 +4642,7 @@ static int do_check(struct bpf_verifier_env *env)
                         */
                        err = check_mem_access(env, insn_idx, insn->src_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_READ,
-                                              insn->dst_reg);
+                                              insn->dst_reg, false);
                        if (err)
                                return err;
 
@@ -4684,7 +4694,7 @@ static int do_check(struct bpf_verifier_env *env)
                        /* check that memory (dst_reg + off) is writeable */
                        err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_WRITE,
-                                              insn->src_reg);
+                                              insn->src_reg, false);
                        if (err)
                                return err;
 
@@ -4719,7 +4729,7 @@ static int do_check(struct bpf_verifier_env *env)
                        /* check that memory (dst_reg + off) is writeable */
                        err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off,
                                               BPF_SIZE(insn->code), BPF_WRITE,
-                                              -1);
+                                              -1, false);
                        if (err)
                                return err;
 
index 8cda3bc..4bfb290 100644 (file)
@@ -3183,6 +3183,16 @@ static int cgroup_enable_threaded(struct cgroup *cgrp)
        if (cgroup_is_threaded(cgrp))
                return 0;
 
+       /*
+        * If @cgroup is populated or has domain controllers enabled, it
+        * can't be switched.  While the below cgroup_can_be_thread_root()
+        * test can catch the same conditions, that's only when @parent is
+        * not mixable, so let's check it explicitly.
+        */
+       if (cgroup_is_populated(cgrp) ||
+           cgrp->subtree_control & ~cgrp_dfl_threaded_ss_mask)
+               return -EOPNOTSUPP;
+
        /* we're joining the parent's domain, ensure its validity */
        if (!cgroup_is_valid_domain(dom_cgrp) ||
            !cgroup_can_be_thread_root(dom_cgrp))
index 3247fe7..3f5fa89 100644 (file)
@@ -488,25 +488,6 @@ get_compat_sigset(sigset_t *set, const compat_sigset_t __user *compat)
 }
 EXPORT_SYMBOL_GPL(get_compat_sigset);
 
-int
-put_compat_sigset(compat_sigset_t __user *compat, const sigset_t *set,
-                 unsigned int size)
-{
-       /* size <= sizeof(compat_sigset_t) <= sizeof(sigset_t) */
-#ifdef __BIG_ENDIAN
-       compat_sigset_t v;
-       switch (_NSIG_WORDS) {
-       case 4: v.sig[7] = (set->sig[3] >> 32); v.sig[6] = set->sig[3];
-       case 3: v.sig[5] = (set->sig[2] >> 32); v.sig[4] = set->sig[2];
-       case 2: v.sig[3] = (set->sig[1] >> 32); v.sig[2] = set->sig[1];
-       case 1: v.sig[1] = (set->sig[0] >> 32); v.sig[0] = set->sig[0];
-       }
-       return copy_to_user(compat, &v, size) ? -EFAULT : 0;
-#else
-       return copy_to_user(compat, set, size) ? -EFAULT : 0;
-#endif
-}
-
 #ifdef CONFIG_NUMA
 COMPAT_SYSCALL_DEFINE6(move_pages, pid_t, pid, compat_ulong_t, nr_pages,
                       compat_uptr_t __user *, pages32,
index 96db9ae..709a55b 100644 (file)
@@ -724,9 +724,15 @@ static inline void __update_cgrp_time(struct perf_cgroup *cgrp)
 
 static inline void update_cgrp_time_from_cpuctx(struct perf_cpu_context *cpuctx)
 {
-       struct perf_cgroup *cgrp_out = cpuctx->cgrp;
-       if (cgrp_out)
-               __update_cgrp_time(cgrp_out);
+       struct perf_cgroup *cgrp = cpuctx->cgrp;
+       struct cgroup_subsys_state *css;
+
+       if (cgrp) {
+               for (css = &cgrp->css; css; css = css->parent) {
+                       cgrp = container_of(css, struct perf_cgroup, css);
+                       __update_cgrp_time(cgrp);
+               }
+       }
 }
 
 static inline void update_cgrp_time_from_event(struct perf_event *event)
@@ -754,6 +760,7 @@ perf_cgroup_set_timestamp(struct task_struct *task,
 {
        struct perf_cgroup *cgrp;
        struct perf_cgroup_info *info;
+       struct cgroup_subsys_state *css;
 
        /*
         * ctx->lock held by caller
@@ -764,8 +771,12 @@ perf_cgroup_set_timestamp(struct task_struct *task,
                return;
 
        cgrp = perf_cgroup_from_task(task, ctx);
-       info = this_cpu_ptr(cgrp->info);
-       info->timestamp = ctx->timestamp;
+
+       for (css = &cgrp->css; css; css = css->parent) {
+               cgrp = container_of(css, struct perf_cgroup, css);
+               info = this_cpu_ptr(cgrp->info);
+               info->timestamp = ctx->timestamp;
+       }
 }
 
 static DEFINE_PER_CPU(struct list_head, cgrp_cpuctx_list);
@@ -2246,7 +2257,7 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
                        struct perf_event_context *task_ctx,
                        enum event_type_t event_type)
 {
-       enum event_type_t ctx_event_type = event_type & EVENT_ALL;
+       enum event_type_t ctx_event_type;
        bool cpu_event = !!(event_type & EVENT_CPU);
 
        /*
@@ -2256,6 +2267,8 @@ static void ctx_resched(struct perf_cpu_context *cpuctx,
        if (event_type & EVENT_PINNED)
                event_type |= EVENT_FLEXIBLE;
 
+       ctx_event_type = event_type & EVENT_ALL;
+
        perf_pmu_disable(cpuctx->ctx.pmu);
        if (task_ctx)
                task_ctx_sched_out(cpuctx, task_ctx, event_type);
index 21b0122..1d5632d 100644 (file)
 
 static int fei_kprobe_handler(struct kprobe *kp, struct pt_regs *regs);
 
+static void fei_post_handler(struct kprobe *kp, struct pt_regs *regs,
+                            unsigned long flags)
+{
+       /*
+        * A dummy post handler is required to prohibit optimizing, because
+        * jump optimization does not support execution path overriding.
+        */
+}
+
 struct fei_attr {
        struct list_head list;
        struct kprobe kp;
@@ -56,6 +65,7 @@ static struct fei_attr *fei_attr_new(const char *sym, unsigned long addr)
                        return NULL;
                }
                attr->kp.pre_handler = fei_kprobe_handler;
+               attr->kp.post_handler = fei_post_handler;
                attr->retval = adjust_error_retval(addr, 0);
                INIT_LIST_HEAD(&attr->list);
        }
index be8aa5b..e5d9d40 100644 (file)
@@ -592,7 +592,7 @@ static void check_mm(struct mm_struct *mm)
  * is dropped: either by a lazy thread or by
  * mmput. Free the page directory and the mm.
  */
-static void __mmdrop(struct mm_struct *mm)
+void __mmdrop(struct mm_struct *mm)
 {
        BUG_ON(mm == &init_mm);
        mm_free_pgd(mm);
@@ -603,18 +603,7 @@ static void __mmdrop(struct mm_struct *mm)
        put_user_ns(mm->user_ns);
        free_mm(mm);
 }
-
-void mmdrop(struct mm_struct *mm)
-{
-       /*
-        * The implicit full barrier implied by atomic_dec_and_test() is
-        * required by the membarrier system call before returning to
-        * user-space, after storing to rq->curr.
-        */
-       if (unlikely(atomic_dec_and_test(&mm->mm_count)))
-               __mmdrop(mm);
-}
-EXPORT_SYMBOL_GPL(mmdrop);
+EXPORT_SYMBOL_GPL(__mmdrop);
 
 static void mmdrop_async_fn(struct work_struct *work)
 {
index e6a9c36..82b8b18 100644 (file)
@@ -1726,25 +1726,14 @@ static int irq_domain_debug_show(struct seq_file *m, void *p)
        irq_domain_debug_show_one(m, d, 0);
        return 0;
 }
-
-static int irq_domain_debug_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, irq_domain_debug_show, inode->i_private);
-}
-
-static const struct file_operations dfs_domain_ops = {
-       .open           = irq_domain_debug_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
+DEFINE_SHOW_ATTRIBUTE(irq_domain_debug);
 
 static void debugfs_add_domain_dir(struct irq_domain *d)
 {
        if (!d->name || !domain_dir || d->debugfs_file)
                return;
        d->debugfs_file = debugfs_create_file(d->name, 0444, domain_dir, d,
-                                             &dfs_domain_ops);
+                                             &irq_domain_debug_fops);
 }
 
 static void debugfs_remove_domain_dir(struct irq_domain *d)
@@ -1760,7 +1749,8 @@ void __init irq_domain_debugfs_init(struct dentry *root)
        if (!domain_dir)
                return;
 
-       debugfs_create_file("default", 0444, domain_dir, NULL, &dfs_domain_ops);
+       debugfs_create_file("default", 0444, domain_dir, NULL,
+                           &irq_domain_debug_fops);
        mutex_lock(&irq_domain_mutex);
        list_for_each_entry(d, &irq_domain_list, link)
                debugfs_add_domain_dir(d);
index 5187dfe..4c57704 100644 (file)
@@ -16,6 +16,7 @@ struct cpumap {
        unsigned int            available;
        unsigned int            allocated;
        unsigned int            managed;
+       bool                    initialized;
        bool                    online;
        unsigned long           alloc_map[IRQ_MATRIX_SIZE];
        unsigned long           managed_map[IRQ_MATRIX_SIZE];
@@ -81,9 +82,11 @@ void irq_matrix_online(struct irq_matrix *m)
 
        BUG_ON(cm->online);
 
-       bitmap_zero(cm->alloc_map, m->matrix_bits);
-       cm->available = m->alloc_size - (cm->managed + m->systembits_inalloc);
-       cm->allocated = 0;
+       if (!cm->initialized) {
+               cm->available = m->alloc_size;
+               cm->available -= cm->managed + m->systembits_inalloc;
+               cm->initialized = true;
+       }
        m->global_available += cm->available;
        cm->online = true;
        m->online_maps++;
@@ -370,14 +373,16 @@ void irq_matrix_free(struct irq_matrix *m, unsigned int cpu,
        if (WARN_ON_ONCE(bit < m->alloc_start || bit >= m->alloc_end))
                return;
 
-       if (cm->online) {
-               clear_bit(bit, cm->alloc_map);
-               cm->allocated--;
+       clear_bit(bit, cm->alloc_map);
+       cm->allocated--;
+
+       if (cm->online)
                m->total_allocated--;
-               if (!managed) {
-                       cm->available++;
+
+       if (!managed) {
+               cm->available++;
+               if (cm->online)
                        m->global_available++;
-               }
        }
        trace_irq_matrix_free(bit, cpu, m, cm);
 }
index e721409..01ebdf1 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/jump_label_ratelimit.h>
 #include <linux/bug.h>
 #include <linux/cpu.h>
+#include <asm/sections.h>
 
 #ifdef HAVE_JUMP_LABEL
 
@@ -421,15 +422,15 @@ void __init jump_label_init(void)
        cpus_read_unlock();
 }
 
-/* Disable any jump label entries in __init code */
-void __init jump_label_invalidate_init(void)
+/* Disable any jump label entries in __init/__exit code */
+void __init jump_label_invalidate_initmem(void)
 {
        struct jump_entry *iter_start = __start___jump_table;
        struct jump_entry *iter_stop = __stop___jump_table;
        struct jump_entry *iter;
 
        for (iter = iter_start; iter < iter_stop; iter++) {
-               if (init_kernel_text(iter->code))
+               if (init_section_contains((void *)(unsigned long)iter->code, 1))
                        iter->code = 0;
        }
 }
index da2ccf1..102160f 100644 (file)
@@ -978,67 +978,90 @@ static int prepare_kprobe(struct kprobe *p)
 }
 
 /* Caller must lock kprobe_mutex */
-static void arm_kprobe_ftrace(struct kprobe *p)
+static int arm_kprobe_ftrace(struct kprobe *p)
 {
-       int ret;
+       int ret = 0;
 
        ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
                                   (unsigned long)p->addr, 0, 0);
-       WARN(ret < 0, "Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret);
-       kprobe_ftrace_enabled++;
-       if (kprobe_ftrace_enabled == 1) {
+       if (ret) {
+               pr_debug("Failed to arm kprobe-ftrace at %p (%d)\n", p->addr, ret);
+               return ret;
+       }
+
+       if (kprobe_ftrace_enabled == 0) {
                ret = register_ftrace_function(&kprobe_ftrace_ops);
-               WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
+               if (ret) {
+                       pr_debug("Failed to init kprobe-ftrace (%d)\n", ret);
+                       goto err_ftrace;
+               }
        }
+
+       kprobe_ftrace_enabled++;
+       return ret;
+
+err_ftrace:
+       /*
+        * Note: Since kprobe_ftrace_ops has IPMODIFY set, and ftrace requires a
+        * non-empty filter_hash for IPMODIFY ops, we're safe from an accidental
+        * empty filter_hash which would undesirably trace all functions.
+        */
+       ftrace_set_filter_ip(&kprobe_ftrace_ops, (unsigned long)p->addr, 1, 0);
+       return ret;
 }
 
 /* Caller must lock kprobe_mutex */
-static void disarm_kprobe_ftrace(struct kprobe *p)
+static int disarm_kprobe_ftrace(struct kprobe *p)
 {
-       int ret;
+       int ret = 0;
 
-       kprobe_ftrace_enabled--;
-       if (kprobe_ftrace_enabled == 0) {
+       if (kprobe_ftrace_enabled == 1) {
                ret = unregister_ftrace_function(&kprobe_ftrace_ops);
-               WARN(ret < 0, "Failed to init kprobe-ftrace (%d)\n", ret);
+               if (WARN(ret < 0, "Failed to unregister kprobe-ftrace (%d)\n", ret))
+                       return ret;
        }
+
+       kprobe_ftrace_enabled--;
+
        ret = ftrace_set_filter_ip(&kprobe_ftrace_ops,
                           (unsigned long)p->addr, 1, 0);
        WARN(ret < 0, "Failed to disarm kprobe-ftrace at %p (%d)\n", p->addr, ret);
+       return ret;
 }
 #else  /* !CONFIG_KPROBES_ON_FTRACE */
 #define prepare_kprobe(p)      arch_prepare_kprobe(p)
-#define arm_kprobe_ftrace(p)   do {} while (0)
-#define disarm_kprobe_ftrace(p)        do {} while (0)
+#define arm_kprobe_ftrace(p)   (-ENODEV)
+#define disarm_kprobe_ftrace(p)        (-ENODEV)
 #endif
 
 /* Arm a kprobe with text_mutex */
-static void arm_kprobe(struct kprobe *kp)
+static int arm_kprobe(struct kprobe *kp)
 {
-       if (unlikely(kprobe_ftrace(kp))) {
-               arm_kprobe_ftrace(kp);
-               return;
-       }
+       if (unlikely(kprobe_ftrace(kp)))
+               return arm_kprobe_ftrace(kp);
+
        cpus_read_lock();
        mutex_lock(&text_mutex);
        __arm_kprobe(kp);
        mutex_unlock(&text_mutex);
        cpus_read_unlock();
+
+       return 0;
 }
 
 /* Disarm a kprobe with text_mutex */
-static void disarm_kprobe(struct kprobe *kp, bool reopt)
+static int disarm_kprobe(struct kprobe *kp, bool reopt)
 {
-       if (unlikely(kprobe_ftrace(kp))) {
-               disarm_kprobe_ftrace(kp);
-               return;
-       }
+       if (unlikely(kprobe_ftrace(kp)))
+               return disarm_kprobe_ftrace(kp);
 
        cpus_read_lock();
        mutex_lock(&text_mutex);
        __disarm_kprobe(kp, reopt);
        mutex_unlock(&text_mutex);
        cpus_read_unlock();
+
+       return 0;
 }
 
 /*
@@ -1362,9 +1385,15 @@ out:
 
        if (ret == 0 && kprobe_disabled(ap) && !kprobe_disabled(p)) {
                ap->flags &= ~KPROBE_FLAG_DISABLED;
-               if (!kprobes_all_disarmed)
+               if (!kprobes_all_disarmed) {
                        /* Arm the breakpoint again. */
-                       arm_kprobe(ap);
+                       ret = arm_kprobe(ap);
+                       if (ret) {
+                               ap->flags |= KPROBE_FLAG_DISABLED;
+                               list_del_rcu(&p->list);
+                               synchronize_sched();
+                       }
+               }
        }
        return ret;
 }
@@ -1573,8 +1602,14 @@ int register_kprobe(struct kprobe *p)
        hlist_add_head_rcu(&p->hlist,
                       &kprobe_table[hash_ptr(p->addr, KPROBE_HASH_BITS)]);
 
-       if (!kprobes_all_disarmed && !kprobe_disabled(p))
-               arm_kprobe(p);
+       if (!kprobes_all_disarmed && !kprobe_disabled(p)) {
+               ret = arm_kprobe(p);
+               if (ret) {
+                       hlist_del_rcu(&p->hlist);
+                       synchronize_sched();
+                       goto out;
+               }
+       }
 
        /* Try to optimize kprobe */
        try_to_optimize_kprobe(p);
@@ -1608,11 +1643,12 @@ static int aggr_kprobe_disabled(struct kprobe *ap)
 static struct kprobe *__disable_kprobe(struct kprobe *p)
 {
        struct kprobe *orig_p;
+       int ret;
 
        /* Get an original kprobe for return */
        orig_p = __get_valid_kprobe(p);
        if (unlikely(orig_p == NULL))
-               return NULL;
+               return ERR_PTR(-EINVAL);
 
        if (!kprobe_disabled(p)) {
                /* Disable probe if it is a child probe */
@@ -1626,8 +1662,13 @@ static struct kprobe *__disable_kprobe(struct kprobe *p)
                         * should have already been disarmed, so
                         * skip unneed disarming process.
                         */
-                       if (!kprobes_all_disarmed)
-                               disarm_kprobe(orig_p, true);
+                       if (!kprobes_all_disarmed) {
+                               ret = disarm_kprobe(orig_p, true);
+                               if (ret) {
+                                       p->flags &= ~KPROBE_FLAG_DISABLED;
+                                       return ERR_PTR(ret);
+                               }
+                       }
                        orig_p->flags |= KPROBE_FLAG_DISABLED;
                }
        }
@@ -1644,8 +1685,8 @@ static int __unregister_kprobe_top(struct kprobe *p)
 
        /* Disable kprobe. This will disarm it if needed. */
        ap = __disable_kprobe(p);
-       if (ap == NULL)
-               return -EINVAL;
+       if (IS_ERR(ap))
+               return PTR_ERR(ap);
 
        if (ap == p)
                /*
@@ -2078,12 +2119,14 @@ static void kill_kprobe(struct kprobe *p)
 int disable_kprobe(struct kprobe *kp)
 {
        int ret = 0;
+       struct kprobe *p;
 
        mutex_lock(&kprobe_mutex);
 
        /* Disable this kprobe */
-       if (__disable_kprobe(kp) == NULL)
-               ret = -EINVAL;
+       p = __disable_kprobe(kp);
+       if (IS_ERR(p))
+               ret = PTR_ERR(p);
 
        mutex_unlock(&kprobe_mutex);
        return ret;
@@ -2116,7 +2159,9 @@ int enable_kprobe(struct kprobe *kp)
 
        if (!kprobes_all_disarmed && kprobe_disabled(p)) {
                p->flags &= ~KPROBE_FLAG_DISABLED;
-               arm_kprobe(p);
+               ret = arm_kprobe(p);
+               if (ret)
+                       p->flags |= KPROBE_FLAG_DISABLED;
        }
 out:
        mutex_unlock(&kprobe_mutex);
@@ -2407,11 +2452,12 @@ static const struct file_operations debugfs_kprobe_blacklist_ops = {
        .release        = seq_release,
 };
 
-static void arm_all_kprobes(void)
+static int arm_all_kprobes(void)
 {
        struct hlist_head *head;
        struct kprobe *p;
-       unsigned int i;
+       unsigned int i, total = 0, errors = 0;
+       int err, ret = 0;
 
        mutex_lock(&kprobe_mutex);
 
@@ -2428,46 +2474,74 @@ static void arm_all_kprobes(void)
        /* Arming kprobes doesn't optimize kprobe itself */
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
-               hlist_for_each_entry_rcu(p, head, hlist)
-                       if (!kprobe_disabled(p))
-                               arm_kprobe(p);
+               /* Arm all kprobes on a best-effort basis */
+               hlist_for_each_entry_rcu(p, head, hlist) {
+                       if (!kprobe_disabled(p)) {
+                               err = arm_kprobe(p);
+                               if (err)  {
+                                       errors++;
+                                       ret = err;
+                               }
+                               total++;
+                       }
+               }
        }
 
-       printk(KERN_INFO "Kprobes globally enabled\n");
+       if (errors)
+               pr_warn("Kprobes globally enabled, but failed to arm %d out of %d probes\n",
+                       errors, total);
+       else
+               pr_info("Kprobes globally enabled\n");
 
 already_enabled:
        mutex_unlock(&kprobe_mutex);
-       return;
+       return ret;
 }
 
-static void disarm_all_kprobes(void)
+static int disarm_all_kprobes(void)
 {
        struct hlist_head *head;
        struct kprobe *p;
-       unsigned int i;
+       unsigned int i, total = 0, errors = 0;
+       int err, ret = 0;
 
        mutex_lock(&kprobe_mutex);
 
        /* If kprobes are already disarmed, just return */
        if (kprobes_all_disarmed) {
                mutex_unlock(&kprobe_mutex);
-               return;
+               return 0;
        }
 
        kprobes_all_disarmed = true;
-       printk(KERN_INFO "Kprobes globally disabled\n");
 
        for (i = 0; i < KPROBE_TABLE_SIZE; i++) {
                head = &kprobe_table[i];
+               /* Disarm all kprobes on a best-effort basis */
                hlist_for_each_entry_rcu(p, head, hlist) {
-                       if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p))
-                               disarm_kprobe(p, false);
+                       if (!arch_trampoline_kprobe(p) && !kprobe_disabled(p)) {
+                               err = disarm_kprobe(p, false);
+                               if (err) {
+                                       errors++;
+                                       ret = err;
+                               }
+                               total++;
+                       }
                }
        }
+
+       if (errors)
+               pr_warn("Kprobes globally disabled, but failed to disarm %d out of %d probes\n",
+                       errors, total);
+       else
+               pr_info("Kprobes globally disabled\n");
+
        mutex_unlock(&kprobe_mutex);
 
        /* Wait for disarming all kprobes by optimizer */
        wait_for_kprobe_optimizer();
+
+       return ret;
 }
 
 /*
@@ -2494,6 +2568,7 @@ static ssize_t write_enabled_file_bool(struct file *file,
 {
        char buf[32];
        size_t buf_size;
+       int ret = 0;
 
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
@@ -2504,17 +2579,20 @@ static ssize_t write_enabled_file_bool(struct file *file,
        case 'y':
        case 'Y':
        case '1':
-               arm_all_kprobes();
+               ret = arm_all_kprobes();
                break;
        case 'n':
        case 'N':
        case '0':
-               disarm_all_kprobes();
+               ret = disarm_all_kprobes();
                break;
        default:
                return -EINVAL;
        }
 
+       if (ret)
+               return ret;
+
        return count;
 }
 
index 858a075..2048359 100644 (file)
@@ -1082,15 +1082,16 @@ static noinline int __sched
 __mutex_lock_interruptible_slowpath(struct mutex *lock);
 
 /**
- * mutex_lock_interruptible - acquire the mutex, interruptible
- * @lock: the mutex to be acquired
+ * mutex_lock_interruptible() - Acquire the mutex, interruptible by signals.
+ * @lock: The mutex to be acquired.
  *
- * Lock the mutex like mutex_lock(), and return 0 if the mutex has
- * been acquired or sleep until the mutex becomes available. If a
- * signal arrives while waiting for the lock then this function
- * returns -EINTR.
+ * Lock the mutex like mutex_lock().  If a signal is delivered while the
+ * process is sleeping, this function will return without acquiring the
+ * mutex.
  *
- * This function is similar to (but not equivalent to) down_interruptible().
+ * Context: Process context.
+ * Return: 0 if the lock was successfully acquired or %-EINTR if a
+ * signal arrived.
  */
 int __sched mutex_lock_interruptible(struct mutex *lock)
 {
@@ -1104,6 +1105,18 @@ int __sched mutex_lock_interruptible(struct mutex *lock)
 
 EXPORT_SYMBOL(mutex_lock_interruptible);
 
+/**
+ * mutex_lock_killable() - Acquire the mutex, interruptible by fatal signals.
+ * @lock: The mutex to be acquired.
+ *
+ * Lock the mutex like mutex_lock().  If a signal which will be fatal to
+ * the current process is delivered while the process is sleeping, this
+ * function will return without acquiring the mutex.
+ *
+ * Context: Process context.
+ * Return: 0 if the lock was successfully acquired or %-EINTR if a
+ * fatal signal arrived.
+ */
 int __sched mutex_lock_killable(struct mutex *lock)
 {
        might_sleep();
@@ -1115,6 +1128,16 @@ int __sched mutex_lock_killable(struct mutex *lock)
 }
 EXPORT_SYMBOL(mutex_lock_killable);
 
+/**
+ * mutex_lock_io() - Acquire the mutex and mark the process as waiting for I/O
+ * @lock: The mutex to be acquired.
+ *
+ * Lock the mutex like mutex_lock().  While the task is waiting for this
+ * mutex, it will be accounted as being in the IO wait state by the
+ * scheduler.
+ *
+ * Context: Process context.
+ */
 void __sched mutex_lock_io(struct mutex *lock)
 {
        int token;
index 38ece03..d880296 100644 (file)
@@ -379,6 +379,14 @@ queue:
        tail = encode_tail(smp_processor_id(), idx);
 
        node += idx;
+
+       /*
+        * Ensure that we increment the head node->count before initialising
+        * the actual node. If the compiler is kind enough to reorder these
+        * stores, then an IRQ could overwrite our assignments.
+        */
+       barrier();
+
        node->locked = 0;
        node->next = NULL;
        pv_init_node(node);
@@ -408,14 +416,15 @@ queue:
         */
        if (old & _Q_TAIL_MASK) {
                prev = decode_tail(old);
+
                /*
-                * The above xchg_tail() is also a load of @lock which
-                * generates, through decode_tail(), a pointer.  The address
-                * dependency matches the RELEASE of xchg_tail() such that
-                * the subsequent access to @prev happens after.
+                * We must ensure that the stores to @node are observed before
+                * the write to prev->next. The address dependency from
+                * xchg_tail is not sufficient to ensure this because the read
+                * component of xchg_tail is unordered with respect to the
+                * initialisation of @node.
                 */
-
-               WRITE_ONCE(prev->next, node);
+               smp_store_release(&prev->next, node);
 
                pv_wait_node(node, prev);
                arch_mcs_spin_lock_contended(&node->locked);
index 65cc0cb..940633c 100644 (file)
@@ -1616,11 +1616,12 @@ bool __sched __rt_mutex_futex_unlock(struct rt_mutex *lock,
 void __sched rt_mutex_futex_unlock(struct rt_mutex *lock)
 {
        DEFINE_WAKE_Q(wake_q);
+       unsigned long flags;
        bool postunlock;
 
-       raw_spin_lock_irq(&lock->wait_lock);
+       raw_spin_lock_irqsave(&lock->wait_lock, flags);
        postunlock = __rt_mutex_futex_unlock(lock, &wake_q);
-       raw_spin_unlock_irq(&lock->wait_lock);
+       raw_spin_unlock_irqrestore(&lock->wait_lock, flags);
 
        if (postunlock)
                rt_mutex_postunlock(&wake_q);
index 4849be5..895e6b7 100644 (file)
@@ -275,8 +275,15 @@ static unsigned long pfn_end(struct dev_pagemap *pgmap)
        return (res->start + resource_size(res)) >> PAGE_SHIFT;
 }
 
+static unsigned long pfn_next(unsigned long pfn)
+{
+       if (pfn % 1024 == 0)
+               cond_resched();
+       return pfn + 1;
+}
+
 #define for_each_device_pfn(pfn, map) \
-       for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++)
+       for (pfn = pfn_first(map); pfn < pfn_end(map); pfn = pfn_next(pfn))
 
 static void devm_memremap_pages_release(void *data)
 {
@@ -337,10 +344,10 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
        resource_size_t align_start, align_size, align_end;
        struct vmem_altmap *altmap = pgmap->altmap_valid ?
                        &pgmap->altmap : NULL;
+       struct resource *res = &pgmap->res;
        unsigned long pfn, pgoff, order;
        pgprot_t pgprot = PAGE_KERNEL;
-       int error, nid, is_ram, i = 0;
-       struct resource *res = &pgmap->res;
+       int error, nid, is_ram;
 
        align_start = res->start & ~(SECTION_SIZE - 1);
        align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE)
@@ -409,8 +416,6 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
                list_del(&page->lru);
                page->pgmap = pgmap;
                percpu_ref_get(pgmap->ref);
-               if (!(++i % 1024))
-                       cond_resched();
        }
 
        devm_add_action(dev, devm_memremap_pages_release, pgmap);
@@ -422,7 +427,6 @@ void *devm_memremap_pages(struct device *dev, struct dev_pagemap *pgmap)
  err_pfn_remap:
  err_radix:
        pgmap_radix_release(res, pgoff);
-       devres_free(pgmap);
        return ERR_PTR(error);
 }
 EXPORT_SYMBOL(devm_memremap_pages);
index ad2d420..e42764a 100644 (file)
@@ -4228,7 +4228,7 @@ static int modules_open(struct inode *inode, struct file *file)
                m->private = kallsyms_show_value() ? NULL : (void *)8ul;
        }
 
-       return 0;
+       return err;
 }
 
 static const struct file_operations proc_modules_operations = {
index 2cfef40..4b794f1 100644 (file)
@@ -640,7 +640,7 @@ device_initcall(register_warn_debugfs);
  */
 __visible void __stack_chk_fail(void)
 {
-       panic("stack-protector: Kernel stack is corrupted in: %p\n",
+       panic("stack-protector: Kernel stack is corrupted in: %pB\n",
                __builtin_return_address(0));
 }
 EXPORT_SYMBOL(__stack_chk_fail);
index fc11235..f274fbe 100644 (file)
@@ -2397,7 +2397,7 @@ skip:
 
                if (console_lock_spinning_disable_and_check()) {
                        printk_safe_exit_irqrestore(flags);
-                       return;
+                       goto out;
                }
 
                printk_safe_exit_irqrestore(flags);
@@ -2430,6 +2430,7 @@ skip:
        if (retry && console_trylock())
                goto again;
 
+out:
        if (wake_klogd)
                wake_up_klogd();
 }
index c302940..c955b10 100644 (file)
@@ -163,7 +163,7 @@ static struct rchan_buf *relay_create_buf(struct rchan *chan)
 {
        struct rchan_buf *buf;
 
-       if (chan->n_subbufs > UINT_MAX / sizeof(size_t *))
+       if (chan->n_subbufs > KMALLOC_MAX_SIZE / sizeof(size_t *))
                return NULL;
 
        buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL);
index bf724c1..c94895b 100644 (file)
@@ -2601,19 +2601,31 @@ static inline void finish_task(struct task_struct *prev)
 #endif
 }
 
-static inline void finish_lock_switch(struct rq *rq)
+static inline void
+prepare_lock_switch(struct rq *rq, struct task_struct *next, struct rq_flags *rf)
 {
+       /*
+        * Since the runqueue lock will be released by the next
+        * task (which is an invalid locking op but in the case
+        * of the scheduler it's an obvious special-case), so we
+        * do an early lockdep release here:
+        */
+       rq_unpin_lock(rq, rf);
+       spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
 #ifdef CONFIG_DEBUG_SPINLOCK
        /* this is a valid case when another task releases the spinlock */
-       rq->lock.owner = current;
+       rq->lock.owner = next;
 #endif
+}
+
+static inline void finish_lock_switch(struct rq *rq)
+{
        /*
         * If we are tracking spinlock dependencies then we have to
         * fix up the runqueue lock - which gets 'carried over' from
         * prev into current:
         */
        spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_);
-
        raw_spin_unlock_irq(&rq->lock);
 }
 
@@ -2844,14 +2856,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
 
        rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);
 
-       /*
-        * Since the runqueue lock will be released by the next
-        * task (which is an invalid locking op but in the case
-        * of the scheduler it's an obvious special-case), so we
-        * do an early lockdep release here:
-        */
-       rq_unpin_lock(rq, rf);
-       spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
+       prepare_lock_switch(rq, next, rf);
 
        /* Here we just switch the register state and the stack. */
        switch_to(prev, next, prev);
@@ -6678,13 +6683,18 @@ static int tg_cfs_schedulable_down(struct task_group *tg, void *data)
                parent_quota = parent_b->hierarchical_quota;
 
                /*
-                * Ensure max(child_quota) <= parent_quota, inherit when no
+                * Ensure max(child_quota) <= parent_quota.  On cgroup2,
+                * always take the min.  On cgroup1, only inherit when no
                 * limit is set:
                 */
-               if (quota == RUNTIME_INF)
-                       quota = parent_quota;
-               else if (parent_quota != RUNTIME_INF && quota > parent_quota)
-                       return -EINVAL;
+               if (cgroup_subsys_on_dfl(cpu_cgrp_subsys)) {
+                       quota = min(quota, parent_quota);
+               } else {
+                       if (quota == RUNTIME_INF)
+                               quota = parent_quota;
+                       else if (parent_quota != RUNTIME_INF && quota > parent_quota)
+                               return -EINVAL;
+               }
        }
        cfs_b->hierarchical_quota = quota;
 
index dd062a1..7936f54 100644 (file)
@@ -19,8 +19,6 @@
 
 #include "sched.h"
 
-#define SUGOV_KTHREAD_PRIORITY 50
-
 struct sugov_tunables {
        struct gov_attr_set attr_set;
        unsigned int rate_limit_us;
index 9bb0e0c..9df0978 100644 (file)
@@ -1153,6 +1153,7 @@ static void update_curr_dl(struct rq *rq)
        struct sched_dl_entity *dl_se = &curr->dl;
        u64 delta_exec, scaled_delta_exec;
        int cpu = cpu_of(rq);
+       u64 now;
 
        if (!dl_task(curr) || !on_dl_rq(dl_se))
                return;
@@ -1165,7 +1166,8 @@ static void update_curr_dl(struct rq *rq)
         * natural solution, but the full ramifications of this
         * approach need further study.
         */
-       delta_exec = rq_clock_task(rq) - curr->se.exec_start;
+       now = rq_clock_task(rq);
+       delta_exec = now - curr->se.exec_start;
        if (unlikely((s64)delta_exec <= 0)) {
                if (unlikely(dl_se->dl_yielded))
                        goto throttle;
@@ -1178,7 +1180,7 @@ static void update_curr_dl(struct rq *rq)
        curr->se.sum_exec_runtime += delta_exec;
        account_group_exec_runtime(curr, delta_exec);
 
-       curr->se.exec_start = rq_clock_task(rq);
+       curr->se.exec_start = now;
        cgroup_account_cputime(curr, delta_exec);
 
        sched_rt_avg_update(rq, delta_exec);
index 1ca0130..72c401b 100644 (file)
@@ -32,7 +32,7 @@ static DEFINE_SPINLOCK(sched_debug_lock);
        if (m)                                  \
                seq_printf(m, x);               \
        else                                    \
-               printk(x);                      \
+               pr_cont(x);                     \
  } while (0)
 
 /*
@@ -501,12 +501,12 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
 {
        struct task_struct *g, *p;
 
-       SEQ_printf(m,
-       "\nrunnable tasks:\n"
-       " S           task   PID         tree-key  switches  prio"
-       "     wait-time             sum-exec        sum-sleep\n"
-       "-------------------------------------------------------"
-       "----------------------------------------------------\n");
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "runnable tasks:\n");
+       SEQ_printf(m, " S           task   PID         tree-key  switches  prio"
+                  "     wait-time             sum-exec        sum-sleep\n");
+       SEQ_printf(m, "-------------------------------------------------------"
+                  "----------------------------------------------------\n");
 
        rcu_read_lock();
        for_each_process_thread(g, p) {
@@ -527,9 +527,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
        unsigned long flags;
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-       SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "cfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg));
 #else
-       SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu);
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "cfs_rq[%d]:\n", cpu);
 #endif
        SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
                        SPLIT_NS(cfs_rq->exec_clock));
@@ -595,9 +597,11 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
 {
 #ifdef CONFIG_RT_GROUP_SCHED
-       SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "rt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg));
 #else
-       SEQ_printf(m, "\nrt_rq[%d]:\n", cpu);
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "rt_rq[%d]:\n", cpu);
 #endif
 
 #define P(x) \
@@ -624,7 +628,8 @@ void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq)
 {
        struct dl_bw *dl_bw;
 
-       SEQ_printf(m, "\ndl_rq[%d]:\n", cpu);
+       SEQ_printf(m, "\n");
+       SEQ_printf(m, "dl_rq[%d]:\n", cpu);
 
 #define PU(x) \
        SEQ_printf(m, "  .%-30s: %lu\n", #x, (unsigned long)(dl_rq->x))
index 663b235..aad4945 100644 (file)
@@ -950,12 +950,13 @@ static void update_curr_rt(struct rq *rq)
 {
        struct task_struct *curr = rq->curr;
        struct sched_rt_entity *rt_se = &curr->rt;
-       u64 now = rq_clock_task(rq);
        u64 delta_exec;
+       u64 now;
 
        if (curr->sched_class != &rt_sched_class)
                return;
 
+       now = rq_clock_task(rq);
        delta_exec = now - curr->se.exec_start;
        if (unlikely((s64)delta_exec <= 0))
                return;
index 940fa40..dc77548 100644 (file)
@@ -1076,14 +1076,16 @@ long seccomp_get_metadata(struct task_struct *task,
 
        size = min_t(unsigned long, size, sizeof(kmd));
 
-       if (copy_from_user(&kmd, data, size))
+       if (size < sizeof(kmd.filter_off))
+               return -EINVAL;
+
+       if (copy_from_user(&kmd.filter_off, data, sizeof(kmd.filter_off)))
                return -EFAULT;
 
        filter = get_nth_filter(task, kmd.filter_off);
        if (IS_ERR(filter))
                return PTR_ERR(filter);
 
-       memset(&kmd, 0, sizeof(kmd));
        if (filter->log)
                kmd.flags |= SECCOMP_FILTER_FLAG_LOG;
 
index 7504304..10b7186 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/export.h>
 #include <linux/hashtable.h>
 #include <linux/compat.h>
+#include <linux/nospec.h>
 
 #include "timekeeping.h"
 #include "posix-timers.h"
@@ -1346,11 +1347,15 @@ static const struct k_clock * const posix_clocks[] = {
 
 static const struct k_clock *clockid_to_kclock(const clockid_t id)
 {
-       if (id < 0)
+       clockid_t idx = id;
+
+       if (id < 0) {
                return (id & CLOCKFD_MASK) == CLOCKFD ?
                        &clock_posix_dynamic : &clock_posix_cpu;
+       }
 
-       if (id >= ARRAY_SIZE(posix_clocks) || !posix_clocks[id])
+       if (id >= ARRAY_SIZE(posix_clocks))
                return NULL;
-       return posix_clocks[id];
+
+       return posix_clocks[array_index_nospec(idx, ARRAY_SIZE(posix_clocks))];
 }
index 48150ab..4a4fd56 100644 (file)
@@ -1894,6 +1894,12 @@ int timers_dead_cpu(unsigned int cpu)
                raw_spin_lock_irq(&new_base->lock);
                raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
 
+               /*
+                * The current CPUs base clock might be stale. Update it
+                * before moving the timers over.
+                */
+               forward_timer_base(new_base);
+
                BUG_ON(old_base->running_timer);
 
                for (i = 0; i < WHEEL_SIZE; i++)
index fc2838a..01e6b3a 100644 (file)
@@ -661,7 +661,41 @@ static const struct bpf_func_proto bpf_get_stackid_proto_tp = {
        .arg3_type      = ARG_ANYTHING,
 };
 
-BPF_CALL_3(bpf_perf_prog_read_value_tp, struct bpf_perf_event_data_kern *, ctx,
+static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
+{
+       switch (func_id) {
+       case BPF_FUNC_perf_event_output:
+               return &bpf_perf_event_output_proto_tp;
+       case BPF_FUNC_get_stackid:
+               return &bpf_get_stackid_proto_tp;
+       default:
+               return tracing_func_proto(func_id);
+       }
+}
+
+static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
+                                   struct bpf_insn_access_aux *info)
+{
+       if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
+               return false;
+       if (type != BPF_READ)
+               return false;
+       if (off % size != 0)
+               return false;
+
+       BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(__u64));
+       return true;
+}
+
+const struct bpf_verifier_ops tracepoint_verifier_ops = {
+       .get_func_proto  = tp_prog_func_proto,
+       .is_valid_access = tp_prog_is_valid_access,
+};
+
+const struct bpf_prog_ops tracepoint_prog_ops = {
+};
+
+BPF_CALL_3(bpf_perf_prog_read_value, struct bpf_perf_event_data_kern *, ctx,
           struct bpf_perf_event_value *, buf, u32, size)
 {
        int err = -EINVAL;
@@ -678,8 +712,8 @@ clear:
        return err;
 }
 
-static const struct bpf_func_proto bpf_perf_prog_read_value_proto_tp = {
-         .func           = bpf_perf_prog_read_value_tp,
+static const struct bpf_func_proto bpf_perf_prog_read_value_proto = {
+         .func           = bpf_perf_prog_read_value,
          .gpl_only       = true,
          .ret_type       = RET_INTEGER,
          .arg1_type      = ARG_PTR_TO_CTX,
@@ -687,7 +721,7 @@ static const struct bpf_func_proto bpf_perf_prog_read_value_proto_tp = {
          .arg3_type      = ARG_CONST_SIZE,
 };
 
-static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
+static const struct bpf_func_proto *pe_prog_func_proto(enum bpf_func_id func_id)
 {
        switch (func_id) {
        case BPF_FUNC_perf_event_output:
@@ -695,34 +729,12 @@ static const struct bpf_func_proto *tp_prog_func_proto(enum bpf_func_id func_id)
        case BPF_FUNC_get_stackid:
                return &bpf_get_stackid_proto_tp;
        case BPF_FUNC_perf_prog_read_value:
-               return &bpf_perf_prog_read_value_proto_tp;
+               return &bpf_perf_prog_read_value_proto;
        default:
                return tracing_func_proto(func_id);
        }
 }
 
-static bool tp_prog_is_valid_access(int off, int size, enum bpf_access_type type,
-                                   struct bpf_insn_access_aux *info)
-{
-       if (off < sizeof(void *) || off >= PERF_MAX_TRACE_SIZE)
-               return false;
-       if (type != BPF_READ)
-               return false;
-       if (off % size != 0)
-               return false;
-
-       BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(__u64));
-       return true;
-}
-
-const struct bpf_verifier_ops tracepoint_verifier_ops = {
-       .get_func_proto  = tp_prog_func_proto,
-       .is_valid_access = tp_prog_is_valid_access,
-};
-
-const struct bpf_prog_ops tracepoint_prog_ops = {
-};
-
 static bool pe_prog_is_valid_access(int off, int size, enum bpf_access_type type,
                                    struct bpf_insn_access_aux *info)
 {
@@ -779,7 +791,7 @@ static u32 pe_prog_convert_ctx_access(enum bpf_access_type type,
 }
 
 const struct bpf_verifier_ops perf_event_verifier_ops = {
-       .get_func_proto         = tp_prog_func_proto,
+       .get_func_proto         = pe_prog_func_proto,
        .is_valid_access        = pe_prog_is_valid_access,
        .convert_ctx_access     = pe_prog_convert_ctx_access,
 };
@@ -872,6 +884,8 @@ int perf_event_query_prog_array(struct perf_event *event, void __user *info)
                return -EINVAL;
        if (copy_from_user(&query, uquery, sizeof(query)))
                return -EFAULT;
+       if (query.ids_len > BPF_TRACE_MAX_PROGS)
+               return -E2BIG;
 
        mutex_lock(&bpf_event_mutex);
        ret = bpf_prog_array_copy_info(event->tp_event->prog_array,
index 1fad24a..ae4147e 100644 (file)
@@ -659,7 +659,7 @@ static int create_trace_kprobe(int argc, char **argv)
        char *symbol = NULL, *event = NULL, *group = NULL;
        int maxactive = 0;
        char *arg;
-       unsigned long offset = 0;
+       long offset = 0;
        void *addr = NULL;
        char buf[MAX_EVENT_NAME_LEN];
 
@@ -747,7 +747,7 @@ static int create_trace_kprobe(int argc, char **argv)
                symbol = argv[1];
                /* TODO: support .init module functions */
                ret = traceprobe_split_symbol_offset(symbol, &offset);
-               if (ret) {
+               if (ret || offset < 0 || offset > UINT_MAX) {
                        pr_info("Failed to parse either an address or a symbol.\n");
                        return ret;
                }
index d593573..daf54bd 100644 (file)
@@ -320,7 +320,7 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type,
 }
 
 /* Split symbol and offset. */
-int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
+int traceprobe_split_symbol_offset(char *symbol, long *offset)
 {
        char *tmp;
        int ret;
@@ -328,13 +328,11 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset)
        if (!offset)
                return -EINVAL;
 
-       tmp = strchr(symbol, '+');
+       tmp = strpbrk(symbol, "+-");
        if (tmp) {
-               /* skip sign because kstrtoul doesn't accept '+' */
-               ret = kstrtoul(tmp + 1, 0, offset);
+               ret = kstrtol(tmp, 0, offset);
                if (ret)
                        return ret;
-
                *tmp = '\0';
        } else
                *offset = 0;
index e101c5b..6a4d3fa 100644 (file)
@@ -365,7 +365,7 @@ extern int traceprobe_conflict_field_name(const char *name,
 extern void traceprobe_update_arg(struct probe_arg *arg);
 extern void traceprobe_free_probe_arg(struct probe_arg *arg);
 
-extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset);
+extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
 
 /* Sum up total data length for dynamic arraies (strings) */
 static nokprobe_inline int
index 9a20acc..36288d8 100644 (file)
@@ -101,6 +101,7 @@ struct user_struct root_user = {
        .sigpending     = ATOMIC_INIT(0),
        .locked_shm     = 0,
        .uid            = GLOBAL_ROOT_UID,
+       .ratelimit      = RATELIMIT_STATE_INIT(root_user.ratelimit, 0, 0),
 };
 
 /*
@@ -191,6 +192,8 @@ struct user_struct *alloc_uid(kuid_t uid)
 
                new->uid = uid;
                atomic_set(&new->__count, 1);
+               ratelimit_state_init(&new->ratelimit, HZ, 100);
+               ratelimit_set_flags(&new->ratelimit, RATELIMIT_MSG_ON_RELEASE);
 
                /*
                 * Before adding this, check whether we raced
index 017044c..6ec6ba6 100644 (file)
@@ -3018,14 +3018,6 @@ static bool __cancel_work(struct work_struct *work, bool is_dwork)
        return ret;
 }
 
-/*
- * See cancel_delayed_work()
- */
-bool cancel_work(struct work_struct *work)
-{
-       return __cancel_work(work, false);
-}
-
 /**
  * cancel_delayed_work - cancel a delayed work
  * @dwork: delayed_work to cancel
@@ -4180,6 +4172,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)
 EXPORT_SYMBOL_GPL(workqueue_set_max_active);
 
 /**
+ * current_work - retrieve %current task's work struct
+ *
+ * Determine if %current task is a workqueue worker and what it's working on.
+ * Useful to find out the context that the %current task is running in.
+ *
+ * Return: work struct if %current task is a workqueue worker, %NULL otherwise.
+ */
+struct work_struct *current_work(void)
+{
+       struct worker *worker = current_wq_worker();
+
+       return worker ? worker->current_work : NULL;
+}
+EXPORT_SYMBOL(current_work);
+
+/**
  * current_is_workqueue_rescuer - is %current workqueue rescuer?
  *
  * Determine whether %current is a workqueue rescuer.  Can be used from
@@ -5321,7 +5329,7 @@ int workqueue_sysfs_register(struct workqueue_struct *wq)
 
        ret = device_register(&wq_dev->dev);
        if (ret) {
-               kfree(wq_dev);
+               put_device(&wq_dev->dev);
                wq->wq_dev = NULL;
                return ret;
        }
index 6088408..64155e3 100644 (file)
@@ -1642,6 +1642,7 @@ config DMA_API_DEBUG
 
 menuconfig RUNTIME_TESTING_MENU
        bool "Runtime Testing"
+       def_bool y
 
 if RUNTIME_TESTING_MENU
 
index f93a945..590facb 100644 (file)
@@ -3,7 +3,7 @@
  *
  * As should be obvious for Linux kernel code, license is GPLv2
  *
- * Copyright (c) 2007-2008 Joern Engel <joern@logfs.org>
+ * Copyright (c) 2007-2008 Joern Engel <joern@purestorage.com>
  * Bits and pieces stolen from Peter Zijlstra's code, which is
  * Copyright 2007, Red Hat Inc. Peter Zijlstra
  * GPLv2
@@ -76,6 +76,8 @@ struct btree_geo btree_geo128 = {
 };
 EXPORT_SYMBOL_GPL(btree_geo128);
 
+#define MAX_KEYLEN     (2 * LONG_PER_U64)
+
 static struct kmem_cache *btree_cachep;
 
 void *btree_alloc(gfp_t gfp_mask, void *pool_data)
@@ -313,7 +315,7 @@ void *btree_get_prev(struct btree_head *head, struct btree_geo *geo,
 {
        int i, height;
        unsigned long *node, *oldnode;
-       unsigned long *retry_key = NULL, key[geo->keylen];
+       unsigned long *retry_key = NULL, key[MAX_KEYLEN];
 
        if (keyzero(geo, __key))
                return NULL;
@@ -639,8 +641,8 @@ EXPORT_SYMBOL_GPL(btree_remove);
 int btree_merge(struct btree_head *target, struct btree_head *victim,
                struct btree_geo *geo, gfp_t gfp)
 {
-       unsigned long key[geo->keylen];
-       unsigned long dup[geo->keylen];
+       unsigned long key[MAX_KEYLEN];
+       unsigned long dup[MAX_KEYLEN];
        void *val;
        int err;
 
index c1b0fad..1077366 100644 (file)
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -150,6 +150,8 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
                return BUG_TRAP_TYPE_NONE;
 
        bug = find_bug(bugaddr);
+       if (!bug)
+               return BUG_TRAP_TYPE_NONE;
 
        file = NULL;
        line = 0;
@@ -191,7 +193,7 @@ enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
        if (file)
                pr_crit("kernel BUG at %s:%u!\n", file, line);
        else
-               pr_crit("Kernel BUG at %p [verbose debug info unavailable]\n",
+               pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n",
                        (void *)bugaddr);
 
        return BUG_TRAP_TYPE_BUG;
index 1b34d21..7f5cdc1 100644 (file)
@@ -1491,12 +1491,12 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
        if (unlikely(virt == NULL))
                return;
 
-       entry = dma_entry_alloc();
-       if (!entry)
+       /* handle vmalloc and linear addresses */
+       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
                return;
 
-       /* handle vmalloc and linear addresses */
-       if (!is_vmalloc_addr(virt) && !virt_to_page(virt))
+       entry = dma_entry_alloc();
+       if (!entry)
                return;
 
        entry->type      = dma_debug_coherent;
@@ -1528,7 +1528,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
        };
 
        /* handle vmalloc and linear addresses */
-       if (!is_vmalloc_addr(virt) && !virt_to_page(virt))
+       if (!is_vmalloc_addr(virt) && !virt_addr_valid(virt))
                return;
 
        if (is_vmalloc_addr(virt))
index 40b1f92..c9e8e21 100644 (file)
@@ -84,6 +84,10 @@ again:
        return page_address(page);
 }
 
+/*
+ * NOTE: this function must never look at the dma_addr argument, because we want
+ * to be able to use it as a helper for iommu implementations as well.
+ */
 void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,
                dma_addr_t dma_addr, unsigned long attrs)
 {
@@ -152,5 +156,6 @@ const struct dma_map_ops dma_direct_ops = {
        .map_sg                 = dma_direct_map_sg,
        .dma_supported          = dma_direct_supported,
        .mapping_error          = dma_direct_mapping_error,
+       .is_phys                = 1,
 };
 EXPORT_SYMBOL(dma_direct_ops);
index c98d77f..823b813 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -36,8 +36,8 @@ int idr_alloc_u32(struct idr *idr, void *ptr, u32 *nextid,
 {
        struct radix_tree_iter iter;
        void __rcu **slot;
-       int base = idr->idr_base;
-       int id = *nextid;
+       unsigned int base = idr->idr_base;
+       unsigned int id = *nextid;
 
        if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
                return -EINVAL;
@@ -204,10 +204,11 @@ int idr_for_each(const struct idr *idr,
 
        radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) {
                int ret;
+               unsigned long id = iter.index + base;
 
-               if (WARN_ON_ONCE(iter.index > INT_MAX))
+               if (WARN_ON_ONCE(id > INT_MAX))
                        break;
-               ret = fn(iter.index + base, rcu_dereference_raw(*slot), data);
+               ret = fn(id, rcu_dereference_raw(*slot), data);
                if (ret)
                        return ret;
        }
@@ -230,8 +231,8 @@ void *idr_get_next(struct idr *idr, int *nextid)
 {
        struct radix_tree_iter iter;
        void __rcu **slot;
-       int base = idr->idr_base;
-       int id = *nextid;
+       unsigned long base = idr->idr_base;
+       unsigned long id = *nextid;
 
        id = (id < base) ? 0 : id - base;
        slot = radix_tree_iter_find(&idr->idr_rt, &iter, id);
@@ -431,7 +432,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
                        bitmap = this_cpu_xchg(ida_bitmap, NULL);
                        if (!bitmap)
                                return -EAGAIN;
-                       memset(bitmap, 0, sizeof(*bitmap));
                        bitmap->bitmap[0] = tmp >> RADIX_TREE_EXCEPTIONAL_SHIFT;
                        rcu_assign_pointer(*slot, bitmap);
                }
@@ -464,7 +464,6 @@ int ida_get_new_above(struct ida *ida, int start, int *id)
                        bitmap = this_cpu_xchg(ida_bitmap, NULL);
                        if (!bitmap)
                                return -EAGAIN;
-                       memset(bitmap, 0, sizeof(*bitmap));
                        __set_bit(bit, bitmap->bitmap);
                        radix_tree_iter_replace(root, &iter, slot, bitmap);
                }
index b808a39..54e5bba 100644 (file)
@@ -91,7 +91,8 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
 
                if (ioremap_pmd_enabled() &&
                    ((next - addr) == PMD_SIZE) &&
-                   IS_ALIGNED(phys_addr + addr, PMD_SIZE)) {
+                   IS_ALIGNED(phys_addr + addr, PMD_SIZE) &&
+                   pmd_free_pte_page(pmd)) {
                        if (pmd_set_huge(pmd, phys_addr + addr, prot))
                                continue;
                }
@@ -117,7 +118,8 @@ static inline int ioremap_pud_range(p4d_t *p4d, unsigned long addr,
 
                if (ioremap_pud_enabled() &&
                    ((next - addr) == PUD_SIZE) &&
-                   IS_ALIGNED(phys_addr + addr, PUD_SIZE)) {
+                   IS_ALIGNED(phys_addr + addr, PUD_SIZE) &&
+                   pud_free_pmd_page(pud)) {
                        if (pud_set_huge(pud, phys_addr + addr, prot))
                                continue;
                }
index 30e7dd8..9f96fa7 100644 (file)
@@ -322,6 +322,8 @@ EXPORT_SYMBOL_GPL(percpu_ref_switch_to_percpu);
  * This function normally doesn't block and can be called from any context
  * but it may block if @confirm_kill is specified and @ref is in the
  * process of switching to atomic mode by percpu_ref_switch_to_atomic().
+ *
+ * There are no implied RCU grace periods between kill and release.
  */
 void percpu_ref_kill_and_confirm(struct percpu_ref *ref,
                                 percpu_ref_func_t *confirm_kill)
index 0a7ae32..8e00138 100644 (file)
@@ -2125,7 +2125,7 @@ int ida_pre_get(struct ida *ida, gfp_t gfp)
                preempt_enable();
 
        if (!this_cpu_read(ida_bitmap)) {
-               struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp);
+               struct ida_bitmap *bitmap = kzalloc(sizeof(*bitmap), gfp);
                if (!bitmap)
                        return 0;
                if (this_cpu_cmpxchg(ida_bitmap, NULL, bitmap))
index 3825c30..47de025 100644 (file)
@@ -506,8 +506,10 @@ static void *rhashtable_lookup_one(struct rhashtable *ht,
                if (!key ||
                    (ht->p.obj_cmpfn ?
                     ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) :
-                    rhashtable_compare(&arg, rht_obj(ht, head))))
+                    rhashtable_compare(&arg, rht_obj(ht, head)))) {
+                       pprev = &head->next;
                        continue;
+               }
 
                if (!ht->rhlist)
                        return rht_obj(ht, head);
index b4e2234..3e93354 100644 (file)
 #include <linux/if_vlan.h>
 #include <linux/random.h>
 #include <linux/highmem.h>
+#include <linux/sched.h>
 
 /* General test specific settings */
 #define MAX_SUBTESTS   3
-#define MAX_TESTRUNS   10000
+#define MAX_TESTRUNS   1000
 #define MAX_DATA       128
 #define MAX_INSNS      512
 #define MAX_K          0xffffFFFF
@@ -5466,7 +5467,7 @@ static struct bpf_test tests[] = {
        {
                "BPF_MAXINSNS: Jump, gap, jump, ...",
                { },
-#ifdef CONFIG_BPF_JIT_ALWAYS_ON
+#if defined(CONFIG_BPF_JIT_ALWAYS_ON) && defined(CONFIG_X86)
                CLASSIC | FLAG_NO_DATA | FLAG_EXPECTED_FAIL,
 #else
                CLASSIC | FLAG_NO_DATA,
@@ -6582,6 +6583,7 @@ static __init int test_bpf(void)
                struct bpf_prog *fp;
                int err;
 
+               cond_resched();
                if (exclude_test(i))
                        continue;
 
index e372b97..0e5b7a6 100644 (file)
@@ -1141,7 +1141,7 @@ static struct kmod_test_device *register_test_dev_kmod(void)
        mutex_lock(&reg_dev_mutex);
 
        /* int should suffice for number of devices, test for wrap */
-       if (unlikely(num_test_devs + 1) < 0) {
+       if (num_test_devs + 1 == INT_MAX) {
                pr_err("reached limit of number of test devices\n");
                goto out;
        }
index 76d3667..f4000c1 100644 (file)
@@ -79,6 +79,21 @@ struct thread_data {
        struct test_obj *objs;
 };
 
+static u32 my_hashfn(const void *data, u32 len, u32 seed)
+{
+       const struct test_obj_rhl *obj = data;
+
+       return (obj->value.id % 10) << RHT_HASH_RESERVED_SPACE;
+}
+
+static int my_cmpfn(struct rhashtable_compare_arg *arg, const void *obj)
+{
+       const struct test_obj_rhl *test_obj = obj;
+       const struct test_obj_val *val = arg->key;
+
+       return test_obj->value.id - val->id;
+}
+
 static struct rhashtable_params test_rht_params = {
        .head_offset = offsetof(struct test_obj, node),
        .key_offset = offsetof(struct test_obj, value),
@@ -87,6 +102,17 @@ static struct rhashtable_params test_rht_params = {
        .nulls_base = (3U << RHT_BASE_SHIFT),
 };
 
+static struct rhashtable_params test_rht_params_dup = {
+       .head_offset = offsetof(struct test_obj_rhl, list_node),
+       .key_offset = offsetof(struct test_obj_rhl, value),
+       .key_len = sizeof(struct test_obj_val),
+       .hashfn = jhash,
+       .obj_hashfn = my_hashfn,
+       .obj_cmpfn = my_cmpfn,
+       .nelem_hint = 128,
+       .automatic_shrinking = false,
+};
+
 static struct semaphore prestart_sem;
 static struct semaphore startup_sem = __SEMAPHORE_INITIALIZER(startup_sem, 0);
 
@@ -465,6 +491,112 @@ static int __init test_rhashtable_max(struct test_obj *array,
        return err;
 }
 
+static unsigned int __init print_ht(struct rhltable *rhlt)
+{
+       struct rhashtable *ht;
+       const struct bucket_table *tbl;
+       char buff[512] = "";
+       unsigned int i, cnt = 0;
+
+       ht = &rhlt->ht;
+       tbl = rht_dereference(ht->tbl, ht);
+       for (i = 0; i < tbl->size; i++) {
+               struct rhash_head *pos, *next;
+               struct test_obj_rhl *p;
+
+               pos = rht_dereference(tbl->buckets[i], ht);
+               next = !rht_is_a_nulls(pos) ? rht_dereference(pos->next, ht) : NULL;
+
+               if (!rht_is_a_nulls(pos)) {
+                       sprintf(buff, "%s\nbucket[%d] -> ", buff, i);
+               }
+
+               while (!rht_is_a_nulls(pos)) {
+                       struct rhlist_head *list = container_of(pos, struct rhlist_head, rhead);
+                       sprintf(buff, "%s[[", buff);
+                       do {
+                               pos = &list->rhead;
+                               list = rht_dereference(list->next, ht);
+                               p = rht_obj(ht, pos);
+
+                               sprintf(buff, "%s val %d (tid=%d)%s", buff, p->value.id, p->value.tid,
+                                       list? ", " : " ");
+                               cnt++;
+                       } while (list);
+
+                       pos = next,
+                       next = !rht_is_a_nulls(pos) ?
+                               rht_dereference(pos->next, ht) : NULL;
+
+                       sprintf(buff, "%s]]%s", buff, !rht_is_a_nulls(pos) ? " -> " : "");
+               }
+       }
+       printk(KERN_ERR "\n---- ht: ----%s\n-------------\n", buff);
+
+       return cnt;
+}
+
+static int __init test_insert_dup(struct test_obj_rhl *rhl_test_objects,
+                                 int cnt, bool slow)
+{
+       struct rhltable rhlt;
+       unsigned int i, ret;
+       const char *key;
+       int err = 0;
+
+       err = rhltable_init(&rhlt, &test_rht_params_dup);
+       if (WARN_ON(err))
+               return err;
+
+       for (i = 0; i < cnt; i++) {
+               rhl_test_objects[i].value.tid = i;
+               key = rht_obj(&rhlt.ht, &rhl_test_objects[i].list_node.rhead);
+               key += test_rht_params_dup.key_offset;
+
+               if (slow) {
+                       err = PTR_ERR(rhashtable_insert_slow(&rhlt.ht, key,
+                                                            &rhl_test_objects[i].list_node.rhead));
+                       if (err == -EAGAIN)
+                               err = 0;
+               } else
+                       err = rhltable_insert(&rhlt,
+                                             &rhl_test_objects[i].list_node,
+                                             test_rht_params_dup);
+               if (WARN(err, "error %d on element %d/%d (%s)\n", err, i, cnt, slow? "slow" : "fast"))
+                       goto skip_print;
+       }
+
+       ret = print_ht(&rhlt);
+       WARN(ret != cnt, "missing rhltable elements (%d != %d, %s)\n", ret, cnt, slow? "slow" : "fast");
+
+skip_print:
+       rhltable_destroy(&rhlt);
+
+       return 0;
+}
+
+static int __init test_insert_duplicates_run(void)
+{
+       struct test_obj_rhl rhl_test_objects[3] = {};
+
+       pr_info("test inserting duplicates\n");
+
+       /* two different values that map to same bucket */
+       rhl_test_objects[0].value.id = 1;
+       rhl_test_objects[1].value.id = 21;
+
+       /* and another duplicate with same as [0] value
+        * which will be second on the bucket list */
+       rhl_test_objects[2].value.id = rhl_test_objects[0].value.id;
+
+       test_insert_dup(rhl_test_objects, 2, false);
+       test_insert_dup(rhl_test_objects, 3, false);
+       test_insert_dup(rhl_test_objects, 2, true);
+       test_insert_dup(rhl_test_objects, 3, true);
+
+       return 0;
+}
+
 static int thread_lookup_test(struct thread_data *tdata)
 {
        unsigned int entries = tdata->entries;
@@ -613,6 +745,8 @@ static int __init test_rht_init(void)
        do_div(total_time, runs);
        pr_info("Average test time: %llu\n", total_time);
 
+       test_insert_duplicates_run();
+
        if (!tcount)
                return 0;
 
index 77ee6ce..d7a708f 100644 (file)
@@ -1849,7 +1849,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 {
        const int default_width = 2 * sizeof(void *);
 
-       if (!ptr && *fmt != 'K') {
+       if (!ptr && *fmt != 'K' && *fmt != 'x') {
                /*
                 * Print (null) with the same width as a pointer so it makes
                 * tabular output look nice.
index 1b46e6e..6afae32 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
        }
 
        if (ret & VM_FAULT_RETRY) {
-               if (nonblocking)
+               if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT))
                        *nonblocking = 0;
                return -EBUSY;
        }
@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
                                break;
                }
                if (*locked) {
-                       /* VM_FAULT_RETRY didn't trigger */
+                       /*
+                        * VM_FAULT_RETRY didn't trigger or it was a
+                        * FOLL_NOWAIT.
+                        */
                        if (!pages_done)
                                pages_done = ret;
                        break;
index 87ab9b8..5a68730 100644 (file)
@@ -555,7 +555,8 @@ static int __do_huge_pmd_anonymous_page(struct vm_fault *vmf, struct page *page,
 
        VM_BUG_ON_PAGE(!PageCompound(page), page);
 
-       if (mem_cgroup_try_charge(page, vma->vm_mm, gfp, &memcg, true)) {
+       if (mem_cgroup_try_charge(page, vma->vm_mm, gfp | __GFP_NORETRY, &memcg,
+                                 true)) {
                put_page(page);
                count_vm_event(THP_FAULT_FALLBACK);
                return VM_FAULT_FALLBACK;
@@ -1316,7 +1317,7 @@ alloc:
        }
 
        if (unlikely(mem_cgroup_try_charge(new_page, vma->vm_mm,
-                                       huge_gfp, &memcg, true))) {
+                               huge_gfp | __GFP_NORETRY, &memcg, true))) {
                put_page(new_page);
                split_huge_pmd(vma, vmf->pmd, vmf->address);
                if (page)
@@ -2783,11 +2784,13 @@ static unsigned long deferred_split_scan(struct shrinker *shrink,
 
        list_for_each_safe(pos, next, &list) {
                page = list_entry((void *)pos, struct page, mapping);
-               lock_page(page);
+               if (!trylock_page(page))
+                       goto next;
                /* split_huge_page() removes page from list on success */
                if (!split_huge_page(page))
                        split++;
                unlock_page(page);
+next:
                put_page(page);
        }
 
index 7c204e3..976bbc5 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/bootmem.h>
 #include <linux/sysfs.h>
 #include <linux/slab.h>
+#include <linux/mmdebug.h>
 #include <linux/sched/signal.h>
 #include <linux/rmap.h>
 #include <linux/string_helpers.h>
@@ -1583,7 +1584,7 @@ static struct page *alloc_surplus_huge_page(struct hstate *h, gfp_t gfp_mask,
                page = NULL;
        } else {
                h->surplus_huge_pages++;
-               h->nr_huge_pages_node[page_to_nid(page)]++;
+               h->surplus_huge_pages_node[page_to_nid(page)]++;
        }
 
 out_unlock:
@@ -4374,6 +4375,12 @@ int hugetlb_reserve_pages(struct inode *inode,
        struct resv_map *resv_map;
        long gbl_reserve;
 
+       /* This should never happen */
+       if (from > to) {
+               VM_WARN(1, "%s called with a negative range\n", __func__);
+               return -EINVAL;
+       }
+
        /*
         * Only apply hugepage reservation if asked. At fault time, an
         * attempt will be made for VM_NORESERVE to allocate a page
index b7e2268..e425682 100644 (file)
@@ -530,7 +530,12 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma,
                        goto out;
                }
 
-               VM_BUG_ON_PAGE(PageCompound(page), page);
+               /* TODO: teach khugepaged to collapse THP mapped with pte */
+               if (PageCompound(page)) {
+                       result = SCAN_PAGE_COMPOUND;
+                       goto out;
+               }
+
                VM_BUG_ON_PAGE(!PageAnon(page), page);
 
                /*
@@ -960,7 +965,9 @@ static void collapse_huge_page(struct mm_struct *mm,
                goto out_nolock;
        }
 
-       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
+       /* Do not oom kill for khugepaged charges */
+       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY,
+                                          &memcg, true))) {
                result = SCAN_CGROUP_CHARGE_FAIL;
                goto out_nolock;
        }
@@ -1319,7 +1326,9 @@ static void collapse_shmem(struct mm_struct *mm,
                goto out;
        }
 
-       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp, &memcg, true))) {
+       /* Do not oom kill for khugepaged charges */
+       if (unlikely(mem_cgroup_try_charge(new_page, mm, gfp | __GFP_NORETRY,
+                                          &memcg, true))) {
                result = SCAN_CGROUP_CHARGE_FAIL;
                goto out;
        }
index e83987c..46c2290 100644 (file)
@@ -1657,8 +1657,7 @@ static void start_scan_thread(void)
 }
 
 /*
- * Stop the automatic memory scanning thread. This function must be called
- * with the scan_mutex held.
+ * Stop the automatic memory scanning thread.
  */
 static void stop_scan_thread(void)
 {
@@ -1921,12 +1920,15 @@ static void kmemleak_do_cleanup(struct work_struct *work)
 {
        stop_scan_thread();
 
+       mutex_lock(&scan_mutex);
        /*
-        * Once the scan thread has stopped, it is safe to no longer track
-        * object freeing. Ordering of the scan thread stopping and the memory
-        * accesses below is guaranteed by the kthread_stop() function.
+        * Once it is made sure that kmemleak_scan has stopped, it is safe to no
+        * longer track object freeing. Ordering of the scan thread stopping and
+        * the memory accesses below is guaranteed by the kthread_stop()
+        * function.
         */
        kmemleak_free_enabled = 0;
+       mutex_unlock(&scan_mutex);
 
        if (!kmemleak_found_leaks)
                __kmemleak_do_cleanup();
index 5a9ca2a..48376bd 100644 (file)
@@ -1101,34 +1101,6 @@ void __init_memblock __next_mem_pfn_range(int *idx, int nid,
                *out_nid = r->nid;
 }
 
-unsigned long __init_memblock memblock_next_valid_pfn(unsigned long pfn,
-                                                     unsigned long max_pfn)
-{
-       struct memblock_type *type = &memblock.memory;
-       unsigned int right = type->cnt;
-       unsigned int mid, left = 0;
-       phys_addr_t addr = PFN_PHYS(pfn + 1);
-
-       do {
-               mid = (right + left) / 2;
-
-               if (addr < type->regions[mid].base)
-                       right = mid;
-               else if (addr >= (type->regions[mid].base +
-                                 type->regions[mid].size))
-                       left = mid + 1;
-               else {
-                       /* addr is within the region, so pfn + 1 is valid */
-                       return min(pfn + 1, max_pfn);
-               }
-       } while (left < right);
-
-       if (right == type->cnt)
-               return max_pfn;
-       else
-               return min(PHYS_PFN(type->regions[right].base), max_pfn);
-}
-
 /**
  * memblock_set_node - set node ID on memblock regions
  * @base: base of area to set node ID for
index 670e99b..9ec024b 100644 (file)
@@ -714,9 +714,9 @@ static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
  * invocations for reference counting, or use mem_cgroup_iter_break()
  * to cancel a hierarchy walk before the round-trip is complete.
  *
- * Reclaimers can specify a zone and a priority level in @reclaim to
+ * Reclaimers can specify a node and a priority level in @reclaim to
  * divide up the memcgs in the hierarchy among all concurrent
- * reclaimers operating on the same zone and priority.
+ * reclaimers operating on the same node and priority.
  */
 struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                                   struct mem_cgroup *prev,
@@ -2299,7 +2299,7 @@ void memcg_kmem_put_cache(struct kmem_cache *cachep)
 }
 
 /**
- * memcg_kmem_charge: charge a kmem page
+ * memcg_kmem_charge_memcg: charge a kmem page
  * @page: page to charge
  * @gfp: reclaim mode
  * @order: allocation order
index 4b80cce..8291b75 100644 (file)
@@ -1139,8 +1139,6 @@ int memory_failure(unsigned long pfn, int flags)
                return 0;
        }
 
-       arch_unmap_kpfn(pfn);
-
        orig_head = hpage = compound_head(p);
        num_poisoned_pages_inc();
 
index dd8de96..5fcfc24 100644 (file)
@@ -80,7 +80,7 @@
 
 #include "internal.h"
 
-#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
+#if defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) && !defined(CONFIG_COMPILE_TEST)
 #warning Unfortunate NUMA and NUMA Balancing config, growing page-frame for last_cpupid.
 #endif
 
index d879f1d..32cba03 100644 (file)
@@ -2124,6 +2124,9 @@ bool __mpol_equal(struct mempolicy *a, struct mempolicy *b)
        case MPOL_INTERLEAVE:
                return !!nodes_equal(a->v.nodes, b->v.nodes);
        case MPOL_PREFERRED:
+               /* a's ->flags is the same as b's */
+               if (a->flags & MPOL_F_LOCAL)
+                       return true;
                return a->v.preferred_node == b->v.preferred_node;
        default:
                BUG();
index 7939820..74e5a65 100644 (file)
@@ -64,6 +64,12 @@ void clear_page_mlock(struct page *page)
        mod_zone_page_state(page_zone(page), NR_MLOCK,
                            -hpage_nr_pages(page));
        count_vm_event(UNEVICTABLE_PGCLEARED);
+       /*
+        * The previous TestClearPageMlocked() corresponds to the smp_mb()
+        * in __pagevec_lru_add_fn().
+        *
+        * See __pagevec_lru_add_fn for more explanation.
+        */
        if (!isolate_lru_page(page)) {
                putback_lru_page(page);
        } else {
index 81e18ce..1741dd2 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/stop_machine.h>
 #include <linux/sort.h>
 #include <linux/pfn.h>
+#include <xen/xen.h>
 #include <linux/backing-dev.h>
 #include <linux/fault-inject.h>
 #include <linux/page-isolation.h>
@@ -347,6 +348,9 @@ static inline bool update_defer_init(pg_data_t *pgdat,
        /* Always populate low zones for address-constrained allocations */
        if (zone_end < pgdat_end_pfn(pgdat))
                return true;
+       /* Xen PV domains need page structures early */
+       if (xen_pv_domain())
+               return true;
        (*nr_initialised)++;
        if ((*nr_initialised > pgdat->static_init_pgcnt) &&
            (pfn & (PAGES_PER_SECTION - 1)) == 0) {
@@ -1906,7 +1910,9 @@ static int move_freepages(struct zone *zone,
         * Remove at a later date when no bug reports exist related to
         * grouping pages by mobility
         */
-       VM_BUG_ON(page_zone(start_page) != page_zone(end_page));
+       VM_BUG_ON(pfn_valid(page_to_pfn(start_page)) &&
+                 pfn_valid(page_to_pfn(end_page)) &&
+                 page_zone(start_page) != page_zone(end_page));
 #endif
 
        if (num_movable)
@@ -3590,7 +3596,7 @@ static bool __need_fs_reclaim(gfp_t gfp_mask)
                return false;
 
        /* this guy won't enter reclaim */
-       if ((current->flags & PF_MEMALLOC) && !(gfp_mask & __GFP_NOMEMALLOC))
+       if (current->flags & PF_MEMALLOC)
                return false;
 
        /* We're only interested __GFP_FS allocations for now */
@@ -5350,17 +5356,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
                if (context != MEMMAP_EARLY)
                        goto not_early;
 
-               if (!early_pfn_valid(pfn)) {
-#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
-                       /*
-                        * Skip to the pfn preceding the next valid one (or
-                        * end_pfn), such that we hit a valid pfn (or end_pfn)
-                        * on our next iteration of the loop.
-                        */
-                       pfn = memblock_next_valid_pfn(pfn, end_pfn) - 1;
-#endif
+               if (!early_pfn_valid(pfn))
                        continue;
-               }
                if (!early_pfn_in_nid(pfn, nid))
                        continue;
                if (!update_defer_init(pgdat, pfn, end_pfn, &nr_initialised))
index 9886c60..7172e0a 100644 (file)
@@ -123,13 +123,13 @@ void __reset_page_owner(struct page *page, unsigned int order)
 static inline bool check_recursive_alloc(struct stack_trace *trace,
                                        unsigned long ip)
 {
-       int i, count;
+       int i;
 
        if (!trace->nr_entries)
                return false;
 
-       for (i = 0, count = 0; i < trace->nr_entries; i++) {
-               if (trace->entries[i] == ip && ++count == 2)
+       for (i = 0; i < trace->nr_entries; i++) {
+               if (trace->entries[i] == ip)
                        return true;
        }
 
index d2a7664..38de70a 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/log2.h>
 
 static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
-                              int page_start, int page_end)
+                              int page_start, int page_end, gfp_t gfp)
 {
        return 0;
 }
@@ -45,18 +45,18 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
        /* nada */
 }
 
-static struct pcpu_chunk *pcpu_create_chunk(void)
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
 {
        const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT;
        struct pcpu_chunk *chunk;
        struct page *pages;
        int i;
 
-       chunk = pcpu_alloc_chunk();
+       chunk = pcpu_alloc_chunk(gfp);
        if (!chunk)
                return NULL;
 
-       pages = alloc_pages(GFP_KERNEL, order_base_2(nr_pages));
+       pages = alloc_pages(gfp, order_base_2(nr_pages));
        if (!pages) {
                pcpu_free_chunk(chunk);
                return NULL;
index 9158e5a..d8078de 100644 (file)
@@ -37,7 +37,7 @@ static struct page **pcpu_get_pages(void)
        lockdep_assert_held(&pcpu_alloc_mutex);
 
        if (!pages)
-               pages = pcpu_mem_zalloc(pages_size);
+               pages = pcpu_mem_zalloc(pages_size, GFP_KERNEL);
        return pages;
 }
 
@@ -73,18 +73,21 @@ static void pcpu_free_pages(struct pcpu_chunk *chunk,
  * @pages: array to put the allocated pages into, indexed by pcpu_page_idx()
  * @page_start: page index of the first page to be allocated
  * @page_end: page index of the last page to be allocated + 1
+ * @gfp: allocation flags passed to the underlying allocator
  *
  * Allocate pages [@page_start,@page_end) into @pages for all units.
  * The allocation is for @chunk.  Percpu core doesn't care about the
  * content of @pages and will pass it verbatim to pcpu_map_pages().
  */
 static int pcpu_alloc_pages(struct pcpu_chunk *chunk,
-                           struct page **pages, int page_start, int page_end)
+                           struct page **pages, int page_start, int page_end,
+                           gfp_t gfp)
 {
-       const gfp_t gfp = GFP_KERNEL | __GFP_HIGHMEM;
        unsigned int cpu, tcpu;
        int i;
 
+       gfp |= __GFP_HIGHMEM;
+
        for_each_possible_cpu(cpu) {
                for (i = page_start; i < page_end; i++) {
                        struct page **pagep = &pages[pcpu_page_idx(cpu, i)];
@@ -262,6 +265,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
  * @chunk: chunk of interest
  * @page_start: the start page
  * @page_end: the end page
+ * @gfp: allocation flags passed to the underlying memory allocator
  *
  * For each cpu, populate and map pages [@page_start,@page_end) into
  * @chunk.
@@ -270,7 +274,7 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk,
  * pcpu_alloc_mutex, does GFP_KERNEL allocation.
  */
 static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
-                              int page_start, int page_end)
+                              int page_start, int page_end, gfp_t gfp)
 {
        struct page **pages;
 
@@ -278,7 +282,7 @@ static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
        if (!pages)
                return -ENOMEM;
 
-       if (pcpu_alloc_pages(chunk, pages, page_start, page_end))
+       if (pcpu_alloc_pages(chunk, pages, page_start, page_end, gfp))
                return -ENOMEM;
 
        if (pcpu_map_pages(chunk, pages, page_start, page_end)) {
@@ -325,12 +329,12 @@ static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
        pcpu_free_pages(chunk, pages, page_start, page_end);
 }
 
-static struct pcpu_chunk *pcpu_create_chunk(void)
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp)
 {
        struct pcpu_chunk *chunk;
        struct vm_struct **vms;
 
-       chunk = pcpu_alloc_chunk();
+       chunk = pcpu_alloc_chunk(gfp);
        if (!chunk)
                return NULL;
 
index 50e7fdf..9297098 100644 (file)
@@ -80,6 +80,7 @@
 #include <linux/vmalloc.h>
 #include <linux/workqueue.h>
 #include <linux/kmemleak.h>
+#include <linux/sched.h>
 
 #include <asm/cacheflush.h>
 #include <asm/sections.h>
@@ -447,26 +448,25 @@ static void pcpu_next_fit_region(struct pcpu_chunk *chunk, int alloc_bits,
 /**
  * pcpu_mem_zalloc - allocate memory
  * @size: bytes to allocate
+ * @gfp: allocation flags
  *
  * Allocate @size bytes.  If @size is smaller than PAGE_SIZE,
- * kzalloc() is used; otherwise, vzalloc() is used.  The returned
- * memory is always zeroed.
- *
- * CONTEXT:
- * Does GFP_KERNEL allocation.
+ * kzalloc() is used; otherwise, the equivalent of vzalloc() is used.
+ * This is to facilitate passing through whitelisted flags.  The
+ * returned memory is always zeroed.
  *
  * RETURNS:
  * Pointer to the allocated area on success, NULL on failure.
  */
-static void *pcpu_mem_zalloc(size_t size)
+static void *pcpu_mem_zalloc(size_t size, gfp_t gfp)
 {
        if (WARN_ON_ONCE(!slab_is_available()))
                return NULL;
 
        if (size <= PAGE_SIZE)
-               return kzalloc(size, GFP_KERNEL);
+               return kzalloc(size, gfp);
        else
-               return vzalloc(size);
+               return __vmalloc(size, gfp | __GFP_ZERO, PAGE_KERNEL);
 }
 
 /**
@@ -1154,12 +1154,12 @@ static struct pcpu_chunk * __init pcpu_alloc_first_chunk(unsigned long tmp_addr,
        return chunk;
 }
 
-static struct pcpu_chunk *pcpu_alloc_chunk(void)
+static struct pcpu_chunk *pcpu_alloc_chunk(gfp_t gfp)
 {
        struct pcpu_chunk *chunk;
        int region_bits;
 
-       chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size);
+       chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size, gfp);
        if (!chunk)
                return NULL;
 
@@ -1168,17 +1168,17 @@ static struct pcpu_chunk *pcpu_alloc_chunk(void)
        region_bits = pcpu_chunk_map_bits(chunk);
 
        chunk->alloc_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits) *
-                                          sizeof(chunk->alloc_map[0]));
+                                          sizeof(chunk->alloc_map[0]), gfp);
        if (!chunk->alloc_map)
                goto alloc_map_fail;
 
        chunk->bound_map = pcpu_mem_zalloc(BITS_TO_LONGS(region_bits + 1) *
-                                          sizeof(chunk->bound_map[0]));
+                                          sizeof(chunk->bound_map[0]), gfp);
        if (!chunk->bound_map)
                goto bound_map_fail;
 
        chunk->md_blocks = pcpu_mem_zalloc(pcpu_chunk_nr_blocks(chunk) *
-                                          sizeof(chunk->md_blocks[0]));
+                                          sizeof(chunk->md_blocks[0]), gfp);
        if (!chunk->md_blocks)
                goto md_blocks_fail;
 
@@ -1277,9 +1277,11 @@ static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk,
  * pcpu_addr_to_page           - translate address to physical address
  * pcpu_verify_alloc_info      - check alloc_info is acceptable during init
  */
-static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size);
-static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size);
-static struct pcpu_chunk *pcpu_create_chunk(void);
+static int pcpu_populate_chunk(struct pcpu_chunk *chunk,
+                              int page_start, int page_end, gfp_t gfp);
+static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk,
+                                 int page_start, int page_end);
+static struct pcpu_chunk *pcpu_create_chunk(gfp_t gfp);
 static void pcpu_destroy_chunk(struct pcpu_chunk *chunk);
 static struct page *pcpu_addr_to_page(void *addr);
 static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai);
@@ -1339,6 +1341,8 @@ static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr)
 static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
                                 gfp_t gfp)
 {
+       /* whitelisted flags that can be passed to the backing allocators */
+       gfp_t pcpu_gfp = gfp & (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN);
        bool is_atomic = (gfp & GFP_KERNEL) != GFP_KERNEL;
        bool do_warn = !(gfp & __GFP_NOWARN);
        static int warn_limit = 10;
@@ -1369,8 +1373,17 @@ static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved,
                return NULL;
        }
 
-       if (!is_atomic)
-               mutex_lock(&pcpu_alloc_mutex);
+       if (!is_atomic) {
+               /*
+                * pcpu_balance_workfn() allocates memory under this mutex,
+                * and it may wait for memory reclaim. Allow current task
+                * to become OOM victim, in case of memory pressure.
+                */
+               if (gfp & __GFP_NOFAIL)
+                       mutex_lock(&pcpu_alloc_mutex);
+               else if (mutex_lock_killable(&pcpu_alloc_mutex))
+                       return NULL;
+       }
 
        spin_lock_irqsave(&pcpu_lock, flags);
 
@@ -1421,7 +1434,7 @@ restart:
        }
 
        if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) {
-               chunk = pcpu_create_chunk();
+               chunk = pcpu_create_chunk(pcpu_gfp);
                if (!chunk) {
                        err = "failed to allocate new chunk";
                        goto fail;
@@ -1450,7 +1463,7 @@ area_found:
                                           page_start, page_end) {
                        WARN_ON(chunk->immutable);
 
-                       ret = pcpu_populate_chunk(chunk, rs, re);
+                       ret = pcpu_populate_chunk(chunk, rs, re, pcpu_gfp);
 
                        spin_lock_irqsave(&pcpu_lock, flags);
                        if (ret) {
@@ -1561,10 +1574,17 @@ void __percpu *__alloc_reserved_percpu(size_t size, size_t align)
  * pcpu_balance_workfn - manage the amount of free chunks and populated pages
  * @work: unused
  *
- * Reclaim all fully free chunks except for the first one.
+ * Reclaim all fully free chunks except for the first one.  This is also
+ * responsible for maintaining the pool of empty populated pages.  However,
+ * it is possible that this is called when physical memory is scarce causing
+ * OOM killer to be triggered.  We should avoid doing so until an actual
+ * allocation causes the failure as it is possible that requests can be
+ * serviced from already backed regions.
  */
 static void pcpu_balance_workfn(struct work_struct *work)
 {
+       /* gfp flags passed to underlying allocators */
+       const gfp_t gfp = GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
        LIST_HEAD(to_free);
        struct list_head *free_head = &pcpu_slot[pcpu_nr_slots - 1];
        struct pcpu_chunk *chunk, *next;
@@ -1600,6 +1620,7 @@ static void pcpu_balance_workfn(struct work_struct *work)
                        spin_unlock_irq(&pcpu_lock);
                }
                pcpu_destroy_chunk(chunk);
+               cond_resched();
        }
 
        /*
@@ -1645,7 +1666,7 @@ retry_pop:
                                           chunk->nr_pages) {
                        int nr = min(re - rs, nr_to_pop);
 
-                       ret = pcpu_populate_chunk(chunk, rs, rs + nr);
+                       ret = pcpu_populate_chunk(chunk, rs, rs + nr, gfp);
                        if (!ret) {
                                nr_to_pop -= nr;
                                spin_lock_irq(&pcpu_lock);
@@ -1662,7 +1683,7 @@ retry_pop:
 
        if (nr_to_pop) {
                /* ran out of chunks to populate, create a new one and retry */
-               chunk = pcpu_create_chunk();
+               chunk = pcpu_create_chunk(gfp);
                if (chunk) {
                        spin_lock_irq(&pcpu_lock);
                        pcpu_chunk_relocate(chunk, -1);
index 1907688..b859192 100644 (file)
@@ -493,36 +493,45 @@ next:
                info = list_entry(pos, struct shmem_inode_info, shrinklist);
                inode = &info->vfs_inode;
 
-               if (nr_to_split && split >= nr_to_split) {
-                       iput(inode);
-                       continue;
-               }
+               if (nr_to_split && split >= nr_to_split)
+                       goto leave;
 
-               page = find_lock_page(inode->i_mapping,
+               page = find_get_page(inode->i_mapping,
                                (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT);
                if (!page)
                        goto drop;
 
+               /* No huge page at the end of the file: nothing to split */
                if (!PageTransHuge(page)) {
-                       unlock_page(page);
                        put_page(page);
                        goto drop;
                }
 
+               /*
+                * Leave the inode on the list if we failed to lock
+                * the page at this time.
+                *
+                * Waiting for the lock may lead to deadlock in the
+                * reclaim path.
+                */
+               if (!trylock_page(page)) {
+                       put_page(page);
+                       goto leave;
+               }
+
                ret = split_huge_page(page);
                unlock_page(page);
                put_page(page);
 
-               if (ret) {
-                       /* split failed: leave it on the list */
-                       iput(inode);
-                       continue;
-               }
+               /* If split failed leave the inode on the list */
+               if (ret)
+                       goto leave;
 
                split++;
 drop:
                list_del_init(&info->shrinklist);
                removed++;
+leave:
                iput(inode);
        }
 
index 3244466..9095c39 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1283,6 +1283,7 @@ void __init kmem_cache_init(void)
                                  nr_node_ids * sizeof(struct kmem_cache_node *),
                                  SLAB_HWCACHE_ALIGN, 0, 0);
        list_add(&kmem_cache->list, &slab_caches);
+       memcg_link_cache(kmem_cache);
        slab_state = PARTIAL;
 
        /*
index 567a7b9..0f17330 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -446,30 +446,6 @@ void lru_cache_add(struct page *page)
 }
 
 /**
- * add_page_to_unevictable_list - add a page to the unevictable list
- * @page:  the page to be added to the unevictable list
- *
- * Add page directly to its zone's unevictable list.  To avoid races with
- * tasks that might be making the page evictable, through eg. munlock,
- * munmap or exit, while it's not on the lru, we want to add the page
- * while it's locked or otherwise "invisible" to other tasks.  This is
- * difficult to do when using the pagevec cache, so bypass that.
- */
-void add_page_to_unevictable_list(struct page *page)
-{
-       struct pglist_data *pgdat = page_pgdat(page);
-       struct lruvec *lruvec;
-
-       spin_lock_irq(&pgdat->lru_lock);
-       lruvec = mem_cgroup_page_lruvec(page, pgdat);
-       ClearPageActive(page);
-       SetPageUnevictable(page);
-       SetPageLRU(page);
-       add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE);
-       spin_unlock_irq(&pgdat->lru_lock);
-}
-
-/**
  * lru_cache_add_active_or_unevictable
  * @page:  the page to be added to LRU
  * @vma:   vma in which page is mapped for determining reclaimability
@@ -484,13 +460,9 @@ void lru_cache_add_active_or_unevictable(struct page *page,
 {
        VM_BUG_ON_PAGE(PageLRU(page), page);
 
-       if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) {
+       if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED))
                SetPageActive(page);
-               lru_cache_add(page);
-               return;
-       }
-
-       if (!TestSetPageMlocked(page)) {
+       else if (!TestSetPageMlocked(page)) {
                /*
                 * We use the irq-unsafe __mod_zone_page_stat because this
                 * counter is not modified from interrupt context, and the pte
@@ -500,7 +472,7 @@ void lru_cache_add_active_or_unevictable(struct page *page,
                                    hpage_nr_pages(page));
                count_vm_event(UNEVICTABLE_PGMLOCKED);
        }
-       add_page_to_unevictable_list(page);
+       lru_cache_add(page);
 }
 
 /*
@@ -886,15 +858,55 @@ void lru_add_page_tail(struct page *page, struct page *page_tail,
 static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec,
                                 void *arg)
 {
-       int file = page_is_file_cache(page);
-       int active = PageActive(page);
-       enum lru_list lru = page_lru(page);
+       enum lru_list lru;
+       int was_unevictable = TestClearPageUnevictable(page);
 
        VM_BUG_ON_PAGE(PageLRU(page), page);
 
        SetPageLRU(page);
+       /*
+        * Page becomes evictable in two ways:
+        * 1) Within LRU lock [munlock_vma_pages() and __munlock_pagevec()].
+        * 2) Before acquiring LRU lock to put the page to correct LRU and then
+        *   a) do PageLRU check with lock [check_move_unevictable_pages]
+        *   b) do PageLRU check before lock [clear_page_mlock]
+        *
+        * (1) & (2a) are ok as LRU lock will serialize them. For (2b), we need
+        * following strict ordering:
+        *
+        * #0: __pagevec_lru_add_fn             #1: clear_page_mlock
+        *
+        * SetPageLRU()                         TestClearPageMlocked()
+        * smp_mb() // explicit ordering        // above provides strict
+        *                                      // ordering
+        * PageMlocked()                        PageLRU()
+        *
+        *
+        * if '#1' does not observe setting of PG_lru by '#0' and fails
+        * isolation, the explicit barrier will make sure that page_evictable
+        * check will put the page in correct LRU. Without smp_mb(), SetPageLRU
+        * can be reordered after PageMlocked check and can make '#1' to fail
+        * the isolation of the page whose Mlocked bit is cleared (#0 is also
+        * looking at the same page) and the evictable page will be stranded
+        * in an unevictable LRU.
+        */
+       smp_mb();
+
+       if (page_evictable(page)) {
+               lru = page_lru(page);
+               update_page_reclaim_stat(lruvec, page_is_file_cache(page),
+                                        PageActive(page));
+               if (was_unevictable)
+                       count_vm_event(UNEVICTABLE_PGRESCUED);
+       } else {
+               lru = LRU_UNEVICTABLE;
+               ClearPageActive(page);
+               SetPageUnevictable(page);
+               if (!was_unevictable)
+                       count_vm_event(UNEVICTABLE_PGCULLED);
+       }
+
        add_page_to_lru_list(page, lruvec, lru);
-       update_page_reclaim_stat(lruvec, file, active);
        trace_mm_lru_insertion(page, lru);
 }
 
@@ -913,7 +925,7 @@ EXPORT_SYMBOL(__pagevec_lru_add);
  * @pvec:      Where the resulting entries are placed
  * @mapping:   The address_space to search
  * @start:     The starting entry index
- * @nr_pages:  The maximum number of pages
+ * @nr_entries:        The maximum number of pages
  * @indices:   The cache indices corresponding to the entries in @pvec
  *
  * pagevec_lookup_entries() will search for and return a group of up
index 6739420..ebff729 100644 (file)
@@ -1943,11 +1943,15 @@ void *vmalloc_exec(unsigned long size)
 }
 
 #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32)
-#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL
+#define GFP_VMALLOC32 (GFP_DMA32 | GFP_KERNEL)
 #elif defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA)
-#define GFP_VMALLOC32 GFP_DMA | GFP_KERNEL
+#define GFP_VMALLOC32 (GFP_DMA | GFP_KERNEL)
 #else
-#define GFP_VMALLOC32 GFP_KERNEL
+/*
+ * 64b systems should always have either DMA or DMA32 zones. For others
+ * GFP_DMA32 should do the right thing and use the normal zone.
+ */
+#define GFP_VMALLOC32 GFP_DMA32 | GFP_KERNEL
 #endif
 
 /**
index 4447496..cd5dc3f 100644 (file)
@@ -769,64 +769,7 @@ int remove_mapping(struct address_space *mapping, struct page *page)
  */
 void putback_lru_page(struct page *page)
 {
-       bool is_unevictable;
-       int was_unevictable = PageUnevictable(page);
-
-       VM_BUG_ON_PAGE(PageLRU(page), page);
-
-redo:
-       ClearPageUnevictable(page);
-
-       if (page_evictable(page)) {
-               /*
-                * For evictable pages, we can use the cache.
-                * In event of a race, worst case is we end up with an
-                * unevictable page on [in]active list.
-                * We know how to handle that.
-                */
-               is_unevictable = false;
-               lru_cache_add(page);
-       } else {
-               /*
-                * Put unevictable pages directly on zone's unevictable
-                * list.
-                */
-               is_unevictable = true;
-               add_page_to_unevictable_list(page);
-               /*
-                * When racing with an mlock or AS_UNEVICTABLE clearing
-                * (page is unlocked) make sure that if the other thread
-                * does not observe our setting of PG_lru and fails
-                * isolation/check_move_unevictable_pages,
-                * we see PG_mlocked/AS_UNEVICTABLE cleared below and move
-                * the page back to the evictable list.
-                *
-                * The other side is TestClearPageMlocked() or shmem_lock().
-                */
-               smp_mb();
-       }
-
-       /*
-        * page's status can change while we move it among lru. If an evictable
-        * page is on unevictable list, it never be freed. To avoid that,
-        * check after we added it to the list, again.
-        */
-       if (is_unevictable && page_evictable(page)) {
-               if (!isolate_lru_page(page)) {
-                       put_page(page);
-                       goto redo;
-               }
-               /* This means someone else dropped this page from LRU
-                * So, it will be freed or putback to LRU again. There is
-                * nothing to do here.
-                */
-       }
-
-       if (was_unevictable && !is_unevictable)
-               count_vm_event(UNEVICTABLE_PGRESCUED);
-       else if (!was_unevictable && is_unevictable)
-               count_vm_event(UNEVICTABLE_PGCULLED);
-
+       lru_cache_add(page);
        put_page(page);         /* drop ref from isolate */
 }
 
@@ -1837,6 +1780,20 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
                set_bit(PGDAT_WRITEBACK, &pgdat->flags);
 
        /*
+        * If dirty pages are scanned that are not queued for IO, it
+        * implies that flushers are not doing their job. This can
+        * happen when memory pressure pushes dirty pages to the end of
+        * the LRU before the dirty limits are breached and the dirty
+        * data has expired. It can also happen when the proportion of
+        * dirty pages grows not through writes but through memory
+        * pressure reclaiming all the clean cache. And in some cases,
+        * the flushers simply cannot keep up with the allocation
+        * rate. Nudge the flusher threads in case they are asleep.
+        */
+       if (stat.nr_unqueued_dirty == nr_taken)
+               wakeup_flusher_threads(WB_REASON_VMSCAN);
+
+       /*
         * Legacy memcg will stall in page writeback so avoid forcibly
         * stalling here.
         */
@@ -1848,22 +1805,9 @@ shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec,
                if (stat.nr_dirty && stat.nr_dirty == stat.nr_congested)
                        set_bit(PGDAT_CONGESTED, &pgdat->flags);
 
-               /*
-                * If dirty pages are scanned that are not queued for IO, it
-                * implies that flushers are not doing their job. This can
-                * happen when memory pressure pushes dirty pages to the end of
-                * the LRU before the dirty limits are breached and the dirty
-                * data has expired. It can also happen when the proportion of
-                * dirty pages grows not through writes but through memory
-                * pressure reclaiming all the clean cache. And in some cases,
-                * the flushers simply cannot keep up with the allocation
-                * rate. Nudge the flusher threads in case they are asleep, but
-                * also allow kswapd to start writing pages during reclaim.
-                */
-               if (stat.nr_unqueued_dirty == nr_taken) {
-                       wakeup_flusher_threads(WB_REASON_VMSCAN);
+               /* Allow kswapd to start writing pages during reclaim. */
+               if (stat.nr_unqueued_dirty == nr_taken)
                        set_bit(PGDAT_DIRTY, &pgdat->flags);
-               }
 
                /*
                 * If kswapd scans pages marked marked for immediate
index 40b2db6..33581be 100644 (file)
@@ -1839,9 +1839,11 @@ static void vmstat_update(struct work_struct *w)
                 * to occur in the future. Keep on running the
                 * update worker thread.
                 */
+               preempt_disable();
                queue_delayed_work_on(smp_processor_id(), mm_percpu_wq,
                                this_cpu_ptr(&vmstat_work),
                                round_jiffies_relative(sysctl_stat_interval));
+               preempt_enable();
        }
 }
 
index f8cb83e..01a771e 100644 (file)
@@ -360,7 +360,7 @@ u64 zpool_get_total_size(struct zpool *zpool)
 
 /**
  * zpool_evictable() - Test if zpool is potentially evictable
- * @pool       The zpool to test
+ * @zpool:     The zpool to test
  *
  * Zpool is only potentially evictable when it's created with struct
  * zpool_ops.evict and its driver implements struct zpool_driver.shrink.
index c004aa4..61a5c41 100644 (file)
@@ -1007,6 +1007,12 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
        u8 *src, *dst;
        struct zswap_header zhdr = { .swpentry = swp_entry(type, offset) };
 
+       /* THP isn't supported */
+       if (PageTransHuge(page)) {
+               ret = -EINVAL;
+               goto reject;
+       }
+
        if (!zswap_enabled || !tree) {
                ret = -ENODEV;
                goto reject;
index 64aa9f7..45c9bf5 100644 (file)
@@ -48,8 +48,8 @@ bool vlan_do_receive(struct sk_buff **skbp)
                 * original position later
                 */
                skb_push(skb, offset);
-               skb = *skbp = vlan_insert_tag(skb, skb->vlan_proto,
-                                             skb->vlan_tci);
+               skb = *skbp = vlan_insert_inner_tag(skb, skb->vlan_proto,
+                                                   skb->vlan_tci, skb->mac_len);
                if (!skb)
                        return false;
                skb_pull(skb, offset + VLAN_HLEN);
index f3a4efc..3aa5a93 100644 (file)
@@ -160,7 +160,8 @@ static void req_done(struct virtqueue *vq)
                spin_unlock_irqrestore(&chan->lock, flags);
                /* Wakeup if anyone waiting for VirtIO ring space. */
                wake_up(chan->vc_wq);
-               p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
+               if (len)
+                       p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
        }
 }
 
index 79e3263..99abead 100644 (file)
@@ -157,7 +157,7 @@ static void batadv_iv_ogm_orig_free(struct batadv_orig_node *orig_node)
  * Return: 0 on success, a negative error code otherwise.
  */
 static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node,
-                                    int max_if_num)
+                                    unsigned int max_if_num)
 {
        void *data_ptr;
        size_t old_size;
@@ -201,7 +201,8 @@ unlock:
  */
 static void
 batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node,
-                                  int max_if_num, int del_if_num)
+                                  unsigned int max_if_num,
+                                  unsigned int del_if_num)
 {
        size_t chunk_size;
        size_t if_offset;
@@ -239,7 +240,8 @@ batadv_iv_ogm_drop_bcast_own_entry(struct batadv_orig_node *orig_node,
  */
 static void
 batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node,
-                                      int max_if_num, int del_if_num)
+                                      unsigned int max_if_num,
+                                      unsigned int del_if_num)
 {
        size_t if_offset;
        void *data_ptr;
@@ -276,7 +278,8 @@ batadv_iv_ogm_drop_bcast_own_sum_entry(struct batadv_orig_node *orig_node,
  * Return: 0 on success, a negative error code otherwise.
  */
 static int batadv_iv_ogm_orig_del_if(struct batadv_orig_node *orig_node,
-                                    int max_if_num, int del_if_num)
+                                    unsigned int max_if_num,
+                                    unsigned int del_if_num)
 {
        spin_lock_bh(&orig_node->bat_iv.ogm_cnt_lock);
 
@@ -311,7 +314,8 @@ static struct batadv_orig_node *
 batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr)
 {
        struct batadv_orig_node *orig_node;
-       int size, hash_added;
+       int hash_added;
+       size_t size;
 
        orig_node = batadv_orig_hash_find(bat_priv, addr);
        if (orig_node)
@@ -893,7 +897,7 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface)
        u32 i;
        size_t word_index;
        u8 *w;
-       int if_num;
+       unsigned int if_num;
 
        for (i = 0; i < hash->size; i++) {
                head = &hash->table[i];
@@ -1023,7 +1027,7 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv,
        struct batadv_neigh_node *tmp_neigh_node = NULL;
        struct batadv_neigh_node *router = NULL;
        struct batadv_orig_node *orig_node_tmp;
-       int if_num;
+       unsigned int if_num;
        u8 sum_orig, sum_neigh;
        u8 *neigh_addr;
        u8 tq_avg;
@@ -1182,7 +1186,7 @@ static bool batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node,
        u8 total_count;
        u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own;
        unsigned int neigh_rq_inv_cube, neigh_rq_max_cube;
-       int if_num;
+       unsigned int if_num;
        unsigned int tq_asym_penalty, inv_asym_penalty;
        unsigned int combined_tq;
        unsigned int tq_iface_penalty;
@@ -1702,9 +1706,9 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset,
 
        if (is_my_orig) {
                unsigned long *word;
-               int offset;
+               size_t offset;
                s32 bit_pos;
-               s16 if_num;
+               unsigned int if_num;
                u8 *weight;
 
                orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv,
@@ -2729,7 +2733,7 @@ static int batadv_iv_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
        struct batadv_neigh_ifinfo *router_ifinfo = NULL;
        struct batadv_neigh_node *router;
        struct batadv_gw_node *curr_gw;
-       int ret = -EINVAL;
+       int ret = 0;
        void *hdr;
 
        router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
index 27e165a..c74f813 100644 (file)
@@ -928,7 +928,7 @@ static int batadv_v_gw_dump_entry(struct sk_buff *msg, u32 portid, u32 seq,
        struct batadv_neigh_ifinfo *router_ifinfo = NULL;
        struct batadv_neigh_node *router;
        struct batadv_gw_node *curr_gw;
-       int ret = -EINVAL;
+       int ret = 0;
        void *hdr;
 
        router = batadv_orig_router_get(gw_node->orig_node, BATADV_IF_DEFAULT);
index fad4785..b1a0837 100644 (file)
@@ -2161,22 +2161,25 @@ batadv_bla_claim_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 {
        struct batadv_bla_claim *claim;
        int idx = 0;
+       int ret = 0;
 
        rcu_read_lock();
        hlist_for_each_entry_rcu(claim, head, hash_entry) {
                if (idx++ < *idx_skip)
                        continue;
-               if (batadv_bla_claim_dump_entry(msg, portid, seq,
-                                               primary_if, claim)) {
+
+               ret = batadv_bla_claim_dump_entry(msg, portid, seq,
+                                                 primary_if, claim);
+               if (ret) {
                        *idx_skip = idx - 1;
                        goto unlock;
                }
        }
 
-       *idx_skip = idx;
+       *idx_skip = 0;
 unlock:
        rcu_read_unlock();
-       return 0;
+       return ret;
 }
 
 /**
@@ -2391,22 +2394,25 @@ batadv_bla_backbone_dump_bucket(struct sk_buff *msg, u32 portid, u32 seq,
 {
        struct batadv_bla_backbone_gw *backbone_gw;
        int idx = 0;
+       int ret = 0;
 
        rcu_read_lock();
        hlist_for_each_entry_rcu(backbone_gw, head, hash_entry) {
                if (idx++ < *idx_skip)
                        continue;
-               if (batadv_bla_backbone_dump_entry(msg, portid, seq,
-                                                  primary_if, backbone_gw)) {
+
+               ret = batadv_bla_backbone_dump_entry(msg, portid, seq,
+                                                    primary_if, backbone_gw);
+               if (ret) {
                        *idx_skip = idx - 1;
                        goto unlock;
                }
        }
 
-       *idx_skip = idx;
+       *idx_skip = 0;
 unlock:
        rcu_read_unlock();
-       return 0;
+       return ret;
 }
 
 /**
index 9703c79..87cd962 100644 (file)
@@ -393,7 +393,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb,
                   batadv_arp_hw_src(skb, hdr_size), &ip_src,
                   batadv_arp_hw_dst(skb, hdr_size), &ip_dst);
 
-       if (hdr_size == 0)
+       if (hdr_size < sizeof(struct batadv_unicast_packet))
                return;
 
        unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
index 22dde42..5afe641 100644 (file)
@@ -288,7 +288,8 @@ batadv_frag_merge_packets(struct hlist_head *chain)
        /* Move the existing MAC header to just before the payload. (Override
         * the fragment header.)
         */
-       skb_pull_rcsum(skb_out, hdr_size);
+       skb_pull(skb_out, hdr_size);
+       skb_out->ip_summed = CHECKSUM_NONE;
        memmove(skb_out->data - ETH_HLEN, skb_mac_header(skb_out), ETH_HLEN);
        skb_set_mac_header(skb_out, -ETH_HLEN);
        skb_reset_network_header(skb_out);
index 37fe9a6..808d2dd 100644 (file)
@@ -746,7 +746,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 {
        struct batadv_neigh_node *neigh_curr = NULL;
        struct batadv_neigh_node *neigh_old = NULL;
-       struct batadv_orig_node *orig_dst_node;
+       struct batadv_orig_node *orig_dst_node = NULL;
        struct batadv_gw_node *gw_node = NULL;
        struct batadv_gw_node *curr_gw = NULL;
        struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo;
@@ -757,6 +757,9 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv,
 
        vid = batadv_get_vid(skb, 0);
 
+       if (is_multicast_ether_addr(ethhdr->h_dest))
+               goto out;
+
        orig_dst_node = batadv_transtable_search(bat_priv, ethhdr->h_source,
                                                 ethhdr->h_dest, vid);
        if (!orig_dst_node)
index 5f186bf..68b54a3 100644 (file)
@@ -763,6 +763,11 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
        hard_iface->soft_iface = soft_iface;
        bat_priv = netdev_priv(hard_iface->soft_iface);
 
+       if (bat_priv->num_ifaces >= UINT_MAX) {
+               ret = -ENOSPC;
+               goto err_dev;
+       }
+
        ret = netdev_master_upper_dev_link(hard_iface->net_dev,
                                           soft_iface, NULL, NULL, NULL);
        if (ret)
@@ -876,7 +881,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface,
        batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface);
 
        /* nobody uses this interface anymore */
-       if (!bat_priv->num_ifaces) {
+       if (bat_priv->num_ifaces == 0) {
                batadv_gw_check_client_stop(bat_priv);
 
                if (autodel == BATADV_IF_CLEANUP_AUTO)
@@ -912,7 +917,7 @@ batadv_hardif_add_interface(struct net_device *net_dev)
        if (ret)
                goto free_if;
 
-       hard_iface->if_num = -1;
+       hard_iface->if_num = 0;
        hard_iface->net_dev = net_dev;
        hard_iface->soft_iface = NULL;
        hard_iface->if_status = BATADV_IF_NOT_IN_USE;
index e91f29c..5daa3d5 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/debugfs.h>
 #include <linux/errno.h>
 #include <linux/etherdevice.h>
+#include <linux/eventpoll.h>
 #include <linux/export.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
index dc9fa37..cdbe0e5 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/compiler.h>
 #include <linux/debugfs.h>
 #include <linux/errno.h>
+#include <linux/eventpoll.h>
 #include <linux/export.h>
 #include <linux/fcntl.h>
 #include <linux/fs.h>
index cbdeb47..ee56af5 100644 (file)
@@ -543,8 +543,8 @@ update:
                bat_priv->mcast.enabled = true;
        }
 
-       return !(mcast_data.flags &
-                (BATADV_MCAST_WANT_ALL_IPV4 | BATADV_MCAST_WANT_ALL_IPV6));
+       return !(mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV4 &&
+                mcast_data.flags & BATADV_MCAST_WANT_ALL_IPV6);
 }
 
 /**
@@ -814,8 +814,8 @@ static struct batadv_orig_node *
 batadv_mcast_forw_tt_node_get(struct batadv_priv *bat_priv,
                              struct ethhdr *ethhdr)
 {
-       return batadv_transtable_search(bat_priv, ethhdr->h_source,
-                                       ethhdr->h_dest, BATADV_NO_FLAGS);
+       return batadv_transtable_search(bat_priv, NULL, ethhdr->h_dest,
+                                       BATADV_NO_FLAGS);
 }
 
 /**
index 58a7d92..7478242 100644 (file)
@@ -1569,7 +1569,7 @@ int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb)
  * Return: 0 on success or negative error number in case of failure
  */
 int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
-                           int max_if_num)
+                           unsigned int max_if_num)
 {
        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        struct batadv_algo_ops *bao = bat_priv->algo_ops;
@@ -1611,7 +1611,7 @@ err:
  * Return: 0 on success or negative error number in case of failure
  */
 int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
-                           int max_if_num)
+                           unsigned int max_if_num)
 {
        struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface);
        struct batadv_hashtable *hash = bat_priv->orig_hash;
index 8e543a3..15d896b 100644 (file)
@@ -73,9 +73,9 @@ int batadv_orig_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_orig_dump(struct sk_buff *msg, struct netlink_callback *cb);
 int batadv_orig_hardif_seq_print_text(struct seq_file *seq, void *offset);
 int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface,
-                           int max_if_num);
+                           unsigned int max_if_num);
 int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface,
-                           int max_if_num);
+                           unsigned int max_if_num);
 struct batadv_orig_node_vlan *
 batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node,
                          unsigned short vid);
index b6891e8..e61dc12 100644 (file)
@@ -759,6 +759,7 @@ free_skb:
 /**
  * batadv_reroute_unicast_packet() - update the unicast header for re-routing
  * @bat_priv: the bat priv with all the soft interface information
+ * @skb: unicast packet to process
  * @unicast_packet: the unicast header to be updated
  * @dst_addr: the payload destination
  * @vid: VLAN identifier
@@ -770,7 +771,7 @@ free_skb:
  * Return: true if the packet header has been updated, false otherwise
  */
 static bool
-batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
+batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct sk_buff *skb,
                              struct batadv_unicast_packet *unicast_packet,
                              u8 *dst_addr, unsigned short vid)
 {
@@ -799,8 +800,10 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv,
        }
 
        /* update the packet header */
+       skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
        ether_addr_copy(unicast_packet->dest, orig_addr);
        unicast_packet->ttvn = orig_ttvn;
+       skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
 
        ret = true;
 out:
@@ -841,7 +844,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
         * the packet to
         */
        if (batadv_tt_local_client_is_roaming(bat_priv, ethhdr->h_dest, vid)) {
-               if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
+               if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet,
                                                  ethhdr->h_dest, vid))
                        batadv_dbg_ratelimited(BATADV_DBG_TT,
                                               bat_priv,
@@ -887,7 +890,7 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
         * destination can possibly be updated and forwarded towards the new
         * target host
         */
-       if (batadv_reroute_unicast_packet(bat_priv, unicast_packet,
+       if (batadv_reroute_unicast_packet(bat_priv, skb, unicast_packet,
                                          ethhdr->h_dest, vid)) {
                batadv_dbg_ratelimited(BATADV_DBG_TT, bat_priv,
                                       "Rerouting unicast packet to %pM (dst=%pM): TTVN mismatch old_ttvn=%u new_ttvn=%u\n",
@@ -910,12 +913,14 @@ static bool batadv_check_unicast_ttvn(struct batadv_priv *bat_priv,
        if (!primary_if)
                return false;
 
+       /* update the packet header */
+       skb_postpull_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
        ether_addr_copy(unicast_packet->dest, primary_if->net_dev->dev_addr);
+       unicast_packet->ttvn = curr_ttvn;
+       skb_postpush_rcsum(skb, unicast_packet, sizeof(*unicast_packet));
 
        batadv_hardif_put(primary_if);
 
-       unicast_packet->ttvn = curr_ttvn;
-
        return true;
 }
 
@@ -968,14 +973,10 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
        struct batadv_orig_node *orig_node = NULL, *orig_node_gw = NULL;
        int check, hdr_size = sizeof(*unicast_packet);
        enum batadv_subtype subtype;
-       struct ethhdr *ethhdr;
        int ret = NET_RX_DROP;
        bool is4addr, is_gw;
 
        unicast_packet = (struct batadv_unicast_packet *)skb->data;
-       unicast_4addr_packet = (struct batadv_unicast_4addr_packet *)skb->data;
-       ethhdr = eth_hdr(skb);
-
        is4addr = unicast_packet->packet_type == BATADV_UNICAST_4ADDR;
        /* the caller function should have already pulled 2 bytes */
        if (is4addr)
@@ -995,12 +996,14 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
        if (!batadv_check_unicast_ttvn(bat_priv, skb, hdr_size))
                goto free_skb;
 
+       unicast_packet = (struct batadv_unicast_packet *)skb->data;
+
        /* packet for me */
        if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
                /* If this is a unicast packet from another backgone gw,
                 * drop it.
                 */
-               orig_addr_gw = ethhdr->h_source;
+               orig_addr_gw = eth_hdr(skb)->h_source;
                orig_node_gw = batadv_orig_hash_find(bat_priv, orig_addr_gw);
                if (orig_node_gw) {
                        is_gw = batadv_bla_is_backbone_gw(skb, orig_node_gw,
@@ -1015,6 +1018,8 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
                }
 
                if (is4addr) {
+                       unicast_4addr_packet =
+                               (struct batadv_unicast_4addr_packet *)skb->data;
                        subtype = unicast_4addr_packet->subtype;
                        batadv_dat_inc_counter(bat_priv, subtype);
 
index 900c5ce..367a81f 100644 (file)
@@ -459,13 +459,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
 
        /* skb->dev & skb->pkt_type are set here */
        skb->protocol = eth_type_trans(skb, soft_iface);
-
-       /* should not be necessary anymore as we use skb_pull_rcsum()
-        * TODO: please verify this and remove this TODO
-        * -- Dec 21st 2009, Simon Wunderlich
-        */
-
-       /* skb->ip_summed = CHECKSUM_UNNECESSARY; */
+       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
 
        batadv_inc_counter(bat_priv, BATADV_CNT_RX);
        batadv_add_counter(bat_priv, BATADV_CNT_RX_BYTES,
index bb15784..a5aa6d6 100644 (file)
@@ -167,7 +167,7 @@ struct batadv_hard_iface {
        struct list_head list;
 
        /** @if_num: identificator of the interface */
-       s16 if_num;
+       unsigned int if_num;
 
        /** @if_status: status of the interface for batman-adv */
        char if_status;
@@ -1596,7 +1596,7 @@ struct batadv_priv {
        atomic_t batman_queue_left;
 
        /** @num_ifaces: number of interfaces assigned to this mesh interface */
-       char num_ifaces;
+       unsigned int num_ifaces;
 
        /** @mesh_obj: kobject for sysfs mesh subdirectory */
        struct kobject *mesh_obj;
@@ -2186,15 +2186,16 @@ struct batadv_algo_orig_ops {
         *  orig_node due to a new hard-interface being added into the mesh
         *  (optional)
         */
-       int (*add_if)(struct batadv_orig_node *orig_node, int max_if_num);
+       int (*add_if)(struct batadv_orig_node *orig_node,
+                     unsigned int max_if_num);
 
        /**
         * @del_if: ask the routing algorithm to apply the needed changes to the
         *  orig_node due to an hard-interface being removed from the mesh
         *  (optional)
         */
-       int (*del_if)(struct batadv_orig_node *orig_node, int max_if_num,
-                     int del_if_num);
+       int (*del_if)(struct batadv_orig_node *orig_node,
+                     unsigned int max_if_num, unsigned int del_if_num);
 
 #ifdef CONFIG_BATMAN_ADV_DEBUGFS
        /** @print: print the originator table (optional) */
index 01117ae..a2ddae2 100644 (file)
@@ -2296,8 +2296,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
        else
                sec_level = authreq_to_seclevel(auth);
 
-       if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK))
+       if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) {
+               /* If link is already encrypted with sufficient security we
+                * still need refresh encryption as per Core Spec 5.0 Vol 3,
+                * Part H 2.4.6
+                */
+               smp_ltk_encrypt(conn, hcon->sec_level);
                return 0;
+       }
 
        if (sec_level > hcon->pending_sec_level)
                hcon->pending_sec_level = sec_level;
index 27f1d4f..9b16eaf 100644 (file)
@@ -214,7 +214,7 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
 
        iph = ip_hdr(skb);
        if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
-               goto inhdr_error;
+               goto csum_error;
 
        len = ntohs(iph->tot_len);
        if (skb->len < len) {
@@ -236,6 +236,8 @@ static int br_validate_ipv4(struct net *net, struct sk_buff *skb)
         */
        return 0;
 
+csum_error:
+       __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
 inhdr_error:
        __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
 drop:
index 0254c35..126a8ea 100644 (file)
@@ -255,6 +255,9 @@ static ssize_t brport_show(struct kobject *kobj,
        struct brport_attribute *brport_attr = to_brport_attr(attr);
        struct net_bridge_port *p = to_brport(kobj);
 
+       if (!brport_attr->show)
+               return -EINVAL;
+
        return brport_attr->show(p, buf);
 }
 
index 5193527..9896f49 100644 (file)
@@ -168,6 +168,8 @@ static struct net_bridge_vlan *br_vlan_get_master(struct net_bridge *br, u16 vid
                masterv = br_vlan_find(vg, vid);
                if (WARN_ON(!masterv))
                        return NULL;
+               refcount_set(&masterv->refcnt, 1);
+               return masterv;
        }
        refcount_inc(&masterv->refcnt);
 
index 279527f..620e54f 100644 (file)
@@ -172,32 +172,83 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par)
        return true;
 }
 
+static bool poolsize_invalid(const struct ebt_mac_wormhash *w)
+{
+       return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple));
+}
+
+static bool wormhash_offset_invalid(int off, unsigned int len)
+{
+       if (off == 0) /* not present */
+               return false;
+
+       if (off < (int)sizeof(struct ebt_among_info) ||
+           off % __alignof__(struct ebt_mac_wormhash))
+               return true;
+
+       off += sizeof(struct ebt_mac_wormhash);
+
+       return off > len;
+}
+
+static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b)
+{
+       if (a == 0)
+               a = sizeof(struct ebt_among_info);
+
+       return ebt_mac_wormhash_size(wh) + a == b;
+}
+
 static int ebt_among_mt_check(const struct xt_mtchk_param *par)
 {
        const struct ebt_among_info *info = par->matchinfo;
        const struct ebt_entry_match *em =
                container_of(par->matchinfo, const struct ebt_entry_match, data);
-       int expected_length = sizeof(struct ebt_among_info);
+       unsigned int expected_length = sizeof(struct ebt_among_info);
        const struct ebt_mac_wormhash *wh_dst, *wh_src;
        int err;
 
+       if (expected_length > em->match_size)
+               return -EINVAL;
+
+       if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) ||
+           wormhash_offset_invalid(info->wh_src_ofs, em->match_size))
+               return -EINVAL;
+
        wh_dst = ebt_among_wh_dst(info);
-       wh_src = ebt_among_wh_src(info);
+       if (poolsize_invalid(wh_dst))
+               return -EINVAL;
+
        expected_length += ebt_mac_wormhash_size(wh_dst);
+       if (expected_length > em->match_size)
+               return -EINVAL;
+
+       wh_src = ebt_among_wh_src(info);
+       if (poolsize_invalid(wh_src))
+               return -EINVAL;
+
+       if (info->wh_src_ofs < info->wh_dst_ofs) {
+               if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs))
+                       return -EINVAL;
+       } else {
+               if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs))
+                       return -EINVAL;
+       }
+
        expected_length += ebt_mac_wormhash_size(wh_src);
 
        if (em->match_size != EBT_ALIGN(expected_length)) {
-               pr_info("wrong size: %d against expected %d, rounded to %zd\n",
-                       em->match_size, expected_length,
-                       EBT_ALIGN(expected_length));
+               pr_err_ratelimited("wrong size: %d against expected %d, rounded to %zd\n",
+                                  em->match_size, expected_length,
+                                  EBT_ALIGN(expected_length));
                return -EINVAL;
        }
        if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) {
-               pr_info("dst integrity fail: %x\n", -err);
+               pr_err_ratelimited("dst integrity fail: %x\n", -err);
                return -EINVAL;
        }
        if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) {
-               pr_info("src integrity fail: %x\n", -err);
+               pr_err_ratelimited("src integrity fail: %x\n", -err);
                return -EINVAL;
        }
        return 0;
index 61a9f1b..165b9d6 100644 (file)
@@ -72,8 +72,8 @@ static int ebt_limit_mt_check(const struct xt_mtchk_param *par)
        /* Check for overflow. */
        if (info->burst == 0 ||
            user2credits(info->avg * info->burst) < user2credits(info->avg)) {
-               pr_info("overflow, try lower: %u/%u\n",
-                       info->avg, info->burst);
+               pr_info_ratelimited("overflow, try lower: %u/%u\n",
+                                   info->avg, info->burst);
                return -EINVAL;
        }
 
index 02c4b40..a94d23b 100644 (file)
@@ -1641,7 +1641,8 @@ static int compat_match_to_user(struct ebt_entry_match *m, void __user **dstptr,
        int off = ebt_compat_match_offset(match, m->match_size);
        compat_uint_t msize = m->match_size - off;
 
-       BUG_ON(off >= m->match_size);
+       if (WARN_ON(off >= m->match_size))
+               return -EINVAL;
 
        if (copy_to_user(cm->u.name, match->name,
            strlen(match->name) + 1) || put_user(msize, &cm->match_size))
@@ -1671,7 +1672,8 @@ static int compat_target_to_user(struct ebt_entry_target *t,
        int off = xt_compat_target_offset(target);
        compat_uint_t tsize = t->target_size - off;
 
-       BUG_ON(off >= t->target_size);
+       if (WARN_ON(off >= t->target_size))
+               return -EINVAL;
 
        if (copy_to_user(cm->u.name, target->name,
            strlen(target->name) + 1) || put_user(tsize, &cm->match_size))
@@ -1902,7 +1904,8 @@ static int ebt_buf_add(struct ebt_entries_buf_state *state,
        if (state->buf_kern_start == NULL)
                goto count_only;
 
-       BUG_ON(state->buf_kern_offset + sz > state->buf_kern_len);
+       if (WARN_ON(state->buf_kern_offset + sz > state->buf_kern_len))
+               return -EINVAL;
 
        memcpy(state->buf_kern_start + state->buf_kern_offset, data, sz);
 
@@ -1915,7 +1918,8 @@ static int ebt_buf_add_pad(struct ebt_entries_buf_state *state, unsigned int sz)
 {
        char *b = state->buf_kern_start;
 
-       BUG_ON(b && state->buf_kern_offset > state->buf_kern_len);
+       if (WARN_ON(b && state->buf_kern_offset > state->buf_kern_len))
+               return -EINVAL;
 
        if (b != NULL && sz > 0)
                memset(b + state->buf_kern_offset, 0, sz);
@@ -1992,8 +1996,10 @@ static int compat_mtw_from_user(struct compat_ebt_entry_mwt *mwt,
        pad = XT_ALIGN(size_kern) - size_kern;
 
        if (pad > 0 && dst) {
-               BUG_ON(state->buf_kern_len <= pad);
-               BUG_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad);
+               if (WARN_ON(state->buf_kern_len <= pad))
+                       return -EINVAL;
+               if (WARN_ON(state->buf_kern_offset - (match_size + off) + size_kern > state->buf_kern_len - pad))
+                       return -EINVAL;
                memset(dst + size_kern, 0, pad);
        }
        return off + match_size;
@@ -2043,7 +2049,8 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
                if (ret < 0)
                        return ret;
 
-               BUG_ON(ret < match32->match_size);
+               if (WARN_ON(ret < match32->match_size))
+                       return -EINVAL;
                growth += ret - match32->match_size;
                growth += ebt_compat_entry_padsize();
 
@@ -2053,7 +2060,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32,
                if (match_kern)
                        match_kern->match_size = ret;
 
-               WARN_ON(type == EBT_COMPAT_TARGET && size_left);
+               if (WARN_ON(type == EBT_COMPAT_TARGET && size_left))
+                       return -EINVAL;
+
                match32 = (struct compat_ebt_entry_mwt *) buf;
        }
 
@@ -2109,6 +2118,19 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
         *
         * offsets are relative to beginning of struct ebt_entry (i.e., 0).
         */
+       for (i = 0; i < 4 ; ++i) {
+               if (offsets[i] > *total)
+                       return -EINVAL;
+
+               if (i < 3 && offsets[i] == *total)
+                       return -EINVAL;
+
+               if (i == 0)
+                       continue;
+               if (offsets[i-1] > offsets[i])
+                       return -EINVAL;
+       }
+
        for (i = 0, j = 1 ; j < 4 ; j++, i++) {
                struct compat_ebt_entry_mwt *match32;
                unsigned int size;
@@ -2140,7 +2162,8 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base,
 
        startoff = state->buf_user_offset - startoff;
 
-       BUG_ON(*total < startoff);
+       if (WARN_ON(*total < startoff))
+               return -EINVAL;
        *total -= startoff;
        return 0;
 }
@@ -2267,7 +2290,8 @@ static int compat_do_replace(struct net *net, void __user *user,
        state.buf_kern_len = size64;
 
        ret = compat_copy_entries(entries_tmp, tmp.entries_size, &state);
-       BUG_ON(ret < 0);        /* parses same data again */
+       if (WARN_ON(ret < 0))
+               goto out_unlock;
 
        vfree(entries_tmp);
        tmp.entries_size = size64;
index 1e492ef..4d4c822 100644 (file)
@@ -418,6 +418,7 @@ ceph_parse_options(char *options, const char *dev_name,
                                opt->flags |= CEPH_OPT_FSID;
                        break;
                case Opt_name:
+                       kfree(opt->name);
                        opt->name = kstrndup(argstr[0].from,
                                              argstr[0].to-argstr[0].from,
                                              GFP_KERNEL);
@@ -427,6 +428,9 @@ ceph_parse_options(char *options, const char *dev_name,
                        }
                        break;
                case Opt_secret:
+                       ceph_crypto_key_destroy(opt->key);
+                       kfree(opt->key);
+
                        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
                        if (!opt->key) {
                                err = -ENOMEM;
@@ -437,6 +441,9 @@ ceph_parse_options(char *options, const char *dev_name,
                                goto out;
                        break;
                case Opt_key:
+                       ceph_crypto_key_destroy(opt->key);
+                       kfree(opt->key);
+
                        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
                        if (!opt->key) {
                                err = -ENOMEM;
index dda9d7b..ef0cc6e 100644 (file)
@@ -2382,8 +2382,11 @@ EXPORT_SYMBOL(netdev_set_num_tc);
  */
 int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
 {
+       bool disabling;
        int rc;
 
+       disabling = txq < dev->real_num_tx_queues;
+
        if (txq < 1 || txq > dev->num_tx_queues)
                return -EINVAL;
 
@@ -2399,15 +2402,19 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq)
                if (dev->num_tc)
                        netif_setup_tc(dev, txq);
 
-               if (txq < dev->real_num_tx_queues) {
+               dev->real_num_tx_queues = txq;
+
+               if (disabling) {
+                       synchronize_net();
                        qdisc_reset_all_tx_gt(dev, txq);
 #ifdef CONFIG_XPS
                        netif_reset_xps_queues_gt(dev, txq);
 #endif
                }
+       } else {
+               dev->real_num_tx_queues = txq;
        }
 
-       dev->real_num_tx_queues = txq;
        return 0;
 }
 EXPORT_SYMBOL(netif_set_real_num_tx_queues);
@@ -2728,7 +2735,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth)
                if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
                        return 0;
 
-               eth = (struct ethhdr *)skb_mac_header(skb);
+               eth = (struct ethhdr *)skb->data;
                type = eth->h_proto;
        }
 
@@ -3271,15 +3278,23 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
 #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
 static void skb_update_prio(struct sk_buff *skb)
 {
-       struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap);
+       const struct netprio_map *map;
+       const struct sock *sk;
+       unsigned int prioidx;
 
-       if (!skb->priority && skb->sk && map) {
-               unsigned int prioidx =
-                       sock_cgroup_prioidx(&skb->sk->sk_cgrp_data);
+       if (skb->priority)
+               return;
+       map = rcu_dereference_bh(skb->dev->priomap);
+       if (!map)
+               return;
+       sk = skb_to_full_sk(skb);
+       if (!sk)
+               return;
 
-               if (prioidx < map->priomap_len)
-                       skb->priority = map->priomap[prioidx];
-       }
+       prioidx = sock_cgroup_prioidx(&sk->sk_cgrp_data);
+
+       if (prioidx < map->priomap_len)
+               skb->priority = map->priomap[prioidx];
 }
 #else
 #define skb_update_prio(skb)
@@ -6389,6 +6404,7 @@ static int __netdev_upper_dev_link(struct net_device *dev,
                .linking = true,
                .upper_info = upper_info,
        };
+       struct net_device *master_dev;
        int ret = 0;
 
        ASSERT_RTNL();
@@ -6400,11 +6416,14 @@ static int __netdev_upper_dev_link(struct net_device *dev,
        if (netdev_has_upper_dev(upper_dev, dev))
                return -EBUSY;
 
-       if (netdev_has_upper_dev(dev, upper_dev))
-               return -EEXIST;
-
-       if (master && netdev_master_upper_dev_get(dev))
-               return -EBUSY;
+       if (!master) {
+               if (netdev_has_upper_dev(dev, upper_dev))
+                       return -EEXIST;
+       } else {
+               master_dev = netdev_master_upper_dev_get(dev);
+               if (master_dev)
+                       return master_dev == upper_dev ? -EEXIST : -EBUSY;
+       }
 
        ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER,
                                            &changeupper_info.info);
index 0ab1af0..a04e1e8 100644 (file)
@@ -402,8 +402,6 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
        if (colon)
                *colon = 0;
 
-       dev_load(net, ifr->ifr_name);
-
        /*
         *      See which interface the caller is talking about.
         */
@@ -423,6 +421,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
        case SIOCGIFMAP:
        case SIOCGIFINDEX:
        case SIOCGIFTXQLEN:
+               dev_load(net, ifr->ifr_name);
                rcu_read_lock();
                ret = dev_ifsioc_locked(net, ifr, cmd);
                rcu_read_unlock();
@@ -431,6 +430,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
                return ret;
 
        case SIOCETHTOOL:
+               dev_load(net, ifr->ifr_name);
                rtnl_lock();
                ret = dev_ethtool(net, ifr);
                rtnl_unlock();
@@ -447,6 +447,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
        case SIOCGMIIPHY:
        case SIOCGMIIREG:
        case SIOCSIFNAME:
+               dev_load(net, ifr->ifr_name);
                if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
                        return -EPERM;
                rtnl_lock();
@@ -494,6 +495,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
                /* fall through */
        case SIOCBONDSLAVEINFOQUERY:
        case SIOCBONDINFOQUERY:
+               dev_load(net, ifr->ifr_name);
                rtnl_lock();
                ret = dev_ifsioc(net, ifr, cmd);
                rtnl_unlock();
@@ -518,6 +520,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, struct ifreq *ifr, bool *need_c
                    cmd == SIOCGHWTSTAMP ||
                    (cmd >= SIOCDEVPRIVATE &&
                     cmd <= SIOCDEVPRIVATE + 15)) {
+                       dev_load(net, ifr->ifr_name);
                        rtnl_lock();
                        ret = dev_ifsioc(net, ifr, cmd);
                        rtnl_unlock();
index 18d385e..effd484 100644 (file)
@@ -1695,10 +1695,11 @@ static int devlink_dpipe_table_put(struct sk_buff *skb,
                goto nla_put_failure;
 
        if (table->resource_valid) {
-               nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
-                                 table->resource_id, DEVLINK_ATTR_PAD);
-               nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
-                                 table->resource_units, DEVLINK_ATTR_PAD);
+               if (nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
+                                     table->resource_id, DEVLINK_ATTR_PAD) ||
+                   nla_put_u64_64bit(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
+                                     table->resource_units, DEVLINK_ATTR_PAD))
+                       goto nla_put_failure;
        }
        if (devlink_dpipe_matches_put(table, skb))
                goto nla_put_failure;
@@ -1797,7 +1798,7 @@ send_done:
        if (!nlh) {
                err = devlink_dpipe_send_and_alloc_skb(&skb, info);
                if (err)
-                       goto err_skb_send_alloc;
+                       return err;
                goto send_done;
        }
 
@@ -1806,7 +1807,6 @@ send_done:
 nla_put_failure:
        err = -EMSGSIZE;
 err_table_put:
-err_skb_send_alloc:
        genlmsg_cancel(skb, hdr);
        nlmsg_free(skb);
        return err;
@@ -2072,7 +2072,7 @@ static int devlink_dpipe_entries_fill(struct genl_info *info,
                                             table->counters_enabled,
                                             &dump_ctx);
        if (err)
-               goto err_entries_dump;
+               return err;
 
 send_done:
        nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
@@ -2080,16 +2080,10 @@ send_done:
        if (!nlh) {
                err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
                if (err)
-                       goto err_skb_send_alloc;
+                       return err;
                goto send_done;
        }
        return genlmsg_reply(dump_ctx.skb, info);
-
-err_entries_dump:
-err_skb_send_alloc:
-       genlmsg_cancel(dump_ctx.skb, dump_ctx.hdr);
-       nlmsg_free(dump_ctx.skb);
-       return err;
 }
 
 static int devlink_nl_cmd_dpipe_entries_get(struct sk_buff *skb,
@@ -2228,7 +2222,7 @@ send_done:
        if (!nlh) {
                err = devlink_dpipe_send_and_alloc_skb(&skb, info);
                if (err)
-                       goto err_skb_send_alloc;
+                       return err;
                goto send_done;
        }
        return genlmsg_reply(skb, info);
@@ -2236,7 +2230,6 @@ send_done:
 nla_put_failure:
        err = -EMSGSIZE;
 err_table_put:
-err_skb_send_alloc:
        genlmsg_cancel(skb, hdr);
        nlmsg_free(skb);
        return err;
@@ -2332,7 +2325,7 @@ devlink_resource_validate_children(struct devlink_resource *resource)
        list_for_each_entry(child_resource, &resource->resource_list, list)
                parts_size += child_resource->size_new;
 
-       if (parts_size > resource->size)
+       if (parts_size > resource->size_new)
                size_valid = false;
 out:
        resource->size_valid = size_valid;
@@ -2372,20 +2365,22 @@ static int devlink_nl_cmd_resource_set(struct sk_buff *skb,
        return 0;
 }
 
-static void
+static int
 devlink_resource_size_params_put(struct devlink_resource *resource,
                                 struct sk_buff *skb)
 {
        struct devlink_resource_size_params *size_params;
 
-       size_params = resource->size_params;
-       nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
-                         size_params->size_granularity, DEVLINK_ATTR_PAD);
-       nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
-                         size_params->size_max, DEVLINK_ATTR_PAD);
-       nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
-                         size_params->size_min, DEVLINK_ATTR_PAD);
-       nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit);
+       size_params = &resource->size_params;
+       if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_GRAN,
+                             size_params->size_granularity, DEVLINK_ATTR_PAD) ||
+           nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MAX,
+                             size_params->size_max, DEVLINK_ATTR_PAD) ||
+           nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_MIN,
+                             size_params->size_min, DEVLINK_ATTR_PAD) ||
+           nla_put_u8(skb, DEVLINK_ATTR_RESOURCE_UNIT, size_params->unit))
+               return -EMSGSIZE;
+       return 0;
 }
 
 static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
@@ -2409,10 +2404,12 @@ static int devlink_resource_put(struct devlink *devlink, struct sk_buff *skb,
                nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_SIZE_NEW,
                                  resource->size_new, DEVLINK_ATTR_PAD);
        if (resource->resource_ops && resource->resource_ops->occ_get)
-               nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
-                                 resource->resource_ops->occ_get(devlink),
-                                 DEVLINK_ATTR_PAD);
-       devlink_resource_size_params_put(resource, skb);
+               if (nla_put_u64_64bit(skb, DEVLINK_ATTR_RESOURCE_OCC,
+                                     resource->resource_ops->occ_get(devlink),
+                                     DEVLINK_ATTR_PAD))
+                       goto nla_put_failure;
+       if (devlink_resource_size_params_put(resource, skb))
+               goto nla_put_failure;
        if (list_empty(&resource->resource_list))
                goto out;
 
@@ -3151,7 +3148,7 @@ int devlink_resource_register(struct devlink *devlink,
                              u64 resource_size,
                              u64 resource_id,
                              u64 parent_resource_id,
-                             struct devlink_resource_size_params *size_params,
+                             const struct devlink_resource_size_params *size_params,
                              const struct devlink_resource_ops *resource_ops)
 {
        struct devlink_resource *resource;
@@ -3194,7 +3191,8 @@ int devlink_resource_register(struct devlink *devlink,
        resource->id = resource_id;
        resource->resource_ops = resource_ops;
        resource->size_valid = true;
-       resource->size_params = size_params;
+       memcpy(&resource->size_params, size_params,
+              sizeof(resource->size_params));
        INIT_LIST_HEAD(&resource->resource_list);
        list_add_tail(&resource->list, resource_list);
 out:
index 494e6a5..3f89c76 100644 (file)
@@ -2520,11 +2520,14 @@ static int set_phy_tunable(struct net_device *dev, void __user *useraddr)
 static int ethtool_get_fecparam(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_fecparam fecparam = { ETHTOOL_GFECPARAM };
+       int rc;
 
        if (!dev->ethtool_ops->get_fecparam)
                return -EOPNOTSUPP;
 
-       dev->ethtool_ops->get_fecparam(dev, &fecparam);
+       rc = dev->ethtool_ops->get_fecparam(dev, &fecparam);
+       if (rc)
+               return rc;
 
        if (copy_to_user(useraddr, &fecparam, sizeof(fecparam)))
                return -EFAULT;
index 08ab4c6..48aa7c7 100644 (file)
@@ -2087,6 +2087,10 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
        u32 off = skb_mac_header_len(skb);
        int ret;
 
+       /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */
+       if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb)))
+               return -ENOTSUPP;
+
        ret = skb_cow(skb, len_diff);
        if (unlikely(ret < 0))
                return ret;
@@ -2096,19 +2100,21 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
                return ret;
 
        if (skb_is_gso(skb)) {
+               struct skb_shared_info *shinfo = skb_shinfo(skb);
+
                /* SKB_GSO_TCPV4 needs to be changed into
                 * SKB_GSO_TCPV6.
                 */
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) {
-                       skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV4;
-                       skb_shinfo(skb)->gso_type |=  SKB_GSO_TCPV6;
+               if (shinfo->gso_type & SKB_GSO_TCPV4) {
+                       shinfo->gso_type &= ~SKB_GSO_TCPV4;
+                       shinfo->gso_type |=  SKB_GSO_TCPV6;
                }
 
                /* Due to IPv6 header, MSS needs to be downgraded. */
-               skb_shinfo(skb)->gso_size -= len_diff;
+               skb_decrease_gso_size(shinfo, len_diff);
                /* Header must be checked, and gso_segs recomputed. */
-               skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-               skb_shinfo(skb)->gso_segs = 0;
+               shinfo->gso_type |= SKB_GSO_DODGY;
+               shinfo->gso_segs = 0;
        }
 
        skb->protocol = htons(ETH_P_IPV6);
@@ -2123,6 +2129,10 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
        u32 off = skb_mac_header_len(skb);
        int ret;
 
+       /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */
+       if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb)))
+               return -ENOTSUPP;
+
        ret = skb_unclone(skb, GFP_ATOMIC);
        if (unlikely(ret < 0))
                return ret;
@@ -2132,19 +2142,21 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
                return ret;
 
        if (skb_is_gso(skb)) {
+               struct skb_shared_info *shinfo = skb_shinfo(skb);
+
                /* SKB_GSO_TCPV6 needs to be changed into
                 * SKB_GSO_TCPV4.
                 */
-               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
-                       skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV6;
-                       skb_shinfo(skb)->gso_type |=  SKB_GSO_TCPV4;
+               if (shinfo->gso_type & SKB_GSO_TCPV6) {
+                       shinfo->gso_type &= ~SKB_GSO_TCPV6;
+                       shinfo->gso_type |=  SKB_GSO_TCPV4;
                }
 
                /* Due to IPv4 header, MSS can be upgraded. */
-               skb_shinfo(skb)->gso_size += len_diff;
+               skb_increase_gso_size(shinfo, len_diff);
                /* Header must be checked, and gso_segs recomputed. */
-               skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-               skb_shinfo(skb)->gso_segs = 0;
+               shinfo->gso_type |= SKB_GSO_DODGY;
+               shinfo->gso_segs = 0;
        }
 
        skb->protocol = htons(ETH_P_IP);
@@ -2243,6 +2255,10 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 len_diff)
        u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb);
        int ret;
 
+       /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */
+       if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb)))
+               return -ENOTSUPP;
+
        ret = skb_cow(skb, len_diff);
        if (unlikely(ret < 0))
                return ret;
@@ -2252,11 +2268,13 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 len_diff)
                return ret;
 
        if (skb_is_gso(skb)) {
+               struct skb_shared_info *shinfo = skb_shinfo(skb);
+
                /* Due to header grow, MSS needs to be downgraded. */
-               skb_shinfo(skb)->gso_size -= len_diff;
+               skb_decrease_gso_size(shinfo, len_diff);
                /* Header must be checked, and gso_segs recomputed. */
-               skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-               skb_shinfo(skb)->gso_segs = 0;
+               shinfo->gso_type |= SKB_GSO_DODGY;
+               shinfo->gso_segs = 0;
        }
 
        return 0;
@@ -2267,6 +2285,10 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 len_diff)
        u32 off = skb_mac_header_len(skb) + bpf_skb_net_base_len(skb);
        int ret;
 
+       /* SCTP uses GSO_BY_FRAGS, thus cannot adjust it. */
+       if (skb_is_gso(skb) && unlikely(skb_is_gso_sctp(skb)))
+               return -ENOTSUPP;
+
        ret = skb_unclone(skb, GFP_ATOMIC);
        if (unlikely(ret < 0))
                return ret;
@@ -2276,11 +2298,13 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 len_diff)
                return ret;
 
        if (skb_is_gso(skb)) {
+               struct skb_shared_info *shinfo = skb_shinfo(skb);
+
                /* Due to header shrink, MSS can be upgraded. */
-               skb_shinfo(skb)->gso_size += len_diff;
+               skb_increase_gso_size(shinfo, len_diff);
                /* Header must be checked, and gso_segs recomputed. */
-               skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-               skb_shinfo(skb)->gso_segs = 0;
+               shinfo->gso_type |= SKB_GSO_DODGY;
+               shinfo->gso_segs = 0;
        }
 
        return 0;
@@ -3381,17 +3405,13 @@ BPF_CALL_2(bpf_sock_ops_cb_flags_set, struct bpf_sock_ops_kern *, bpf_sock,
        struct sock *sk = bpf_sock->sk;
        int val = argval & BPF_SOCK_OPS_ALL_CB_FLAGS;
 
-       if (!sk_fullsock(sk))
+       if (!IS_ENABLED(CONFIG_INET) || !sk_fullsock(sk))
                return -EINVAL;
 
-#ifdef CONFIG_INET
        if (val)
                tcp_sk(sk)->bpf_sock_ops_cb_flags = val;
 
        return argval & (~BPF_SOCK_OPS_ALL_CB_FLAGS);
-#else
-       return -EINVAL;
-#endif
 }
 
 static const struct bpf_func_proto bpf_sock_ops_cb_flags_set_proto = {
index 0a3f88f..98fd127 100644 (file)
@@ -66,6 +66,7 @@ struct net_rate_estimator {
 static void est_fetch_counters(struct net_rate_estimator *e,
                               struct gnet_stats_basic_packed *b)
 {
+       memset(b, 0, sizeof(*b));
        if (e->stats_lock)
                spin_lock(e->stats_lock);
 
index 09bd89c..857e4e6 100644 (file)
@@ -4179,7 +4179,7 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
 
        skb_queue_tail(&sk->sk_error_queue, skb);
        if (!sock_flag(sk, SOCK_DEAD))
-               sk->sk_data_ready(sk);
+               sk->sk_error_report(sk);
        return 0;
 }
 EXPORT_SYMBOL(sock_queue_err_skb);
@@ -4891,7 +4891,7 @@ EXPORT_SYMBOL_GPL(skb_scrub_packet);
  *
  * The MAC/L2 or network (IP, IPv6) headers are not accounted for.
  */
-unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
+static unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
 {
        const struct skb_shared_info *shinfo = skb_shinfo(skb);
        unsigned int thlen = 0;
@@ -4904,7 +4904,7 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
                        thlen += inner_tcp_hdrlen(skb);
        } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) {
                thlen = tcp_hdrlen(skb);
-       } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) {
+       } else if (unlikely(skb_is_gso_sctp(skb))) {
                thlen = sizeof(struct sctphdr);
        }
        /* UFO sets gso_size to the size of the fragmentation
@@ -4913,7 +4913,40 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
         */
        return thlen + shinfo->gso_size;
 }
-EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
+
+/**
+ * skb_gso_network_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_network_seglen is used to determine the real size of the
+ * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP).
+ *
+ * The MAC/L2 header is not accounted for.
+ */
+static unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
+{
+       unsigned int hdr_len = skb_transport_header(skb) -
+                              skb_network_header(skb);
+
+       return hdr_len + skb_gso_transport_seglen(skb);
+}
+
+/**
+ * skb_gso_mac_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_mac_seglen is used to determine the real size of the
+ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
+ * headers (TCP/UDP).
+ */
+static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
+{
+       unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
+
+       return hdr_len + skb_gso_transport_seglen(skb);
+}
 
 /**
  * skb_gso_size_check - check the skb size, considering GSO_BY_FRAGS
@@ -4955,19 +4988,20 @@ static inline bool skb_gso_size_check(const struct sk_buff *skb,
 }
 
 /**
- * skb_gso_validate_mtu - Return in case such skb fits a given MTU
+ * skb_gso_validate_network_len - Will a split GSO skb fit into a given MTU?
  *
  * @skb: GSO skb
  * @mtu: MTU to validate against
  *
- * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU
- * once split.
+ * skb_gso_validate_network_len validates if a given skb will fit a
+ * wanted MTU once split. It considers L3 headers, L4 headers, and the
+ * payload.
  */
-bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu)
+bool skb_gso_validate_network_len(const struct sk_buff *skb, unsigned int mtu)
 {
        return skb_gso_size_check(skb, skb_gso_network_seglen(skb), mtu);
 }
-EXPORT_SYMBOL_GPL(skb_gso_validate_mtu);
+EXPORT_SYMBOL_GPL(skb_gso_validate_network_len);
 
 /**
  * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
@@ -4986,13 +5020,18 @@ EXPORT_SYMBOL_GPL(skb_gso_validate_mac_len);
 
 static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
 {
+       int mac_len;
+
        if (skb_cow(skb, skb_headroom(skb)) < 0) {
                kfree_skb(skb);
                return NULL;
        }
 
-       memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN,
-               2 * ETH_ALEN);
+       mac_len = skb->data - skb_mac_header(skb);
+       if (likely(mac_len > VLAN_HLEN + ETH_TLEN)) {
+               memmove(skb_mac_header(skb) + VLAN_HLEN, skb_mac_header(skb),
+                       mac_len - VLAN_HLEN - ETH_TLEN);
+       }
        skb->mac_header += VLAN_HLEN;
        return skb;
 }
index c501499..85b0b64 100644 (file)
@@ -3261,6 +3261,27 @@ void proto_unregister(struct proto *prot)
 }
 EXPORT_SYMBOL(proto_unregister);
 
+int sock_load_diag_module(int family, int protocol)
+{
+       if (!protocol) {
+               if (!sock_is_registered(family))
+                       return -ENOENT;
+
+               return request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
+                                     NETLINK_SOCK_DIAG, family);
+       }
+
+#ifdef CONFIG_INET
+       if (family == AF_INET &&
+           !rcu_access_pointer(inet_protos[protocol]))
+               return -ENOENT;
+#endif
+
+       return request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK,
+                             NETLINK_SOCK_DIAG, family, protocol);
+}
+EXPORT_SYMBOL(sock_load_diag_module);
+
 #ifdef CONFIG_PROC_FS
 static void *proto_seq_start(struct seq_file *seq, loff_t *pos)
        __acquires(proto_list_mutex)
index 146b50e..c37b5be 100644 (file)
@@ -220,8 +220,7 @@ static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh)
                return -EINVAL;
 
        if (sock_diag_handlers[req->sdiag_family] == NULL)
-               request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-                               NETLINK_SOCK_DIAG, req->sdiag_family);
+               sock_load_diag_module(req->sdiag_family, 0);
 
        mutex_lock(&sock_diag_table_mutex);
        hndl = sock_diag_handlers[req->sdiag_family];
@@ -247,8 +246,7 @@ static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
        case TCPDIAG_GETSOCK:
        case DCCPDIAG_GETSOCK:
                if (inet_rcv_compat == NULL)
-                       request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-                                       NETLINK_SOCK_DIAG, AF_INET);
+                       sock_load_diag_module(AF_INET, 0);
 
                mutex_lock(&sock_diag_table_mutex);
                if (inet_rcv_compat != NULL)
@@ -281,14 +279,12 @@ static int sock_diag_bind(struct net *net, int group)
        case SKNLGRP_INET_TCP_DESTROY:
        case SKNLGRP_INET_UDP_DESTROY:
                if (!sock_diag_handlers[AF_INET])
-                       request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-                                      NETLINK_SOCK_DIAG, AF_INET);
+                       sock_load_diag_module(AF_INET, 0);
                break;
        case SKNLGRP_INET6_TCP_DESTROY:
        case SKNLGRP_INET6_UDP_DESTROY:
                if (!sock_diag_handlers[AF_INET6])
-                       request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
-                                      NETLINK_SOCK_DIAG, AF_INET6);
+                       sock_load_diag_module(AF_INET6, 0);
                break;
        }
        return 0;
index 15bdc00..84cd4e3 100644 (file)
@@ -794,6 +794,11 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        if (skb == NULL)
                goto out_release;
 
+       if (sk->sk_state == DCCP_CLOSED) {
+               rc = -ENOTCONN;
+               goto out_discard;
+       }
+
        skb_reserve(skb, sk->sk_prot->max_header);
        rc = memcpy_from_msg(skb_put(skb, len), msg, len);
        if (rc != 0)
index 91dd09f..791aff6 100644 (file)
@@ -1338,6 +1338,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+           optname != DSO_STREAM && optname != DSO_SEQPACKET)
+               err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
 
        return err;
 }
@@ -1445,15 +1451,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-               return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
-       case DSO_LINKINFO:
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (optlen != sizeof(unsigned long))
                        return -EINVAL;
@@ -1501,6 +1498,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        return -EINVAL;
                scp->info_loc = u.info;
                break;
+
+       case DSO_LINKINFO:
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       default:
+               return -ENOPROTOOPT;
        }
 
        return 0;
@@ -1514,6 +1517,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+           optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+           optname != DSO_CONREJECT) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
 
        return err;
 }
@@ -1579,26 +1596,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                r_data = &link;
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-       {
-               int ret, len;
-
-               if (get_user(len, optlen))
-                       return -EFAULT;
-
-               ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
-               if (ret >= 0)
-                       ret = put_user(len, optlen);
-               return ret;
-       }
-#endif
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-       case DSO_CONACCEPT:
-       case DSO_CONREJECT:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (r_len > sizeof(unsigned long))
                        r_len = sizeof(unsigned long);
@@ -1630,6 +1627,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                        r_len = sizeof(unsigned char);
                r_data = &scp->info_rem;
                break;
+
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       case DSO_CONACCEPT:
+       case DSO_CONREJECT:
+       default:
+               return -ENOPROTOOPT;
        }
 
        if (r_data) {
index cb54b81..42a7b85 100644 (file)
@@ -194,7 +194,7 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
                ds->ports[i].dn = cd->port_dn[i];
                ds->ports[i].cpu_dp = dst->cpu_dp;
 
-               if (dsa_is_user_port(ds, i))
+               if (!dsa_is_user_port(ds, i))
                        continue;
 
                ret = dsa_slave_create(&ds->ports[i]);
index 974765b..e9f0489 100644 (file)
@@ -206,9 +206,13 @@ static inline void lowpan_netlink_fini(void)
 static int lowpan_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
-       struct net_device *wdev = netdev_notifier_info_to_dev(ptr);
+       struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+       struct wpan_dev *wpan_dev;
 
-       if (wdev->type != ARPHRD_IEEE802154)
+       if (ndev->type != ARPHRD_IEEE802154)
+               return NOTIFY_DONE;
+       wpan_dev = ndev->ieee802154_ptr;
+       if (!wpan_dev)
                return NOTIFY_DONE;
 
        switch (event) {
@@ -217,8 +221,8 @@ static int lowpan_device_event(struct notifier_block *unused,
                 * also delete possible lowpan interfaces which belongs
                 * to the wpan interface.
                 */
-               if (wdev->ieee802154_ptr->lowpan_dev)
-                       lowpan_dellink(wdev->ieee802154_ptr->lowpan_dev, NULL);
+               if (wpan_dev->lowpan_dev)
+                       lowpan_dellink(wpan_dev->lowpan_dev, NULL);
                break;
        default:
                return NOTIFY_DONE;
index c586597..7d36a95 100644 (file)
@@ -646,6 +646,11 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi,
                                            fi->fib_nh, cfg, extack))
                                return 1;
                }
+#ifdef CONFIG_IP_ROUTE_CLASSID
+               if (cfg->fc_flow &&
+                   cfg->fc_flow != fi->fib_nh->nh_tclassid)
+                       return 1;
+#endif
                if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) &&
                    (!cfg->fc_gw  || cfg->fc_gw == fi->fib_nh->nh_gw))
                        return 0;
index a383f29..4e5bc4b 100644 (file)
@@ -53,8 +53,7 @@ static DEFINE_MUTEX(inet_diag_table_mutex);
 static const struct inet_diag_handler *inet_diag_lock_handler(int proto)
 {
        if (!inet_diag_table[proto])
-               request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK,
-                              NETLINK_SOCK_DIAG, AF_INET, proto);
+               sock_load_diag_module(AF_INET, proto);
 
        mutex_lock(&inet_diag_table_mutex);
        if (!inet_diag_table[proto])
index 26a3d03..e8ec289 100644 (file)
@@ -119,6 +119,9 @@ out:
 
 static bool inet_fragq_should_evict(const struct inet_frag_queue *q)
 {
+       if (!hlist_unhashed(&q->list_evictor))
+               return false;
+
        return q->net->low_thresh == 0 ||
               frag_mem_limit(q->net) >= q->net->low_thresh;
 }
index 2dd21c3..b54b948 100644 (file)
@@ -55,7 +55,7 @@ static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
        if (skb->ignore_df)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+       if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                return false;
 
        return true;
index 45d97e9..0901de4 100644 (file)
@@ -970,9 +970,6 @@ static void __gre_tunnel_init(struct net_device *dev)
 
        t_hlen = tunnel->hlen + sizeof(struct iphdr);
 
-       dev->needed_headroom    = LL_MAX_HEADER + t_hlen + 4;
-       dev->mtu                = ETH_DATA_LEN - t_hlen - 4;
-
        dev->features           |= GRE_FEATURES;
        dev->hw_features        |= GRE_FEATURES;
 
@@ -1290,8 +1287,6 @@ static int erspan_tunnel_init(struct net_device *dev)
                       erspan_hdr_len(tunnel->erspan_ver);
        t_hlen = tunnel->hlen + sizeof(struct iphdr);
 
-       dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4;
-       dev->mtu = ETH_DATA_LEN - t_hlen - 4;
        dev->features           |= GRE_FEATURES;
        dev->hw_features        |= GRE_FEATURES;
        dev->priv_flags         |= IFF_LIVE_ADDR_CHANGE;
index e8e675b..66340ab 100644 (file)
@@ -248,7 +248,7 @@ static int ip_finish_output_gso(struct net *net, struct sock *sk,
 
        /* common case: seglen is <= mtu
         */
-       if (skb_gso_validate_mtu(skb, mtu))
+       if (skb_gso_validate_network_len(skb, mtu))
                return ip_finish_output2(net, sk, skb);
 
        /* Slowpath -  GSO segment length exceeds the egress MTU.
index 008be04..74c962b 100644 (file)
@@ -258,7 +258,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
                        src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg);
                        if (!ipv6_addr_v4mapped(&src_info->ipi6_addr))
                                return -EINVAL;
-                       ipc->oif = src_info->ipi6_ifindex;
+                       if (src_info->ipi6_ifindex)
+                               ipc->oif = src_info->ipi6_ifindex;
                        ipc->addr = src_info->ipi6_addr.s6_addr32[3];
                        continue;
                }
@@ -288,7 +289,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc,
                        if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo)))
                                return -EINVAL;
                        info = (struct in_pktinfo *)CMSG_DATA(cmsg);
-                       ipc->oif = info->ipi_ifindex;
+                       if (info->ipi_ifindex)
+                               ipc->oif = info->ipi_ifindex;
                        ipc->addr = info->ipi_spec_dst.s_addr;
                        break;
                }
@@ -1567,10 +1569,7 @@ int ip_getsockopt(struct sock *sk, int level,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = nf_getsockopt(sk, PF_INET, optname, optval,
-                               &len);
-               release_sock(sk);
+               err = nf_getsockopt(sk, PF_INET, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
                return err;
@@ -1602,9 +1601,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
                err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len);
-               release_sock(sk);
                if (err >= 0)
                        err = put_user(len, optlen);
                return err;
index d786a84..a7fd1c5 100644 (file)
@@ -362,13 +362,18 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
        struct ip_tunnel *nt;
        struct net_device *dev;
        int t_hlen;
+       int mtu;
+       int err;
 
        BUG_ON(!itn->fb_tunnel_dev);
        dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms);
        if (IS_ERR(dev))
                return ERR_CAST(dev);
 
-       dev->mtu = ip_tunnel_bind_dev(dev);
+       mtu = ip_tunnel_bind_dev(dev);
+       err = dev_set_mtu(dev, mtu);
+       if (err)
+               goto err_dev_set_mtu;
 
        nt = netdev_priv(dev);
        t_hlen = nt->hlen + sizeof(struct iphdr);
@@ -376,6 +381,10 @@ static struct ip_tunnel *ip_tunnel_create(struct net *net,
        dev->max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen;
        ip_tunnel_add(itn, nt);
        return nt;
+
+err_dev_set_mtu:
+       unregister_netdevice(dev);
+       return ERR_PTR(err);
 }
 
 int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb,
@@ -710,16 +719,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
                }
        }
 
-       if (tunnel->fwmark) {
-               init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
-                                tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
-                                tunnel->fwmark);
-       }
-       else {
-               init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
-                                tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
-                                skb->mark);
-       }
+       init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr,
+                        tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link,
+                        tunnel->fwmark);
 
        if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
                goto tx_error;
@@ -1109,17 +1111,29 @@ int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[],
        nt->fwmark = fwmark;
        err = register_netdevice(dev);
        if (err)
-               goto out;
+               goto err_register_netdevice;
 
        if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
                eth_hw_addr_random(dev);
 
        mtu = ip_tunnel_bind_dev(dev);
-       if (!tb[IFLA_MTU])
-               dev->mtu = mtu;
+       if (tb[IFLA_MTU]) {
+               unsigned int max = 0xfff8 - dev->hard_header_len - nt->hlen;
+
+               mtu = clamp(dev->mtu, (unsigned int)ETH_MIN_MTU,
+                           (unsigned int)(max - sizeof(struct iphdr)));
+       }
+
+       err = dev_set_mtu(dev, mtu);
+       if (err)
+               goto err_dev_set_mtu;
 
        ip_tunnel_add(itn, nt);
-out:
+       return 0;
+
+err_dev_set_mtu:
+       unregister_netdevice(dev);
+err_register_netdevice:
        return err;
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_newlink);
index 51b1669..3f091cc 100644 (file)
@@ -387,8 +387,6 @@ static int vti_tunnel_init(struct net_device *dev)
        memcpy(dev->dev_addr, &iph->saddr, 4);
        memcpy(dev->broadcast, &iph->daddr, 4);
 
-       dev->hard_header_len    = LL_MAX_HEADER + sizeof(struct iphdr);
-       dev->mtu                = ETH_DATA_LEN;
        dev->flags              = IFF_NOARP;
        dev->addr_len           = 4;
        dev->features           |= NETIF_F_LLTX;
index 2dad20e..9bd19cd 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_NF_NAT_H323) += nf_nat_h323.o
 obj-$(CONFIG_NF_NAT_PPTP) += nf_nat_pptp.o
 
 nf_nat_snmp_basic-y := nf_nat_snmp_basic-asn1.o nf_nat_snmp_basic_main.o
-nf_nat_snmp_basic-y : nf_nat_snmp_basic-asn1.h nf_nat_snmp_basic-asn1.c
+$(obj)/nf_nat_snmp_basic_main.o: $(obj)/nf_nat_snmp_basic-asn1.h
 obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o
 clean-files := nf_nat_snmp_basic-asn1.c nf_nat_snmp_basic-asn1.h
 
index 4ffe302..e3e420f 100644 (file)
@@ -252,6 +252,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
                        }
                        if (table_base + v
                            != arpt_next_entry(e)) {
+                               if (unlikely(stackidx >= private->stacksize)) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
                                jumpstack[stackidx++] = e;
                        }
 
index 9a71f31..e38395a 100644 (file)
@@ -330,8 +330,13 @@ ipt_do_table(struct sk_buff *skb,
                                continue;
                        }
                        if (table_base + v != ipt_next_entry(e) &&
-                           !(e->ip.flags & IPT_F_GOTO))
+                           !(e->ip.flags & IPT_F_GOTO)) {
+                               if (unlikely(stackidx >= private->stacksize)) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
                                jumpstack[stackidx++] = e;
+                       }
 
                        e = get_entry(table_base, v);
                        continue;
index 3a84a60..8a8ae61 100644 (file)
@@ -107,12 +107,6 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
 
        local_bh_disable();
        if (refcount_dec_and_lock(&c->entries, &cn->lock)) {
-               list_del_rcu(&c->list);
-               spin_unlock(&cn->lock);
-               local_bh_enable();
-
-               unregister_netdevice_notifier(&c->notifier);
-
                /* In case anyone still accesses the file, the open/close
                 * functions are also incrementing the refcount on their own,
                 * so it's safe to remove the entry even if it's in use. */
@@ -120,6 +114,12 @@ clusterip_config_entry_put(struct net *net, struct clusterip_config *c)
                if (cn->procdir)
                        proc_remove(c->pde);
 #endif
+               list_del_rcu(&c->list);
+               spin_unlock(&cn->lock);
+               local_bh_enable();
+
+               unregister_netdevice_notifier(&c->notifier);
+
                return;
        }
        local_bh_enable();
@@ -154,8 +154,12 @@ clusterip_config_find_get(struct net *net, __be32 clusterip, int entry)
 #endif
                if (unlikely(!refcount_inc_not_zero(&c->refcount)))
                        c = NULL;
-               else if (entry)
-                       refcount_inc(&c->entries);
+               else if (entry) {
+                       if (unlikely(!refcount_inc_not_zero(&c->entries))) {
+                               clusterip_config_put(c);
+                               c = NULL;
+                       }
+               }
        }
        rcu_read_unlock_bh();
 
@@ -228,7 +232,6 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
        c->hash_mode = i->hash_mode;
        c->hash_initval = i->hash_initval;
        refcount_set(&c->refcount, 1);
-       refcount_set(&c->entries, 1);
 
        spin_lock_bh(&cn->lock);
        if (__clusterip_config_find(net, ip)) {
@@ -259,8 +262,10 @@ clusterip_config_init(struct net *net, const struct ipt_clusterip_tgt_info *i,
 
        c->notifier.notifier_call = clusterip_netdev_event;
        err = register_netdevice_notifier(&c->notifier);
-       if (!err)
+       if (!err) {
+               refcount_set(&c->entries, 1);
                return c;
+       }
 
 #ifdef CONFIG_PROC_FS
        proc_remove(c->pde);
@@ -269,7 +274,7 @@ err:
        spin_lock_bh(&cn->lock);
        list_del_rcu(&c->list);
        spin_unlock_bh(&cn->lock);
-       kfree(c);
+       clusterip_config_put(c);
 
        return ERR_PTR(err);
 }
@@ -492,12 +497,15 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
                                return PTR_ERR(config);
                }
        }
-       cipinfo->config = config;
 
        ret = nf_ct_netns_get(par->net, par->family);
-       if (ret < 0)
+       if (ret < 0) {
                pr_info("cannot load conntrack support for proto=%u\n",
                        par->family);
+               clusterip_config_entry_put(par->net, config);
+               clusterip_config_put(config);
+               return ret;
+       }
 
        if (!par->net->xt.clusterip_deprecated_warning) {
                pr_info("ipt_CLUSTERIP is deprecated and it will removed soon, "
@@ -505,6 +513,7 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par)
                par->net->xt.clusterip_deprecated_warning = true;
        }
 
+       cipinfo->config = config;
        return ret;
 }
 
index 2707652..aaaf9a8 100644 (file)
@@ -98,17 +98,15 @@ static int ecn_tg_check(const struct xt_tgchk_param *par)
        const struct ipt_ECN_info *einfo = par->targinfo;
        const struct ipt_entry *e = par->entryinfo;
 
-       if (einfo->operation & IPT_ECN_OP_MASK) {
-               pr_info("unsupported ECN operation %x\n", einfo->operation);
+       if (einfo->operation & IPT_ECN_OP_MASK)
                return -EINVAL;
-       }
-       if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
-               pr_info("new ECT codepoint %x out of mask\n", einfo->ip_ect);
+
+       if (einfo->ip_ect & ~IPT_ECN_IP_MASK)
                return -EINVAL;
-       }
+
        if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR)) &&
            (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
-               pr_info("cannot use TCP operations on a non-tcp rule\n");
+               pr_info_ratelimited("cannot use operation on non-tcp rule\n");
                return -EINVAL;
        }
        return 0;
index 8bd0d7b..e8bed33 100644 (file)
@@ -74,13 +74,13 @@ static int reject_tg_check(const struct xt_tgchk_param *par)
        const struct ipt_entry *e = par->entryinfo;
 
        if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
-               pr_info("ECHOREPLY no longer supported.\n");
+               pr_info_ratelimited("ECHOREPLY no longer supported.\n");
                return -EINVAL;
        } else if (rejinfo->with == IPT_TCP_RESET) {
                /* Must specify that it's a TCP packet */
                if (e->ip.proto != IPPROTO_TCP ||
                    (e->ip.invflags & XT_INV_PROTO)) {
-                       pr_info("TCP_RESET invalid for non-tcp\n");
+                       pr_info_ratelimited("TCP_RESET invalid for non-tcp\n");
                        return -EINVAL;
                }
        }
index 37fb955..fd01f13 100644 (file)
@@ -105,14 +105,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par)
        const struct xt_rpfilter_info *info = par->matchinfo;
        unsigned int options = ~XT_RPFILTER_OPTION_MASK;
        if (info->flags & options) {
-               pr_info("unknown options encountered");
+               pr_info_ratelimited("unknown options\n");
                return -EINVAL;
        }
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "raw") != 0) {
-               pr_info("match only valid in the \'raw\' "
-                       "or \'mangle\' tables, not \'%s\'.\n", par->table);
+               pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
+                                   par->table);
                return -EINVAL;
        }
 
index b50721d..9db988f 100644 (file)
@@ -154,8 +154,20 @@ static unsigned int ipv4_conntrack_local(void *priv,
                                         struct sk_buff *skb,
                                         const struct nf_hook_state *state)
 {
-       if (ip_is_fragment(ip_hdr(skb))) /* IP_NODEFRAG setsockopt set */
+       if (ip_is_fragment(ip_hdr(skb))) { /* IP_NODEFRAG setsockopt set */
+               enum ip_conntrack_info ctinfo;
+               struct nf_conn *tmpl;
+
+               tmpl = nf_ct_get(skb, &ctinfo);
+               if (tmpl && nf_ct_is_template(tmpl)) {
+                       /* when skipping ct, clear templates to avoid fooling
+                        * later targets/matches
+                        */
+                       skb->_nfct = 0;
+                       nf_ct_put(tmpl);
+               }
                return NF_ACCEPT;
+       }
 
        return nf_conntrack_in(state->net, PF_INET, state->hook, skb);
 }
index 25d2975..0cd46bf 100644 (file)
@@ -111,6 +111,7 @@ static int nf_flow_dnat_ip(const struct flow_offload *flow, struct sk_buff *skb,
        default:
                return -1;
        }
+       csum_replace4(&iph->check, addr, new_addr);
 
        return nf_flow_nat_ip_l4proto(skb, iph, thoff, addr, new_addr);
 }
@@ -185,7 +186,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
        if ((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+       if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                return false;
 
        return true;
index e9293bd..4824b1e 100644 (file)
@@ -108,10 +108,12 @@ struct sock *nf_sk_lookup_slow_v4(struct net *net, const struct sk_buff *skb,
        int doff = 0;
 
        if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_TCP) {
-               struct udphdr _hdr, *hp;
+               struct tcphdr _hdr;
+               struct udphdr *hp;
 
                hp = skb_header_pointer(skb, ip_hdrlen(skb),
-                                       sizeof(_hdr), &_hdr);
+                                       iph->protocol == IPPROTO_UDP ?
+                                       sizeof(*hp) : sizeof(_hdr), &_hdr);
                if (hp == NULL)
                        return NULL;
 
index 49cc1c1..299e247 100644 (file)
@@ -128,10 +128,11 @@ static int ip_rt_redirect_silence __read_mostly   = ((HZ / 50) << (9 + 1));
 static int ip_rt_error_cost __read_mostly      = HZ;
 static int ip_rt_error_burst __read_mostly     = 5 * HZ;
 static int ip_rt_mtu_expires __read_mostly     = 10 * 60 * HZ;
-static int ip_rt_min_pmtu __read_mostly                = 512 + 20 + 20;
+static u32 ip_rt_min_pmtu __read_mostly                = 512 + 20 + 20;
 static int ip_rt_min_advmss __read_mostly      = 256;
 
 static int ip_rt_gc_timeout __read_mostly      = RT_GC_TIMEOUT;
+
 /*
  *     Interface to generic destination cache.
  */
@@ -633,6 +634,7 @@ static inline u32 fnhe_hashfun(__be32 daddr)
 static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe)
 {
        rt->rt_pmtu = fnhe->fnhe_pmtu;
+       rt->rt_mtu_locked = fnhe->fnhe_mtu_locked;
        rt->dst.expires = fnhe->fnhe_expires;
 
        if (fnhe->fnhe_gw) {
@@ -643,7 +645,7 @@ static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnh
 }
 
 static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
-                                 u32 pmtu, unsigned long expires)
+                                 u32 pmtu, bool lock, unsigned long expires)
 {
        struct fnhe_hash_bucket *hash;
        struct fib_nh_exception *fnhe;
@@ -680,8 +682,10 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
                        fnhe->fnhe_genid = genid;
                if (gw)
                        fnhe->fnhe_gw = gw;
-               if (pmtu)
+               if (pmtu) {
                        fnhe->fnhe_pmtu = pmtu;
+                       fnhe->fnhe_mtu_locked = lock;
+               }
                fnhe->fnhe_expires = max(1UL, expires);
                /* Update all cached dsts too */
                rt = rcu_dereference(fnhe->fnhe_rth_input);
@@ -705,6 +709,7 @@ static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw,
                fnhe->fnhe_daddr = daddr;
                fnhe->fnhe_gw = gw;
                fnhe->fnhe_pmtu = pmtu;
+               fnhe->fnhe_mtu_locked = lock;
                fnhe->fnhe_expires = expires;
 
                /* Exception created; mark the cached routes for the nexthop
@@ -786,7 +791,8 @@ static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flow
                                struct fib_nh *nh = &FIB_RES_NH(res);
 
                                update_or_create_fnhe(nh, fl4->daddr, new_gw,
-                                               0, jiffies + ip_rt_gc_timeout);
+                                               0, false,
+                                               jiffies + ip_rt_gc_timeout);
                        }
                        if (kill_route)
                                rt->dst.obsolete = DST_OBSOLETE_KILL;
@@ -930,14 +936,23 @@ out_put_peer:
 
 static int ip_error(struct sk_buff *skb)
 {
-       struct in_device *in_dev = __in_dev_get_rcu(skb->dev);
        struct rtable *rt = skb_rtable(skb);
+       struct net_device *dev = skb->dev;
+       struct in_device *in_dev;
        struct inet_peer *peer;
        unsigned long now;
        struct net *net;
        bool send;
        int code;
 
+       if (netif_is_l3_master(skb->dev)) {
+               dev = __dev_get_by_index(dev_net(skb->dev), IPCB(skb)->iif);
+               if (!dev)
+                       goto out;
+       }
+
+       in_dev = __in_dev_get_rcu(dev);
+
        /* IP on this device is disabled. */
        if (!in_dev)
                goto out;
@@ -999,15 +1014,18 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
 {
        struct dst_entry *dst = &rt->dst;
        struct fib_result res;
+       bool lock = false;
 
-       if (dst_metric_locked(dst, RTAX_MTU))
+       if (ip_mtu_locked(dst))
                return;
 
        if (ipv4_mtu(dst) < mtu)
                return;
 
-       if (mtu < ip_rt_min_pmtu)
+       if (mtu < ip_rt_min_pmtu) {
+               lock = true;
                mtu = ip_rt_min_pmtu;
+       }
 
        if (rt->rt_pmtu == mtu &&
            time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2))
@@ -1017,7 +1035,7 @@ static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu)
        if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) {
                struct fib_nh *nh = &FIB_RES_NH(res);
 
-               update_or_create_fnhe(nh, fl4->daddr, 0, mtu,
+               update_or_create_fnhe(nh, fl4->daddr, 0, mtu, lock,
                                      jiffies + ip_rt_mtu_expires);
        }
        rcu_read_unlock();
@@ -1270,7 +1288,7 @@ static unsigned int ipv4_mtu(const struct dst_entry *dst)
 
        mtu = READ_ONCE(dst->dev->mtu);
 
-       if (unlikely(dst_metric_locked(dst, RTAX_MTU))) {
+       if (unlikely(ip_mtu_locked(dst))) {
                if (rt->rt_uses_gateway && mtu > 576)
                        mtu = 576;
        }
@@ -1383,7 +1401,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
 
-static void rt_add_uncached_list(struct rtable *rt)
+void rt_add_uncached_list(struct rtable *rt)
 {
        struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list);
 
@@ -1394,14 +1412,8 @@ static void rt_add_uncached_list(struct rtable *rt)
        spin_unlock_bh(&ul->lock);
 }
 
-static void ipv4_dst_destroy(struct dst_entry *dst)
+void rt_del_uncached_list(struct rtable *rt)
 {
-       struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
-       struct rtable *rt = (struct rtable *) dst;
-
-       if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
-               kfree(p);
-
        if (!list_empty(&rt->rt_uncached)) {
                struct uncached_list *ul = rt->rt_uncached_list;
 
@@ -1411,6 +1423,17 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
        }
 }
 
+static void ipv4_dst_destroy(struct dst_entry *dst)
+{
+       struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
+       struct rtable *rt = (struct rtable *)dst;
+
+       if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
+               kfree(p);
+
+       rt_del_uncached_list(rt);
+}
+
 void rt_flush_dev(struct net_device *dev)
 {
        struct net *net = dev_net(dev);
@@ -1506,6 +1529,7 @@ struct rtable *rt_dst_alloc(struct net_device *dev,
                rt->rt_is_input = 0;
                rt->rt_iif = 0;
                rt->rt_pmtu = 0;
+               rt->rt_mtu_locked = 0;
                rt->rt_gateway = 0;
                rt->rt_uses_gateway = 0;
                rt->rt_table_id = 0;
@@ -1826,6 +1850,8 @@ int fib_multipath_hash(const struct fib_info *fi, const struct flowi4 *fl4,
                                return skb_get_hash_raw(skb) >> 1;
                        memset(&hash_keys, 0, sizeof(hash_keys));
                        skb_flow_dissect_flow_keys(skb, &keys, flag);
+
+                       hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
                        hash_keys.addrs.v4addrs.src = keys.addrs.v4addrs.src;
                        hash_keys.addrs.v4addrs.dst = keys.addrs.v4addrs.dst;
                        hash_keys.ports.src = keys.ports.src;
@@ -2529,6 +2555,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or
                rt->rt_is_input = ort->rt_is_input;
                rt->rt_iif = ort->rt_iif;
                rt->rt_pmtu = ort->rt_pmtu;
+               rt->rt_mtu_locked = ort->rt_mtu_locked;
 
                rt->rt_genid = rt_genid_ipv4(net);
                rt->rt_flags = ort->rt_flags;
@@ -2631,6 +2658,8 @@ static int rt_fill_info(struct net *net,  __be32 dst, __be32 src, u32 table_id,
        memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics));
        if (rt->rt_pmtu && expires)
                metrics[RTAX_MTU - 1] = rt->rt_pmtu;
+       if (rt->rt_mtu_locked && expires)
+               metrics[RTAX_LOCK - 1] |= BIT(RTAX_MTU);
        if (rtnetlink_put_metrics(skb, metrics) < 0)
                goto nla_put_failure;
 
@@ -2816,6 +2845,7 @@ void ip_rt_multicast_event(struct in_device *in_dev)
 static int ip_rt_gc_interval __read_mostly  = 60 * HZ;
 static int ip_rt_gc_min_interval __read_mostly = HZ / 2;
 static int ip_rt_gc_elasticity __read_mostly   = 8;
+static int ip_min_valid_pmtu __read_mostly     = IPV4_MIN_MTU;
 
 static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write,
                                        void __user *buffer,
@@ -2931,7 +2961,8 @@ static struct ctl_table ipv4_route_table[] = {
                .data           = &ip_rt_min_pmtu,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &ip_min_valid_pmtu,
        },
        {
                .procname       = "min_adv_mss",
index fda37f2..c3387df 100644 (file)
@@ -349,6 +349,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
        req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
        treq->snt_synack        = 0;
        treq->tfo_listener      = false;
+       if (IS_ENABLED(CONFIG_SMC))
+               ireq->smc_ok = 0;
 
        ireq->ir_iif = inet_request_bound_dev_if(sk, skb);
 
index 48636ae..8b8059b 100644 (file)
@@ -3566,6 +3566,7 @@ int tcp_abort(struct sock *sk, int err)
 
        bh_unlock_sock(sk);
        local_bh_enable();
+       tcp_write_queue_purge(sk);
        release_sock(sk);
        return 0;
 }
index 7c84357..faddf4f 100644 (file)
@@ -6,7 +6,7 @@
  * The algorithm is described in:
  * "TCP-Illinois: A Loss and Delay-Based Congestion Control Algorithm
  *  for High-Speed Networks"
- * http://www.ifp.illinois.edu/~srikant/Papers/liubassri06perf.pdf
+ * http://tamerbasar.csl.illinois.edu/LiuBasarSrikantPerfEvalArtJun2008.pdf
  *
  * Implemented from description in paper and ns-2 simulation.
  * Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
index 575d3c1..ff6cd98 100644 (file)
@@ -1971,11 +1971,6 @@ void tcp_enter_loss(struct sock *sk)
        /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous
         * loss recovery is underway except recurring timeout(s) on
         * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing
-        *
-        * In theory F-RTO can be used repeatedly during loss recovery.
-        * In practice this interacts badly with broken middle-boxes that
-        * falsely raise the receive window, which results in repeated
-        * timeouts and stop-and-go behavior.
         */
        tp->frto = net->ipv4.sysctl_tcp_frto &&
                   (new_recovery || icsk->icsk_retransmits) &&
@@ -2631,18 +2626,14 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack,
            tcp_try_undo_loss(sk, false))
                return;
 
-       /* The ACK (s)acks some never-retransmitted data meaning not all
-        * the data packets before the timeout were lost. Therefore we
-        * undo the congestion window and state. This is essentially
-        * the operation in F-RTO (RFC5682 section 3.1 step 3.b). Since
-        * a retransmitted skb is permantly marked, we can apply such an
-        * operation even if F-RTO was not used.
-        */
-       if ((flag & FLAG_ORIG_SACK_ACKED) &&
-           tcp_try_undo_loss(sk, tp->undo_marker))
-               return;
-
        if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */
+               /* Step 3.b. A timeout is spurious if not all data are
+                * lost, i.e., never-retransmitted data are (s)acked.
+                */
+               if ((flag & FLAG_ORIG_SACK_ACKED) &&
+                   tcp_try_undo_loss(sk, true))
+                       return;
+
                if (after(tp->snd_nxt, tp->high_seq)) {
                        if (flag & FLAG_DATA_SACKED || is_dupack)
                                tp->frto = 0; /* Step 3.a. loss was real */
@@ -4001,6 +3992,7 @@ void tcp_reset(struct sock *sk)
        /* This barrier is coupled with smp_rmb() in tcp_poll() */
        smp_wmb();
 
+       tcp_write_queue_purge(sk);
        tcp_done(sk);
 
        if (!sock_flag(sk, SOCK_DEAD))
@@ -6264,6 +6256,9 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
 
+       if (IS_ENABLED(CONFIG_SMC) && want_cookie)
+               tmp_opt.smc_ok = 0;
+
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
        tcp_openreq_init(req, &tmp_opt, skb, sk);
        inet_rsk(req)->no_srccheck = inet_sk(sk)->transparent;
index e9f985e..6818042 100644 (file)
@@ -1730,7 +1730,7 @@ u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now,
         */
        segs = max_t(u32, bytes / mss_now, min_tso_segs);
 
-       return min_t(u32, segs, sk->sk_gso_max_segs);
+       return segs;
 }
 EXPORT_SYMBOL(tcp_tso_autosize);
 
@@ -1742,9 +1742,10 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now)
        const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops;
        u32 tso_segs = ca_ops->tso_segs_goal ? ca_ops->tso_segs_goal(sk) : 0;
 
-       return tso_segs ? :
-               tcp_tso_autosize(sk, mss_now,
-                                sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs);
+       if (!tso_segs)
+               tso_segs = tcp_tso_autosize(sk, mss_now,
+                               sock_net(sk)->ipv4.sysctl_tcp_min_tso_segs);
+       return min_t(u32, tso_segs, sk->sk_gso_max_segs);
 }
 
 /* Returns the portion of skb which can be sent right away */
@@ -2027,6 +2028,24 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk)
        }
 }
 
+static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len)
+{
+       struct sk_buff *skb, *next;
+
+       skb = tcp_send_head(sk);
+       tcp_for_write_queue_from_safe(skb, next, sk) {
+               if (len <= skb->len)
+                       break;
+
+               if (unlikely(TCP_SKB_CB(skb)->eor))
+                       return false;
+
+               len -= skb->len;
+       }
+
+       return true;
+}
+
 /* Create a new MTU probe if we are ready.
  * MTU probe is regularly attempting to increase the path MTU by
  * deliberately sending larger packets.  This discovers routing
@@ -2099,6 +2118,9 @@ static int tcp_mtu_probe(struct sock *sk)
                        return 0;
        }
 
+       if (!tcp_can_coalesce_send_queue_head(sk, probe_size))
+               return -1;
+
        /* We're allowed to probe.  Build it now. */
        nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false);
        if (!nskb)
@@ -2134,6 +2156,10 @@ static int tcp_mtu_probe(struct sock *sk)
                        /* We've eaten all the data from this skb.
                         * Throw it away. */
                        TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags;
+                       /* If this is the last SKB we copy and eor is set
+                        * we need to propagate it to the new skb.
+                        */
+                       TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor;
                        tcp_unlink_write_queue(skb, sk);
                        sk_wmem_free_skb(sk, skb);
                } else {
index 71fc60f..f7d9448 100644 (file)
@@ -34,6 +34,7 @@ static void tcp_write_err(struct sock *sk)
        sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT;
        sk->sk_error_report(sk);
 
+       tcp_write_queue_purge(sk);
        tcp_done(sk);
        __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT);
 }
index bfaefe5..e5ef7c3 100644 (file)
@@ -2024,6 +2024,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
                err = udplite_checksum_init(skb, uh);
                if (err)
                        return err;
+
+               if (UDP_SKB_CB(skb)->partial_cov) {
+                       skb->csum = inet_compute_pseudo(skb, proto);
+                       return 0;
+               }
        }
 
        /* Note, we are only interested in != 0 or == 0, thus the
index 63faeee..2a9764b 100644 (file)
@@ -92,7 +92,8 @@ static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 
        skb_reset_network_header(skb);
        skb_mac_header_rebuild(skb);
-       eth_hdr(skb)->h_proto = skb->protocol;
+       if (skb->mac_len)
+               eth_hdr(skb)->h_proto = skb->protocol;
 
        err = 0;
 
index 94b8702..be980c1 100644 (file)
@@ -30,7 +30,8 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb)
 
        mtu = dst_mtu(skb_dst(skb));
        if ((!skb_is_gso(skb) && skb->len > mtu) ||
-           (skb_is_gso(skb) && skb_gso_network_seglen(skb) > ip_skb_dst_mtu(skb->sk, skb))) {
+           (skb_is_gso(skb) &&
+            !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
                skb->protocol = htons(ETH_P_IP);
 
                if (skb->sk)
index 05017e2..fbebda6 100644 (file)
@@ -100,8 +100,10 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        xdst->u.rt.rt_gateway = rt->rt_gateway;
        xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway;
        xdst->u.rt.rt_pmtu = rt->rt_pmtu;
+       xdst->u.rt.rt_mtu_locked = rt->rt_mtu_locked;
        xdst->u.rt.rt_table_id = rt->rt_table_id;
        INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
+       rt_add_uncached_list(&xdst->u.rt);
 
        return 0;
 }
@@ -241,7 +243,8 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
        struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 
        dst_destroy_metrics_generic(dst);
-
+       if (xdst->u.rt.rt_uncached_list)
+               rt_del_uncached_list(&xdst->u.rt);
        xfrm_dst_destroy(xdst);
 }
 
index fbf08ce..a9f7eca 100644 (file)
@@ -146,10 +146,12 @@ int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr,
        struct sockaddr_in6     *usin = (struct sockaddr_in6 *) uaddr;
        struct inet_sock        *inet = inet_sk(sk);
        struct ipv6_pinfo       *np = inet6_sk(sk);
-       struct in6_addr         *daddr;
+       struct in6_addr         *daddr, old_daddr;
+       __be32                  fl6_flowlabel = 0;
+       __be32                  old_fl6_flowlabel;
+       __be16                  old_dport;
        int                     addr_type;
        int                     err;
-       __be32                  fl6_flowlabel = 0;
 
        if (usin->sin6_family == AF_INET) {
                if (__ipv6_only_sock(sk))
@@ -238,9 +240,13 @@ ipv4_connected:
                }
        }
 
+       /* save the current peer information before updating it */
+       old_daddr = sk->sk_v6_daddr;
+       old_fl6_flowlabel = np->flow_label;
+       old_dport = inet->inet_dport;
+
        sk->sk_v6_daddr = *daddr;
        np->flow_label = fl6_flowlabel;
-
        inet->inet_dport = usin->sin6_port;
 
        /*
@@ -250,11 +256,12 @@ ipv4_connected:
 
        err = ip6_datagram_dst_update(sk, true);
        if (err) {
-               /* Reset daddr and dport so that udp_v6_early_demux()
-                * fails to find this socket
+               /* Restore the socket peer info, to keep it consistent with
+                * the old socket state
                 */
-               memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr));
-               inet->inet_dport = 0;
+               sk->sk_v6_daddr = old_daddr;
+               np->flow_label = old_fl6_flowlabel;
+               inet->inet_dport = old_dport;
                goto out;
        }
 
index ec43d18..547515e 100644 (file)
@@ -73,6 +73,11 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
                err = udplite_checksum_init(skb, uh);
                if (err)
                        return err;
+
+               if (UDP_SKB_CB(skb)->partial_cov) {
+                       skb->csum = ip6_compute_pseudo(skb, proto);
+                       return 0;
+               }
        }
 
        /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
index 3c35312..1bbd093 100644 (file)
@@ -126,7 +126,8 @@ static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
        struct ip6_tnl *t, *cand = NULL;
        struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
        int dev_type = (gre_proto == htons(ETH_P_TEB) ||
-                       gre_proto == htons(ETH_P_ERSPAN)) ?
+                       gre_proto == htons(ETH_P_ERSPAN) ||
+                       gre_proto == htons(ETH_P_ERSPAN2)) ?
                       ARPHRD_ETHER : ARPHRD_IP6GRE;
        int score, cand_score = 4;
 
@@ -902,6 +903,9 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
                truncate = true;
        }
 
+       if (skb_cow_head(skb, dev->needed_headroom))
+               goto tx_err;
+
        t->parms.o_flags &= ~TUNNEL_KEY;
        IPCB(skb)->flags = 0;
 
@@ -944,6 +948,8 @@ static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb,
                                               md->u.md2.dir,
                                               get_hwid(&md->u.md2),
                                               truncate, false);
+               } else {
+                       goto tx_err;
                }
        } else {
                switch (skb->protocol) {
index 997c7f1..5cb18c8 100644 (file)
@@ -412,7 +412,7 @@ static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
        if (skb->ignore_df)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+       if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                return false;
 
        return true;
@@ -1246,7 +1246,7 @@ static int __ip6_append_data(struct sock *sk,
                             const struct sockcm_cookie *sockc)
 {
        struct sk_buff *skb, *skb_prev = NULL;
-       unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
+       unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu;
        int exthdrlen = 0;
        int dst_exthdrlen = 0;
        int hh_len;
@@ -1282,6 +1282,12 @@ static int __ip6_append_data(struct sock *sk,
                      sizeof(struct frag_hdr) : 0) +
                     rt->rt6i_nfheader_len;
 
+       /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
+        * the first fragment
+        */
+       if (headersize + transhdrlen > mtu)
+               goto emsgsize;
+
        if (cork->length + length > mtu - headersize && ipc6->dontfrag &&
            (sk->sk_protocol == IPPROTO_UDP ||
             sk->sk_protocol == IPPROTO_RAW)) {
@@ -1297,9 +1303,8 @@ static int __ip6_append_data(struct sock *sk,
 
        if (cork->length + length > maxnonfragsize - headersize) {
 emsgsize:
-               ipv6_local_error(sk, EMSGSIZE, fl6,
-                                mtu - headersize +
-                                sizeof(struct ipv6hdr));
+               pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0);
+               ipv6_local_error(sk, EMSGSIZE, fl6, pmtu);
                return -EMSGSIZE;
        }
 
index 4b15fe9..6e0f21e 100644 (file)
@@ -1982,14 +1982,14 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
 {
        struct net *net = dev_net(dev);
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
-       struct ip6_tnl *nt, *t;
        struct ip_tunnel_encap ipencap;
+       struct ip6_tnl *nt, *t;
+       int err;
 
        nt = netdev_priv(dev);
 
        if (ip6_tnl_netlink_encap_parms(data, &ipencap)) {
-               int err = ip6_tnl_encap_setup(nt, &ipencap);
-
+               err = ip6_tnl_encap_setup(nt, &ipencap);
                if (err < 0)
                        return err;
        }
@@ -2005,7 +2005,11 @@ static int ip6_tnl_newlink(struct net *src_net, struct net_device *dev,
                        return -EEXIST;
        }
 
-       return ip6_tnl_create2(dev);
+       err = ip6_tnl_create2(dev);
+       if (!err && tb[IFLA_MTU])
+               ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU]));
+
+       return err;
 }
 
 static int ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[],
index fa3ae1c..ce18cd2 100644 (file)
@@ -622,11 +622,12 @@ static int vti6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        return 0;
 }
 
-static void vti6_link_config(struct ip6_tnl *t)
+static void vti6_link_config(struct ip6_tnl *t, bool keep_mtu)
 {
        struct net_device *dev = t->dev;
        struct __ip6_tnl_parm *p = &t->parms;
        struct net_device *tdev = NULL;
+       int mtu;
 
        memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
        memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
@@ -640,6 +641,11 @@ static void vti6_link_config(struct ip6_tnl *t)
        else
                dev->flags &= ~IFF_POINTOPOINT;
 
+       if (keep_mtu && dev->mtu) {
+               dev->mtu = clamp(dev->mtu, dev->min_mtu, dev->max_mtu);
+               return;
+       }
+
        if (p->flags & IP6_TNL_F_CAP_XMIT) {
                int strict = (ipv6_addr_type(&p->raddr) &
                              (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL));
@@ -656,20 +662,25 @@ static void vti6_link_config(struct ip6_tnl *t)
                tdev = __dev_get_by_index(t->net, p->link);
 
        if (tdev)
-               dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len,
-                                IPV6_MIN_MTU);
+               mtu = tdev->mtu - sizeof(struct ipv6hdr);
+       else
+               mtu = ETH_DATA_LEN - LL_MAX_HEADER - sizeof(struct ipv6hdr);
+
+       dev->mtu = max_t(int, mtu, IPV6_MIN_MTU);
 }
 
 /**
  * vti6_tnl_change - update the tunnel parameters
  *   @t: tunnel to be changed
  *   @p: tunnel configuration parameters
+ *   @keep_mtu: MTU was set from userspace, don't re-compute it
  *
  * Description:
  *   vti6_tnl_change() updates the tunnel parameters
  **/
 static int
-vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
+vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p,
+               bool keep_mtu)
 {
        t->parms.laddr = p->laddr;
        t->parms.raddr = p->raddr;
@@ -679,11 +690,12 @@ vti6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
        t->parms.proto = p->proto;
        t->parms.fwmark = p->fwmark;
        dst_cache_reset(&t->dst_cache);
-       vti6_link_config(t);
+       vti6_link_config(t, keep_mtu);
        return 0;
 }
 
-static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
+static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p,
+                      bool keep_mtu)
 {
        struct net *net = dev_net(t->dev);
        struct vti6_net *ip6n = net_generic(net, vti6_net_id);
@@ -691,7 +703,7 @@ static int vti6_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p)
 
        vti6_tnl_unlink(ip6n, t);
        synchronize_net();
-       err = vti6_tnl_change(t, p);
+       err = vti6_tnl_change(t, p, keep_mtu);
        vti6_tnl_link(ip6n, t);
        netdev_state_change(t->dev);
        return err;
@@ -804,7 +816,7 @@ vti6_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        } else
                                t = netdev_priv(dev);
 
-                       err = vti6_update(t, &p1);
+                       err = vti6_update(t, &p1, false);
                }
                if (t) {
                        err = 0;
@@ -866,10 +878,8 @@ static void vti6_dev_setup(struct net_device *dev)
        dev->priv_destructor = vti6_dev_free;
 
        dev->type = ARPHRD_TUNNEL6;
-       dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr);
-       dev->mtu = ETH_DATA_LEN;
        dev->min_mtu = IPV6_MIN_MTU;
-       dev->max_mtu = IP_MAX_MTU;
+       dev->max_mtu = IP_MAX_MTU - sizeof(struct ipv6hdr);
        dev->flags |= IFF_NOARP;
        dev->addr_len = sizeof(struct in6_addr);
        netif_keep_dst(dev);
@@ -905,7 +915,7 @@ static int vti6_dev_init(struct net_device *dev)
 
        if (err)
                return err;
-       vti6_link_config(t);
+       vti6_link_config(t, true);
        return 0;
 }
 
@@ -1010,7 +1020,7 @@ static int vti6_changelink(struct net_device *dev, struct nlattr *tb[],
        } else
                t = netdev_priv(dev);
 
-       return vti6_update(t, &p);
+       return vti6_update(t, &p, tb && tb[IFLA_MTU]);
 }
 
 static size_t vti6_get_size(const struct net_device *dev)
index d78d41f..2453516 100644 (file)
@@ -1367,10 +1367,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = nf_getsockopt(sk, PF_INET6, optname, optval,
-                               &len);
-               release_sock(sk);
+               err = nf_getsockopt(sk, PF_INET6, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
        }
@@ -1409,10 +1406,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
                if (get_user(len, optlen))
                        return -EFAULT;
 
-               lock_sock(sk);
-               err = compat_nf_getsockopt(sk, PF_INET6,
-                                          optname, optval, &len);
-               release_sock(sk);
+               err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len);
                if (err >= 0)
                        err = put_user(len, optlen);
        }
index f61a5b6..ba5e04c 100644 (file)
@@ -1554,7 +1554,8 @@ static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb,
        *(opt++) = (rd_len >> 3);
        opt += 6;
 
-       memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8);
+       skb_copy_bits(orig_skb, skb_network_offset(orig_skb), opt,
+                     rd_len - 8);
 }
 
 void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
index d95ceca..531d695 100644 (file)
 int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
 {
        const struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct sock *sk = sk_to_full_sk(skb->sk);
        unsigned int hh_len;
        struct dst_entry *dst;
        struct flowi6 fl6 = {
-               .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
+               .flowi6_oif = sk ? sk->sk_bound_dev_if : 0,
                .flowi6_mark = skb->mark,
-               .flowi6_uid = sock_net_uid(net, skb->sk),
+               .flowi6_uid = sock_net_uid(net, sk),
                .daddr = iph->daddr,
                .saddr = iph->saddr,
        };
        int err;
 
-       dst = ip6_route_output(net, skb->sk, &fl6);
+       dst = ip6_route_output(net, sk, &fl6);
        err = dst->error;
        if (err) {
                IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
@@ -50,7 +51,7 @@ int ip6_route_me_harder(struct net *net, struct sk_buff *skb)
        if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) &&
            xfrm_decode_session(skb, flowi6_to_flowi(&fl6), AF_INET6) == 0) {
                skb_dst_set(skb, NULL);
-               dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), skb->sk, 0);
+               dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0);
                if (IS_ERR(dst))
                        return PTR_ERR(dst);
                skb_dst_set(skb, dst);
index af4c917..62358b9 100644 (file)
@@ -352,6 +352,10 @@ ip6t_do_table(struct sk_buff *skb,
                        }
                        if (table_base + v != ip6t_next_entry(e) &&
                            !(e->ipv6.flags & IP6T_F_GOTO)) {
+                               if (unlikely(stackidx >= private->stacksize)) {
+                                       verdict = NF_DROP;
+                                       break;
+                               }
                                jumpstack[stackidx++] = e;
                        }
 
index fa51a20..38dea8f 100644 (file)
@@ -85,14 +85,14 @@ static int reject_tg6_check(const struct xt_tgchk_param *par)
        const struct ip6t_entry *e = par->entryinfo;
 
        if (rejinfo->with == IP6T_ICMP6_ECHOREPLY) {
-               pr_info("ECHOREPLY is not supported.\n");
+               pr_info_ratelimited("ECHOREPLY is not supported\n");
                return -EINVAL;
        } else if (rejinfo->with == IP6T_TCP_RESET) {
                /* Must specify that it's a TCP packet */
                if (!(e->ipv6.flags & IP6T_F_PROTO) ||
                    e->ipv6.proto != IPPROTO_TCP ||
                    (e->ipv6.invflags & XT_INV_PROTO)) {
-                       pr_info("TCP_RESET illegal for non-tcp\n");
+                       pr_info_ratelimited("TCP_RESET illegal for non-tcp\n");
                        return -EINVAL;
                }
        }
index b12e61b..91ed25a 100644 (file)
@@ -48,10 +48,6 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb,
        }
 
        fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
-       if ((flags & XT_RPFILTER_LOOSE) == 0) {
-               fl6.flowi6_oif = dev->ifindex;
-               lookup_flags |= RT6_LOOKUP_F_IFACE;
-       }
 
        rt = (void *) ip6_route_lookup(net, &fl6, lookup_flags);
        if (rt->dst.error)
@@ -103,14 +99,14 @@ static int rpfilter_check(const struct xt_mtchk_param *par)
        unsigned int options = ~XT_RPFILTER_OPTION_MASK;
 
        if (info->flags & options) {
-               pr_info("unknown options encountered");
+               pr_info_ratelimited("unknown options\n");
                return -EINVAL;
        }
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "raw") != 0) {
-               pr_info("match only valid in the \'raw\' "
-                       "or \'mangle\' tables, not \'%s\'.\n", par->table);
+               pr_info_ratelimited("only valid in \'raw\' or \'mangle\' table, not \'%s\'\n",
+                                   par->table);
                return -EINVAL;
        }
 
index 9642164..33719d5 100644 (file)
@@ -122,12 +122,14 @@ static int srh_mt6_check(const struct xt_mtchk_param *par)
        const struct ip6t_srh *srhinfo = par->matchinfo;
 
        if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
-               pr_err("unknown srh match flags  %X\n", srhinfo->mt_flags);
+               pr_info_ratelimited("unknown srh match flags  %X\n",
+                                   srhinfo->mt_flags);
                return -EINVAL;
        }
 
        if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
-               pr_err("unknown srh invflags %X\n", srhinfo->mt_invflags);
+               pr_info_ratelimited("unknown srh invflags %X\n",
+                                   srhinfo->mt_invflags);
                return -EINVAL;
        }
 
index d346705..207cb35 100644 (file)
@@ -178,7 +178,7 @@ static bool __nf_flow_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu)
        if (skb->len <= mtu)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+       if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                return false;
 
        return true;
index bed57ee..6b7f075 100644 (file)
@@ -99,6 +99,10 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb,
            !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff,
                                target, maniptype))
                return false;
+
+       /* must reload, offset might have changed */
+       ipv6h = (void *)skb->data + iphdroff;
+
 manip_addr:
        if (maniptype == NF_NAT_MANIP_SRC)
                ipv6h->saddr = target->src.u3.in6;
index ebb2bf8..f14de4b 100644 (file)
@@ -116,9 +116,11 @@ struct sock *nf_sk_lookup_slow_v6(struct net *net, const struct sk_buff *skb,
        }
 
        if (tproto == IPPROTO_UDP || tproto == IPPROTO_TCP) {
-               struct udphdr _hdr, *hp;
+               struct tcphdr _hdr;
+               struct udphdr *hp;
 
-               hp = skb_header_pointer(skb, thoff, sizeof(_hdr), &_hdr);
+               hp = skb_header_pointer(skb, thoff, tproto == IPPROTO_UDP ?
+                                       sizeof(*hp) : sizeof(_hdr), &_hdr);
                if (hp == NULL)
                        return NULL;
 
index cc5174c..62fc84d 100644 (file)
@@ -180,7 +180,6 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
        }
 
        *dest = 0;
- again:
        rt = (void *)ip6_route_lookup(nft_net(pkt), &fl6, lookup_flags);
        if (rt->dst.error)
                goto put_rt_err;
@@ -189,15 +188,8 @@ void nft_fib6_eval(const struct nft_expr *expr, struct nft_regs *regs,
        if (rt->rt6i_flags & (RTF_REJECT | RTF_ANYCAST | RTF_LOCAL))
                goto put_rt_err;
 
-       if (oif && oif != rt->rt6i_idev->dev) {
-               /* multipath route? Try again with F_IFACE */
-               if ((lookup_flags & RT6_LOOKUP_F_IFACE) == 0) {
-                       lookup_flags |= RT6_LOOKUP_F_IFACE;
-                       fl6.flowi6_oif = oif->ifindex;
-                       ip6_rt_put(rt);
-                       goto again;
-               }
-       }
+       if (oif && oif != rt->rt6i_idev->dev)
+               goto put_rt_err;
 
        switch (priv->result) {
        case NFT_FIB_RESULT_OIF:
index 9dcfadd..fc74352 100644 (file)
@@ -128,7 +128,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
 
-static void rt6_uncached_list_add(struct rt6_info *rt)
+void rt6_uncached_list_add(struct rt6_info *rt)
 {
        struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
 
@@ -139,7 +139,7 @@ static void rt6_uncached_list_add(struct rt6_info *rt)
        spin_unlock_bh(&ul->lock);
 }
 
-static void rt6_uncached_list_del(struct rt6_info *rt)
+void rt6_uncached_list_del(struct rt6_info *rt)
 {
        if (!list_empty(&rt->rt6i_uncached)) {
                struct uncached_list *ul = rt->rt6i_uncached_list;
@@ -919,6 +919,9 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net,
        struct rt6_info *rt, *rt_cache;
        struct fib6_node *fn;
 
+       if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF)
+               flags &= ~RT6_LOOKUP_F_IFACE;
+
        rcu_read_lock();
        fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr);
 restart:
@@ -1509,7 +1512,30 @@ static void rt6_exceptions_remove_prefsrc(struct rt6_info *rt)
        }
 }
 
-static void rt6_exceptions_update_pmtu(struct rt6_info *rt, int mtu)
+static bool rt6_mtu_change_route_allowed(struct inet6_dev *idev,
+                                        struct rt6_info *rt, int mtu)
+{
+       /* If the new MTU is lower than the route PMTU, this new MTU will be the
+        * lowest MTU in the path: always allow updating the route PMTU to
+        * reflect PMTU decreases.
+        *
+        * If the new MTU is higher, and the route PMTU is equal to the local
+        * MTU, this means the old MTU is the lowest in the path, so allow
+        * updating it: if other nodes now have lower MTUs, PMTU discovery will
+        * handle this.
+        */
+
+       if (dst_mtu(&rt->dst) >= mtu)
+               return true;
+
+       if (dst_mtu(&rt->dst) == idev->cnf.mtu6)
+               return true;
+
+       return false;
+}
+
+static void rt6_exceptions_update_pmtu(struct inet6_dev *idev,
+                                      struct rt6_info *rt, int mtu)
 {
        struct rt6_exception_bucket *bucket;
        struct rt6_exception *rt6_ex;
@@ -1518,20 +1544,22 @@ static void rt6_exceptions_update_pmtu(struct rt6_info *rt, int mtu)
        bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
                                        lockdep_is_held(&rt6_exception_lock));
 
-       if (bucket) {
-               for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
-                       hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
-                               struct rt6_info *entry = rt6_ex->rt6i;
-                               /* For RTF_CACHE with rt6i_pmtu == 0
-                                * (i.e. a redirected route),
-                                * the metrics of its rt->dst.from has already
-                                * been updated.
-                                */
-                               if (entry->rt6i_pmtu && entry->rt6i_pmtu > mtu)
-                                       entry->rt6i_pmtu = mtu;
-                       }
-                       bucket++;
+       if (!bucket)
+               return;
+
+       for (i = 0; i < FIB6_EXCEPTION_BUCKET_SIZE; i++) {
+               hlist_for_each_entry(rt6_ex, &bucket->chain, hlist) {
+                       struct rt6_info *entry = rt6_ex->rt6i;
+
+                       /* For RTF_CACHE with rt6i_pmtu == 0 (i.e. a redirected
+                        * route), the metrics of its rt->dst.from have already
+                        * been updated.
+                        */
+                       if (entry->rt6i_pmtu &&
+                           rt6_mtu_change_route_allowed(idev, entry, mtu))
+                               entry->rt6i_pmtu = mtu;
                }
+               bucket++;
        }
 }
 
@@ -1601,11 +1629,10 @@ static void rt6_age_examine_exception(struct rt6_exception_bucket *bucket,
                struct neighbour *neigh;
                __u8 neigh_flags = 0;
 
-               neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway);
-               if (neigh) {
+               neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway);
+               if (neigh)
                        neigh_flags = neigh->flags;
-                       neigh_release(neigh);
-               }
+
                if (!(neigh_flags & NTF_ROUTER)) {
                        RT6_TRACE("purging route %p via non-router but gateway\n",
                                  rt);
@@ -1629,7 +1656,8 @@ void rt6_age_exceptions(struct rt6_info *rt,
        if (!rcu_access_pointer(rt->rt6i_exception_bucket))
                return;
 
-       spin_lock_bh(&rt6_exception_lock);
+       rcu_read_lock_bh();
+       spin_lock(&rt6_exception_lock);
        bucket = rcu_dereference_protected(rt->rt6i_exception_bucket,
                                    lockdep_is_held(&rt6_exception_lock));
 
@@ -1643,7 +1671,8 @@ void rt6_age_exceptions(struct rt6_info *rt,
                        bucket++;
                }
        }
-       spin_unlock_bh(&rt6_exception_lock);
+       spin_unlock(&rt6_exception_lock);
+       rcu_read_unlock_bh();
 }
 
 struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
@@ -3809,25 +3838,13 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
           Since RFC 1981 doesn't include administrative MTU increase
           update PMTU increase is a MUST. (i.e. jumbo frame)
         */
-       /*
-          If new MTU is less than route PMTU, this new MTU will be the
-          lowest MTU in the path, update the route PMTU to reflect PMTU
-          decreases; if new MTU is greater than route PMTU, and the
-          old MTU is the lowest MTU in the path, update the route PMTU
-          to reflect the increase. In this case if the other nodes' MTU
-          also have the lowest MTU, TOO BIG MESSAGE will be lead to
-          PMTU discovery.
-        */
        if (rt->dst.dev == arg->dev &&
-           dst_metric_raw(&rt->dst, RTAX_MTU) &&
            !dst_metric_locked(&rt->dst, RTAX_MTU)) {
                spin_lock_bh(&rt6_exception_lock);
-               if (dst_mtu(&rt->dst) >= arg->mtu ||
-                   (dst_mtu(&rt->dst) < arg->mtu &&
-                    dst_mtu(&rt->dst) == idev->cnf.mtu6)) {
+               if (dst_metric_raw(&rt->dst, RTAX_MTU) &&
+                   rt6_mtu_change_route_allowed(idev, rt, arg->mtu))
                        dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
-               }
-               rt6_exceptions_update_pmtu(rt, arg->mtu);
+               rt6_exceptions_update_pmtu(idev, rt, arg->mtu);
                spin_unlock_bh(&rt6_exception_lock);
        }
        return 0;
@@ -4099,6 +4116,7 @@ static int ip6_route_multipath_add(struct fib6_config *cfg,
                                r_cfg.fc_encap_type = nla_get_u16(nla);
                }
 
+               r_cfg.fc_flags |= (rtnh->rtnh_flags & RTNH_F_ONLINK);
                rt = ip6_route_info_create(&r_cfg, extack);
                if (IS_ERR(rt)) {
                        err = PTR_ERR(rt);
index bd6cc68..f343e6f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/net.h>
 #include <linux/module.h>
 #include <net/ip.h>
+#include <net/ip_tunnels.h>
 #include <net/lwtunnel.h>
 #include <net/netevent.h>
 #include <net/netns/generic.h>
@@ -93,7 +94,8 @@ static void set_tun_src(struct net *net, struct net_device *dev,
 /* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
 int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
 {
-       struct net *net = dev_net(skb_dst(skb)->dev);
+       struct dst_entry *dst = skb_dst(skb);
+       struct net *net = dev_net(dst->dev);
        struct ipv6hdr *hdr, *inner_hdr;
        struct ipv6_sr_hdr *isrh;
        int hdrlen, tot_len, err;
@@ -134,7 +136,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        isrh->nexthdr = proto;
 
        hdr->daddr = isrh->segments[isrh->first_segment];
-       set_tun_src(net, skb->dev, &hdr->daddr, &hdr->saddr);
+       set_tun_src(net, ip6_dst_idev(dst)->dev, &hdr->daddr, &hdr->saddr);
 
 #ifdef CONFIG_IPV6_SEG6_HMAC
        if (sr_has_hmac(isrh)) {
@@ -210,11 +212,6 @@ static int seg6_do_srh(struct sk_buff *skb)
 
        tinfo = seg6_encap_lwtunnel(dst->lwtstate);
 
-       if (likely(!skb->encapsulation)) {
-               skb_reset_inner_headers(skb);
-               skb->encapsulation = 1;
-       }
-
        switch (tinfo->mode) {
        case SEG6_IPTUN_MODE_INLINE:
                if (skb->protocol != htons(ETH_P_IPV6))
@@ -223,10 +220,12 @@ static int seg6_do_srh(struct sk_buff *skb)
                err = seg6_do_srh_inline(skb, tinfo->srh);
                if (err)
                        return err;
-
-               skb_reset_inner_headers(skb);
                break;
        case SEG6_IPTUN_MODE_ENCAP:
+               err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
+               if (err)
+                       return err;
+
                if (skb->protocol == htons(ETH_P_IPV6))
                        proto = IPPROTO_IPV6;
                else if (skb->protocol == htons(ETH_P_IP))
@@ -238,6 +237,8 @@ static int seg6_do_srh(struct sk_buff *skb)
                if (err)
                        return err;
 
+               skb_set_inner_transport_header(skb, skb_transport_offset(skb));
+               skb_set_inner_protocol(skb, skb->protocol);
                skb->protocol = htons(ETH_P_IPV6);
                break;
        case SEG6_IPTUN_MODE_L2ENCAP:
@@ -261,8 +262,6 @@ static int seg6_do_srh(struct sk_buff *skb)
        ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
-       skb_set_inner_protocol(skb, skb->protocol);
-
        return 0;
 }
 
@@ -418,7 +417,7 @@ static int seg6_build_state(struct nlattr *nla,
 
        slwt = seg6_lwt_lwtunnel(newts);
 
-       err = dst_cache_init(&slwt->cache, GFP_KERNEL);
+       err = dst_cache_init(&slwt->cache, GFP_ATOMIC);
        if (err) {
                kfree(newts);
                return err;
index 3873d38..0195598 100644 (file)
@@ -182,7 +182,7 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn)
 #ifdef CONFIG_IPV6_SIT_6RD
        struct ip_tunnel *t = netdev_priv(dev);
 
-       if (t->dev == sitn->fb_tunnel_dev) {
+       if (dev == sitn->fb_tunnel_dev) {
                ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0);
                t->ip6rd.relay_prefix = 0;
                t->ip6rd.prefixlen = 16;
@@ -1578,6 +1578,13 @@ static int ipip6_newlink(struct net *src_net, struct net_device *dev,
        if (err < 0)
                return err;
 
+       if (tb[IFLA_MTU]) {
+               u32 mtu = nla_get_u32(tb[IFLA_MTU]);
+
+               if (mtu >= IPV6_MIN_MTU && mtu <= 0xFFF8 - dev->hard_header_len)
+                       dev->mtu = mtu;
+       }
+
 #ifdef CONFIG_IPV6_SIT_6RD
        if (ipip6_netlink_6rd_parms(data, &ip6rd))
                err = ipip6_tunnel_update_6rd(nt, &ip6rd);
index e7a3a6b..e997141 100644 (file)
@@ -217,6 +217,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        treq->snt_isn = cookie;
        treq->ts_off = 0;
        treq->txhash = net_tx_rndhash();
+       if (IS_ENABLED(CONFIG_SMC))
+               ireq->smc_ok = 0;
 
        /*
         * We need to lookup the dst_entry to get the correct window size.
index bb935a3..de1b0b8 100644 (file)
@@ -92,7 +92,8 @@ static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
 
        skb_reset_network_header(skb);
        skb_mac_header_rebuild(skb);
-       eth_hdr(skb)->h_proto = skb->protocol;
+       if (skb->mac_len)
+               eth_hdr(skb)->h_proto = skb->protocol;
 
        err = 0;
 
index 8ae87d4..5959ce9 100644 (file)
@@ -82,7 +82,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
 
        if ((!skb_is_gso(skb) && skb->len > mtu) ||
            (skb_is_gso(skb) &&
-            skb_gso_network_seglen(skb) > ip6_skb_dst_mtu(skb))) {
+            !skb_gso_validate_network_len(skb, ip6_skb_dst_mtu(skb)))) {
                skb->dev = dst->dev;
                skb->protocol = htons(ETH_P_IPV6);
 
index 09fb44e..416fe67 100644 (file)
@@ -113,6 +113,9 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
        xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
        xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
        xdst->u.rt6.rt6i_src = rt->rt6i_src;
+       INIT_LIST_HEAD(&xdst->u.rt6.rt6i_uncached);
+       rt6_uncached_list_add(&xdst->u.rt6);
+       atomic_inc(&dev_net(dev)->ipv6.rt6_stats->fib_rt_uncache);
 
        return 0;
 }
@@ -244,6 +247,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
        if (likely(xdst->u.rt6.rt6i_idev))
                in6_dev_put(xdst->u.rt6.rt6i_idev);
        dst_destroy_metrics_generic(dst);
+       if (xdst->u.rt6.rt6i_uncached_list)
+               rt6_uncached_list_del(&xdst->u.rt6);
        xfrm_dst_destroy(xdst);
 }
 
index 1e8cc7b..9e2643a 100644 (file)
@@ -2433,9 +2433,11 @@ static int afiucv_iucv_init(void)
        af_iucv_dev->driver = &af_iucv_driver;
        err = device_register(af_iucv_dev);
        if (err)
-               goto out_driver;
+               goto out_iucv_dev;
        return 0;
 
+out_iucv_dev:
+       put_device(af_iucv_dev);
 out_driver:
        driver_unregister(&af_iucv_driver);
 out_iucv:
index f297d53..34355fd 100644 (file)
@@ -1381,24 +1381,32 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
                .parse_msg = kcm_parse_func_strparser,
                .read_sock_done = kcm_read_sock_done,
        };
-       int err;
+       int err = 0;
 
        csk = csock->sk;
        if (!csk)
                return -EINVAL;
 
+       lock_sock(csk);
+
        /* Only allow TCP sockets to be attached for now */
        if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) ||
-           csk->sk_protocol != IPPROTO_TCP)
-               return -EOPNOTSUPP;
+           csk->sk_protocol != IPPROTO_TCP) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
 
        /* Don't allow listeners or closed sockets */
-       if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE)
-               return -EOPNOTSUPP;
+       if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
 
        psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
-       if (!psock)
-               return -ENOMEM;
+       if (!psock) {
+               err = -ENOMEM;
+               goto out;
+       }
 
        psock->mux = mux;
        psock->sk = csk;
@@ -1407,7 +1415,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
        err = strp_init(&psock->strp, csk, &cb);
        if (err) {
                kmem_cache_free(kcm_psockp, psock);
-               return err;
+               goto out;
        }
 
        write_lock_bh(&csk->sk_callback_lock);
@@ -1419,7 +1427,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
                write_unlock_bh(&csk->sk_callback_lock);
                strp_done(&psock->strp);
                kmem_cache_free(kcm_psockp, psock);
-               return -EALREADY;
+               err = -EALREADY;
+               goto out;
        }
 
        psock->save_data_ready = csk->sk_data_ready;
@@ -1455,7 +1464,10 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
        /* Schedule RX work in case there are already bytes queued */
        strp_check_rcv(&psock->strp);
 
-       return 0;
+out:
+       release_sock(csk);
+
+       return err;
 }
 
 static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info)
@@ -1507,6 +1519,7 @@ static void kcm_unattach(struct kcm_psock *psock)
 
        if (WARN_ON(psock->rx_kcm)) {
                write_unlock_bh(&csk->sk_callback_lock);
+               release_sock(csk);
                return;
        }
 
index 194a748..14b67df 100644 (file)
@@ -111,6 +111,13 @@ struct l2tp_net {
        spinlock_t l2tp_session_hlist_lock;
 };
 
+#if IS_ENABLED(CONFIG_IPV6)
+static bool l2tp_sk_is_v6(struct sock *sk)
+{
+       return sk->sk_family == PF_INET6 &&
+              !ipv6_addr_v4mapped(&sk->sk_v6_daddr);
+}
+#endif
 
 static inline struct l2tp_tunnel *l2tp_tunnel(struct sock *sk)
 {
@@ -136,51 +143,6 @@ l2tp_session_id_hash_2(struct l2tp_net *pn, u32 session_id)
 
 }
 
-/* Lookup the tunnel socket, possibly involving the fs code if the socket is
- * owned by userspace.  A struct sock returned from this function must be
- * released using l2tp_tunnel_sock_put once you're done with it.
- */
-static struct sock *l2tp_tunnel_sock_lookup(struct l2tp_tunnel *tunnel)
-{
-       int err = 0;
-       struct socket *sock = NULL;
-       struct sock *sk = NULL;
-
-       if (!tunnel)
-               goto out;
-
-       if (tunnel->fd >= 0) {
-               /* Socket is owned by userspace, who might be in the process
-                * of closing it.  Look the socket up using the fd to ensure
-                * consistency.
-                */
-               sock = sockfd_lookup(tunnel->fd, &err);
-               if (sock)
-                       sk = sock->sk;
-       } else {
-               /* Socket is owned by kernelspace */
-               sk = tunnel->sock;
-               sock_hold(sk);
-       }
-
-out:
-       return sk;
-}
-
-/* Drop a reference to a tunnel socket obtained via. l2tp_tunnel_sock_put */
-static void l2tp_tunnel_sock_put(struct sock *sk)
-{
-       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
-       if (tunnel) {
-               if (tunnel->fd >= 0) {
-                       /* Socket is owned by userspace */
-                       sockfd_put(sk->sk_socket);
-               }
-               sock_put(sk);
-       }
-       sock_put(sk);
-}
-
 /* Session hash list.
  * The session_id SHOULD be random according to RFC2661, but several
  * L2TP implementations (Cisco and Microsoft) use incrementing
@@ -193,6 +155,13 @@ l2tp_session_id_hash(struct l2tp_tunnel *tunnel, u32 session_id)
        return &tunnel->session_hlist[hash_32(session_id, L2TP_HASH_BITS)];
 }
 
+void l2tp_tunnel_free(struct l2tp_tunnel *tunnel)
+{
+       sock_put(tunnel->sock);
+       /* the tunnel is freed in the socket destructor */
+}
+EXPORT_SYMBOL(l2tp_tunnel_free);
+
 /* Lookup a tunnel. A new reference is held on the returned tunnel. */
 struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
 {
@@ -345,13 +314,11 @@ int l2tp_session_register(struct l2tp_session *session,
                        }
 
                l2tp_tunnel_inc_refcount(tunnel);
-               sock_hold(tunnel->sock);
                hlist_add_head_rcu(&session->global_hlist, g_head);
 
                spin_unlock_bh(&pn->l2tp_session_hlist_lock);
        } else {
                l2tp_tunnel_inc_refcount(tunnel);
-               sock_hold(tunnel->sock);
        }
 
        hlist_add_head(&session->hlist, head);
@@ -969,7 +936,7 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
 {
        struct l2tp_tunnel *tunnel;
 
-       tunnel = l2tp_sock_to_tunnel(sk);
+       tunnel = l2tp_tunnel(sk);
        if (tunnel == NULL)
                goto pass_up;
 
@@ -977,13 +944,10 @@ int l2tp_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
                 tunnel->name, skb->len);
 
        if (l2tp_udp_recv_core(tunnel, skb, tunnel->recv_payload_hook))
-               goto pass_up_put;
+               goto pass_up;
 
-       sock_put(sk);
        return 0;
 
-pass_up_put:
-       sock_put(sk);
 pass_up:
        return 1;
 }
@@ -1092,7 +1056,7 @@ static int l2tp_xmit_core(struct l2tp_session *session, struct sk_buff *skb,
        /* Queue the packet to IP for output */
        skb->ignore_df = 1;
 #if IS_ENABLED(CONFIG_IPV6)
-       if (tunnel->sock->sk_family == PF_INET6 && !tunnel->v4mapped)
+       if (l2tp_sk_is_v6(tunnel->sock))
                error = inet6_csk_xmit(tunnel->sock, skb, NULL);
        else
 #endif
@@ -1155,6 +1119,15 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
                goto out_unlock;
        }
 
+       /* The user-space may change the connection status for the user-space
+        * provided socket at run time: we must check it under the socket lock
+        */
+       if (tunnel->fd >= 0 && sk->sk_state != TCP_ESTABLISHED) {
+               kfree_skb(skb);
+               ret = NET_XMIT_DROP;
+               goto out_unlock;
+       }
+
        /* Get routing info from the tunnel socket */
        skb_dst_drop(skb);
        skb_dst_set(skb, dst_clone(__sk_dst_check(sk, 0)));
@@ -1174,7 +1147,7 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len
 
                /* Calculate UDP checksum if configured to do so */
 #if IS_ENABLED(CONFIG_IPV6)
-               if (sk->sk_family == PF_INET6 && !tunnel->v4mapped)
+               if (l2tp_sk_is_v6(sk))
                        udp6_set_csum(udp_get_no_check6_tx(sk),
                                      skb, &inet6_sk(sk)->saddr,
                                      &sk->sk_v6_daddr, udp_len);
@@ -1207,14 +1180,12 @@ EXPORT_SYMBOL_GPL(l2tp_xmit_skb);
 static void l2tp_tunnel_destruct(struct sock *sk)
 {
        struct l2tp_tunnel *tunnel = l2tp_tunnel(sk);
-       struct l2tp_net *pn;
 
        if (tunnel == NULL)
                goto end;
 
        l2tp_info(tunnel, L2TP_MSG_CONTROL, "%s: closing...\n", tunnel->name);
 
-
        /* Disable udp encapsulation */
        switch (tunnel->encap) {
        case L2TP_ENCAPTYPE_UDP:
@@ -1231,18 +1202,11 @@ static void l2tp_tunnel_destruct(struct sock *sk)
        sk->sk_destruct = tunnel->old_sk_destruct;
        sk->sk_user_data = NULL;
 
-       /* Remove the tunnel struct from the tunnel list */
-       pn = l2tp_pernet(tunnel->l2tp_net);
-       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
-       list_del_rcu(&tunnel->list);
-       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
-
-       tunnel->sock = NULL;
-       l2tp_tunnel_dec_refcount(tunnel);
-
        /* Call the original destructor */
        if (sk->sk_destruct)
                (*sk->sk_destruct)(sk);
+
+       kfree_rcu(tunnel, rcu);
 end:
        return;
 }
@@ -1303,49 +1267,43 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_closeall);
 /* Tunnel socket destroy hook for UDP encapsulation */
 static void l2tp_udp_encap_destroy(struct sock *sk)
 {
-       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
-       if (tunnel) {
-               l2tp_tunnel_closeall(tunnel);
-               sock_put(sk);
-       }
+       struct l2tp_tunnel *tunnel = l2tp_tunnel(sk);
+
+       if (tunnel)
+               l2tp_tunnel_delete(tunnel);
 }
 
 /* Workqueue tunnel deletion function */
 static void l2tp_tunnel_del_work(struct work_struct *work)
 {
-       struct l2tp_tunnel *tunnel = NULL;
-       struct socket *sock = NULL;
-       struct sock *sk = NULL;
-
-       tunnel = container_of(work, struct l2tp_tunnel, del_work);
+       struct l2tp_tunnel *tunnel = container_of(work, struct l2tp_tunnel,
+                                                 del_work);
+       struct sock *sk = tunnel->sock;
+       struct socket *sock = sk->sk_socket;
+       struct l2tp_net *pn;
 
        l2tp_tunnel_closeall(tunnel);
 
-       sk = l2tp_tunnel_sock_lookup(tunnel);
-       if (!sk)
-               goto out;
-
-       sock = sk->sk_socket;
-
-       /* If the tunnel socket was created by userspace, then go through the
-        * inet layer to shut the socket down, and let userspace close it.
-        * Otherwise, if we created the socket directly within the kernel, use
+       /* If the tunnel socket was created within the kernel, use
         * the sk API to release it here.
-        * In either case the tunnel resources are freed in the socket
-        * destructor when the tunnel socket goes away.
         */
-       if (tunnel->fd >= 0) {
-               if (sock)
-                       inet_shutdown(sock, 2);
-       } else {
+       if (tunnel->fd < 0) {
                if (sock) {
                        kernel_sock_shutdown(sock, SHUT_RDWR);
                        sock_release(sock);
                }
        }
 
-       l2tp_tunnel_sock_put(sk);
-out:
+       /* Remove the tunnel struct from the tunnel list */
+       pn = l2tp_pernet(tunnel->l2tp_net);
+       spin_lock_bh(&pn->l2tp_tunnel_list_lock);
+       list_del_rcu(&tunnel->list);
+       spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
+
+       /* drop initial ref */
+       l2tp_tunnel_dec_refcount(tunnel);
+
+       /* drop workqueue ref */
        l2tp_tunnel_dec_refcount(tunnel);
 }
 
@@ -1515,9 +1473,14 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                encap = cfg->encap;
 
        /* Quick sanity checks */
+       err = -EPROTONOSUPPORT;
+       if (sk->sk_type != SOCK_DGRAM) {
+               pr_debug("tunl %hu: fd %d wrong socket type\n",
+                        tunnel_id, fd);
+               goto err;
+       }
        switch (encap) {
        case L2TP_ENCAPTYPE_UDP:
-               err = -EPROTONOSUPPORT;
                if (sk->sk_protocol != IPPROTO_UDP) {
                        pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
                               tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP);
@@ -1525,7 +1488,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                }
                break;
        case L2TP_ENCAPTYPE_IP:
-               err = -EPROTONOSUPPORT;
                if (sk->sk_protocol != IPPROTO_L2TP) {
                        pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n",
                               tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP);
@@ -1565,24 +1527,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
        if (cfg != NULL)
                tunnel->debug = cfg->debug;
 
-#if IS_ENABLED(CONFIG_IPV6)
-       if (sk->sk_family == PF_INET6) {
-               struct ipv6_pinfo *np = inet6_sk(sk);
-
-               if (ipv6_addr_v4mapped(&np->saddr) &&
-                   ipv6_addr_v4mapped(&sk->sk_v6_daddr)) {
-                       struct inet_sock *inet = inet_sk(sk);
-
-                       tunnel->v4mapped = true;
-                       inet->inet_saddr = np->saddr.s6_addr32[3];
-                       inet->inet_rcv_saddr = sk->sk_v6_rcv_saddr.s6_addr32[3];
-                       inet->inet_daddr = sk->sk_v6_daddr.s6_addr32[3];
-               } else {
-                       tunnel->v4mapped = false;
-               }
-       }
-#endif
-
        /* Mark socket as an encapsulation socket. See net/ipv4/udp.c */
        tunnel->encap = encap;
        if (encap == L2TP_ENCAPTYPE_UDP) {
@@ -1598,13 +1542,22 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
                sk->sk_user_data = tunnel;
        }
 
+       /* Bump the reference count. The tunnel context is deleted
+        * only when this drops to zero. A reference is also held on
+        * the tunnel socket to ensure that it is not released while
+        * the tunnel is extant. Must be done before sk_destruct is
+        * set.
+        */
+       refcount_set(&tunnel->ref_count, 1);
+       sock_hold(sk);
+       tunnel->sock = sk;
+       tunnel->fd = fd;
+
        /* Hook on the tunnel socket destructor so that we can cleanup
         * if the tunnel socket goes away.
         */
        tunnel->old_sk_destruct = sk->sk_destruct;
        sk->sk_destruct = &l2tp_tunnel_destruct;
-       tunnel->sock = sk;
-       tunnel->fd = fd;
        lockdep_set_class_and_name(&sk->sk_lock.slock, &l2tp_socket_class, "l2tp_sock");
 
        sk->sk_allocation = GFP_ATOMIC;
@@ -1614,11 +1567,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32
 
        /* Add tunnel to our list */
        INIT_LIST_HEAD(&tunnel->list);
-
-       /* Bump the reference count. The tunnel context is deleted
-        * only when this drops to zero. Must be done before list insertion
-        */
-       refcount_set(&tunnel->ref_count, 1);
        spin_lock_bh(&pn->l2tp_tunnel_list_lock);
        list_add_rcu(&tunnel->list, &pn->l2tp_tunnel_list);
        spin_unlock_bh(&pn->l2tp_tunnel_list_lock);
@@ -1659,8 +1607,6 @@ void l2tp_session_free(struct l2tp_session *session)
 
        if (tunnel) {
                BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-               sock_put(tunnel->sock);
-               session->tunnel = NULL;
                l2tp_tunnel_dec_refcount(tunnel);
        }
 
index 9bbee90..2718d0b 100644 (file)
@@ -188,9 +188,6 @@ struct l2tp_tunnel {
        struct sock             *sock;          /* Parent socket */
        int                     fd;             /* Parent fd, if tunnel socket
                                                 * was created by userspace */
-#if IS_ENABLED(CONFIG_IPV6)
-       bool                    v4mapped;
-#endif
 
        struct work_struct      del_work;
 
@@ -214,27 +211,8 @@ static inline void *l2tp_session_priv(struct l2tp_session *session)
        return &session->priv[0];
 }
 
-static inline struct l2tp_tunnel *l2tp_sock_to_tunnel(struct sock *sk)
-{
-       struct l2tp_tunnel *tunnel;
-
-       if (sk == NULL)
-               return NULL;
-
-       sock_hold(sk);
-       tunnel = (struct l2tp_tunnel *)(sk->sk_user_data);
-       if (tunnel == NULL) {
-               sock_put(sk);
-               goto out;
-       }
-
-       BUG_ON(tunnel->magic != L2TP_TUNNEL_MAGIC);
-
-out:
-       return tunnel;
-}
-
 struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id);
+void l2tp_tunnel_free(struct l2tp_tunnel *tunnel);
 
 struct l2tp_session *l2tp_session_get(const struct net *net,
                                      struct l2tp_tunnel *tunnel,
@@ -283,7 +261,7 @@ static inline void l2tp_tunnel_inc_refcount(struct l2tp_tunnel *tunnel)
 static inline void l2tp_tunnel_dec_refcount(struct l2tp_tunnel *tunnel)
 {
        if (refcount_dec_and_test(&tunnel->ref_count))
-               kfree_rcu(tunnel, rcu);
+               l2tp_tunnel_free(tunnel);
 }
 
 /* Session reference counts. Incremented when code obtains a reference
index ff61124..3428fba 100644 (file)
@@ -234,17 +234,13 @@ static void l2tp_ip_close(struct sock *sk, long timeout)
 static void l2tp_ip_destroy_sock(struct sock *sk)
 {
        struct sk_buff *skb;
-       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
+       struct l2tp_tunnel *tunnel = sk->sk_user_data;
 
        while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
                kfree_skb(skb);
 
-       if (tunnel) {
-               l2tp_tunnel_closeall(tunnel);
-               sock_put(sk);
-       }
-
-       sk_refcnt_debug_dec(sk);
+       if (tunnel)
+               l2tp_tunnel_delete(tunnel);
 }
 
 static int l2tp_ip_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
index 1923446..6f009ea 100644 (file)
@@ -248,16 +248,14 @@ static void l2tp_ip6_close(struct sock *sk, long timeout)
 
 static void l2tp_ip6_destroy_sock(struct sock *sk)
 {
-       struct l2tp_tunnel *tunnel = l2tp_sock_to_tunnel(sk);
+       struct l2tp_tunnel *tunnel = sk->sk_user_data;
 
        lock_sock(sk);
        ip6_flush_pending_frames(sk);
        release_sock(sk);
 
-       if (tunnel) {
-               l2tp_tunnel_closeall(tunnel);
-               sock_put(sk);
-       }
+       if (tunnel)
+               l2tp_tunnel_delete(tunnel);
 
        inet6_destroy_sock(sk);
 }
index 59f246d..3b02f24 100644 (file)
@@ -416,20 +416,28 @@ abort:
  * Session (and tunnel control) socket create/destroy.
  *****************************************************************************/
 
+static void pppol2tp_put_sk(struct rcu_head *head)
+{
+       struct pppol2tp_session *ps;
+
+       ps = container_of(head, typeof(*ps), rcu);
+       sock_put(ps->__sk);
+}
+
 /* Called by l2tp_core when a session socket is being closed.
  */
 static void pppol2tp_session_close(struct l2tp_session *session)
 {
-       struct sock *sk;
-
-       BUG_ON(session->magic != L2TP_SESSION_MAGIC);
+       struct pppol2tp_session *ps;
 
-       sk = pppol2tp_session_get_sock(session);
-       if (sk) {
-               if (sk->sk_socket)
-                       inet_shutdown(sk->sk_socket, SEND_SHUTDOWN);
-               sock_put(sk);
-       }
+       ps = l2tp_session_priv(session);
+       mutex_lock(&ps->sk_lock);
+       ps->__sk = rcu_dereference_protected(ps->sk,
+                                            lockdep_is_held(&ps->sk_lock));
+       RCU_INIT_POINTER(ps->sk, NULL);
+       if (ps->__sk)
+               call_rcu(&ps->rcu, pppol2tp_put_sk);
+       mutex_unlock(&ps->sk_lock);
 }
 
 /* Really kill the session socket. (Called from sock_put() if
@@ -449,14 +457,6 @@ static void pppol2tp_session_destruct(struct sock *sk)
        }
 }
 
-static void pppol2tp_put_sk(struct rcu_head *head)
-{
-       struct pppol2tp_session *ps;
-
-       ps = container_of(head, typeof(*ps), rcu);
-       sock_put(ps->__sk);
-}
-
 /* Called when the PPPoX socket (session) is closed.
  */
 static int pppol2tp_release(struct socket *sock)
@@ -480,26 +480,17 @@ static int pppol2tp_release(struct socket *sock)
        sock_orphan(sk);
        sock->sk = NULL;
 
+       /* If the socket is associated with a session,
+        * l2tp_session_delete will call pppol2tp_session_close which
+        * will drop the session's ref on the socket.
+        */
        session = pppol2tp_sock_to_session(sk);
-
-       if (session != NULL) {
-               struct pppol2tp_session *ps;
-
+       if (session) {
                l2tp_session_delete(session);
-
-               ps = l2tp_session_priv(session);
-               mutex_lock(&ps->sk_lock);
-               ps->__sk = rcu_dereference_protected(ps->sk,
-                                                    lockdep_is_held(&ps->sk_lock));
-               RCU_INIT_POINTER(ps->sk, NULL);
-               mutex_unlock(&ps->sk_lock);
-               call_rcu(&ps->rcu, pppol2tp_put_sk);
-
-               /* Rely on the sock_put() call at the end of the function for
-                * dropping the reference held by pppol2tp_sock_to_session().
-                * The last reference will be dropped by pppol2tp_put_sk().
-                */
+               /* drop the ref obtained by pppol2tp_sock_to_session */
+               sock_put(sk);
        }
+
        release_sock(sk);
 
        /* This will delete the session context via
@@ -796,6 +787,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
 
 out_no_ppp:
        /* This is how we get the session context from the socket. */
+       sock_hold(sk);
        sk->sk_user_data = session;
        rcu_assign_pointer(ps->sk, sk);
        mutex_unlock(&ps->sk_lock);
index f596480..1631211 100644 (file)
@@ -389,7 +389,7 @@ static int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
        llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
        rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
        if (likely(!rc)) {
-               llc_conn_send_pdu(sk, skb);
+               rc = llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
        return rc;
@@ -916,7 +916,7 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
        llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR);
        rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
        if (likely(!rc)) {
-               llc_conn_send_pdu(sk, skb);
+               rc = llc_conn_send_pdu(sk, skb);
                llc_conn_ac_inc_vs_by_1(sk, skb);
        }
        return rc;
@@ -935,14 +935,17 @@ static int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk,
 int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
 {
        struct llc_sock *llc = llc_sk(sk);
+       int ret;
 
        if (llc->ack_must_be_send) {
-               llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
+               ret = llc_conn_ac_send_i_rsp_f_set_ackpf(sk, skb);
                llc->ack_must_be_send = 0 ;
                llc->ack_pf = 0;
-       } else
-               llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
-       return 0;
+       } else {
+               ret = llc_conn_ac_send_i_cmd_p_set_0(sk, skb);
+       }
+
+       return ret;
 }
 
 /**
index 9177dbb..110e32b 100644 (file)
@@ -30,7 +30,7 @@
 #endif
 
 static int llc_find_offset(int state, int ev_type);
-static void llc_conn_send_pdus(struct sock *sk);
+static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *skb);
 static int llc_conn_service(struct sock *sk, struct sk_buff *skb);
 static int llc_exec_conn_trans_actions(struct sock *sk,
                                       struct llc_conn_state_trans *trans,
@@ -193,11 +193,11 @@ out_skb_put:
        return rc;
 }
 
-void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
+int llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
 {
        /* queue PDU to send to MAC layer */
        skb_queue_tail(&sk->sk_write_queue, skb);
-       llc_conn_send_pdus(sk);
+       return llc_conn_send_pdus(sk, skb);
 }
 
 /**
@@ -255,7 +255,7 @@ void llc_conn_resend_i_pdu_as_cmd(struct sock *sk, u8 nr, u8 first_p_bit)
        if (howmany_resend > 0)
                llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
        /* any PDUs to re-send are queued up; start sending to MAC */
-       llc_conn_send_pdus(sk);
+       llc_conn_send_pdus(sk, NULL);
 out:;
 }
 
@@ -296,7 +296,7 @@ void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit)
        if (howmany_resend > 0)
                llc->vS = (llc->vS + 1) % LLC_2_SEQ_NBR_MODULO;
        /* any PDUs to re-send are queued up; start sending to MAC */
-       llc_conn_send_pdus(sk);
+       llc_conn_send_pdus(sk, NULL);
 out:;
 }
 
@@ -340,12 +340,16 @@ out:
 /**
  *     llc_conn_send_pdus - Sends queued PDUs
  *     @sk: active connection
+ *     @hold_skb: the skb held by caller, or NULL if does not care
  *
- *     Sends queued pdus to MAC layer for transmission.
+ *     Sends queued pdus to MAC layer for transmission. When @hold_skb is
+ *     NULL, always return 0. Otherwise, return 0 if @hold_skb is sent
+ *     successfully, or 1 for failure.
  */
-static void llc_conn_send_pdus(struct sock *sk)
+static int llc_conn_send_pdus(struct sock *sk, struct sk_buff *hold_skb)
 {
        struct sk_buff *skb;
+       int ret = 0;
 
        while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) {
                struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
@@ -357,10 +361,20 @@ static void llc_conn_send_pdus(struct sock *sk)
                        skb_queue_tail(&llc_sk(sk)->pdu_unack_q, skb);
                        if (!skb2)
                                break;
-                       skb = skb2;
+                       dev_queue_xmit(skb2);
+               } else {
+                       bool is_target = skb == hold_skb;
+                       int rc;
+
+                       if (is_target)
+                               skb_get(skb);
+                       rc = dev_queue_xmit(skb);
+                       if (is_target)
+                               ret = rc;
                }
-               dev_queue_xmit(skb);
        }
+
+       return ret;
 }
 
 /**
index a8b1616..1f3188d 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
+ * Copyright (C) 2018        Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -304,9 +305,6 @@ void ___ieee80211_start_rx_ba_session(struct sta_info *sta,
                         * driver so reject the timeout update.
                         */
                        status = WLAN_STATUS_REQUEST_DECLINED;
-                       ieee80211_send_addba_resp(sta->sdata, sta->sta.addr,
-                                                 tid, dialog_token, status,
-                                                 1, buf_size, timeout);
                        goto end;
                }
 
index 46028e1..f4195a0 100644 (file)
@@ -2892,7 +2892,7 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon)
        }
        if (beacon->probe_resp_len) {
                new_beacon->probe_resp_len = beacon->probe_resp_len;
-               beacon->probe_resp = pos;
+               new_beacon->probe_resp = pos;
                memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
                pos += beacon->probe_resp_len;
        }
index 1f466d1..94c7ee9 100644 (file)
@@ -212,6 +212,7 @@ static const char *hw_flag_names[] = {
        FLAG(REPORTS_LOW_ACK),
        FLAG(SUPPORTS_TX_FRAG),
        FLAG(SUPPORTS_TDLS_BUFFER_STA),
+       FLAG(DOESNT_SUPPORT_QOS_NDP),
 #undef FLAG
 };
 
index 2690002..ae9c33c 100644 (file)
@@ -1467,7 +1467,7 @@ struct ieee802_11_elems {
        const struct ieee80211_timeout_interval_ie *timeout_int;
        const u8 *opmode_notif;
        const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
-       const struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
+       struct ieee80211_mesh_chansw_params_ie *mesh_chansw_params_ie;
        const struct ieee80211_bss_max_idle_period_ie *max_idle_period_ie;
 
        /* length of them, respectively */
index 73ac607..6a381cb 100644 (file)
@@ -1255,13 +1255,12 @@ int ieee80211_mesh_csa_beacon(struct ieee80211_sub_if_data *sdata,
 }
 
 static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
-                              struct ieee80211_mgmt *mgmt, size_t len)
+                              struct ieee80211_mgmt *mgmt, size_t len,
+                              struct ieee802_11_elems *elems)
 {
        struct ieee80211_mgmt *mgmt_fwd;
        struct sk_buff *skb;
        struct ieee80211_local *local = sdata->local;
-       u8 *pos = mgmt->u.action.u.chan_switch.variable;
-       size_t offset_ttl;
 
        skb = dev_alloc_skb(local->tx_headroom + len);
        if (!skb)
@@ -1269,13 +1268,9 @@ static int mesh_fwd_csa_frame(struct ieee80211_sub_if_data *sdata,
        skb_reserve(skb, local->tx_headroom);
        mgmt_fwd = skb_put(skb, len);
 
-       /* offset_ttl is based on whether the secondary channel
-        * offset is available or not. Subtract 1 from the mesh TTL
-        * and disable the initiator flag before forwarding.
-        */
-       offset_ttl = (len < 42) ? 7 : 10;
-       *(pos + offset_ttl) -= 1;
-       *(pos + offset_ttl + 1) &= ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
+       elems->mesh_chansw_params_ie->mesh_ttl--;
+       elems->mesh_chansw_params_ie->mesh_flags &=
+               ~WLAN_EID_CHAN_SWITCH_PARAM_INITIATOR;
 
        memcpy(mgmt_fwd, mgmt, len);
        eth_broadcast_addr(mgmt_fwd->da);
@@ -1323,7 +1318,7 @@ static void mesh_rx_csa_frame(struct ieee80211_sub_if_data *sdata,
 
        /* forward or re-broadcast the CSA frame */
        if (fwd_csa) {
-               if (mesh_fwd_csa_frame(sdata, mgmt, len) < 0)
+               if (mesh_fwd_csa_frame(sdata, mgmt, len, &elems) < 0)
                        mcsa_dbg(sdata, "Failed to forward the CSA frame");
        }
 }
index 39b660b..5f303ab 100644 (file)
@@ -896,7 +896,8 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        struct ieee80211_hdr_3addr *nullfunc;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, true);
+       skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif,
+               !ieee80211_hw_check(&local->hw, DOESNT_SUPPORT_QOS_NDP));
        if (!skb)
                return;
 
index fd58061..56fe16b 100644 (file)
@@ -3921,7 +3921,7 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
        if ((hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_FROMDS |
                                              IEEE80211_FCTL_TODS)) !=
            fast_rx->expected_ds_bits)
-               goto drop;
+               return false;
 
        /* assign the key to drop unencrypted frames (later)
         * and strip the IV/MIC if necessary
index ee01817..0293348 100644 (file)
@@ -8,6 +8,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2008, Intel Corporation
  * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (C) 2018        Intel Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -27,7 +28,7 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
                                 u32 sta_flags, u8 *bssid,
                                 struct ieee80211_csa_ie *csa_ie)
 {
-       enum nl80211_band new_band;
+       enum nl80211_band new_band = current_band;
        int new_freq;
        u8 new_chan_no;
        struct ieee80211_channel *new_chan;
@@ -55,15 +56,13 @@ int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
                                elems->ext_chansw_ie->new_operating_class,
                                &new_band)) {
                        sdata_info(sdata,
-                                  "cannot understand ECSA IE operating class %d, disconnecting\n",
+                                  "cannot understand ECSA IE operating class, %d, ignoring\n",
                                   elems->ext_chansw_ie->new_operating_class);
-                       return -EINVAL;
                }
                new_chan_no = elems->ext_chansw_ie->new_ch_num;
                csa_ie->count = elems->ext_chansw_ie->count;
                csa_ie->mode = elems->ext_chansw_ie->mode;
        } else if (elems->ch_switch_ie) {
-               new_band = current_band;
                new_chan_no = elems->ch_switch_ie->new_ch_num;
                csa_ie->count = elems->ch_switch_ie->count;
                csa_ie->mode = elems->ch_switch_ie->mode;
index 0c5627f..af0b608 100644 (file)
@@ -314,7 +314,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 
        if (ieee80211_hw_check(hw, USES_RSS)) {
                sta->pcpu_rx_stats =
-                       alloc_percpu(struct ieee80211_sta_rx_stats);
+                       alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp);
                if (!sta->pcpu_rx_stats)
                        goto free;
        }
@@ -433,6 +433,7 @@ free_txq:
        if (sta->sta.txq[0])
                kfree(to_txq_info(sta->sta.txq[0]));
 free:
+       free_percpu(sta->pcpu_rx_stats);
 #ifdef CONFIG_MAC80211_MESH
        kfree(sta->mesh);
 #endif
index 25904af..6972250 100644 (file)
@@ -3574,6 +3574,14 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (!IS_ERR_OR_NULL(sta)) {
                struct ieee80211_fast_tx *fast_tx;
 
+               /* We need a bit of data queued to build aggregates properly, so
+                * instruct the TCP stack to allow more than a single ms of data
+                * to be queued in the stack. The value is a bit-shift of 1
+                * second, so 8 is ~4ms of queued data. Only affects local TCP
+                * sockets.
+                */
+               sk_pacing_shift_update(skb->sk, 8);
+
                fast_tx = rcu_dereference(sta->fast_tx);
 
                if (fast_tx &&
index e545a3c..7a4de6d 100644 (file)
@@ -122,7 +122,7 @@ bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu)
        if (skb->len <= mtu)
                return false;
 
-       if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+       if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                return false;
 
        return true;
index 3e17d32..58d5d05 100644 (file)
@@ -260,7 +260,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
                buf_len = strlen(buf);
 
                ct = nf_ct_get(skb, &ctinfo);
-               if (ct && (ct->status & IPS_NAT_MASK)) {
+               if (ct) {
                        bool mangled;
 
                        /* If mangling fails this function will return 0
index fbce552..7d7466d 100644 (file)
@@ -41,7 +41,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
                                 const struct nf_conn *ct,
                                 u16 *rover)
 {
-       unsigned int range_size, min, i;
+       unsigned int range_size, min, max, i;
        __be16 *portptr;
        u_int16_t off;
 
@@ -71,7 +71,10 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto,
                }
        } else {
                min = ntohs(range->min_proto.all);
-               range_size = ntohs(range->max_proto.all) - min + 1;
+               max = ntohs(range->max_proto.all);
+               if (unlikely(max < min))
+                       swap(max, min);
+               range_size = max - min + 1;
        }
 
        if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) {
index 8b9fe30..530e12a 100644 (file)
@@ -74,15 +74,77 @@ static void nft_trans_destroy(struct nft_trans *trans)
        kfree(trans);
 }
 
+/* removal requests are queued in the commit_list, but not acted upon
+ * until after all new rules are in place.
+ *
+ * Therefore, nf_register_net_hook(net, &nat_hook) runs before pending
+ * nf_unregister_net_hook().
+ *
+ * nf_register_net_hook thus fails if a nat hook is already in place
+ * even if the conflicting hook is about to be removed.
+ *
+ * If collision is detected, search commit_log for DELCHAIN matching
+ * the new nat hooknum; if we find one collision is temporary:
+ *
+ * Either transaction is aborted (new/colliding hook is removed), or
+ * transaction is committed (old hook is removed).
+ */
+static bool nf_tables_allow_nat_conflict(const struct net *net,
+                                        const struct nf_hook_ops *ops)
+{
+       const struct nft_trans *trans;
+       bool ret = false;
+
+       if (!ops->nat_hook)
+               return false;
+
+       list_for_each_entry(trans, &net->nft.commit_list, list) {
+               const struct nf_hook_ops *pending_ops;
+               const struct nft_chain *pending;
+
+               if (trans->msg_type != NFT_MSG_NEWCHAIN &&
+                   trans->msg_type != NFT_MSG_DELCHAIN)
+                       continue;
+
+               pending = trans->ctx.chain;
+               if (!nft_is_base_chain(pending))
+                       continue;
+
+               pending_ops = &nft_base_chain(pending)->ops;
+               if (pending_ops->nat_hook &&
+                   pending_ops->pf == ops->pf &&
+                   pending_ops->hooknum == ops->hooknum) {
+                       /* other hook registration already pending? */
+                       if (trans->msg_type == NFT_MSG_NEWCHAIN)
+                               return false;
+
+                       ret = true;
+               }
+       }
+
+       return ret;
+}
+
 static int nf_tables_register_hook(struct net *net,
                                   const struct nft_table *table,
                                   struct nft_chain *chain)
 {
+       struct nf_hook_ops *ops;
+       int ret;
+
        if (table->flags & NFT_TABLE_F_DORMANT ||
            !nft_is_base_chain(chain))
                return 0;
 
-       return nf_register_net_hook(net, &nft_base_chain(chain)->ops);
+       ops = &nft_base_chain(chain)->ops;
+       ret = nf_register_net_hook(net, ops);
+       if (ret == -EBUSY && nf_tables_allow_nat_conflict(net, ops)) {
+               ops->nat_hook = false;
+               ret = nf_register_net_hook(net, ops);
+               ops->nat_hook = true;
+       }
+
+       return ret;
 }
 
 static void nf_tables_unregister_hook(struct net *net,
@@ -1226,8 +1288,6 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
                free_percpu(basechain->stats);
                if (basechain->stats)
                        static_branch_dec(&nft_counters_enabled);
-               if (basechain->ops.dev != NULL)
-                       dev_put(basechain->ops.dev);
                kfree(chain->name);
                kfree(basechain);
        } else {
@@ -1294,7 +1354,7 @@ static int nft_chain_parse_hook(struct net *net,
                }
 
                nla_strlcpy(ifname, ha[NFTA_HOOK_DEV], IFNAMSIZ);
-               dev = dev_get_by_name(net, ifname);
+               dev = __dev_get_by_name(net, ifname);
                if (!dev) {
                        module_put(type->owner);
                        return -ENOENT;
@@ -1311,8 +1371,6 @@ static int nft_chain_parse_hook(struct net *net,
 static void nft_chain_release_hook(struct nft_chain_hook *hook)
 {
        module_put(hook->type->owner);
-       if (hook->dev != NULL)
-               dev_put(hook->dev);
 }
 
 static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
@@ -1911,6 +1969,7 @@ static const struct nla_policy nft_rule_policy[NFTA_RULE_MAX + 1] = {
        [NFTA_RULE_POSITION]    = { .type = NLA_U64 },
        [NFTA_RULE_USERDATA]    = { .type = NLA_BINARY,
                                    .len = NFT_USERDATA_MAXLEN },
+       [NFTA_RULE_ID]          = { .type = NLA_U32 },
 };
 
 static int nf_tables_fill_rule_info(struct sk_buff *skb, struct net *net,
@@ -2446,6 +2505,9 @@ EXPORT_SYMBOL_GPL(nft_unregister_set);
 
 static bool nft_set_ops_candidate(const struct nft_set_ops *ops, u32 flags)
 {
+       if ((flags & NFT_SET_EVAL) && !ops->update)
+               return false;
+
        return (flags & ops->features) == (flags & NFT_SET_FEATURES);
 }
 
@@ -2510,7 +2572,7 @@ nft_select_set_ops(const struct nft_ctx *ctx,
                                if (est.space == best.space &&
                                    est.lookup < best.lookup)
                                        break;
-                       } else if (est.size < best.size) {
+                       } else if (est.size < best.size || !bops) {
                                break;
                        }
                        continue;
@@ -3315,6 +3377,8 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
        [NFTA_SET_ELEM_TIMEOUT]         = { .type = NLA_U64 },
        [NFTA_SET_ELEM_USERDATA]        = { .type = NLA_BINARY,
                                            .len = NFT_USERDATA_MAXLEN },
+       [NFTA_SET_ELEM_EXPR]            = { .type = NLA_NESTED },
+       [NFTA_SET_ELEM_OBJREF]          = { .type = NLA_STRING },
 };
 
 static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
@@ -4864,8 +4928,6 @@ nf_tables_flowtable_lookup_byhandle(const struct nft_table *table,
        return ERR_PTR(-ENOENT);
 }
 
-#define NFT_FLOWTABLE_DEVICE_MAX       8
-
 static int nf_tables_parse_devices(const struct nft_ctx *ctx,
                                   const struct nlattr *attr,
                                   struct net_device *dev_array[], int *len)
@@ -4882,7 +4944,7 @@ static int nf_tables_parse_devices(const struct nft_ctx *ctx,
                }
 
                nla_strlcpy(ifname, tmp, IFNAMSIZ);
-               dev = dev_get_by_name(ctx->net, ifname);
+               dev = __dev_get_by_name(ctx->net, ifname);
                if (!dev) {
                        err = -ENOENT;
                        goto err1;
@@ -4938,13 +5000,11 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
        err = nf_tables_parse_devices(ctx, tb[NFTA_FLOWTABLE_HOOK_DEVS],
                                      dev_array, &n);
        if (err < 0)
-               goto err1;
+               return err;
 
        ops = kzalloc(sizeof(struct nf_hook_ops) * n, GFP_KERNEL);
-       if (!ops) {
-               err = -ENOMEM;
-               goto err1;
-       }
+       if (!ops)
+               return -ENOMEM;
 
        flowtable->hooknum      = hooknum;
        flowtable->priority     = priority;
@@ -4958,13 +5018,10 @@ static int nf_tables_flowtable_parse_hook(const struct nft_ctx *ctx,
                flowtable->ops[i].priv          = &flowtable->data.rhashtable;
                flowtable->ops[i].hook          = flowtable->data.type->hook;
                flowtable->ops[i].dev           = dev_array[i];
+               flowtable->dev_name[i]          = kstrdup(dev_array[i]->name,
+                                                         GFP_KERNEL);
        }
 
-       err = 0;
-err1:
-       for (i = 0; i < n; i++)
-               dev_put(dev_array[i]);
-
        return err;
 }
 
@@ -5037,9 +5094,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
 {
        const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
        const struct nf_flowtable_type *type;
+       struct nft_flowtable *flowtable, *ft;
        u8 genmask = nft_genmask_next(net);
        int family = nfmsg->nfgen_family;
-       struct nft_flowtable *flowtable;
        struct nft_table *table;
        struct nft_ctx ctx;
        int err, i, k;
@@ -5099,6 +5156,22 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
                goto err3;
 
        for (i = 0; i < flowtable->ops_len; i++) {
+               if (!flowtable->ops[i].dev)
+                       continue;
+
+               list_for_each_entry(ft, &table->flowtables, list) {
+                       for (k = 0; k < ft->ops_len; k++) {
+                               if (!ft->ops[k].dev)
+                                       continue;
+
+                               if (flowtable->ops[i].dev == ft->ops[k].dev &&
+                                   flowtable->ops[i].pf == ft->ops[k].pf) {
+                                       err = -EBUSY;
+                                       goto err4;
+                               }
+                       }
+               }
+
                err = nf_register_net_hook(net, &flowtable->ops[i]);
                if (err < 0)
                        goto err4;
@@ -5119,8 +5192,10 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
 err5:
        i = flowtable->ops_len;
 err4:
-       for (k = i - 1; k >= 0; k--)
-               nf_unregister_net_hook(net, &flowtable->ops[i]);
+       for (k = i - 1; k >= 0; k--) {
+               kfree(flowtable->dev_name[k]);
+               nf_unregister_net_hook(net, &flowtable->ops[k]);
+       }
 
        kfree(flowtable->ops);
 err3:
@@ -5145,6 +5220,11 @@ static int nf_tables_delflowtable(struct net *net, struct sock *nlsk,
        struct nft_table *table;
        struct nft_ctx ctx;
 
+       if (!nla[NFTA_FLOWTABLE_TABLE] ||
+           (!nla[NFTA_FLOWTABLE_NAME] &&
+            !nla[NFTA_FLOWTABLE_HANDLE]))
+               return -EINVAL;
+
        table = nf_tables_table_lookup(net, nla[NFTA_FLOWTABLE_TABLE],
                                       family, genmask);
        if (IS_ERR(table))
@@ -5205,9 +5285,9 @@ static int nf_tables_fill_flowtable_info(struct sk_buff *skb, struct net *net,
                goto nla_put_failure;
 
        for (i = 0; i < flowtable->ops_len; i++) {
-               if (flowtable->ops[i].dev &&
+               if (flowtable->dev_name[i][0] &&
                    nla_put_string(skb, NFTA_DEVICE_NAME,
-                                  flowtable->ops[i].dev->name))
+                                  flowtable->dev_name[i]))
                        goto nla_put_failure;
        }
        nla_nest_end(skb, nest_devs);
@@ -5402,6 +5482,7 @@ err:
 static void nf_tables_flowtable_destroy(struct nft_flowtable *flowtable)
 {
        cancel_delayed_work_sync(&flowtable->data.gc_work);
+       kfree(flowtable->ops);
        kfree(flowtable->name);
        flowtable->data.type->free(&flowtable->data);
        rhashtable_destroy(&flowtable->data.rhashtable);
@@ -5448,6 +5529,7 @@ static void nft_flowtable_event(unsigned long event, struct net_device *dev,
                        continue;
 
                nf_unregister_net_hook(dev_net(dev), &flowtable->ops[i]);
+               flowtable->dev_name[i][0] = '\0';
                flowtable->ops[i].dev = NULL;
                break;
        }
index 3f1624e..fc9c6d5 100644 (file)
@@ -674,7 +674,7 @@ static const struct nft_set_ops *
 nft_hash_select_ops(const struct nft_ctx *ctx, const struct nft_set_desc *desc,
                    u32 flags)
 {
-       if (desc->size) {
+       if (desc->size && !(flags & (NFT_SET_EVAL | NFT_SET_TIMEOUT))) {
                switch (desc->klen) {
                case 4:
                        return &nft_hash_fast_ops;
index 2f685ee..4aa01c9 100644 (file)
@@ -423,6 +423,36 @@ textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto)
        return buf;
 }
 
+/**
+ * xt_check_proc_name - check that name is suitable for /proc file creation
+ *
+ * @name: file name candidate
+ * @size: length of buffer
+ *
+ * some x_tables modules wish to create a file in /proc.
+ * This function makes sure that the name is suitable for this
+ * purpose, it checks that name is NUL terminated and isn't a 'special'
+ * name, like "..".
+ *
+ * returns negative number on error or 0 if name is useable.
+ */
+int xt_check_proc_name(const char *name, unsigned int size)
+{
+       if (name[0] == '\0')
+               return -EINVAL;
+
+       if (strnlen(name, size) == size)
+               return -ENAMETOOLONG;
+
+       if (strcmp(name, ".") == 0 ||
+           strcmp(name, "..") == 0 ||
+           strchr(name, '/'))
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL(xt_check_proc_name);
+
 int xt_check_match(struct xt_mtchk_param *par,
                   unsigned int size, u_int8_t proto, bool inv_proto)
 {
@@ -434,36 +464,35 @@ int xt_check_match(struct xt_mtchk_param *par,
                 * ebt_among is exempt from centralized matchsize checking
                 * because it uses a dynamic-size data set.
                 */
-               pr_err("%s_tables: %s.%u match: invalid size "
-                      "%u (kernel) != (user) %u\n",
-                      xt_prefix[par->family], par->match->name,
-                      par->match->revision,
-                      XT_ALIGN(par->match->matchsize), size);
+               pr_err_ratelimited("%s_tables: %s.%u match: invalid size %u (kernel) != (user) %u\n",
+                                  xt_prefix[par->family], par->match->name,
+                                  par->match->revision,
+                                  XT_ALIGN(par->match->matchsize), size);
                return -EINVAL;
        }
        if (par->match->table != NULL &&
            strcmp(par->match->table, par->table) != 0) {
-               pr_err("%s_tables: %s match: only valid in %s table, not %s\n",
-                      xt_prefix[par->family], par->match->name,
-                      par->match->table, par->table);
+               pr_info_ratelimited("%s_tables: %s match: only valid in %s table, not %s\n",
+                                   xt_prefix[par->family], par->match->name,
+                                   par->match->table, par->table);
                return -EINVAL;
        }
        if (par->match->hooks && (par->hook_mask & ~par->match->hooks) != 0) {
                char used[64], allow[64];
 
-               pr_err("%s_tables: %s match: used from hooks %s, but only "
-                      "valid from %s\n",
-                      xt_prefix[par->family], par->match->name,
-                      textify_hooks(used, sizeof(used), par->hook_mask,
-                                    par->family),
-                      textify_hooks(allow, sizeof(allow), par->match->hooks,
-                                    par->family));
+               pr_info_ratelimited("%s_tables: %s match: used from hooks %s, but only valid from %s\n",
+                                   xt_prefix[par->family], par->match->name,
+                                   textify_hooks(used, sizeof(used),
+                                                 par->hook_mask, par->family),
+                                   textify_hooks(allow, sizeof(allow),
+                                                 par->match->hooks,
+                                                 par->family));
                return -EINVAL;
        }
        if (par->match->proto && (par->match->proto != proto || inv_proto)) {
-               pr_err("%s_tables: %s match: only valid for protocol %u\n",
-                      xt_prefix[par->family], par->match->name,
-                      par->match->proto);
+               pr_info_ratelimited("%s_tables: %s match: only valid for protocol %u\n",
+                                   xt_prefix[par->family], par->match->name,
+                                   par->match->proto);
                return -EINVAL;
        }
        if (par->match->checkentry != NULL) {
@@ -814,36 +843,35 @@ int xt_check_target(struct xt_tgchk_param *par,
        int ret;
 
        if (XT_ALIGN(par->target->targetsize) != size) {
-               pr_err("%s_tables: %s.%u target: invalid size "
-                      "%u (kernel) != (user) %u\n",
-                      xt_prefix[par->family], par->target->name,
-                      par->target->revision,
-                      XT_ALIGN(par->target->targetsize), size);
+               pr_err_ratelimited("%s_tables: %s.%u target: invalid size %u (kernel) != (user) %u\n",
+                                  xt_prefix[par->family], par->target->name,
+                                  par->target->revision,
+                                  XT_ALIGN(par->target->targetsize), size);
                return -EINVAL;
        }
        if (par->target->table != NULL &&
            strcmp(par->target->table, par->table) != 0) {
-               pr_err("%s_tables: %s target: only valid in %s table, not %s\n",
-                      xt_prefix[par->family], par->target->name,
-                      par->target->table, par->table);
+               pr_info_ratelimited("%s_tables: %s target: only valid in %s table, not %s\n",
+                                   xt_prefix[par->family], par->target->name,
+                                   par->target->table, par->table);
                return -EINVAL;
        }
        if (par->target->hooks && (par->hook_mask & ~par->target->hooks) != 0) {
                char used[64], allow[64];
 
-               pr_err("%s_tables: %s target: used from hooks %s, but only "
-                      "usable from %s\n",
-                      xt_prefix[par->family], par->target->name,
-                      textify_hooks(used, sizeof(used), par->hook_mask,
-                                    par->family),
-                      textify_hooks(allow, sizeof(allow), par->target->hooks,
-                                    par->family));
+               pr_info_ratelimited("%s_tables: %s target: used from hooks %s, but only usable from %s\n",
+                                   xt_prefix[par->family], par->target->name,
+                                   textify_hooks(used, sizeof(used),
+                                                 par->hook_mask, par->family),
+                                   textify_hooks(allow, sizeof(allow),
+                                                 par->target->hooks,
+                                                 par->family));
                return -EINVAL;
        }
        if (par->target->proto && (par->target->proto != proto || inv_proto)) {
-               pr_err("%s_tables: %s target: only valid for protocol %u\n",
-                      xt_prefix[par->family], par->target->name,
-                      par->target->proto);
+               pr_info_ratelimited("%s_tables: %s target: only valid for protocol %u\n",
+                                   xt_prefix[par->family], par->target->name,
+                                   par->target->proto);
                return -EINVAL;
        }
        if (par->target->checkentry != NULL) {
@@ -1004,10 +1032,6 @@ struct xt_table_info *xt_alloc_table_info(unsigned int size)
        if (sz < sizeof(*info))
                return NULL;
 
-       /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
-       if ((size >> PAGE_SHIFT) + 2 > totalram_pages)
-               return NULL;
-
        /* __GFP_NORETRY is not fully supported by kvmalloc but it should
         * work reasonably well if sz is too large and bail out rather
         * than shoot all processes down before realizing there is nothing
index c502419..f368ee6 100644 (file)
@@ -120,8 +120,8 @@ static int audit_tg_check(const struct xt_tgchk_param *par)
        const struct xt_audit_info *info = par->targinfo;
 
        if (info->type > XT_AUDIT_TYPE_MAX) {
-               pr_info("Audit type out of range (valid range: 0..%hhu)\n",
-                       XT_AUDIT_TYPE_MAX);
+               pr_info_ratelimited("Audit type out of range (valid range: 0..%hhu)\n",
+                                   XT_AUDIT_TYPE_MAX);
                return -ERANGE;
        }
 
index 0f642ef..9f4151e 100644 (file)
@@ -36,13 +36,13 @@ static int checksum_tg_check(const struct xt_tgchk_param *par)
        const struct xt_CHECKSUM_info *einfo = par->targinfo;
 
        if (einfo->operation & ~XT_CHECKSUM_OP_FILL) {
-               pr_info("unsupported CHECKSUM operation %x\n", einfo->operation);
+               pr_info_ratelimited("unsupported CHECKSUM operation %x\n",
+                                   einfo->operation);
                return -EINVAL;
        }
-       if (!einfo->operation) {
-               pr_info("no CHECKSUM operation enabled\n");
+       if (!einfo->operation)
                return -EINVAL;
-       }
+
        return 0;
 }
 
index da56c06..f3f1caa 100644 (file)
@@ -91,8 +91,8 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par)
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "security") != 0) {
-               pr_info("target only valid in the \'mangle\' "
-                       "or \'security\' tables, not \'%s\'.\n", par->table);
+               pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
+                                   par->table);
                return -EINVAL;
        }
 
@@ -102,14 +102,14 @@ static int connsecmark_tg_check(const struct xt_tgchk_param *par)
                break;
 
        default:
-               pr_info("invalid mode: %hu\n", info->mode);
+               pr_info_ratelimited("invalid mode: %hu\n", info->mode);
                return -EINVAL;
        }
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
        return ret;
 }
 
index 5a152e2..8790190 100644 (file)
@@ -82,15 +82,14 @@ xt_ct_set_helper(struct nf_conn *ct, const char *helper_name,
 
        proto = xt_ct_find_proto(par);
        if (!proto) {
-               pr_info("You must specify a L4 protocol, and not use "
-                       "inversions on it.\n");
+               pr_info_ratelimited("You must specify a L4 protocol and not use inversions on it\n");
                return -ENOENT;
        }
 
        helper = nf_conntrack_helper_try_module_get(helper_name, par->family,
                                                    proto);
        if (helper == NULL) {
-               pr_info("No such helper \"%s\"\n", helper_name);
+               pr_info_ratelimited("No such helper \"%s\"\n", helper_name);
                return -ENOENT;
        }
 
@@ -124,6 +123,7 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
        const struct nf_conntrack_l4proto *l4proto;
        struct ctnl_timeout *timeout;
        struct nf_conn_timeout *timeout_ext;
+       const char *errmsg = NULL;
        int ret = 0;
        u8 proto;
 
@@ -131,29 +131,29 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
        timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
        if (timeout_find_get == NULL) {
                ret = -ENOENT;
-               pr_info("Timeout policy base is empty\n");
+               errmsg = "Timeout policy base is empty";
                goto out;
        }
 
        proto = xt_ct_find_proto(par);
        if (!proto) {
                ret = -EINVAL;
-               pr_info("You must specify a L4 protocol, and not use "
-                       "inversions on it.\n");
+               errmsg = "You must specify a L4 protocol and not use inversions on it";
                goto out;
        }
 
        timeout = timeout_find_get(par->net, timeout_name);
        if (timeout == NULL) {
                ret = -ENOENT;
-               pr_info("No such timeout policy \"%s\"\n", timeout_name);
+               pr_info_ratelimited("No such timeout policy \"%s\"\n",
+                                   timeout_name);
                goto out;
        }
 
        if (timeout->l3num != par->family) {
                ret = -EINVAL;
-               pr_info("Timeout policy `%s' can only be used by L3 protocol "
-                       "number %d\n", timeout_name, timeout->l3num);
+               pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n",
+                                   timeout_name, 3, timeout->l3num);
                goto err_put_timeout;
        }
        /* Make sure the timeout policy matches any existing protocol tracker,
@@ -162,9 +162,8 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
        l4proto = __nf_ct_l4proto_find(par->family, proto);
        if (timeout->l4proto->l4proto != l4proto->l4proto) {
                ret = -EINVAL;
-               pr_info("Timeout policy `%s' can only be used by L4 protocol "
-                       "number %d\n",
-                       timeout_name, timeout->l4proto->l4proto);
+               pr_info_ratelimited("Timeout policy `%s' can only be used by L%d protocol number %d\n",
+                                   timeout_name, 4, timeout->l4proto->l4proto);
                goto err_put_timeout;
        }
        timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC);
@@ -180,6 +179,8 @@ err_put_timeout:
        __xt_ct_tg_timeout_put(timeout);
 out:
        rcu_read_unlock();
+       if (errmsg)
+               pr_info_ratelimited("%s\n", errmsg);
        return ret;
 #else
        return -EOPNOTSUPP;
index 3f83d38..098ed85 100644 (file)
@@ -66,10 +66,8 @@ static int dscp_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_DSCP_info *info = par->targinfo;
 
-       if (info->dscp > XT_DSCP_MAX) {
-               pr_info("dscp %x out of range\n", info->dscp);
+       if (info->dscp > XT_DSCP_MAX)
                return -EDOM;
-       }
        return 0;
 }
 
index 1535e87..4653b07 100644 (file)
@@ -105,10 +105,8 @@ static int ttl_tg_check(const struct xt_tgchk_param *par)
 {
        const struct ipt_TTL_info *info = par->targinfo;
 
-       if (info->mode > IPT_TTL_MAXMODE) {
-               pr_info("TTL: invalid or unknown mode %u\n", info->mode);
+       if (info->mode > IPT_TTL_MAXMODE)
                return -EINVAL;
-       }
        if (info->mode != IPT_TTL_SET && info->ttl == 0)
                return -EINVAL;
        return 0;
@@ -118,15 +116,10 @@ static int hl_tg6_check(const struct xt_tgchk_param *par)
 {
        const struct ip6t_HL_info *info = par->targinfo;
 
-       if (info->mode > IP6T_HL_MAXMODE) {
-               pr_info("invalid or unknown mode %u\n", info->mode);
+       if (info->mode > IP6T_HL_MAXMODE)
                return -EINVAL;
-       }
-       if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
-               pr_info("increment/decrement does not "
-                       "make sense with value 0\n");
+       if (info->mode != IP6T_HL_SET && info->hop_limit == 0)
                return -EINVAL;
-       }
        return 0;
 }
 
index 60e6dbe..9c75f41 100644 (file)
@@ -9,6 +9,8 @@
  * the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/icmp.h>
@@ -312,29 +314,30 @@ hmark_tg_v4(struct sk_buff *skb, const struct xt_action_param *par)
 static int hmark_tg_check(const struct xt_tgchk_param *par)
 {
        const struct xt_hmark_info *info = par->targinfo;
+       const char *errmsg = "proto mask must be zero with L3 mode";
 
-       if (!info->hmodulus) {
-               pr_info("xt_HMARK: hash modulus can't be zero\n");
+       if (!info->hmodulus)
                return -EINVAL;
-       }
+
        if (info->proto_mask &&
-           (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3))) {
-               pr_info("xt_HMARK: proto mask must be zero with L3 mode\n");
-               return -EINVAL;
-       }
+           (info->flags & XT_HMARK_FLAG(XT_HMARK_METHOD_L3)))
+               goto err;
+
        if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK) &&
            (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT_MASK) |
-                            XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)))) {
-               pr_info("xt_HMARK: spi-mask and port-mask can't be combined\n");
+                            XT_HMARK_FLAG(XT_HMARK_DPORT_MASK))))
                return -EINVAL;
-       }
+
        if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI) &&
            (info->flags & (XT_HMARK_FLAG(XT_HMARK_SPORT) |
                             XT_HMARK_FLAG(XT_HMARK_DPORT)))) {
-               pr_info("xt_HMARK: spi-set and port-set can't be combined\n");
-               return -EINVAL;
+               errmsg = "spi-set and port-set can't be combined";
+               goto err;
        }
        return 0;
+err:
+       pr_info_ratelimited("%s\n", errmsg);
+       return -EINVAL;
 }
 
 static struct xt_target hmark_tg_reg[] __read_mostly = {
index 6c2482b..1ac6600 100644 (file)
@@ -146,11 +146,11 @@ static int idletimer_tg_create(struct idletimer_tg_info *info)
        timer_setup(&info->timer->timer, idletimer_tg_expired, 0);
        info->timer->refcnt = 1;
 
+       INIT_WORK(&info->timer->work, idletimer_tg_work);
+
        mod_timer(&info->timer->timer,
                  msecs_to_jiffies(info->timeout * 1000) + jiffies);
 
-       INIT_WORK(&info->timer->work, idletimer_tg_work);
-
        return 0;
 
 out_free_attr:
@@ -191,7 +191,10 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par)
                pr_debug("timeout value is zero\n");
                return -EINVAL;
        }
-
+       if (info->timeout >= INT_MAX / 1000) {
+               pr_debug("timeout value is too big\n");
+               return -EINVAL;
+       }
        if (info->label[0] == '\0' ||
            strnlen(info->label,
                    MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) {
index 1dcad89..1984644 100644 (file)
@@ -111,10 +111,8 @@ static int led_tg_check(const struct xt_tgchk_param *par)
        struct xt_led_info_internal *ledinternal;
        int err;
 
-       if (ledinfo->id[0] == '\0') {
-               pr_info("No 'id' parameter given.\n");
+       if (ledinfo->id[0] == '\0')
                return -EINVAL;
-       }
 
        mutex_lock(&xt_led_mutex);
 
@@ -138,13 +136,14 @@ static int led_tg_check(const struct xt_tgchk_param *par)
 
        err = led_trigger_register(&ledinternal->netfilter_led_trigger);
        if (err) {
-               pr_err("Trigger name is already in use.\n");
+               pr_info_ratelimited("Trigger name is already in use.\n");
                goto exit_alloc;
        }
 
-       /* See if we need to set up a timer */
-       if (ledinfo->delay > 0)
-               timer_setup(&ledinternal->timer, led_timeout_callback, 0);
+       /* Since the letinternal timer can be shared between multiple targets,
+        * always set it up, even if the current target does not need it
+        */
+       timer_setup(&ledinternal->timer, led_timeout_callback, 0);
 
        list_add_tail(&ledinternal->list, &xt_led_triggers);
 
@@ -181,8 +180,7 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par)
 
        list_del(&ledinternal->list);
 
-       if (ledinfo->delay > 0)
-               del_timer_sync(&ledinternal->timer);
+       del_timer_sync(&ledinternal->timer);
 
        led_trigger_unregister(&ledinternal->netfilter_led_trigger);
 
index a360b99..a9aca80 100644 (file)
@@ -8,6 +8,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
@@ -67,13 +69,13 @@ static int nfqueue_tg_check(const struct xt_tgchk_param *par)
        init_hashrandom(&jhash_initval);
 
        if (info->queues_total == 0) {
-               pr_err("NFQUEUE: number of total queues is 0\n");
+               pr_info_ratelimited("number of total queues is 0\n");
                return -EINVAL;
        }
        maxid = info->queues_total - 1 + info->queuenum;
        if (maxid > 0xffff) {
-               pr_err("NFQUEUE: number of queues (%u) out of range (got %u)\n",
-                      info->queues_total, maxid);
+               pr_info_ratelimited("number of queues (%u) out of range (got %u)\n",
+                                   info->queues_total, maxid);
                return -ERANGE;
        }
        if (par->target->revision == 2 && info->flags > 1)
index 9faf5e0..4ad5fe2 100644 (file)
@@ -60,18 +60,20 @@ static int checkentry_lsm(struct xt_secmark_target_info *info)
                                       &info->secid);
        if (err) {
                if (err == -EINVAL)
-                       pr_info("invalid security context \'%s\'\n", info->secctx);
+                       pr_info_ratelimited("invalid security context \'%s\'\n",
+                                           info->secctx);
                return err;
        }
 
        if (!info->secid) {
-               pr_info("unable to map security context \'%s\'\n", info->secctx);
+               pr_info_ratelimited("unable to map security context \'%s\'\n",
+                                   info->secctx);
                return -ENOENT;
        }
 
        err = security_secmark_relabel_packet(info->secid);
        if (err) {
-               pr_info("unable to obtain relabeling permission\n");
+               pr_info_ratelimited("unable to obtain relabeling permission\n");
                return err;
        }
 
@@ -86,14 +88,14 @@ static int secmark_tg_check(const struct xt_tgchk_param *par)
 
        if (strcmp(par->table, "mangle") != 0 &&
            strcmp(par->table, "security") != 0) {
-               pr_info("target only valid in the \'mangle\' "
-                       "or \'security\' tables, not \'%s\'.\n", par->table);
+               pr_info_ratelimited("only valid in \'mangle\' or \'security\' table, not \'%s\'\n",
+                                   par->table);
                return -EINVAL;
        }
 
        if (mode && mode != info->mode) {
-               pr_info("mode already set to %hu cannot mix with "
-                       "rules for mode %hu\n", mode, info->mode);
+               pr_info_ratelimited("mode already set to %hu cannot mix with rules for mode %hu\n",
+                                   mode, info->mode);
                return -EINVAL;
        }
 
@@ -101,7 +103,7 @@ static int secmark_tg_check(const struct xt_tgchk_param *par)
        case SECMARK_MODE_SEL:
                break;
        default:
-               pr_info("invalid mode: %hu\n", info->mode);
+               pr_info_ratelimited("invalid mode: %hu\n", info->mode);
                return -EINVAL;
        }
 
index 99bb8e4..98efb20 100644 (file)
@@ -273,8 +273,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
            (par->hook_mask & ~((1 << NF_INET_FORWARD) |
                           (1 << NF_INET_LOCAL_OUT) |
                           (1 << NF_INET_POST_ROUTING))) != 0) {
-               pr_info("path-MTU clamping only supported in "
-                       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+               pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
                return -EINVAL;
        }
        if (par->nft_compat)
@@ -283,7 +282,7 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)
        xt_ematch_foreach(ematch, e)
                if (find_syn_match(ematch))
                        return 0;
-       pr_info("Only works on TCP SYN packets\n");
+       pr_info_ratelimited("Only works on TCP SYN packets\n");
        return -EINVAL;
 }
 
@@ -298,8 +297,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
            (par->hook_mask & ~((1 << NF_INET_FORWARD) |
                           (1 << NF_INET_LOCAL_OUT) |
                           (1 << NF_INET_POST_ROUTING))) != 0) {
-               pr_info("path-MTU clamping only supported in "
-                       "FORWARD, OUTPUT and POSTROUTING hooks\n");
+               pr_info_ratelimited("path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\n");
                return -EINVAL;
        }
        if (par->nft_compat)
@@ -308,7 +306,7 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)
        xt_ematch_foreach(ematch, e)
                if (find_syn_match(ematch))
                        return 0;
-       pr_info("Only works on TCP SYN packets\n");
+       pr_info_ratelimited("Only works on TCP SYN packets\n");
        return -EINVAL;
 }
 #endif
index 17d7705..8c89323 100644 (file)
@@ -540,8 +540,7 @@ static int tproxy_tg6_check(const struct xt_tgchk_param *par)
            !(i->invflags & IP6T_INV_PROTO))
                return 0;
 
-       pr_info("Can be used only in combination with "
-               "either -p tcp or -p udp\n");
+       pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
        return -EINVAL;
 }
 #endif
@@ -559,8 +558,7 @@ static int tproxy_tg4_check(const struct xt_tgchk_param *par)
            && !(i->invflags & IPT_INV_PROTO))
                return 0;
 
-       pr_info("Can be used only in combination with "
-               "either -p tcp or -p udp\n");
+       pr_info_ratelimited("Can be used only with -p tcp or -p udp\n");
        return -EINVAL;
 }
 
index 911a7c0..89e281b 100644 (file)
@@ -164,48 +164,47 @@ addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
 
 static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)
 {
+       const char *errmsg = "both incoming and outgoing interface limitation cannot be selected";
        struct xt_addrtype_info_v1 *info = par->matchinfo;
 
        if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&
-           info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
-               pr_info("both incoming and outgoing "
-                       "interface limitation cannot be selected\n");
-               return -EINVAL;
-       }
+           info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)
+               goto err;
 
        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
            (1 << NF_INET_LOCAL_IN)) &&
            info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {
-               pr_info("output interface limitation "
-                       "not valid in PREROUTING and INPUT\n");
-               return -EINVAL;
+               errmsg = "output interface limitation not valid in PREROUTING and INPUT";
+               goto err;
        }
 
        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
            (1 << NF_INET_LOCAL_OUT)) &&
            info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {
-               pr_info("input interface limitation "
-                       "not valid in POSTROUTING and OUTPUT\n");
-               return -EINVAL;
+               errmsg = "input interface limitation not valid in POSTROUTING and OUTPUT";
+               goto err;
        }
 
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
        if (par->family == NFPROTO_IPV6) {
                if ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {
-                       pr_err("ipv6 BLACKHOLE matching not supported\n");
-                       return -EINVAL;
+                       errmsg = "ipv6 BLACKHOLE matching not supported";
+                       goto err;
                }
                if ((info->source | info->dest) >= XT_ADDRTYPE_PROHIBIT) {
-                       pr_err("ipv6 PROHIBIT (THROW, NAT ..) matching not supported\n");
-                       return -EINVAL;
+                       errmsg = "ipv6 PROHIBIT (THROW, NAT ..) matching not supported";
+                       goto err;
                }
                if ((info->source | info->dest) & XT_ADDRTYPE_BROADCAST) {
-                       pr_err("ipv6 does not support BROADCAST matching\n");
-                       return -EINVAL;
+                       errmsg = "ipv6 does not support BROADCAST matching";
+                       goto err;
                }
        }
 #endif
        return 0;
+err:
+       pr_info_ratelimited("%s\n", errmsg);
+       return -EINVAL;
 }
 
 static struct xt_match addrtype_mt_reg[] __read_mostly = {
index 06b090d..a2cf8a6 100644 (file)
@@ -7,6 +7,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/syscalls.h>
 #include <linux/skbuff.h>
@@ -34,7 +36,7 @@ static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len,
        program.filter = insns;
 
        if (bpf_prog_create(ret, &program)) {
-               pr_info("bpf: check failed: parse error\n");
+               pr_info_ratelimited("check failed: parse error\n");
                return -EINVAL;
        }
 
index 891f4e7..7df2dec 100644 (file)
@@ -12,6 +12,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/skbuff.h>
 #include <linux/module.h>
 #include <linux/netfilter/x_tables.h>
@@ -48,7 +50,7 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
        }
 
        if (info->has_path && info->has_classid) {
-               pr_info("xt_cgroup: both path and classid specified\n");
+               pr_info_ratelimited("path and classid specified\n");
                return -EINVAL;
        }
 
@@ -56,8 +58,8 @@ static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
        if (info->has_path) {
                cgrp = cgroup_get_from_path(info->path);
                if (IS_ERR(cgrp)) {
-                       pr_info("xt_cgroup: invalid path, errno=%ld\n",
-                               PTR_ERR(cgrp));
+                       pr_info_ratelimited("invalid path, errno=%ld\n",
+                                           PTR_ERR(cgrp));
                        return -EINVAL;
                }
                info->priv = cgrp;
index 57ef175..0068688 100644 (file)
@@ -135,14 +135,12 @@ static int xt_cluster_mt_checkentry(const struct xt_mtchk_param *par)
        struct xt_cluster_match_info *info = par->matchinfo;
 
        if (info->total_nodes > XT_CLUSTER_NODES_MAX) {
-               pr_info("you have exceeded the maximum "
-                       "number of cluster nodes (%u > %u)\n",
-                       info->total_nodes, XT_CLUSTER_NODES_MAX);
+               pr_info_ratelimited("you have exceeded the maximum number of cluster nodes (%u > %u)\n",
+                                   info->total_nodes, XT_CLUSTER_NODES_MAX);
                return -EINVAL;
        }
        if (info->node_mask >= (1ULL << info->total_nodes)) {
-               pr_info("this node mask cannot be "
-                       "higher than the total number of nodes\n");
+               pr_info_ratelimited("node mask cannot exceed total number of nodes\n");
                return -EDOM;
        }
        return 0;
index cad0b7b..93cb018 100644 (file)
@@ -112,8 +112,8 @@ static int connbytes_mt_check(const struct xt_mtchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
 
        /*
         * This filter cannot function correctly unless connection tracking
index 2337287..4fa4efd 100644 (file)
@@ -57,14 +57,15 @@ static int connlabel_mt_check(const struct xt_mtchk_param *par)
        int ret;
 
        if (info->options & ~options) {
-               pr_err("Unknown options in mask %x\n", info->options);
+               pr_info_ratelimited("Unknown options in mask %x\n",
+                                   info->options);
                return -EINVAL;
        }
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0) {
-               pr_info("cannot load conntrack support for proto=%u\n",
-                                                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
                return ret;
        }
 
index ec377cc..809639c 100644 (file)
@@ -79,8 +79,8 @@ static int connmark_tg_check(const struct xt_tgchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
        return ret;
 }
 
@@ -109,8 +109,8 @@ static int connmark_mt_check(const struct xt_mtchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
        return ret;
 }
 
index 39cf1d0..df80fe7 100644 (file)
@@ -272,8 +272,8 @@ static int conntrack_mt_check(const struct xt_mtchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
        return ret;
 }
 
index 236ac80..a4c2b86 100644 (file)
@@ -46,10 +46,8 @@ static int dscp_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_dscp_info *info = par->matchinfo;
 
-       if (info->dscp > XT_DSCP_MAX) {
-               pr_info("dscp %x out of range\n", info->dscp);
+       if (info->dscp > XT_DSCP_MAX)
                return -EDOM;
-       }
 
        return 0;
 }
index 3c831a8..c7ad4af 100644 (file)
@@ -97,7 +97,7 @@ static int ecn_mt_check4(const struct xt_mtchk_param *par)
 
        if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
            (ip->proto != IPPROTO_TCP || ip->invflags & IPT_INV_PROTO)) {
-               pr_info("cannot match TCP bits in rule for non-tcp packets\n");
+               pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
                return -EINVAL;
        }
 
@@ -139,7 +139,7 @@ static int ecn_mt_check6(const struct xt_mtchk_param *par)
 
        if (info->operation & (XT_ECN_OP_MATCH_ECE | XT_ECN_OP_MATCH_CWR) &&
            (ip->proto != IPPROTO_TCP || ip->invflags & IP6T_INV_PROTO)) {
-               pr_info("cannot match TCP bits in rule for non-tcp packets\n");
+               pr_info_ratelimited("cannot match TCP bits for non-tcp packets\n");
                return -EINVAL;
        }
 
index ca68474..3360f13 100644 (file)
@@ -523,7 +523,8 @@ static u64 user2rate(u64 user)
        if (user != 0) {
                return div64_u64(XT_HASHLIMIT_SCALE_v2, user);
        } else {
-               pr_warn("invalid rate from userspace: %llu\n", user);
+               pr_info_ratelimited("invalid rate from userspace: %llu\n",
+                                   user);
                return 0;
        }
 }
@@ -774,7 +775,7 @@ hashlimit_mt_common(const struct sk_buff *skb, struct xt_action_param *par,
                if (!dh->rateinfo.prev_window &&
                    (dh->rateinfo.current_rate <= dh->rateinfo.burst)) {
                        spin_unlock(&dh->lock);
-                       rcu_read_unlock_bh();
+                       local_bh_enable();
                        return !(cfg->mode & XT_HASHLIMIT_INVERT);
                } else {
                        goto overlimit;
@@ -865,33 +866,34 @@ static int hashlimit_mt_check_common(const struct xt_mtchk_param *par,
        }
 
        if (cfg->mode & ~XT_HASHLIMIT_ALL) {
-               pr_info("Unknown mode mask %X, kernel too old?\n",
-                                               cfg->mode);
+               pr_info_ratelimited("Unknown mode mask %X, kernel too old?\n",
+                                   cfg->mode);
                return -EINVAL;
        }
 
        /* Check for overflow. */
        if (revision >= 3 && cfg->mode & XT_HASHLIMIT_RATE_MATCH) {
                if (cfg->avg == 0 || cfg->avg > U32_MAX) {
-                       pr_info("hashlimit invalid rate\n");
+                       pr_info_ratelimited("invalid rate\n");
                        return -ERANGE;
                }
 
                if (cfg->interval == 0) {
-                       pr_info("hashlimit invalid interval\n");
+                       pr_info_ratelimited("invalid interval\n");
                        return -EINVAL;
                }
        } else if (cfg->mode & XT_HASHLIMIT_BYTES) {
                if (user2credits_byte(cfg->avg) == 0) {
-                       pr_info("overflow, rate too high: %llu\n", cfg->avg);
+                       pr_info_ratelimited("overflow, rate too high: %llu\n",
+                                           cfg->avg);
                        return -EINVAL;
                }
        } else if (cfg->burst == 0 ||
-                   user2credits(cfg->avg * cfg->burst, revision) <
-                   user2credits(cfg->avg, revision)) {
-                       pr_info("overflow, try lower: %llu/%llu\n",
-                               cfg->avg, cfg->burst);
-                       return -ERANGE;
+                  user2credits(cfg->avg * cfg->burst, revision) <
+                  user2credits(cfg->avg, revision)) {
+               pr_info_ratelimited("overflow, try lower: %llu/%llu\n",
+                                   cfg->avg, cfg->burst);
+               return -ERANGE;
        }
 
        mutex_lock(&hashlimit_mutex);
@@ -915,8 +917,9 @@ static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par)
        struct hashlimit_cfg3 cfg = {};
        int ret;
 
-       if (info->name[sizeof(info->name) - 1] != '\0')
-               return -EINVAL;
+       ret = xt_check_proc_name(info->name, sizeof(info->name));
+       if (ret)
+               return ret;
 
        ret = cfg_copy(&cfg, (void *)&info->cfg, 1);
 
@@ -933,8 +936,9 @@ static int hashlimit_mt_check_v2(const struct xt_mtchk_param *par)
        struct hashlimit_cfg3 cfg = {};
        int ret;
 
-       if (info->name[sizeof(info->name) - 1] != '\0')
-               return -EINVAL;
+       ret = xt_check_proc_name(info->name, sizeof(info->name));
+       if (ret)
+               return ret;
 
        ret = cfg_copy(&cfg, (void *)&info->cfg, 2);
 
@@ -948,9 +952,11 @@ static int hashlimit_mt_check_v2(const struct xt_mtchk_param *par)
 static int hashlimit_mt_check(const struct xt_mtchk_param *par)
 {
        struct xt_hashlimit_mtinfo3 *info = par->matchinfo;
+       int ret;
 
-       if (info->name[sizeof(info->name) - 1] != '\0')
-               return -EINVAL;
+       ret = xt_check_proc_name(info->name, sizeof(info->name));
+       if (ret)
+               return ret;
 
        return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg,
                                         info->name, 3);
index 38a7815..fd077ae 100644 (file)
@@ -61,8 +61,8 @@ static int helper_mt_check(const struct xt_mtchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0) {
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
                return ret;
        }
        info->name[sizeof(info->name) - 1] = '\0';
index 7ca64a5..57f1df5 100644 (file)
@@ -72,7 +72,7 @@ static int comp_mt_check(const struct xt_mtchk_param *par)
 
        /* Must specify no unknown invflags */
        if (compinfo->invflags & ~XT_IPCOMP_INV_MASK) {
-               pr_err("unknown flags %X\n", compinfo->invflags);
+               pr_info_ratelimited("unknown flags %X\n", compinfo->invflags);
                return -EINVAL;
        }
        return 0;
index 42540d2..1d950a6 100644 (file)
@@ -158,7 +158,8 @@ static int ipvs_mt_check(const struct xt_mtchk_param *par)
            && par->family != NFPROTO_IPV6
 #endif
                ) {
-               pr_info("protocol family %u not supported\n", par->family);
+               pr_info_ratelimited("protocol family %u not supported\n",
+                                   par->family);
                return -EINVAL;
        }
 
index 8aee572..c43482b 100644 (file)
@@ -216,7 +216,7 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
        /* Check for invalid flags */
        if (info->flags & ~(XT_L2TP_TID | XT_L2TP_SID | XT_L2TP_VERSION |
                            XT_L2TP_TYPE)) {
-               pr_info("unknown flags: %x\n", info->flags);
+               pr_info_ratelimited("unknown flags: %x\n", info->flags);
                return -EINVAL;
        }
 
@@ -225,7 +225,8 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
            (!(info->flags & XT_L2TP_SID)) &&
            ((!(info->flags & XT_L2TP_TYPE)) ||
             (info->type != XT_L2TP_TYPE_CONTROL))) {
-               pr_info("invalid flags combination: %x\n", info->flags);
+               pr_info_ratelimited("invalid flags combination: %x\n",
+                                   info->flags);
                return -EINVAL;
        }
 
@@ -234,19 +235,22 @@ static int l2tp_mt_check(const struct xt_mtchk_param *par)
         */
        if (info->flags & XT_L2TP_VERSION) {
                if ((info->version < 2) || (info->version > 3)) {
-                       pr_info("wrong L2TP version: %u\n", info->version);
+                       pr_info_ratelimited("wrong L2TP version: %u\n",
+                                           info->version);
                        return -EINVAL;
                }
 
                if (info->version == 2) {
                        if ((info->flags & XT_L2TP_TID) &&
                            (info->tid > 0xffff)) {
-                               pr_info("v2 tid > 0xffff: %u\n", info->tid);
+                               pr_info_ratelimited("v2 tid > 0xffff: %u\n",
+                                                   info->tid);
                                return -EINVAL;
                        }
                        if ((info->flags & XT_L2TP_SID) &&
                            (info->sid > 0xffff)) {
-                               pr_info("v2 sid > 0xffff: %u\n", info->sid);
+                               pr_info_ratelimited("v2 sid > 0xffff: %u\n",
+                                                   info->sid);
                                return -EINVAL;
                        }
                }
@@ -268,13 +272,13 @@ static int l2tp_mt_check4(const struct xt_mtchk_param *par)
 
        if ((ip->proto != IPPROTO_UDP) &&
            (ip->proto != IPPROTO_L2TP)) {
-               pr_info("missing protocol rule (udp|l2tpip)\n");
+               pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n");
                return -EINVAL;
        }
 
        if ((ip->proto == IPPROTO_L2TP) &&
            (info->version == 2)) {
-               pr_info("v2 doesn't support IP mode\n");
+               pr_info_ratelimited("v2 doesn't support IP mode\n");
                return -EINVAL;
        }
 
@@ -295,13 +299,13 @@ static int l2tp_mt_check6(const struct xt_mtchk_param *par)
 
        if ((ip->proto != IPPROTO_UDP) &&
            (ip->proto != IPPROTO_L2TP)) {
-               pr_info("missing protocol rule (udp|l2tpip)\n");
+               pr_info_ratelimited("missing protocol rule (udp|l2tpip)\n");
                return -EINVAL;
        }
 
        if ((ip->proto == IPPROTO_L2TP) &&
            (info->version == 2)) {
-               pr_info("v2 doesn't support IP mode\n");
+               pr_info_ratelimited("v2 doesn't support IP mode\n");
                return -EINVAL;
        }
 
index 61403b7..55d18cd 100644 (file)
@@ -106,8 +106,8 @@ static int limit_mt_check(const struct xt_mtchk_param *par)
        /* Check for overflow. */
        if (r->burst == 0
            || user2credits(r->avg * r->burst) < user2credits(r->avg)) {
-               pr_info("Overflow, try lower: %u/%u\n",
-                       r->avg, r->burst);
+               pr_info_ratelimited("Overflow, try lower: %u/%u\n",
+                                   r->avg, r->burst);
                return -ERANGE;
        }
 
index 0fd14d1..bdb689c 100644 (file)
@@ -8,6 +8,8 @@
  * published by the Free Software Foundation.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
@@ -19,8 +21,7 @@ static int xt_nat_checkentry_v0(const struct xt_tgchk_param *par)
        const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
 
        if (mr->rangesize != 1) {
-               pr_info("%s: multiple ranges no longer supported\n",
-                       par->target->name);
+               pr_info_ratelimited("multiple ranges no longer supported\n");
                return -EINVAL;
        }
        return nf_ct_netns_get(par->net, par->family);
index 6f92d25..c8674de 100644 (file)
@@ -6,6 +6,8 @@
  * it under the terms of the GNU General Public License version 2 (or any
  * later at your option) as published by the Free Software Foundation.
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/skbuff.h>
 
@@ -39,8 +41,8 @@ nfacct_mt_checkentry(const struct xt_mtchk_param *par)
 
        nfacct = nfnl_acct_find_get(par->net, info->name);
        if (nfacct == NULL) {
-               pr_info("xt_nfacct: accounting object with name `%s' "
-                       "does not exists\n", info->name);
+               pr_info_ratelimited("accounting object `%s' does not exists\n",
+                                   info->name);
                return -ENOENT;
        }
        info->nfacct = nfacct;
index bb33598..9d6d67b 100644 (file)
@@ -107,9 +107,7 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)
             info->invert & XT_PHYSDEV_OP_BRIDGED) &&
            par->hook_mask & ((1 << NF_INET_LOCAL_OUT) |
            (1 << NF_INET_FORWARD) | (1 << NF_INET_POST_ROUTING))) {
-               pr_info("using --physdev-out and --physdev-is-out are only "
-                       "supported in the FORWARD and POSTROUTING chains with "
-                       "bridged traffic.\n");
+               pr_info_ratelimited("--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\n");
                if (par->hook_mask & (1 << NF_INET_LOCAL_OUT))
                        return -EINVAL;
        }
index 5639fb0..13f8ccf 100644 (file)
@@ -132,26 +132,29 @@ policy_mt(const struct sk_buff *skb, struct xt_action_param *par)
 static int policy_mt_check(const struct xt_mtchk_param *par)
 {
        const struct xt_policy_info *info = par->matchinfo;
+       const char *errmsg = "neither incoming nor outgoing policy selected";
+
+       if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))
+               goto err;
 
-       if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) {
-               pr_info("neither incoming nor outgoing policy selected\n");
-               return -EINVAL;
-       }
        if (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |
            (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {
-               pr_info("output policy not valid in PREROUTING and INPUT\n");
-               return -EINVAL;
+               errmsg = "output policy not valid in PREROUTING and INPUT";
+               goto err;
        }
        if (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |
            (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {
-               pr_info("input policy not valid in POSTROUTING and OUTPUT\n");
-               return -EINVAL;
+               errmsg = "input policy not valid in POSTROUTING and OUTPUT";
+               goto err;
        }
        if (info->len > XT_POLICY_MAX_ELEM) {
-               pr_info("too many policy elements\n");
-               return -EINVAL;
+               errmsg = "too many policy elements";
+               goto err;
        }
        return 0;
+err:
+       pr_info_ratelimited("%s\n", errmsg);
+       return -EINVAL;
 }
 
 static struct xt_match policy_mt_reg[] __read_mostly = {
index 245fa35..81ee1d6 100644 (file)
@@ -342,8 +342,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        net_get_random_once(&hash_rnd, sizeof(hash_rnd));
 
        if (info->check_set & ~XT_RECENT_VALID_FLAGS) {
-               pr_info("Unsupported user space flags (%08x)\n",
-                       info->check_set);
+               pr_info_ratelimited("Unsupported userspace flags (%08x)\n",
+                                   info->check_set);
                return -EINVAL;
        }
        if (hweight8(info->check_set &
@@ -357,13 +357,13 @@ static int recent_mt_check(const struct xt_mtchk_param *par,
        if ((info->check_set & XT_RECENT_REAP) && !info->seconds)
                return -EINVAL;
        if (info->hit_count >= XT_RECENT_MAX_NSTAMPS) {
-               pr_info("hitcount (%u) is larger than allowed maximum (%u)\n",
-                       info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
+               pr_info_ratelimited("hitcount (%u) is larger than allowed maximum (%u)\n",
+                                   info->hit_count, XT_RECENT_MAX_NSTAMPS - 1);
                return -EINVAL;
        }
-       if (info->name[0] == '\0' ||
-           strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
-               return -EINVAL;
+       ret = xt_check_proc_name(info->name, sizeof(info->name));
+       if (ret)
+               return ret;
 
        if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot)
                nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1;
@@ -587,7 +587,7 @@ recent_mt_proc_write(struct file *file, const char __user *input,
                add = true;
                break;
        default:
-               pr_info("Need \"+ip\", \"-ip\" or \"/\"\n");
+               pr_info_ratelimited("Need \"+ip\", \"-ip\" or \"/\"\n");
                return -EINVAL;
        }
 
@@ -601,10 +601,8 @@ recent_mt_proc_write(struct file *file, const char __user *input,
                succ   = in4_pton(c, size, (void *)&addr, '\n', NULL);
        }
 
-       if (!succ) {
-               pr_info("illegal address written to procfs\n");
+       if (!succ)
                return -EINVAL;
-       }
 
        spin_lock_bh(&recent_lock);
        e = recent_entry_lookup(t, &addr, family, 0);
index 16b6b11..6f4c521 100644 (file)
@@ -92,12 +92,12 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
        index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
        if (index == IPSET_INVALID_ID) {
-               pr_warn("Cannot find set identified by id %u to match\n",
-                       info->match_set.index);
+               pr_info_ratelimited("Cannot find set identified by id %u to match\n",
+                                   info->match_set.index);
                return -ENOENT;
        }
        if (info->match_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
-               pr_warn("Protocol error: set match dimension is over the limit!\n");
+               pr_info_ratelimited("set match dimension is over the limit!\n");
                ip_set_nfnl_put(par->net, info->match_set.index);
                return -ERANGE;
        }
@@ -143,12 +143,12 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
        index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 
        if (index == IPSET_INVALID_ID) {
-               pr_warn("Cannot find set identified by id %u to match\n",
-                       info->match_set.index);
+               pr_info_ratelimited("Cannot find set identified by id %u to match\n",
+                                   info->match_set.index);
                return -ENOENT;
        }
        if (info->match_set.dim > IPSET_DIM_MAX) {
-               pr_warn("Protocol error: set match dimension is over the limit!\n");
+               pr_info_ratelimited("set match dimension is over the limit!\n");
                ip_set_nfnl_put(par->net, info->match_set.index);
                return -ERANGE;
        }
@@ -241,8 +241,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find add_set index %u as target\n",
-                               info->add_set.index);
+                       pr_info_ratelimited("Cannot find add_set index %u as target\n",
+                                           info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -250,8 +250,8 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find del_set index %u as target\n",
-                               info->del_set.index);
+                       pr_info_ratelimited("Cannot find del_set index %u as target\n",
+                                           info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net, info->add_set.index);
                        return -ENOENT;
@@ -259,7 +259,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
        }
        if (info->add_set.u.flags[IPSET_DIM_MAX - 1] != 0 ||
            info->del_set.u.flags[IPSET_DIM_MAX - 1] != 0) {
-               pr_warn("Protocol error: SET target dimension is over the limit!\n");
+               pr_info_ratelimited("SET target dimension over the limit!\n");
                if (info->add_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(par->net, info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
@@ -316,8 +316,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find add_set index %u as target\n",
-                               info->add_set.index);
+                       pr_info_ratelimited("Cannot find add_set index %u as target\n",
+                                           info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -325,8 +325,8 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        if (info->del_set.index != IPSET_INVALID_ID) {
                index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find del_set index %u as target\n",
-                               info->del_set.index);
+                       pr_info_ratelimited("Cannot find del_set index %u as target\n",
+                                           info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net, info->add_set.index);
                        return -ENOENT;
@@ -334,7 +334,7 @@ set_target_v1_checkentry(const struct xt_tgchk_param *par)
        }
        if (info->add_set.dim > IPSET_DIM_MAX ||
            info->del_set.dim > IPSET_DIM_MAX) {
-               pr_warn("Protocol error: SET target dimension is over the limit!\n");
+               pr_info_ratelimited("SET target dimension over the limit!\n");
                if (info->add_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(par->net, info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
@@ -444,8 +444,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                index = ip_set_nfnl_get_byindex(par->net,
                                                info->add_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find add_set index %u as target\n",
-                               info->add_set.index);
+                       pr_info_ratelimited("Cannot find add_set index %u as target\n",
+                                           info->add_set.index);
                        return -ENOENT;
                }
        }
@@ -454,8 +454,8 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                index = ip_set_nfnl_get_byindex(par->net,
                                                info->del_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find del_set index %u as target\n",
-                               info->del_set.index);
+                       pr_info_ratelimited("Cannot find del_set index %u as target\n",
+                                           info->del_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net,
                                                info->add_set.index);
@@ -465,7 +465,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
 
        if (info->map_set.index != IPSET_INVALID_ID) {
                if (strncmp(par->table, "mangle", 7)) {
-                       pr_warn("--map-set only usable from mangle table\n");
+                       pr_info_ratelimited("--map-set only usable from mangle table\n");
                        return -EINVAL;
                }
                if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
@@ -473,14 +473,14 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
                     !(par->hook_mask & (1 << NF_INET_FORWARD |
                                         1 << NF_INET_LOCAL_OUT |
                                         1 << NF_INET_POST_ROUTING))) {
-                       pr_warn("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
+                       pr_info_ratelimited("mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\n");
                        return -EINVAL;
                }
                index = ip_set_nfnl_get_byindex(par->net,
                                                info->map_set.index);
                if (index == IPSET_INVALID_ID) {
-                       pr_warn("Cannot find map_set index %u as target\n",
-                               info->map_set.index);
+                       pr_info_ratelimited("Cannot find map_set index %u as target\n",
+                                           info->map_set.index);
                        if (info->add_set.index != IPSET_INVALID_ID)
                                ip_set_nfnl_put(par->net,
                                                info->add_set.index);
@@ -494,7 +494,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)
        if (info->add_set.dim > IPSET_DIM_MAX ||
            info->del_set.dim > IPSET_DIM_MAX ||
            info->map_set.dim > IPSET_DIM_MAX) {
-               pr_warn("Protocol error: SET target dimension is over the limit!\n");
+               pr_info_ratelimited("SET target dimension over the limit!\n");
                if (info->add_set.index != IPSET_INVALID_ID)
                        ip_set_nfnl_put(par->net, info->add_set.index);
                if (info->del_set.index != IPSET_INVALID_ID)
index 575d215..2ac7f67 100644 (file)
@@ -171,7 +171,8 @@ static int socket_mt_v1_check(const struct xt_mtchk_param *par)
                return err;
 
        if (info->flags & ~XT_SOCKET_FLAGS_V1) {
-               pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V1);
+               pr_info_ratelimited("unknown flags 0x%x\n",
+                                   info->flags & ~XT_SOCKET_FLAGS_V1);
                return -EINVAL;
        }
        return 0;
@@ -187,7 +188,8 @@ static int socket_mt_v2_check(const struct xt_mtchk_param *par)
                return err;
 
        if (info->flags & ~XT_SOCKET_FLAGS_V2) {
-               pr_info("unknown flags 0x%x\n", info->flags & ~XT_SOCKET_FLAGS_V2);
+               pr_info_ratelimited("unknown flags 0x%x\n",
+                                   info->flags & ~XT_SOCKET_FLAGS_V2);
                return -EINVAL;
        }
        return 0;
@@ -203,8 +205,8 @@ static int socket_mt_v3_check(const struct xt_mtchk_param *par)
        if (err)
                return err;
        if (info->flags & ~XT_SOCKET_FLAGS_V3) {
-               pr_info("unknown flags 0x%x\n",
-                       info->flags & ~XT_SOCKET_FLAGS_V3);
+               pr_info_ratelimited("unknown flags 0x%x\n",
+                                   info->flags & ~XT_SOCKET_FLAGS_V3);
                return -EINVAL;
        }
        return 0;
index 5fbd791..0b41c0b 100644 (file)
@@ -44,8 +44,8 @@ static int state_mt_check(const struct xt_mtchk_param *par)
 
        ret = nf_ct_netns_get(par->net, par->family);
        if (ret < 0)
-               pr_info("cannot load conntrack support for proto=%u\n",
-                       par->family);
+               pr_info_ratelimited("cannot load conntrack support for proto=%u\n",
+                                   par->family);
        return ret;
 }
 
index 1b01eec..0160f50 100644 (file)
@@ -235,13 +235,13 @@ static int time_mt_check(const struct xt_mtchk_param *par)
 
        if (info->daytime_start > XT_TIME_MAX_DAYTIME ||
            info->daytime_stop > XT_TIME_MAX_DAYTIME) {
-               pr_info("invalid argument - start or "
-                       "stop time greater than 23:59:59\n");
+               pr_info_ratelimited("invalid argument - start or stop time greater than 23:59:59\n");
                return -EDOM;
        }
 
        if (info->flags & ~XT_TIME_ALL_FLAGS) {
-               pr_info("unknown flags 0x%x\n", info->flags & ~XT_TIME_ALL_FLAGS);
+               pr_info_ratelimited("unknown flags 0x%x\n",
+                                   info->flags & ~XT_TIME_ALL_FLAGS);
                return -EINVAL;
        }
 
index 2ad445c..70c4553 100644 (file)
@@ -1085,6 +1085,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr,
        if (addr->sa_family != AF_NETLINK)
                return -EINVAL;
 
+       if (alen < sizeof(struct sockaddr_nl))
+               return -EINVAL;
+
        if ((nladdr->nl_groups || nladdr->nl_pid) &&
            !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND))
                return -EPERM;
@@ -2308,7 +2311,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
        if (cb->start) {
                ret = cb->start(cb);
                if (ret)
-                       goto error_unlock;
+                       goto error_put;
        }
 
        nlk->cb_running = true;
@@ -2328,6 +2331,8 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb,
         */
        return -EINTR;
 
+error_put:
+       module_put(control->module);
 error_unlock:
        sock_put(sk);
        mutex_unlock(nlk->cb_mutex);
index 6f02499..b9ce82c 100644 (file)
@@ -1106,7 +1106,7 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group,
        if (!err)
                delivered = true;
        else if (err != -ESRCH)
-               goto error;
+               return err;
        return delivered ? 0 : -ESRCH;
  error:
        kfree_skb(skb);
index 367d8c0..2ceefa1 100644 (file)
@@ -149,6 +149,10 @@ struct nfc_llcp_sdp_tlv *nfc_llcp_build_sdreq_tlv(u8 tid, char *uri,
 
        pr_debug("uri: %s, len: %zu\n", uri, uri_len);
 
+       /* sdreq->tlv_len is u8, takes uri_len, + 3 for header, + 1 for NULL */
+       if (WARN_ON_ONCE(uri_len > U8_MAX - 4))
+               return NULL;
+
        sdreq = kzalloc(sizeof(struct nfc_llcp_sdp_tlv), GFP_KERNEL);
        if (sdreq == NULL)
                return NULL;
index c0b83dc..f018eaf 100644 (file)
@@ -61,7 +61,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
 };
 
 static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
-       [NFC_SDP_ATTR_URI] = { .type = NLA_STRING },
+       [NFC_SDP_ATTR_URI] = { .type = NLA_STRING,
+                              .len = U8_MAX - 4 },
        [NFC_SDP_ATTR_SAP] = { .type = NLA_U8 },
 };
 
index 04b9428..b891a91 100644 (file)
@@ -242,14 +242,20 @@ static struct dp_meter *dp_meter_create(struct nlattr **a)
 
                band->type = nla_get_u32(attr[OVS_BAND_ATTR_TYPE]);
                band->rate = nla_get_u32(attr[OVS_BAND_ATTR_RATE]);
+               if (band->rate == 0) {
+                       err = -EINVAL;
+                       goto exit_free_meter;
+               }
+
                band->burst_size = nla_get_u32(attr[OVS_BAND_ATTR_BURST]);
                /* Figure out max delta_t that is enough to fill any bucket.
                 * Keep max_delta_t size to the bucket units:
                 * pkts => 1/1000 packets, kilobits => bits.
+                *
+                * Start with a full bucket.
                 */
-               band_max_delta_t = (band->burst_size + band->rate) * 1000;
-               /* Start with a full bucket. */
-               band->bucket = band_max_delta_t;
+               band->bucket = (band->burst_size + band->rate) * 1000;
+               band_max_delta_t = band->bucket / band->rate;
                if (band_max_delta_t > meter->max_delta_t)
                        meter->max_delta_t = band_max_delta_t;
                band++;
index 50615d5..9cf089b 100644 (file)
@@ -114,5 +114,6 @@ static struct rpmsg_driver qcom_smd_qrtr_driver = {
 
 module_rpmsg_driver(qcom_smd_qrtr_driver);
 
+MODULE_ALIAS("rpmsg:IPCRTR");
 MODULE_DESCRIPTION("Qualcomm IPC-Router SMD interface driver");
 MODULE_LICENSE("GPL v2");
index 94e190f..2da3176 100644 (file)
@@ -224,7 +224,7 @@ static struct rds_connection *__rds_conn_create(struct net *net,
        if (rds_destroy_pending(conn))
                ret = -ENETDOWN;
        else
-               ret = trans->conn_alloc(conn, gfp);
+               ret = trans->conn_alloc(conn, GFP_ATOMIC);
        if (ret) {
                rcu_read_unlock();
                kfree(conn->c_path);
index c061d6e..2257118 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006 Oracle.  All rights reserved.
+ * Copyright (c) 2006, 2018 Oracle.  All rights reserved.
  *
  * This software is available to you under a choice of one of two
  * licenses.  You may choose to be licensed under the terms of the GNU
@@ -142,12 +142,20 @@ int rds_tcp_accept_one(struct socket *sock)
        if (ret)
                goto out;
 
-       new_sock->type = sock->type;
-       new_sock->ops = sock->ops;
        ret = sock->ops->accept(sock, new_sock, O_NONBLOCK, true);
        if (ret < 0)
                goto out;
 
+       /* sock_create_lite() does not get a hold on the owner module so we
+        * need to do it here.  Note that sock_release() uses sock->ops to
+        * determine if it needs to decrement the reference count.  So set
+        * sock->ops after calling accept() in case that fails.  And there's
+        * no need to do try_module_get() as the listener should have a hold
+        * already.
+        */
+       new_sock->ops = sock->ops;
+       __module_get(new_sock->ops->owner);
+
        ret = rds_tcp_keepalive(new_sock);
        if (ret < 0)
                goto out;
index 42410e9..cf73dc0 100644 (file)
@@ -445,7 +445,7 @@ send_fragmentable:
                                        (char *)&opt, sizeof(opt));
                if (ret == 0) {
                        ret = kernel_sendmsg(conn->params.local->socket, &msg,
-                                            iov, 1, iov[0].iov_len);
+                                            iov, 2, len);
 
                        opt = IPV6_PMTUDISC_DO;
                        kernel_setsockopt(conn->params.local->socket,
index cc21e8d..9d45d8b 100644 (file)
@@ -517,9 +517,10 @@ try_again:
                        ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
                                       sizeof(unsigned int), &id32);
                } else {
+                       unsigned long idl = call->user_call_ID;
+
                        ret = put_cmsg(msg, SOL_RXRPC, RXRPC_USER_CALL_ID,
-                                      sizeof(unsigned long),
-                                      &call->user_call_ID);
+                                      sizeof(unsigned long), &idl);
                }
                if (ret < 0)
                        goto error_unlock_call;
index eba6682..efc6bfb 100644 (file)
@@ -135,8 +135,10 @@ static int tcf_dump_walker(struct tcf_idrinfo *idrinfo, struct sk_buff *skb,
                        continue;
 
                nest = nla_nest_start(skb, n_i);
-               if (!nest)
+               if (!nest) {
+                       index--;
                        goto nla_put_failure;
+               }
                err = tcf_action_dump_1(skb, p, 0, 0);
                if (err < 0) {
                        index--;
index b3f2c15..9d2cabf 100644 (file)
@@ -352,7 +352,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla,
        return res;
 out:
        if (res == ACT_P_CREATED)
-               tcf_idr_cleanup(*act, est);
+               tcf_idr_release(*act, bind);
 
        return ret;
 }
index b7ba9b0..2a5c8fd 100644 (file)
@@ -350,7 +350,7 @@ static int tcf_csum_sctp(struct sk_buff *skb, unsigned int ihl,
 {
        struct sctphdr *sctph;
 
-       if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_SCTP)
+       if (skb_is_gso(skb) && skb_is_gso_sctp(skb))
                return 1;
 
        sctph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*sctph));
@@ -626,7 +626,8 @@ static void tcf_csum_cleanup(struct tc_action *a)
        struct tcf_csum_params *params;
 
        params = rcu_dereference_protected(p->params, 1);
-       kfree_rcu(params, rcu);
+       if (params)
+               kfree_rcu(params, rcu);
 }
 
 static int tcf_csum_walker(struct net *net, struct sk_buff *skb,
index 06e380a..7e06b9b 100644 (file)
@@ -80,9 +80,12 @@ static void ipt_destroy_target(struct xt_entry_target *t)
 static void tcf_ipt_release(struct tc_action *a)
 {
        struct tcf_ipt *ipt = to_ipt(a);
-       ipt_destroy_target(ipt->tcfi_t);
+
+       if (ipt->tcfi_t) {
+               ipt_destroy_target(ipt->tcfi_t);
+               kfree(ipt->tcfi_t);
+       }
        kfree(ipt->tcfi_tname);
-       kfree(ipt->tcfi_t);
 }
 
 static const struct nla_policy ipt_policy[TCA_IPT_MAX + 1] = {
@@ -187,7 +190,7 @@ err2:
        kfree(tname);
 err1:
        if (ret == ACT_P_CREATED)
-               tcf_idr_cleanup(*a, est);
+               tcf_idr_release(*a, bind);
        return err;
 }
 
index 349beaf..fef0883 100644 (file)
@@ -176,7 +176,7 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla,
                p = to_pedit(*a);
                keys = kmalloc(ksize, GFP_KERNEL);
                if (keys == NULL) {
-                       tcf_idr_cleanup(*a, est);
+                       tcf_idr_release(*a, bind);
                        kfree(keys_ex);
                        return -ENOMEM;
                }
index 95d3c90..faebf82 100644 (file)
@@ -194,7 +194,7 @@ failure:
        qdisc_put_rtab(P_tab);
        qdisc_put_rtab(R_tab);
        if (ret == ACT_P_CREATED)
-               tcf_idr_cleanup(*a, est);
+               tcf_idr_release(*a, bind);
        return err;
 }
 
index 1ba0df2..74c5d7e 100644 (file)
@@ -103,7 +103,8 @@ static void tcf_sample_cleanup(struct tc_action *a)
 
        psample_group = rtnl_dereference(s->psample_group);
        RCU_INIT_POINTER(s->psample_group, NULL);
-       psample_group_put(psample_group);
+       if (psample_group)
+               psample_group_put(psample_group);
 }
 
 static bool tcf_sample_dev_ok_push(struct net_device *dev)
index 425eac1..b1f3806 100644 (file)
@@ -121,7 +121,7 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla,
                d = to_defact(*a);
                ret = alloc_defdata(d, defdata);
                if (ret < 0) {
-                       tcf_idr_cleanup(*a, est);
+                       tcf_idr_release(*a, bind);
                        return ret;
                }
                d->tcf_action = parm->action;
index fa97526..7b0700f 100644 (file)
@@ -152,7 +152,7 @@ static int tcf_skbmod_init(struct net *net, struct nlattr *nla,
        ASSERT_RTNL();
        p = kzalloc(sizeof(struct tcf_skbmod_params), GFP_KERNEL);
        if (unlikely(!p)) {
-               if (ovr)
+               if (ret == ACT_P_CREATED)
                        tcf_idr_release(*a, bind);
                return -ENOMEM;
        }
@@ -190,7 +190,8 @@ static void tcf_skbmod_cleanup(struct tc_action *a)
        struct tcf_skbmod_params  *p;
 
        p = rcu_dereference_protected(d->skbmod_p, 1);
-       kfree_rcu(p, rcu);
+       if (p)
+               kfree_rcu(p, rcu);
 }
 
 static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a,
index 0e23aac..1281ca4 100644 (file)
@@ -153,6 +153,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla,
                metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX;
                break;
        default:
+               ret = -EINVAL;
                goto err_out;
        }
 
@@ -207,11 +208,12 @@ static void tunnel_key_release(struct tc_action *a)
        struct tcf_tunnel_key_params *params;
 
        params = rcu_dereference_protected(t->params, 1);
+       if (params) {
+               if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
+                       dst_release(&params->tcft_enc_metadata->dst);
 
-       if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET)
-               dst_release(&params->tcft_enc_metadata->dst);
-
-       kfree_rcu(params, rcu);
+               kfree_rcu(params, rcu);
+       }
 }
 
 static int tunnel_key_dump_addresses(struct sk_buff *skb,
index e1a1b3f..c49cb61 100644 (file)
@@ -195,7 +195,7 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla,
        ASSERT_RTNL();
        p = kzalloc(sizeof(*p), GFP_KERNEL);
        if (!p) {
-               if (ovr)
+               if (ret == ACT_P_CREATED)
                        tcf_idr_release(*a, bind);
                return -ENOMEM;
        }
@@ -225,7 +225,8 @@ static void tcf_vlan_cleanup(struct tc_action *a)
        struct tcf_vlan_params *p;
 
        p = rcu_dereference_protected(v->vlan_p, 1);
-       kfree_rcu(p, rcu);
+       if (p)
+               kfree_rcu(p, rcu);
 }
 
 static int tcf_vlan_dump(struct sk_buff *skb, struct tc_action *a,
index 2bc1bc2..247b7cc 100644 (file)
@@ -376,17 +376,12 @@ struct tcf_net {
 static unsigned int tcf_net_id;
 
 static int tcf_block_insert(struct tcf_block *block, struct net *net,
-                           u32 block_index, struct netlink_ext_ack *extack)
+                           struct netlink_ext_ack *extack)
 {
        struct tcf_net *tn = net_generic(net, tcf_net_id);
-       int err;
 
-       err = idr_alloc_u32(&tn->idr, block, &block_index, block_index,
-                           GFP_KERNEL);
-       if (err)
-               return err;
-       block->index = block_index;
-       return 0;
+       return idr_alloc_u32(&tn->idr, block, &block->index, block->index,
+                            GFP_KERNEL);
 }
 
 static void tcf_block_remove(struct tcf_block *block, struct net *net)
@@ -397,6 +392,7 @@ static void tcf_block_remove(struct tcf_block *block, struct net *net)
 }
 
 static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
+                                         u32 block_index,
                                          struct netlink_ext_ack *extack)
 {
        struct tcf_block *block;
@@ -419,10 +415,13 @@ static struct tcf_block *tcf_block_create(struct net *net, struct Qdisc *q,
                err = -ENOMEM;
                goto err_chain_create;
        }
-       block->net = qdisc_net(q);
        block->refcnt = 1;
        block->net = net;
-       block->q = q;
+       block->index = block_index;
+
+       /* Don't store q pointer for blocks which are shared */
+       if (!tcf_block_shared(block))
+               block->q = q;
        return block;
 
 err_chain_create:
@@ -518,13 +517,12 @@ int tcf_block_get_ext(struct tcf_block **p_block, struct Qdisc *q,
        }
 
        if (!block) {
-               block = tcf_block_create(net, q, extack);
+               block = tcf_block_create(net, q, ei->block_index, extack);
                if (IS_ERR(block))
                        return PTR_ERR(block);
                created = true;
-               if (ei->block_index) {
-                       err = tcf_block_insert(block, net,
-                                              ei->block_index, extack);
+               if (tcf_block_shared(block)) {
+                       err = tcf_block_insert(block, net, extack);
                        if (err)
                                goto err_block_insert;
                }
@@ -1399,13 +1397,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
                    nla_get_u32(tca[TCA_CHAIN]) != chain->index)
                        continue;
                if (!tcf_chain_dump(chain, q, parent, skb, cb,
-                                   index_start, &index))
+                                   index_start, &index)) {
+                       err = -EMSGSIZE;
                        break;
+               }
        }
 
        cb->args[0] = index;
 
 out:
+       /* If we did no progress, the error (EMSGSIZE) is real */
+       if (skb->len == 0 && err)
+               return err;
        return skb->len;
 }
 
index 6c7601a..ed8b6a2 100644 (file)
@@ -96,7 +96,7 @@ struct tc_u_hnode {
 
 struct tc_u_common {
        struct tc_u_hnode __rcu *hlist;
-       struct tcf_block        *block;
+       void                    *ptr;
        int                     refcnt;
        struct idr              handle_idr;
        struct hlist_node       hnode;
@@ -330,9 +330,25 @@ static struct hlist_head *tc_u_common_hash;
 #define U32_HASH_SHIFT 10
 #define U32_HASH_SIZE (1 << U32_HASH_SHIFT)
 
+static void *tc_u_common_ptr(const struct tcf_proto *tp)
+{
+       struct tcf_block *block = tp->chain->block;
+
+       /* The block sharing is currently supported only
+        * for classless qdiscs. In that case we use block
+        * for tc_u_common identification. In case the
+        * block is not shared, block->q is a valid pointer
+        * and we can use that. That works for classful qdiscs.
+        */
+       if (tcf_block_shared(block))
+               return block;
+       else
+               return block->q;
+}
+
 static unsigned int tc_u_hash(const struct tcf_proto *tp)
 {
-       return hash_ptr(tp->chain->block, U32_HASH_SHIFT);
+       return hash_ptr(tc_u_common_ptr(tp), U32_HASH_SHIFT);
 }
 
 static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp)
@@ -342,7 +358,7 @@ static struct tc_u_common *tc_u_common_find(const struct tcf_proto *tp)
 
        h = tc_u_hash(tp);
        hlist_for_each_entry(tc, &tc_u_common_hash[h], hnode) {
-               if (tc->block == tp->chain->block)
+               if (tc->ptr == tc_u_common_ptr(tp))
                        return tc;
        }
        return NULL;
@@ -371,7 +387,7 @@ static int u32_init(struct tcf_proto *tp)
                        kfree(root_ht);
                        return -ENOBUFS;
                }
-               tp_c->block = tp->chain->block;
+               tp_c->ptr = tc_u_common_ptr(tp);
                INIT_HLIST_NODE(&tp_c->hnode);
                idr_init(&tp_c->handle_idr);
 
index 190570f..39c144b 100644 (file)
@@ -106,6 +106,14 @@ static inline void qdisc_enqueue_skb_bad_txq(struct Qdisc *q,
 
        __skb_queue_tail(&q->skb_bad_txq, skb);
 
+       if (qdisc_is_percpu_stats(q)) {
+               qdisc_qstats_cpu_backlog_inc(q, skb);
+               qdisc_qstats_cpu_qlen_inc(q);
+       } else {
+               qdisc_qstats_backlog_inc(q, skb);
+               q->q.qlen++;
+       }
+
        if (lock)
                spin_unlock(lock);
 }
@@ -196,14 +204,6 @@ static void try_bulk_dequeue_skb_slow(struct Qdisc *q,
                        break;
                if (unlikely(skb_get_queue_mapping(nskb) != mapping)) {
                        qdisc_enqueue_skb_bad_txq(q, nskb);
-
-                       if (qdisc_is_percpu_stats(q)) {
-                               qdisc_qstats_cpu_backlog_inc(q, nskb);
-                               qdisc_qstats_cpu_qlen_inc(q);
-                       } else {
-                               qdisc_qstats_backlog_inc(q, nskb);
-                               q->q.qlen++;
-                       }
                        break;
                }
                skb->next = nskb;
@@ -373,24 +373,33 @@ bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
  */
 static inline bool qdisc_restart(struct Qdisc *q, int *packets)
 {
+       bool more, validate, nolock = q->flags & TCQ_F_NOLOCK;
        spinlock_t *root_lock = NULL;
        struct netdev_queue *txq;
        struct net_device *dev;
        struct sk_buff *skb;
-       bool validate;
 
        /* Dequeue packet */
+       if (nolock && test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+               return false;
+
        skb = dequeue_skb(q, &validate, packets);
-       if (unlikely(!skb))
+       if (unlikely(!skb)) {
+               if (nolock)
+                       clear_bit(__QDISC_STATE_RUNNING, &q->state);
                return false;
+       }
 
-       if (!(q->flags & TCQ_F_NOLOCK))
+       if (!nolock)
                root_lock = qdisc_lock(q);
 
        dev = qdisc_dev(q);
        txq = skb_get_tx_queue(dev, skb);
 
-       return sch_direct_xmit(skb, q, dev, txq, root_lock, validate);
+       more = sch_direct_xmit(skb, q, dev, txq, root_lock, validate);
+       if (nolock)
+               clear_bit(__QDISC_STATE_RUNNING, &q->state);
+       return more;
 }
 
 void __qdisc_run(struct Qdisc *q)
@@ -628,6 +637,7 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,
        int band = prio2band[skb->priority & TC_PRIO_MAX];
        struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
        struct skb_array *q = band2list(priv, band);
+       unsigned int pkt_len = qdisc_pkt_len(skb);
        int err;
 
        err = skb_array_produce(q, skb);
@@ -636,7 +646,10 @@ static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,
                return qdisc_drop_cpu(skb, qdisc, to_free);
 
        qdisc_qstats_cpu_qlen_inc(qdisc);
-       qdisc_qstats_cpu_backlog_inc(qdisc, skb);
+       /* Note: skb can not be used after skb_array_produce(),
+        * so we better not use qdisc_qstats_cpu_backlog_inc()
+        */
+       this_cpu_add(qdisc->cpu_qstats->backlog, pkt_len);
        return NET_XMIT_SUCCESS;
 }
 
index 7c179ad..7d6801f 100644 (file)
@@ -509,7 +509,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
        }
 
        if (unlikely(sch->q.qlen >= sch->limit))
-               return qdisc_drop(skb, sch, to_free);
+               return qdisc_drop_all(skb, sch, to_free);
 
        qdisc_qstats_backlog_inc(sch, skb);
 
index 229172d..03225a8 100644 (file)
@@ -188,7 +188,8 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch,
        int ret;
 
        if (qdisc_pkt_len(skb) > q->max_size) {
-               if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size)
+               if (skb_is_gso(skb) &&
+                   skb_gso_validate_mac_len(skb, q->max_size))
                        return tbf_segment(skb, sch, to_free);
                return qdisc_drop(skb, sch, to_free);
        }
index 291c97b..8f6c2e8 100644 (file)
@@ -81,6 +81,12 @@ const char *sctp_cname(const union sctp_subtype cid)
        case SCTP_CID_RECONF:
                return "RECONF";
 
+       case SCTP_CID_I_DATA:
+               return "I_DATA";
+
+       case SCTP_CID_I_FWD_TSN:
+               return "I_FWD_TSN";
+
        default:
                break;
        }
index 141c9c4..b381d78 100644 (file)
@@ -106,6 +106,7 @@ int sctp_rcv(struct sk_buff *skb)
        int family;
        struct sctp_af *af;
        struct net *net = dev_net(skb->dev);
+       bool is_gso = skb_is_gso(skb) && skb_is_gso_sctp(skb);
 
        if (skb->pkt_type != PACKET_HOST)
                goto discard_it;
@@ -123,8 +124,7 @@ int sctp_rcv(struct sk_buff *skb)
         * it's better to just linearize it otherwise crc computing
         * takes longer.
         */
-       if ((!(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) &&
-            skb_linearize(skb)) ||
+       if ((!is_gso && skb_linearize(skb)) ||
            !pskb_may_pull(skb, sizeof(struct sctphdr)))
                goto discard_it;
 
@@ -135,7 +135,7 @@ int sctp_rcv(struct sk_buff *skb)
        if (skb_csum_unnecessary(skb))
                __skb_decr_checksum_unnecessary(skb);
        else if (!sctp_checksum_disable &&
-                !(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) &&
+                !is_gso &&
                 sctp_rcv_checksum(net, skb) < 0)
                goto discard_it;
        skb->csum_valid = 1;
@@ -897,15 +897,12 @@ int sctp_hash_transport(struct sctp_transport *t)
        rhl_for_each_entry_rcu(transport, tmp, list, node)
                if (transport->asoc->ep == t->asoc->ep) {
                        rcu_read_unlock();
-                       err = -EEXIST;
-                       goto out;
+                       return -EEXIST;
                }
        rcu_read_unlock();
 
        err = rhltable_insert_key(&sctp_transport_hashtable, &arg,
                                  &t->node, sctp_hash_params);
-
-out:
        if (err)
                pr_err_once("insert transport fail, errno %d\n", err);
 
@@ -1221,7 +1218,7 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net,
         * issue as packets hitting this are mostly INIT or INIT-ACK and
         * those cannot be on GSO-style anyway.
         */
-       if ((skb_shinfo(skb)->gso_type & SKB_GSO_SCTP) == SKB_GSO_SCTP)
+       if (skb_is_gso(skb) && skb_is_gso_sctp(skb))
                return NULL;
 
        ch = (struct sctp_chunkhdr *)skb->data;
index 4839255..23ebc53 100644 (file)
@@ -170,7 +170,7 @@ next_chunk:
 
                chunk = list_entry(entry, struct sctp_chunk, list);
 
-               if ((skb_shinfo(chunk->skb)->gso_type & SKB_GSO_SCTP) == SKB_GSO_SCTP) {
+               if (skb_is_gso(chunk->skb) && skb_is_gso_sctp(chunk->skb)) {
                        /* GSO-marked skbs but without frags, handle
                         * them normally
                         */
index 35bc710..123e9f2 100644 (file)
@@ -45,7 +45,7 @@ static struct sk_buff *sctp_gso_segment(struct sk_buff *skb,
        struct sk_buff *segs = ERR_PTR(-EINVAL);
        struct sctphdr *sh;
 
-       if (!(skb_shinfo(skb)->gso_type & SKB_GSO_SCTP))
+       if (!skb_is_gso_sctp(skb))
                goto out;
 
        sh = sctp_hdr(skb);
index cedf672..f799043 100644 (file)
@@ -6,7 +6,7 @@
  *
  * This file is part of the SCTP kernel implementation
  *
- * These functions manipulate sctp tsn mapping array.
+ * This file contains sctp stream maniuplation primitives and helpers.
  *
  * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
index 8c7cf8f..d3764c1 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This file is part of the SCTP kernel implementation
  *
- * These functions manipulate sctp stream queue/scheduling.
+ * These functions implement sctp stream message interleaving, mostly
+ * including I-DATA and I-FORWARD-TSN chunks process.
  *
  * This SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
@@ -954,12 +955,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
        __u32 freed = 0;
        __u16 needed;
 
-       if (chunk) {
-               needed = ntohs(chunk->chunk_hdr->length);
-               needed -= sizeof(struct sctp_idata_chunk);
-       } else {
-               needed = SCTP_DEFAULT_MAXWINDOW;
-       }
+       needed = ntohs(chunk->chunk_hdr->length) -
+                sizeof(struct sctp_idata_chunk);
 
        if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) {
                freed = sctp_ulpq_renege_list(ulpq, &ulpq->lobby, needed);
@@ -971,9 +968,8 @@ static void sctp_renege_events(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
                                                       needed);
        }
 
-       if (chunk && freed >= needed)
-               if (sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
-                       sctp_intl_start_pd(ulpq, gfp);
+       if (freed >= needed && sctp_ulpevent_idata(ulpq, chunk, gfp) <= 0)
+               sctp_intl_start_pd(ulpq, gfp);
 
        sk_mem_reclaim(asoc->base.sk);
 }
index da1a5cd..1e0d780 100644 (file)
@@ -978,10 +978,6 @@ out:
                lsmc->clcsock = NULL;
        }
        release_sock(lsk);
-       /* no more listening, wake up smc_close_wait_listen_clcsock and
-        * accept
-        */
-       lsk->sk_state_change(lsk);
        sock_put(&lsmc->sk); /* sock_hold in smc_listen */
 }
 
@@ -1406,8 +1402,10 @@ static int smc_create(struct net *net, struct socket *sock, int protocol,
        smc->use_fallback = false; /* assume rdma capability first */
        rc = sock_create_kern(net, PF_INET, SOCK_STREAM,
                              IPPROTO_TCP, &smc->clcsock);
-       if (rc)
+       if (rc) {
                sk_common_release(sk);
+               goto out;
+       }
        smc->sk.sk_sndbuf = max(smc->clcsock->sk->sk_sndbuf, SMC_BUF_MIN_SIZE);
        smc->sk.sk_rcvbuf = max(smc->clcsock->sk->sk_rcvbuf, SMC_BUF_MIN_SIZE);
 
index 3cd086e..b42395d 100644 (file)
@@ -269,7 +269,7 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf)
 
        if (wc->byte_len < offsetof(struct smc_cdc_msg, reserved))
                return; /* short message */
-       if (cdc->len != sizeof(*cdc))
+       if (cdc->len != SMC_WR_TX_SIZE)
                return; /* invalid message */
        smc_cdc_msg_recv(cdc, link, wc->wr_id);
 }
index 8ac5158..15c2132 100644 (file)
@@ -133,7 +133,7 @@ int smc_clc_wait_msg(struct smc_sock *smc, void *buf, int buflen,
 
        /* receive the complete CLC message */
        memset(&msg, 0, sizeof(struct msghdr));
-       iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &vec, 1, buflen);
+       iov_iter_kvec(&msg.msg_iter, READ | ITER_KVEC, &vec, 1, datlen);
        krflags = MSG_WAITALL;
        smc->clcsock->sk->sk_rcvtimeo = CLC_WAIT_TIME;
        len = sock_recvmsg(smc->clcsock, &msg, krflags);
index e339c01..fa41d98 100644 (file)
@@ -30,27 +30,6 @@ static void smc_close_cleanup_listen(struct sock *parent)
                smc_close_non_accepted(sk);
 }
 
-static void smc_close_wait_listen_clcsock(struct smc_sock *smc)
-{
-       DEFINE_WAIT_FUNC(wait, woken_wake_function);
-       struct sock *sk = &smc->sk;
-       signed long timeout;
-
-       timeout = SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME;
-       add_wait_queue(sk_sleep(sk), &wait);
-       do {
-               release_sock(sk);
-               if (smc->clcsock)
-                       timeout = wait_woken(&wait, TASK_UNINTERRUPTIBLE,
-                                            timeout);
-               sched_annotate_sleep();
-               lock_sock(sk);
-               if (!smc->clcsock)
-                       break;
-       } while (timeout);
-       remove_wait_queue(sk_sleep(sk), &wait);
-}
-
 /* wait for sndbuf data being transmitted */
 static void smc_close_stream_wait(struct smc_sock *smc, long timeout)
 {
@@ -204,9 +183,11 @@ again:
                        rc = kernel_sock_shutdown(smc->clcsock, SHUT_RDWR);
                        /* wake up kernel_accept of smc_tcp_listen_worker */
                        smc->clcsock->sk->sk_data_ready(smc->clcsock->sk);
-                       smc_close_wait_listen_clcsock(smc);
                }
                smc_close_cleanup_listen(sk);
+               release_sock(sk);
+               flush_work(&smc->tcp_listen_work);
+               lock_sock(sk);
                break;
        case SMC_ACTIVE:
                smc_close_stream_wait(smc, timeout);
index 2424c71..645dd22 100644 (file)
@@ -177,6 +177,7 @@ static int smc_lgr_create(struct smc_sock *smc, __be32 peer_in_addr,
 
        lnk = &lgr->lnk[SMC_SINGLE_LINK];
        /* initialize link */
+       lnk->link_id = SMC_SINGLE_LINK;
        lnk->smcibdev = smcibdev;
        lnk->ibport = ibport;
        lnk->path_mtu = smcibdev->pattr[ibport - 1].active_mtu;
@@ -465,7 +466,7 @@ create:
                rc = smc_link_determine_gid(conn->lgr);
        }
        conn->local_tx_ctrl.common.type = SMC_CDC_MSG_TYPE;
-       conn->local_tx_ctrl.len = sizeof(struct smc_cdc_msg);
+       conn->local_tx_ctrl.len = SMC_WR_TX_SIZE;
 #ifndef KERNEL_HAS_ATOMIC64
        spin_lock_init(&conn->acurs_lock);
 #endif
index 92fe4cc..b4aa4fc 100644 (file)
@@ -92,7 +92,7 @@ int smc_llc_send_confirm_link(struct smc_link *link, u8 mac[],
        memcpy(confllc->sender_mac, mac, ETH_ALEN);
        memcpy(confllc->sender_gid, gid, SMC_GID_SIZE);
        hton24(confllc->sender_qp_num, link->roce_qp->qp_num);
-       /* confllc->link_num = SMC_SINGLE_LINK; already done by memset above */
+       confllc->link_num = link->link_id;
        memcpy(confllc->link_uid, lgr->id, SMC_LGR_ID_SIZE);
        confllc->max_links = SMC_LINKS_PER_LGR_MAX;
        /* send llc message */
index a93c99b..08847c3 100644 (file)
@@ -2587,6 +2587,11 @@ void sock_unregister(int family)
 }
 EXPORT_SYMBOL(sock_unregister);
 
+bool sock_is_registered(int family)
+{
+       return family < NPROTO && rcu_access_pointer(net_families[family]);
+}
+
 static int __init sock_init(void)
 {
        int err;
index 1fdab5c..b9283ce 100644 (file)
@@ -60,7 +60,7 @@ static void strp_abort_strp(struct strparser *strp, int err)
                struct sock *sk = strp->sk;
 
                /* Report an error on the lower socket */
-               sk->sk_err = err;
+               sk->sk_err = -err;
                sk->sk_error_report(sk);
        }
 }
@@ -458,7 +458,7 @@ static void strp_msg_timeout(struct work_struct *w)
        /* Message assembly timed out */
        STRP_STATS_INCR(strp->stats.msg_timeouts);
        strp->cb.lock(strp);
-       strp->cb.abort_parser(strp, ETIMEDOUT);
+       strp->cb.abort_parser(strp, -ETIMEDOUT);
        strp->cb.unlock(strp);
 }
 
index c800147..3e3dce3 100644 (file)
@@ -813,7 +813,7 @@ err_out:
        return err;
 }
 
-int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
 {
        int err;
        char *name;
@@ -835,20 +835,27 @@ int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
 
        name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
 
-       rtnl_lock();
        bearer = tipc_bearer_find(net, name);
-       if (!bearer) {
-               rtnl_unlock();
+       if (!bearer)
                return -EINVAL;
-       }
 
        bearer_disable(net, bearer);
-       rtnl_unlock();
 
        return 0;
 }
 
-int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
+int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+
+       rtnl_lock();
+       err = __tipc_nl_bearer_disable(skb, info);
+       rtnl_unlock();
+
+       return err;
+}
+
+int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
 {
        int err;
        char *bearer;
@@ -890,15 +897,18 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
                        prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]);
        }
 
+       return tipc_enable_bearer(net, bearer, domain, prio, attrs);
+}
+
+int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+
        rtnl_lock();
-       err = tipc_enable_bearer(net, bearer, domain, prio, attrs);
-       if (err) {
-               rtnl_unlock();
-               return err;
-       }
+       err = __tipc_nl_bearer_enable(skb, info);
        rtnl_unlock();
 
-       return 0;
+       return err;
 }
 
 int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
@@ -944,7 +954,7 @@ int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info)
        return 0;
 }
 
-int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
 {
        int err;
        char *name;
@@ -965,22 +975,17 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
        name = nla_data(attrs[TIPC_NLA_BEARER_NAME]);
 
-       rtnl_lock();
        b = tipc_bearer_find(net, name);
-       if (!b) {
-               rtnl_unlock();
+       if (!b)
                return -EINVAL;
-       }
 
        if (attrs[TIPC_NLA_BEARER_PROP]) {
                struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
 
                err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_BEARER_PROP],
                                              props);
-               if (err) {
-                       rtnl_unlock();
+               if (err)
                        return err;
-               }
 
                if (props[TIPC_NLA_PROP_TOL])
                        b->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
@@ -989,11 +994,21 @@ int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
                if (props[TIPC_NLA_PROP_WIN])
                        b->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
        }
-       rtnl_unlock();
 
        return 0;
 }
 
+int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+
+       rtnl_lock();
+       err = __tipc_nl_bearer_set(skb, info);
+       rtnl_unlock();
+
+       return err;
+}
+
 static int __tipc_nl_add_media(struct tipc_nl_msg *msg,
                               struct tipc_media *media, int nlflags)
 {
@@ -1115,7 +1130,7 @@ err_out:
        return err;
 }
 
-int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
 {
        int err;
        char *name;
@@ -1133,22 +1148,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
        name = nla_data(attrs[TIPC_NLA_MEDIA_NAME]);
 
-       rtnl_lock();
        m = tipc_media_find(name);
-       if (!m) {
-               rtnl_unlock();
+       if (!m)
                return -EINVAL;
-       }
 
        if (attrs[TIPC_NLA_MEDIA_PROP]) {
                struct nlattr *props[TIPC_NLA_PROP_MAX + 1];
 
                err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_MEDIA_PROP],
                                              props);
-               if (err) {
-                       rtnl_unlock();
+               if (err)
                        return err;
-               }
 
                if (props[TIPC_NLA_PROP_TOL])
                        m->tolerance = nla_get_u32(props[TIPC_NLA_PROP_TOL]);
@@ -1157,7 +1167,17 @@ int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
                if (props[TIPC_NLA_PROP_WIN])
                        m->window = nla_get_u32(props[TIPC_NLA_PROP_WIN]);
        }
-       rtnl_unlock();
 
        return 0;
 }
+
+int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+
+       rtnl_lock();
+       err = __tipc_nl_media_set(skb, info);
+       rtnl_unlock();
+
+       return err;
+}
index 42d6eee..a53613d 100644 (file)
@@ -188,15 +188,19 @@ extern struct tipc_media udp_media_info;
 #endif
 
 int tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_disable(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_bearer_get(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_bearer_set(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_bearer_add(struct sk_buff *skb, struct genl_info *info);
 
 int tipc_nl_media_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info);
 int tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info);
 
 int tipc_media_set_priority(const char *name, u32 new_value);
 int tipc_media_set_window(const char *name, u32 new_value);
index 122162a..04e516d 100644 (file)
@@ -189,6 +189,7 @@ struct tipc_group *tipc_group_create(struct net *net, u32 portid,
        grp->loopback = mreq->flags & TIPC_GROUP_LOOPBACK;
        grp->events = mreq->flags & TIPC_GROUP_MEMBER_EVTS;
        grp->open = group_is_open;
+       *grp->open = false;
        filter |= global ? TIPC_SUB_CLUSTER_SCOPE : TIPC_SUB_NODE_SCOPE;
        if (tipc_topsrv_kern_subscr(net, portid, type, 0, ~0,
                                    filter, &grp->subid))
index 719c592..1a2fde0 100644 (file)
@@ -200,7 +200,7 @@ out:
        return skb->len;
 }
 
-int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
+int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
 {
        struct net *net = sock_net(skb->sk);
        struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -241,10 +241,19 @@ int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
                if (!tipc_addr_node_valid(addr))
                        return -EINVAL;
 
-               rtnl_lock();
                tipc_net_start(net, addr);
-               rtnl_unlock();
        }
 
        return 0;
 }
+
+int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info)
+{
+       int err;
+
+       rtnl_lock();
+       err = __tipc_nl_net_set(skb, info);
+       rtnl_unlock();
+
+       return err;
+}
index c7c2549..c0306aa 100644 (file)
@@ -47,5 +47,6 @@ void tipc_net_stop(struct net *net);
 
 int tipc_nl_net_dump(struct sk_buff *skb, struct netlink_callback *cb);
 int tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
+int __tipc_nl_net_set(struct sk_buff *skb, struct genl_info *info);
 
 #endif
index e48f0b2..4492cda 100644 (file)
@@ -285,10 +285,6 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
        if (!trans_buf)
                return -ENOMEM;
 
-       err = (*cmd->transcode)(cmd, trans_buf, msg);
-       if (err)
-               goto trans_out;
-
        attrbuf = kmalloc((tipc_genl_family.maxattr + 1) *
                        sizeof(struct nlattr *), GFP_KERNEL);
        if (!attrbuf) {
@@ -296,27 +292,34 @@ static int __tipc_nl_compat_doit(struct tipc_nl_compat_cmd_doit *cmd,
                goto trans_out;
        }
 
-       err = nla_parse(attrbuf, tipc_genl_family.maxattr,
-                       (const struct nlattr *)trans_buf->data,
-                       trans_buf->len, NULL, NULL);
-       if (err)
-               goto parse_out;
-
        doit_buf = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
        if (!doit_buf) {
                err = -ENOMEM;
-               goto parse_out;
+               goto attrbuf_out;
        }
 
-       doit_buf->sk = msg->dst_sk;
-
        memset(&info, 0, sizeof(info));
        info.attrs = attrbuf;
 
+       rtnl_lock();
+       err = (*cmd->transcode)(cmd, trans_buf, msg);
+       if (err)
+               goto doit_out;
+
+       err = nla_parse(attrbuf, tipc_genl_family.maxattr,
+                       (const struct nlattr *)trans_buf->data,
+                       trans_buf->len, NULL, NULL);
+       if (err)
+               goto doit_out;
+
+       doit_buf->sk = msg->dst_sk;
+
        err = (*cmd->doit)(doit_buf, &info);
+doit_out:
+       rtnl_unlock();
 
        kfree_skb(doit_buf);
-parse_out:
+attrbuf_out:
        kfree(attrbuf);
 trans_out:
        kfree_skb(trans_buf);
@@ -722,13 +725,13 @@ static int tipc_nl_compat_link_set(struct tipc_nl_compat_cmd_doit *cmd,
 
        media = tipc_media_find(lc->name);
        if (media) {
-               cmd->doit = &tipc_nl_media_set;
+               cmd->doit = &__tipc_nl_media_set;
                return tipc_nl_compat_media_set(skb, msg);
        }
 
        bearer = tipc_bearer_find(msg->net, lc->name);
        if (bearer) {
-               cmd->doit = &tipc_nl_bearer_set;
+               cmd->doit = &__tipc_nl_bearer_set;
                return tipc_nl_compat_bearer_set(skb, msg);
        }
 
@@ -1089,12 +1092,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
                return tipc_nl_compat_dumpit(&dump, msg);
        case TIPC_CMD_ENABLE_BEARER:
                msg->req_type = TIPC_TLV_BEARER_CONFIG;
-               doit.doit = tipc_nl_bearer_enable;
+               doit.doit = __tipc_nl_bearer_enable;
                doit.transcode = tipc_nl_compat_bearer_enable;
                return tipc_nl_compat_doit(&doit, msg);
        case TIPC_CMD_DISABLE_BEARER:
                msg->req_type = TIPC_TLV_BEARER_NAME;
-               doit.doit = tipc_nl_bearer_disable;
+               doit.doit = __tipc_nl_bearer_disable;
                doit.transcode = tipc_nl_compat_bearer_disable;
                return tipc_nl_compat_doit(&doit, msg);
        case TIPC_CMD_SHOW_LINK_STATS:
@@ -1148,12 +1151,12 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
                return tipc_nl_compat_dumpit(&dump, msg);
        case TIPC_CMD_SET_NODE_ADDR:
                msg->req_type = TIPC_TLV_NET_ADDR;
-               doit.doit = tipc_nl_net_set;
+               doit.doit = __tipc_nl_net_set;
                doit.transcode = tipc_nl_compat_net_set;
                return tipc_nl_compat_doit(&doit, msg);
        case TIPC_CMD_SET_NETID:
                msg->req_type = TIPC_TLV_UNSIGNED;
-               doit.doit = tipc_nl_net_set;
+               doit.doit = __tipc_nl_net_set;
                doit.transcode = tipc_nl_compat_net_set;
                return tipc_nl_compat_doit(&doit, msg);
        case TIPC_CMD_GET_NETID:
index b0323ec..7dfa9fc 100644 (file)
@@ -473,6 +473,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
        sk->sk_write_space = tipc_write_space;
        sk->sk_destruct = tipc_sock_destruct;
        tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
+       tsk->group_is_open = true;
        atomic_set(&tsk->dupl_rcvcnt, 0);
 
        /* Start out with safe limits until we receive an advertised window */
index b0d5fce..d824d54 100644 (file)
@@ -46,16 +46,26 @@ MODULE_DESCRIPTION("Transport Layer Security Support");
 MODULE_LICENSE("Dual BSD/GPL");
 
 enum {
+       TLSV4,
+       TLSV6,
+       TLS_NUM_PROTS,
+};
+
+enum {
        TLS_BASE_TX,
        TLS_SW_TX,
        TLS_NUM_CONFIG,
 };
 
-static struct proto tls_prots[TLS_NUM_CONFIG];
+static struct proto *saved_tcpv6_prot;
+static DEFINE_MUTEX(tcpv6_prot_mutex);
+static struct proto tls_prots[TLS_NUM_PROTS][TLS_NUM_CONFIG];
 
 static inline void update_sk_prot(struct sock *sk, struct tls_context *ctx)
 {
-       sk->sk_prot = &tls_prots[ctx->tx_conf];
+       int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
+
+       sk->sk_prot = &tls_prots[ip_ver][ctx->tx_conf];
 }
 
 int wait_on_pending_writer(struct sock *sk, long *timeo)
@@ -308,8 +318,11 @@ static int do_tls_getsockopt_tx(struct sock *sk, char __user *optval,
                        goto out;
                }
                lock_sock(sk);
-               memcpy(crypto_info_aes_gcm_128->iv, ctx->iv,
+               memcpy(crypto_info_aes_gcm_128->iv,
+                      ctx->iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE,
                       TLS_CIPHER_AES_GCM_128_IV_SIZE);
+               memcpy(crypto_info_aes_gcm_128->rec_seq, ctx->rec_seq,
+                      TLS_CIPHER_AES_GCM_128_REC_SEQ_SIZE);
                release_sock(sk);
                if (copy_to_user(optval,
                                 crypto_info_aes_gcm_128,
@@ -375,7 +388,7 @@ static int do_tls_setsockopt_tx(struct sock *sk, char __user *optval,
        rc = copy_from_user(crypto_info, optval, sizeof(*crypto_info));
        if (rc) {
                rc = -EFAULT;
-               goto out;
+               goto err_crypto_info;
        }
 
        /* check version */
@@ -450,8 +463,21 @@ static int tls_setsockopt(struct sock *sk, int level, int optname,
        return do_tls_setsockopt(sk, optname, optval, optlen);
 }
 
+static void build_protos(struct proto *prot, struct proto *base)
+{
+       prot[TLS_BASE_TX] = *base;
+       prot[TLS_BASE_TX].setsockopt    = tls_setsockopt;
+       prot[TLS_BASE_TX].getsockopt    = tls_getsockopt;
+       prot[TLS_BASE_TX].close         = tls_sk_proto_close;
+
+       prot[TLS_SW_TX] = prot[TLS_BASE_TX];
+       prot[TLS_SW_TX].sendmsg         = tls_sw_sendmsg;
+       prot[TLS_SW_TX].sendpage        = tls_sw_sendpage;
+}
+
 static int tls_init(struct sock *sk)
 {
+       int ip_ver = sk->sk_family == AF_INET6 ? TLSV6 : TLSV4;
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct tls_context *ctx;
        int rc = 0;
@@ -476,6 +502,17 @@ static int tls_init(struct sock *sk)
        ctx->getsockopt = sk->sk_prot->getsockopt;
        ctx->sk_proto_close = sk->sk_prot->close;
 
+       /* Build IPv6 TLS whenever the address of tcpv6_prot changes */
+       if (ip_ver == TLSV6 &&
+           unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) {
+               mutex_lock(&tcpv6_prot_mutex);
+               if (likely(sk->sk_prot != saved_tcpv6_prot)) {
+                       build_protos(tls_prots[TLSV6], sk->sk_prot);
+                       smp_store_release(&saved_tcpv6_prot, sk->sk_prot);
+               }
+               mutex_unlock(&tcpv6_prot_mutex);
+       }
+
        ctx->tx_conf = TLS_BASE_TX;
        update_sk_prot(sk, ctx);
 out:
@@ -490,21 +527,9 @@ static struct tcp_ulp_ops tcp_tls_ulp_ops __read_mostly = {
        .init                   = tls_init,
 };
 
-static void build_protos(struct proto *prot, struct proto *base)
-{
-       prot[TLS_BASE_TX] = *base;
-       prot[TLS_BASE_TX].setsockopt    = tls_setsockopt;
-       prot[TLS_BASE_TX].getsockopt    = tls_getsockopt;
-       prot[TLS_BASE_TX].close         = tls_sk_proto_close;
-
-       prot[TLS_SW_TX] = prot[TLS_BASE_TX];
-       prot[TLS_SW_TX].sendmsg         = tls_sw_sendmsg;
-       prot[TLS_SW_TX].sendpage        = tls_sw_sendpage;
-}
-
 static int __init tls_register(void)
 {
-       build_protos(tls_prots, &tcp_prot);
+       build_protos(tls_prots[TLSV4], &tcp_prot);
 
        tcp_register_ulp(&tcp_tls_ulp_ops);
 
index d545e1d..2d465bd 100644 (file)
@@ -1825,7 +1825,7 @@ out:
 }
 
 /* We use paged skbs for stream sockets, and limit occupancy to 32768
- * bytes, and a minimun of a full page.
+ * bytes, and a minimum of a full page.
  */
 #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768))
 
index 1abcc4f..4172204 100644 (file)
@@ -34,9 +34,10 @@ config CFG80211
 
          When built as a module it will be called cfg80211.
 
+if CFG80211
+
 config NL80211_TESTMODE
        bool "nl80211 testmode command"
-       depends on CFG80211
        help
          The nl80211 testmode command helps implementing things like
          factory calibration or validation tools for wireless chips.
@@ -51,7 +52,6 @@ config NL80211_TESTMODE
 
 config CFG80211_DEVELOPER_WARNINGS
        bool "enable developer warnings"
-       depends on CFG80211
        default n
        help
          This option enables some additional warnings that help
@@ -68,7 +68,7 @@ config CFG80211_DEVELOPER_WARNINGS
 
 config CFG80211_CERTIFICATION_ONUS
        bool "cfg80211 certification onus"
-       depends on CFG80211 && EXPERT
+       depends on EXPERT
        default n
        ---help---
          You should disable this option unless you are both capable
@@ -159,7 +159,6 @@ config CFG80211_REG_RELAX_NO_IR
 
 config CFG80211_DEFAULT_PS
        bool "enable powersave by default"
-       depends on CFG80211
        default y
        help
          This option enables powersave mode by default.
@@ -170,7 +169,6 @@ config CFG80211_DEFAULT_PS
 
 config CFG80211_DEBUGFS
        bool "cfg80211 DebugFS entries"
-       depends on CFG80211
        depends on DEBUG_FS
        ---help---
          You can enable this if you want debugfs entries for cfg80211.
@@ -180,7 +178,6 @@ config CFG80211_DEBUGFS
 config CFG80211_CRDA_SUPPORT
        bool "support CRDA" if EXPERT
        default y
-       depends on CFG80211
        help
          You should enable this option unless you know for sure you have no
          need for it, for example when using internal regdb (above) or the
@@ -190,7 +187,6 @@ config CFG80211_CRDA_SUPPORT
 
 config CFG80211_WEXT
        bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT
-       depends on CFG80211
        select WEXT_CORE
        default y if CFG80211_WEXT_EXPORT
        help
@@ -199,11 +195,12 @@ config CFG80211_WEXT
 
 config CFG80211_WEXT_EXPORT
        bool
-       depends on CFG80211
        help
          Drivers should select this option if they require cfg80211's
          wext compatibility symbols to be exported.
 
+endif # CFG80211
+
 config LIB80211
        tristate
        default n
index 51aa556..b12da6e 100644 (file)
@@ -170,9 +170,28 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                enum nl80211_bss_scan_width scan_width;
                struct ieee80211_supported_band *sband =
                                rdev->wiphy.bands[setup->chandef.chan->band];
-               scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
-               setup->basic_rates = ieee80211_mandatory_rates(sband,
-                                                              scan_width);
+
+               if (setup->chandef.chan->band == NL80211_BAND_2GHZ) {
+                       int i;
+
+                       /*
+                        * Older versions selected the mandatory rates for
+                        * 2.4 GHz as well, but were broken in that only
+                        * 1 Mbps was regarded as a mandatory rate. Keep
+                        * using just 1 Mbps as the default basic rate for
+                        * mesh to be interoperable with older versions.
+                        */
+                       for (i = 0; i < sband->n_bitrates; i++) {
+                               if (sband->bitrates[i].bitrate == 10) {
+                                       setup->basic_rates = BIT(i);
+                                       break;
+                               }
+                       }
+               } else {
+                       scan_width = cfg80211_chandef_to_scan_width(&setup->chandef);
+                       setup->basic_rates = ieee80211_mandatory_rates(sband,
+                                                                      scan_width);
+               }
        }
 
        err = cfg80211_chandef_dfs_required(&rdev->wiphy,
index fdb3646..701cfd7 100644 (file)
@@ -1032,6 +1032,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
        wdev->current_bss = NULL;
        wdev->ssid_len = 0;
        wdev->conn_owner_nlportid = 0;
+       kzfree(wdev->connect_keys);
+       wdev->connect_keys = NULL;
 
        nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap);
 
index 8e70291..e87d6c4 100644 (file)
@@ -217,7 +217,7 @@ bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
                if (skb->len <= mtu)
                        goto ok;
 
-               if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu))
+               if (skb_is_gso(skb) && skb_gso_validate_network_len(skb, mtu))
                        goto ok;
        }
 
index 1472c08..8178810 100644 (file)
@@ -26,6 +26,12 @@ struct xfrm_trans_tasklet {
 };
 
 struct xfrm_trans_cb {
+       union {
+               struct inet_skb_parm    h4;
+#if IS_ENABLED(CONFIG_IPV6)
+               struct inet6_skb_parm   h6;
+#endif
+       } header;
        int (*finish)(struct net *net, struct sock *sk, struct sk_buff *skb);
 };
 
index ccfdc71..a00ec71 100644 (file)
@@ -283,7 +283,7 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name)
                struct crypto_comp *tfm;
 
                /* This can be any valid CPU ID so we don't need locking. */
-               tfm = __this_cpu_read(*pos->tfms);
+               tfm = this_cpu_read(*pos->tfms);
 
                if (!strcmp(crypto_comp_name(tfm), alg_name)) {
                        pos->users++;
index 2346867..89b178a 100644 (file)
@@ -285,8 +285,9 @@ void xfrm_local_error(struct sk_buff *skb, int mtu)
                return;
 
        afinfo = xfrm_state_get_afinfo(proto);
-       if (afinfo)
+       if (afinfo) {
                afinfo->local_error(skb, mtu);
-       rcu_read_unlock();
+               rcu_read_unlock();
+       }
 }
 EXPORT_SYMBOL_GPL(xfrm_local_error);
index 7a23078..625b3fc 100644 (file)
@@ -1458,10 +1458,13 @@ xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl,
 static int xfrm_get_tos(const struct flowi *fl, int family)
 {
        const struct xfrm_policy_afinfo *afinfo;
-       int tos = 0;
+       int tos;
 
        afinfo = xfrm_policy_get_afinfo(family);
-       tos = afinfo ? afinfo->get_tos(fl) : 0;
+       if (!afinfo)
+               return 0;
+
+       tos = afinfo->get_tos(fl);
 
        rcu_read_unlock();
 
@@ -1891,7 +1894,7 @@ static void xfrm_policy_queue_process(struct timer_list *t)
        spin_unlock(&pq->hold_queue.lock);
 
        dst_hold(xfrm_dst_path(dst));
-       dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, 0);
+       dst = xfrm_lookup(net, xfrm_dst_path(dst), &fl, sk, XFRM_LOOKUP_QUEUE);
        if (IS_ERR(dst))
                goto purge_queue;
 
@@ -2729,14 +2732,14 @@ static const void *xfrm_get_dst_nexthop(const struct dst_entry *dst,
        while (dst->xfrm) {
                const struct xfrm_state *xfrm = dst->xfrm;
 
+               dst = xfrm_dst_child(dst);
+
                if (xfrm->props.mode == XFRM_MODE_TRANSPORT)
                        continue;
                if (xfrm->type->flags & XFRM_TYPE_REMOTE_COADDR)
                        daddr = xfrm->coaddr;
                else if (!(xfrm->type->flags & XFRM_TYPE_LOCAL_COADDR))
                        daddr = &xfrm->id.daddr;
-
-               dst = xfrm_dst_child(dst);
        }
        return daddr;
 }
index 1d38c6a..9e3a5e8 100644 (file)
@@ -660,7 +660,7 @@ static int xfrm_replay_overflow_offload_esn(struct xfrm_state *x, struct sk_buff
                } else {
                        XFRM_SKB_CB(skb)->seq.output.low = oseq + 1;
                        XFRM_SKB_CB(skb)->seq.output.hi = oseq_hi;
-                       xo->seq.low = oseq = oseq + 1;
+                       xo->seq.low = oseq + 1;
                        xo->seq.hi = oseq_hi;
                        oseq += skb_shinfo(skb)->gso_segs;
                }
index 54e21f1..f9d2f22 100644 (file)
@@ -2056,6 +2056,11 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen
        struct xfrm_mgr *km;
        struct xfrm_policy *pol = NULL;
 
+#ifdef CONFIG_COMPAT
+       if (in_compat_syscall())
+               return -EOPNOTSUPP;
+#endif
+
        if (!optval && !optlen) {
                xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL);
                xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL);
index 7f52b8e..080035f 100644 (file)
@@ -121,22 +121,17 @@ static inline int verify_replay(struct xfrm_usersa_info *p,
        struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL];
        struct xfrm_replay_state_esn *rs;
 
-       if (p->flags & XFRM_STATE_ESN) {
-               if (!rt)
-                       return -EINVAL;
+       if (!rt)
+               return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0;
 
-               rs = nla_data(rt);
+       rs = nla_data(rt);
 
-               if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
-                       return -EINVAL;
-
-               if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
-                   nla_len(rt) != sizeof(*rs))
-                       return -EINVAL;
-       }
+       if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8)
+               return -EINVAL;
 
-       if (!rt)
-               return 0;
+       if (nla_len(rt) < (int)xfrm_replay_state_esn_len(rs) &&
+           nla_len(rt) != sizeof(*rs))
+               return -EINVAL;
 
        /* As only ESP and AH support ESN feature. */
        if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH))
index 0e349b8..ba942e3 100644 (file)
@@ -1,4 +1,5 @@
 # SPDX-License-Identifier: GPL-2.0
+ifndef CROSS_COMPILE
 hostprogs-$(CONFIG_SAMPLE_SECCOMP) := bpf-fancy dropper bpf-direct
 
 HOSTCFLAGS_bpf-fancy.o += -I$(objtree)/usr/include
@@ -16,7 +17,6 @@ HOSTCFLAGS_bpf-direct.o += -idirafter $(objtree)/include
 bpf-direct-objs := bpf-direct.o
 
 # Try to match the kernel target.
-ifndef CROSS_COMPILE
 ifndef CONFIG_64BIT
 
 # s390 has -m31 flag to build 31 bit binaries
@@ -35,12 +35,4 @@ HOSTLOADLIBES_bpf-fancy += $(MFLAG)
 HOSTLOADLIBES_dropper += $(MFLAG)
 endif
 always := $(hostprogs-m)
-else
-# MIPS system calls are defined based on the -mabi that is passed
-# to the toolchain which may or may not be a valid option
-# for the host toolchain. So disable tests if target architecture
-# is MIPS but the host isn't.
-ifndef CONFIG_MIPS
-always := $(hostprogs-m)
-endif
 endif
index 5589bae..a6f538b 100644 (file)
@@ -297,11 +297,11 @@ cmd_dt_S_dtb=                                             \
        echo '\#include <asm-generic/vmlinux.lds.h>';   \
        echo '.section .dtb.init.rodata,"a"';           \
        echo '.balign STRUCT_ALIGNMENT';                \
-       echo '.global __dtb_$(*F)_begin';               \
-       echo '__dtb_$(*F)_begin:';                      \
+       echo '.global __dtb_$(subst -,_,$(*F))_begin';  \
+       echo '__dtb_$(subst -,_,$(*F))_begin:';         \
        echo '.incbin "$<" ';                           \
-       echo '__dtb_$(*F)_end:';                        \
-       echo '.global __dtb_$(*F)_end';                 \
+       echo '__dtb_$(subst -,_,$(*F))_end:';           \
+       echo '.global __dtb_$(subst -,_,$(*F))_end';    \
        echo '.balign STRUCT_ALIGNMENT';                \
 ) > $@
 
index 513da1a..d67830e 100755 (executable)
@@ -84,6 +84,13 @@ while read sympath; do
        depfile="include/config/ksym/${sympath}.h"
        mkdir -p "$(dirname "$depfile")"
        touch "$depfile"
+       # Filesystems with coarse time precision may create timestamps
+       # equal to the one from a file that was very recently built and that
+       # needs to be rebuild. Let's guard against that by making sure our
+       # dep files are always newer than the first file we created here.
+       while [ ! "$depfile" -nt "$new_ksyms_file" ]; do
+               touch "$depfile"
+       done
        echo $((count += 1))
 done | tail -1 )
 changed=${changed:-0}
index fa3d39b..449b68c 100644 (file)
  * (Note: it'd be easy to port over the complete mkdep state machine,
  *  but I don't think the added complexity is worth it)
  */
-/*
- * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto
- * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not
- * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as
- * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h,
- * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that
- * those files will have correct dependencies.
- */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -233,8 +225,13 @@ static int str_ends_with(const char *s, int slen, const char *sub)
 static void parse_config_file(const char *p)
 {
        const char *q, *r;
+       const char *start = p;
 
        while ((p = strstr(p, "CONFIG_"))) {
+               if (p > start && (isalnum(p[-1]) || p[-1] == '_')) {
+                       p += 7;
+                       continue;
+               }
                p += 7;
                q = p;
                while (*q && (isalnum(*q) || *q == '_'))
@@ -286,8 +283,6 @@ static int is_ignored_file(const char *s, int len)
 {
        return str_ends_with(s, len, "include/generated/autoconf.h") ||
               str_ends_with(s, len, "include/generated/autoksyms.h") ||
-              str_ends_with(s, len, "arch/um/include/uml-config.h") ||
-              str_ends_with(s, len, "include/linux/kconfig.h") ||
               str_ends_with(s, len, ".ver");
 }
 
index 94b6648..d84a567 100755 (executable)
@@ -15,7 +15,7 @@ signal(SIGPIPE, SIG_DFL)
 if len(sys.argv) < 3:
     sys.stderr.write("usage: %s [option] file1 file2\n" % sys.argv[0])
     sys.stderr.write("The options are:\n")
-    sys.stderr.write("-c       cateogrize output based on symbole type\n")
+    sys.stderr.write("-c       categorize output based on symbol type\n")
     sys.stderr.write("-d       Show delta of Data Section\n")
     sys.stderr.write("-t       Show delta of text Section\n")
     sys.exit(-1)
index 1249b72..8fd6437 100644 (file)
@@ -56,10 +56,10 @@ statement S;
 p << r.p;
 @@
 
-coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdep")
+coccilib.org.print_todo(p[0], "WARNING opportunity for kmemdup")
 
 @script:python depends on report@
 p << r.p;
 @@
 
-coccilib.report.print_report(p[0], "WARNING opportunity for kmemdep")
+coccilib.report.print_report(p[0], "WARNING opportunity for kmemdup")
index 9ee9bf7..6579265 100644 (file)
@@ -595,7 +595,7 @@ static void optimize_result(void)
                 * original char code */
                if (!best_table_len[i]) {
 
-                       /* find the token with the breates profit value */
+                       /* find the token with the best profit value */
                        best = find_best_token();
                        if (token_profit[best] == 0)
                                break;
index 5c12dc9..df26c7b 100644 (file)
@@ -178,7 +178,7 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
        case S_HEX:
        done:
                if (sym_string_valid(sym, p)) {
-                       sym->def[def].val = strdup(p);
+                       sym->def[def].val = xstrdup(p);
                        sym->flags |= def_flags;
                } else {
                        if (def != S_DEF_AUTO)
index 2858738..240880a 100644 (file)
@@ -101,7 +101,7 @@ static struct message *message__new(const char *msg, char *option,
        if (self->files == NULL)
                goto out_fail;
 
-       self->msg = strdup(msg);
+       self->msg = xstrdup(msg);
        if (self->msg == NULL)
                goto out_fail_msg;
 
index 4e23feb..2d5ec2d 100644 (file)
@@ -115,6 +115,7 @@ int file_write_dep(const char *name);
 void *xmalloc(size_t size);
 void *xcalloc(size_t nmemb, size_t size);
 void *xrealloc(void *p, size_t size);
+char *xstrdup(const char *s);
 
 struct gstr {
        size_t len;
index a10bd9d..6c0bcd9 100755 (executable)
@@ -55,7 +55,8 @@ EOF
            echo " *** required header files."                            1>&2
            echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2
            echo " *** "                                                  1>&2
-           echo " *** Install ncurses (ncurses-devel) and try again."    1>&2
+           echo " *** Install ncurses (ncurses-devel or libncurses-dev " 1>&2
+           echo " *** depending on your distribution) and try again."    1>&2
            echo " *** "                                                  1>&2
            exit 1
        fi
index 9922285..36cd3e1 100644 (file)
@@ -212,6 +212,7 @@ void menu_add_option(int token, char *arg)
                        sym_defconfig_list = current_entry->sym;
                else if (sym_defconfig_list != current_entry->sym)
                        zconf_error("trying to redefine defconfig symbol");
+               sym_defconfig_list->flags |= SYMBOL_AUTO;
                break;
        case T_OPT_ENV:
                prop_add_env(arg);
index cca9663..2220bc4 100644 (file)
@@ -183,7 +183,7 @@ static void sym_validate_range(struct symbol *sym)
                sprintf(str, "%lld", val2);
        else
                sprintf(str, "0x%llx", val2);
-       sym->curr.val = strdup(str);
+       sym->curr.val = xstrdup(str);
 }
 
 static void sym_set_changed(struct symbol *sym)
@@ -849,7 +849,7 @@ struct symbol *sym_lookup(const char *name, int flags)
                                   : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
                                return symbol;
                }
-               new_name = strdup(name);
+               new_name = xstrdup(name);
        } else {
                new_name = NULL;
                hash = 0;
index b98a79e..c6f6e21 100644 (file)
@@ -154,3 +154,14 @@ void *xrealloc(void *p, size_t size)
        fprintf(stderr, "Out of memory.\n");
        exit(1);
 }
+
+char *xstrdup(const char *s)
+{
+       char *p;
+
+       p = strdup(s);
+       if (p)
+               return p;
+       fprintf(stderr, "Out of memory.\n");
+       exit(1);
+}
index 02de6fe..88b650e 100644 (file)
@@ -332,16 +332,12 @@ void zconf_nextfile(const char *name)
                                "Inclusion path:\n  current file : '%s'\n",
                                zconf_curname(), zconf_lineno(),
                                zconf_curname());
-                       iter = current_file->parent;
-                       while (iter && \
-                              strcmp(iter->name,current_file->name)) {
-                               fprintf(stderr, "  included from: '%s:%d'\n",
-                                       iter->name, iter->lineno-1);
+                       iter = current_file;
+                       do {
                                iter = iter->parent;
-                       }
-                       if (iter)
                                fprintf(stderr, "  included from: '%s:%d'\n",
-                                       iter->name, iter->lineno+1);
+                                       iter->name, iter->lineno - 1);
+                       } while (strcmp(iter->name, current_file->name));
                        exit(1);
                }
        }
index 4be9805..ad6305b 100644 (file)
@@ -127,7 +127,7 @@ no_mainmenu_stmt: /* empty */
         * later regardless of whether it comes from the 'prompt' in
         * mainmenu_stmt or here
         */
-       menu_add_prompt(P_MENU, strdup("Linux Kernel Configuration"), NULL);
+       menu_add_prompt(P_MENU, xstrdup("Linux Kernel Configuration"), NULL);
 };
 
 
@@ -276,6 +276,7 @@ choice: T_CHOICE word_opt T_EOL
        sym->flags |= SYMBOL_AUTO;
        menu_add_entry(sym);
        menu_add_expr(P_CHOICE, NULL, NULL);
+       free($2);
        printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
 };
 
index c0d129d..be56a11 100755 (executable)
@@ -246,7 +246,7 @@ else
 fi;
 
 # final build of init/
-${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}"
+${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init
 
 archive_builtin
 
index b4f0f2b..13fabb1 100755 (executable)
@@ -313,7 +313,7 @@ fi
 
 # Build kernel header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl) > "$objtree/debian/hdrsrcfiles"
-(cd $srctree; find arch/*/include include scripts -type f) >> "$objtree/debian/hdrsrcfiles"
+(cd $srctree; find arch/*/include include scripts -type f -o -type l) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find arch/$SRCARCH -name module.lds -o -name Kbuild.platforms -o -name Platform) >> "$objtree/debian/hdrsrcfiles"
 (cd $srctree; find $(find arch/$SRCARCH -name include -o -name scripts -type d) -type f) >> "$objtree/debian/hdrsrcfiles"
 if grep -q '^CONFIG_STACK_VALIDATION=y' $KCONFIG_CONFIG ; then
index 280027f..61427c6 100755 (executable)
@@ -98,7 +98,7 @@ $M    make %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} KBUILD_SRC= modules_instal
 $S$M   rm -f %{buildroot}/lib/modules/$KERNELRELEASE/build
 $S$M   rm -f %{buildroot}/lib/modules/$KERNELRELEASE/source
 $S$M   mkdir -p %{buildroot}/usr/src/kernels/$KERNELRELEASE
-$S$M   tar cf - . $EXCLUDES | tar xf - -C %{buildroot}/usr/src/kernels/$KERNELRELEASE
+$S$M   tar cf - $EXCLUDES . | tar xf - -C %{buildroot}/usr/src/kernels/$KERNELRELEASE
 $S$M   cd %{buildroot}/lib/modules/$KERNELRELEASE
 $S$M   ln -sf /usr/src/kernels/$KERNELRELEASE build
 $S$M   ln -sf /usr/src/kernels/$KERNELRELEASE source
index 6f9e4ce..9bb0a7f 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/cred.h>
 #include <linux/key-type.h>
 #include <linux/digsig.h>
+#include <linux/vmalloc.h>
 #include <crypto/public_key.h>
 #include <keys/system_keyring.h>
 
index 929e149..fa728f6 100644 (file)
 #include <keys/big_key-type.h>
 #include <crypto/aead.h>
 
+struct big_key_buf {
+       unsigned int            nr_pages;
+       void                    *virt;
+       struct scatterlist      *sg;
+       struct page             *pages[];
+};
+
 /*
  * Layout of key payload words.
  */
@@ -91,10 +98,9 @@ static DEFINE_MUTEX(big_key_aead_lock);
 /*
  * Encrypt/decrypt big_key data
  */
-static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
+static int big_key_crypt(enum big_key_op op, struct big_key_buf *buf, size_t datalen, u8 *key)
 {
        int ret;
-       struct scatterlist sgio;
        struct aead_request *aead_req;
        /* We always use a zero nonce. The reason we can get away with this is
         * because we're using a different randomly generated key for every
@@ -109,8 +115,7 @@ static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
                return -ENOMEM;
 
        memset(zero_nonce, 0, sizeof(zero_nonce));
-       sg_init_one(&sgio, data, datalen + (op == BIG_KEY_ENC ? ENC_AUTHTAG_SIZE : 0));
-       aead_request_set_crypt(aead_req, &sgio, &sgio, datalen, zero_nonce);
+       aead_request_set_crypt(aead_req, buf->sg, buf->sg, datalen, zero_nonce);
        aead_request_set_callback(aead_req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
        aead_request_set_ad(aead_req, 0);
 
@@ -130,21 +135,81 @@ error:
 }
 
 /*
+ * Free up the buffer.
+ */
+static void big_key_free_buffer(struct big_key_buf *buf)
+{
+       unsigned int i;
+
+       if (buf->virt) {
+               memset(buf->virt, 0, buf->nr_pages * PAGE_SIZE);
+               vunmap(buf->virt);
+       }
+
+       for (i = 0; i < buf->nr_pages; i++)
+               if (buf->pages[i])
+                       __free_page(buf->pages[i]);
+
+       kfree(buf);
+}
+
+/*
+ * Allocate a buffer consisting of a set of pages with a virtual mapping
+ * applied over them.
+ */
+static void *big_key_alloc_buffer(size_t len)
+{
+       struct big_key_buf *buf;
+       unsigned int npg = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       unsigned int i, l;
+
+       buf = kzalloc(sizeof(struct big_key_buf) +
+                     sizeof(struct page) * npg +
+                     sizeof(struct scatterlist) * npg,
+                     GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->nr_pages = npg;
+       buf->sg = (void *)(buf->pages + npg);
+       sg_init_table(buf->sg, npg);
+
+       for (i = 0; i < buf->nr_pages; i++) {
+               buf->pages[i] = alloc_page(GFP_KERNEL);
+               if (!buf->pages[i])
+                       goto nomem;
+
+               l = min_t(size_t, len, PAGE_SIZE);
+               sg_set_page(&buf->sg[i], buf->pages[i], l, 0);
+               len -= l;
+       }
+
+       buf->virt = vmap(buf->pages, buf->nr_pages, VM_MAP, PAGE_KERNEL);
+       if (!buf->virt)
+               goto nomem;
+
+       return buf;
+
+nomem:
+       big_key_free_buffer(buf);
+       return NULL;
+}
+
+/*
  * Preparse a big key
  */
 int big_key_preparse(struct key_preparsed_payload *prep)
 {
+       struct big_key_buf *buf;
        struct path *path = (struct path *)&prep->payload.data[big_key_path];
        struct file *file;
        u8 *enckey;
-       u8 *data = NULL;
        ssize_t written;
-       size_t datalen = prep->datalen;
+       size_t datalen = prep->datalen, enclen = datalen + ENC_AUTHTAG_SIZE;
        int ret;
 
-       ret = -EINVAL;
        if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
-               goto error;
+               return -EINVAL;
 
        /* Set an arbitrary quota */
        prep->quotalen = 16;
@@ -157,13 +222,12 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                 *
                 * File content is stored encrypted with randomly generated key.
                 */
-               size_t enclen = datalen + ENC_AUTHTAG_SIZE;
                loff_t pos = 0;
 
-               data = kmalloc(enclen, GFP_KERNEL);
-               if (!data)
+               buf = big_key_alloc_buffer(enclen);
+               if (!buf)
                        return -ENOMEM;
-               memcpy(data, prep->data, datalen);
+               memcpy(buf->virt, prep->data, datalen);
 
                /* generate random key */
                enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
@@ -176,7 +240,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                        goto err_enckey;
 
                /* encrypt aligned data */
-               ret = big_key_crypt(BIG_KEY_ENC, data, datalen, enckey);
+               ret = big_key_crypt(BIG_KEY_ENC, buf, datalen, enckey);
                if (ret)
                        goto err_enckey;
 
@@ -187,7 +251,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                        goto err_enckey;
                }
 
-               written = kernel_write(file, data, enclen, &pos);
+               written = kernel_write(file, buf->virt, enclen, &pos);
                if (written != enclen) {
                        ret = written;
                        if (written >= 0)
@@ -202,7 +266,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
                *path = file->f_path;
                path_get(path);
                fput(file);
-               kzfree(data);
+               big_key_free_buffer(buf);
        } else {
                /* Just store the data in a buffer */
                void *data = kmalloc(datalen, GFP_KERNEL);
@@ -220,7 +284,7 @@ err_fput:
 err_enckey:
        kzfree(enckey);
 error:
-       kzfree(data);
+       big_key_free_buffer(buf);
        return ret;
 }
 
@@ -298,15 +362,15 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
                return datalen;
 
        if (datalen > BIG_KEY_FILE_THRESHOLD) {
+               struct big_key_buf *buf;
                struct path *path = (struct path *)&key->payload.data[big_key_path];
                struct file *file;
-               u8 *data;
                u8 *enckey = (u8 *)key->payload.data[big_key_data];
                size_t enclen = datalen + ENC_AUTHTAG_SIZE;
                loff_t pos = 0;
 
-               data = kmalloc(enclen, GFP_KERNEL);
-               if (!data)
+               buf = big_key_alloc_buffer(enclen);
+               if (!buf)
                        return -ENOMEM;
 
                file = dentry_open(path, O_RDONLY, current_cred());
@@ -316,26 +380,26 @@ long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
                }
 
                /* read file to kernel and decrypt */
-               ret = kernel_read(file, data, enclen, &pos);
+               ret = kernel_read(file, buf->virt, enclen, &pos);
                if (ret >= 0 && ret != enclen) {
                        ret = -EIO;
                        goto err_fput;
                }
 
-               ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
+               ret = big_key_crypt(BIG_KEY_DEC, buf, enclen, enckey);
                if (ret)
                        goto err_fput;
 
                ret = datalen;
 
                /* copy decrypted data to user */
-               if (copy_to_user(buffer, data, datalen) != 0)
+               if (copy_to_user(buffer, buf->virt, datalen) != 0)
                        ret = -EFAULT;
 
 err_fput:
                fput(file);
 error:
-               kzfree(data);
+               big_key_free_buffer(buf);
        } else {
                ret = datalen;
                if (copy_to_user(buffer, key->payload.data[big_key_data],
index f8a64e1..baa5f8e 100644 (file)
@@ -5,7 +5,6 @@
 
 config AC97_BUS_NEW
        tristate
-       select AC97
        help
          This is the new AC97 bus type, successor of AC97_BUS. The ported
          drivers which benefit from the AC97 automatic probing should "select"
index 0b3026d..8a77620 100644 (file)
@@ -889,7 +889,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
 
        index_offset = snd_ctl_get_ioff(kctl, &control->id);
        vd = &kctl->vd[index_offset];
-       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL)
+       if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
                return -EPERM;
 
        snd_ctl_build_ioff(&control->id, kctl, index_offset);
index b044c0a..4414050 100644 (file)
@@ -1326,7 +1326,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha
 static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes)
 {
        size_t xfer = 0;
-       ssize_t tmp;
+       ssize_t tmp = 0;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        if (atomic_read(&substream->mmap_count))
@@ -1433,7 +1433,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf,
 static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes)
 {
        size_t xfer = 0;
-       ssize_t tmp;
+       ssize_t tmp = 0;
        struct snd_pcm_runtime *runtime = substream->runtime;
 
        if (atomic_read(&substream->mmap_count))
@@ -1762,10 +1762,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                return -ENOMEM;
        _snd_pcm_hw_params_any(params);
        err = snd_pcm_hw_refine(substream, params);
-       format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
-       kfree(params);
        if (err < 0)
-               return err;
+               goto error;
+       format_mask = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
        for (fmt = 0; fmt < 32; ++fmt) {
                if (snd_mask_test(format_mask, fmt)) {
                        int f = snd_pcm_oss_format_to(fmt);
@@ -1773,7 +1772,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
                                formats |= f;
                }
        }
-       return formats;
+
+ error:
+       kfree(params);
+       return err < 0 ? err : formats;
 }
 
 static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
index 77ba50d..d18b398 100644 (file)
@@ -3422,7 +3422,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
                                         area,
                                         substream->runtime->dma_area,
                                         substream->runtime->dma_addr,
-                                        area->vm_end - area->vm_start);
+                                        substream->runtime->dma_bytes);
 #endif /* CONFIG_X86 */
        /* mmap with fault handler */
        area->vm_ops = &snd_pcm_vm_ops_data_fault;
index 60db327..61a07fe 100644 (file)
@@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client)
 
        if (!client)
                return 0;
-       snd_seq_delete_all_ports(client);
-       snd_seq_queue_client_leave(client->number);
        spin_lock_irqsave(&clients_lock, flags);
        clienttablock[client->number] = 1;
        clienttab[client->number] = NULL;
        spin_unlock_irqrestore(&clients_lock, flags);
+       snd_seq_delete_all_ports(client);
+       snd_seq_queue_client_leave(client->number);
        snd_use_lock_sync(&client->use_lock);
        snd_seq_queue_client_termination(client->number);
        if (client->pool)
@@ -910,7 +910,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop)
 static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
                                        struct snd_seq_event *event,
                                        struct file *file, int blocking,
-                                       int atomic, int hop)
+                                       int atomic, int hop,
+                                       struct mutex *mutexp)
 {
        struct snd_seq_event_cell *cell;
        int err;
@@ -948,7 +949,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
                return -ENXIO; /* queue is not allocated */
 
        /* allocate an event cell */
-       err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file);
+       err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic,
+                               file, mutexp);
        if (err < 0)
                return err;
 
@@ -1003,7 +1005,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
 {
        struct snd_seq_client *client = file->private_data;
        int written = 0, len;
-       int err = -EINVAL;
+       int err;
        struct snd_seq_event event;
 
        if (!(snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT))
@@ -1017,12 +1019,15 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                return -ENXIO;
 
        /* allocate the pool now if the pool is not allocated yet */ 
+       mutex_lock(&client->ioctl_mutex);
        if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) {
-               if (snd_seq_pool_init(client->pool) < 0)
-                       return -ENOMEM;
+               err = snd_seq_pool_init(client->pool);
+               if (err < 0)
+                       goto out;
        }
 
        /* only process whole events */
+       err = -EINVAL;
        while (count >= sizeof(struct snd_seq_event)) {
                /* Read in the event header from the user */
                len = sizeof(event);
@@ -1069,7 +1074,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                /* ok, enqueue it */
                err = snd_seq_client_enqueue_event(client, &event, file,
                                                   !(file->f_flags & O_NONBLOCK),
-                                                  0, 0);
+                                                  0, 0, &client->ioctl_mutex);
                if (err < 0)
                        break;
 
@@ -1080,6 +1085,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf,
                written += len;
        }
 
+ out:
+       mutex_unlock(&client->ioctl_mutex);
        return written ? written : err;
 }
 
@@ -1834,9 +1841,11 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
            (! snd_seq_write_pool_allocated(client) ||
             info->output_pool != client->pool->size)) {
                if (snd_seq_write_pool_allocated(client)) {
+                       /* is the pool in use? */
+                       if (atomic_read(&client->pool->counter))
+                               return -EBUSY;
                        /* remove all existing cells */
                        snd_seq_pool_mark_closing(client->pool);
-                       snd_seq_queue_client_leave_cells(client->number);
                        snd_seq_pool_done(client->pool);
                }
                client->pool->size = info->output_pool;
@@ -2256,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev,
        if (! cptr->accept_output)
                result = -EPERM;
        else /* send it */
-               result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop);
+               result = snd_seq_client_enqueue_event(cptr, ev, file, blocking,
+                                                     atomic, hop, NULL);
 
        snd_seq_client_unlock(cptr);
        return result;
index a8c2822..72c0302 100644 (file)
@@ -125,7 +125,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f,
                return -EINVAL;
 
        snd_use_lock_use(&f->use_lock);
-       err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */
+       err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */
        if (err < 0) {
                if ((err == -ENOMEM) || (err == -EAGAIN))
                        atomic_inc(&f->overflow);
index f763682..ab1112e 100644 (file)
@@ -220,7 +220,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell)
  */
 static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
                              struct snd_seq_event_cell **cellp,
-                             int nonblock, struct file *file)
+                             int nonblock, struct file *file,
+                             struct mutex *mutexp)
 {
        struct snd_seq_event_cell *cell;
        unsigned long flags;
@@ -244,7 +245,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool,
                set_current_state(TASK_INTERRUPTIBLE);
                add_wait_queue(&pool->output_sleep, &wait);
                spin_unlock_irq(&pool->lock);
+               if (mutexp)
+                       mutex_unlock(mutexp);
                schedule();
+               if (mutexp)
+                       mutex_lock(mutexp);
                spin_lock_irq(&pool->lock);
                remove_wait_queue(&pool->output_sleep, &wait);
                /* interrupted? */
@@ -287,7 +292,7 @@ __error:
  */
 int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
                      struct snd_seq_event_cell **cellp, int nonblock,
-                     struct file *file)
+                     struct file *file, struct mutex *mutexp)
 {
        int ncells, err;
        unsigned int extlen;
@@ -304,7 +309,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
        if (ncells >= pool->total_elements)
                return -ENOMEM;
 
-       err = snd_seq_cell_alloc(pool, &cell, nonblock, file);
+       err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp);
        if (err < 0)
                return err;
 
@@ -330,7 +335,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
                        int size = sizeof(struct snd_seq_event);
                        if (len < size)
                                size = len;
-                       err = snd_seq_cell_alloc(pool, &tmp, nonblock, file);
+                       err = snd_seq_cell_alloc(pool, &tmp, nonblock, file,
+                                                mutexp);
                        if (err < 0)
                                goto __error;
                        if (cell->event.data.ext.ptr == NULL)
index 32f959c..3abe306 100644 (file)
@@ -66,7 +66,8 @@ struct snd_seq_pool {
 void snd_seq_cell_free(struct snd_seq_event_cell *cell);
 
 int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event,
-                     struct snd_seq_event_cell **cellp, int nonblock, struct file *file);
+                     struct snd_seq_event_cell **cellp, int nonblock,
+                     struct file *file, struct mutex *mutexp);
 
 /* return number of unused (free) cells */
 static inline int snd_seq_unused_cells(struct snd_seq_pool *pool)
index bc1c848..2bc6759 100644 (file)
@@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo)
        if (f->cells > 0) {
                /* drain prioQ */
                while (f->cells > 0)
-                       snd_seq_cell_free(snd_seq_prioq_cell_out(f));
+                       snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL));
        }
        
        kfree(f);
@@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f,
        return 0;
 }
 
+/* return 1 if the current time >= event timestamp */
+static int event_is_ready(struct snd_seq_event *ev, void *current_time)
+{
+       if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK)
+               return snd_seq_compare_tick_time(current_time, &ev->time.tick);
+       else
+               return snd_seq_compare_real_time(current_time, &ev->time.time);
+}
+
 /* dequeue cell from prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
+                                                 void *current_time)
 {
        struct snd_seq_event_cell *cell;
        unsigned long flags;
@@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f)
        spin_lock_irqsave(&f->lock, flags);
 
        cell = f->head;
+       if (cell && current_time && !event_is_ready(&cell->event, current_time))
+               cell = NULL;
        if (cell) {
                f->head = cell->next;
 
@@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
        return f->cells;
 }
 
-
-/* peek at cell at the head of the prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f)
-{
-       if (f == NULL) {
-               pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n");
-               return NULL;
-       }
-       return f->head;
-}
-
-
 static inline int prioq_match(struct snd_seq_event_cell *cell,
                              int client, int timestamp)
 {
index d38bb78..2c315ca 100644 (file)
@@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo);
 int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell);
 
 /* dequeue cell from prioq */ 
-struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f);
+struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f,
+                                                 void *current_time);
 
 /* return number of events available in prioq */
 int snd_seq_prioq_avail(struct snd_seq_prioq *f);
 
-/* peek at cell at the head of the prioq */
-struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f);
-
 /* client left queue */
 void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp);        
 
index 0428e90..b377f50 100644 (file)
@@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop)
 
       __again:
        /* Process tick queue... */
-       while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) {
-               if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick,
-                                             &cell->event.time.tick)) {
-                       cell = snd_seq_prioq_cell_out(q->tickq);
-                       if (cell)
-                               snd_seq_dispatch_event(cell, atomic, hop);
-               } else {
-                       /* event remains in the queue */
+       for (;;) {
+               cell = snd_seq_prioq_cell_out(q->tickq,
+                                             &q->timer->tick.cur_tick);
+               if (!cell)
                        break;
-               }
+               snd_seq_dispatch_event(cell, atomic, hop);
        }
 
-
        /* Process time queue... */
-       while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) {
-               if (snd_seq_compare_real_time(&q->timer->cur_time,
-                                             &cell->event.time.time)) {
-                       cell = snd_seq_prioq_cell_out(q->timeq);
-                       if (cell)
-                               snd_seq_dispatch_event(cell, atomic, hop);
-               } else {
-                       /* event remains in the queue */
+       for (;;) {
+               cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time);
+               if (!cell)
                        break;
-               }
+               snd_seq_dispatch_event(cell, atomic, hop);
        }
 
        /* free lock */
index 0333143..1063a43 100644 (file)
@@ -192,6 +192,11 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
        dpcm->timer.expires = 0;
 }
 
+static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm)
+{
+       del_timer_sync(&dpcm->timer);
+}
+
 #define CABLE_VALID_PLAYBACK   (1 << SNDRV_PCM_STREAM_PLAYBACK)
 #define CABLE_VALID_CAPTURE    (1 << SNDRV_PCM_STREAM_CAPTURE)
 #define CABLE_VALID_BOTH       (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
@@ -326,6 +331,8 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
        struct loopback_cable *cable = dpcm->cable;
        int bps, salign;
 
+       loopback_timer_stop_sync(dpcm);
+
        salign = (snd_pcm_format_width(runtime->format) *
                                                runtime->channels) / 8;
        bps = salign * runtime->rate;
@@ -659,7 +666,9 @@ static void free_cable(struct snd_pcm_substream *substream)
                return;
        if (cable->streams[!substream->stream]) {
                /* other stream is still alive */
+               spin_lock_irq(&cable->lock);
                cable->streams[substream->stream] = NULL;
+               spin_unlock_irq(&cable->lock);
        } else {
                /* free the cable */
                loopback->cables[substream->number][dev] = NULL;
@@ -698,7 +707,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
                loopback->cables[substream->number][dev] = cable;
        }
        dpcm->cable = cable;
-       cable->streams[substream->stream] = dpcm;
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
 
@@ -730,6 +738,11 @@ static int loopback_open(struct snd_pcm_substream *substream)
                runtime->hw = loopback_pcm_hardware;
        else
                runtime->hw = cable->hw;
+
+       spin_lock_irq(&cable->lock);
+       cable->streams[substream->stream] = dpcm;
+       spin_unlock_irq(&cable->lock);
+
  unlock:
        if (err < 0) {
                free_cable(substream);
@@ -744,7 +757,7 @@ static int loopback_close(struct snd_pcm_substream *substream)
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm = substream->runtime->private_data;
 
-       loopback_timer_stop(dpcm);
+       loopback_timer_stop_sync(dpcm);
        mutex_lock(&loopback->cable_lock);
        free_cable(substream);
        mutex_unlock(&loopback->cable_lock);
index c71dcac..c507c69 100644 (file)
@@ -186,6 +186,10 @@ module_param(power_save, xint, 0644);
 MODULE_PARM_DESC(power_save, "Automatic power-saving timeout "
                 "(in second, 0 = disable).");
 
+static bool pm_blacklist = true;
+module_param(pm_blacklist, bool, 0644);
+MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist");
+
 /* reset the HD-audio controller in power save mode.
  * this may give more power-saving, but will take longer time to
  * wake up.
@@ -371,6 +375,7 @@ enum {
                                        ((pci)->device == 0x160c))
 
 #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_CFL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa348)
 
 static char *driver_short_names[] = {
        [AZX_DRIVER_ICH] = "HDA Intel",
@@ -1740,6 +1745,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
        else
                chip->bdl_pos_adj = bdl_pos_adj[dev];
 
+       /* Workaround for a communication error on CFL (bko#199007) */
+       if (IS_CFL(pci))
+               chip->polling_mode = 1;
+
        err = azx_bus_init(chip, model[dev], &pci_hda_io_ops);
        if (err < 0) {
                kfree(hda);
@@ -2186,6 +2195,24 @@ out_free:
        return err;
 }
 
+#ifdef CONFIG_PM
+/* On some boards setting power_save to a non 0 value leads to clicking /
+ * popping sounds when ever we enter/leave powersaving mode. Ideally we would
+ * figure out how to avoid these sounds, but that is not always feasible.
+ * So we keep a list of devices where we disable powersaving as its known
+ * to causes problems on these devices.
+ */
+static struct snd_pci_quirk power_save_blacklist[] = {
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+       SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0),
+       /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */
+       SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0),
+       /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */
+       SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0),
+       {}
+};
+#endif /* CONFIG_PM */
+
 /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */
 static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = {
        [AZX_DRIVER_NVIDIA] = 8,
@@ -2198,6 +2225,7 @@ static int azx_probe_continue(struct azx *chip)
        struct hdac_bus *bus = azx_bus(chip);
        struct pci_dev *pci = chip->pci;
        int dev = chip->dev_index;
+       int val;
        int err;
 
        hda->probe_continued = 1;
@@ -2278,7 +2306,21 @@ static int azx_probe_continue(struct azx *chip)
 
        chip->running = 1;
        azx_add_card_list(chip);
-       snd_hda_set_power_save(&chip->bus, power_save * 1000);
+
+       val = power_save;
+#ifdef CONFIG_PM
+       if (pm_blacklist) {
+               const struct snd_pci_quirk *q;
+
+               q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist);
+               if (q && val) {
+                       dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n",
+                                q->subvendor, q->subdevice);
+                       val = 0;
+               }
+       }
+#endif /* CONFIG_PM */
+       snd_hda_set_power_save(&chip->bus, val * 1000);
        if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo)
                pm_runtime_put_autosuspend(&pci->dev);
 
index 37e1cf8..5b4dbce 100644 (file)
@@ -957,6 +957,8 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
        SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
        SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
        SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
        SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
index 2347588..aef1f52 100644 (file)
@@ -3130,6 +3130,8 @@ static void alc256_init(struct hda_codec *codec)
 
        alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
        alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
+       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
 }
 
 static void alc256_shutup(struct hda_codec *codec)
@@ -3465,6 +3467,19 @@ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
                spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
 }
 
+static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec,
+                                                const struct hda_fixup *fix,
+                                                int action)
+{
+       unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21);
+       unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19);
+
+       if (cfg_headphone && cfg_headset_mic == 0x411111f0)
+               snd_hda_codec_set_pincfg(codec, 0x19,
+                       (cfg_headphone & ~AC_DEFCFG_DEVICE) |
+                       (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT));
+}
+
 static void alc269_fixup_hweq(struct hda_codec *codec,
                               const struct hda_fixup *fix, int action)
 {
@@ -3583,8 +3598,12 @@ static void alc269_fixup_mic_mute_hook(void *private_data, int enabled)
        pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid);
        pinval &= ~AC_PINCTL_VREFEN;
        pinval |= enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80;
-       if (spec->mute_led_nid)
+       if (spec->mute_led_nid) {
+               /* temporarily power up/down for setting VREF */
+               snd_hda_power_up_pm(codec);
                snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval);
+               snd_hda_power_down_pm(codec);
+       }
 }
 
 /* Make sure the led works even in runtime suspend */
@@ -4972,6 +4991,29 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec,
        }
 }
 
+static void alc_fixup_tpt470_dock(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x17, 0x21211010 }, /* dock headphone */
+               { 0x19, 0x21a11010 }, /* dock mic */
+               { }
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+       } else if (action == HDA_FIXUP_ACT_INIT) {
+               /* Enable DOCK device */
+               snd_hda_codec_write(codec, 0x17, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+               /* Enable DOCK device */
+               snd_hda_codec_write(codec, 0x19, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+       }
+}
+
 static void alc_shutup_dell_xps13(struct hda_codec *codec)
 {
        struct alc_spec *spec = codec->spec;
@@ -5238,6 +5280,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec,
        }
 }
 
+/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */
+static void alc295_fixup_disable_dac3(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               hda_nid_t conn[2] = { 0x02, 0x03 };
+               snd_hda_override_conn_list(codec, 0x17, 2, conn);
+       }
+}
+
 /* Hook to update amp GPIO4 for automute */
 static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
                                          struct hda_jack_callback *jack)
@@ -5351,6 +5403,7 @@ enum {
        ALC269_FIXUP_LIFEBOOK_EXTMIC,
        ALC269_FIXUP_LIFEBOOK_HP_PIN,
        ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT,
+       ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC,
        ALC269_FIXUP_AMIC,
        ALC269_FIXUP_DMIC,
        ALC269VB_FIXUP_AMIC,
@@ -5429,6 +5482,7 @@ enum {
        ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
        ALC255_FIXUP_DELL_SPK_NOISE,
        ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC295_FIXUP_DISABLE_DAC3,
        ALC280_FIXUP_HP_HEADSET_MIC,
        ALC221_FIXUP_HP_FRONT_MIC,
        ALC292_FIXUP_TPT460,
@@ -5443,9 +5497,13 @@ enum {
        ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
        ALC233_FIXUP_LENOVO_MULTI_CODECS,
        ALC294_FIXUP_LENOVO_MIC_LOCATION,
+       ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE,
        ALC700_FIXUP_INTEL_REFERENCE,
        ALC274_FIXUP_DELL_BIND_DACS,
        ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
+       ALC298_FIXUP_TPT470_DOCK,
+       ALC255_FIXUP_DUMMY_LINEOUT_VERB,
+       ALC255_FIXUP_DELL_HEADSET_MIC,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -5556,6 +5614,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
        },
+       [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pincfg_U7x7_headset_mic,
+       },
        [ALC269_FIXUP_AMIC] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -6156,6 +6218,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
        },
+       [ALC295_FIXUP_DISABLE_DAC3] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_disable_dac3,
+       },
        [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -6241,6 +6307,18 @@ static const struct hda_fixup alc269_fixups[] = {
                        { }
                },
        },
+       [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x0101102f }, /* Rear Headset HP */
+                       { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */
+                       { 0x1a, 0x01a19030 }, /* Rear Headset MIC */
+                       { 0x1b, 0x02011020 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
        [ALC700_FIXUP_INTEL_REFERENCE] = {
                .type = HDA_FIXUP_VERBS,
                .v.verbs = (const struct hda_verb[]) {
@@ -6271,6 +6349,28 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC274_FIXUP_DELL_BIND_DACS
        },
+       [ALC298_FIXUP_TPT470_DOCK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt470_dock,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE
+       },
+       [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0201101f },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC255_FIXUP_DELL_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -6319,8 +6419,15 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
        SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
        SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
+       SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3),
        SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+       SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
        SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -6422,6 +6529,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT),
        SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
        SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+       SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
        SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
        SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
@@ -6450,8 +6558,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x222d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460),
        SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
        SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
@@ -6472,7 +6590,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460),
        SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460),
        SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x505d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
        SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
@@ -6735,6 +6858,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x14, 0x90170110},
                {0x21, 0x02211020}),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x14, 0x01011020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
                ALC256_STANDARD_PINS),
        SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
                {0x14, 0x90170110},
@@ -6803,6 +6931,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
                {0x12, 0x90a60120},
                {0x14, 0x90170110},
                {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+               {0x12, 0xb7a60130},
+               {0x14, 0x90170110},
+               {0x21, 0x04211020}),
        SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
                ALC290_STANDARD_PINS,
                {0x15, 0x04211040},
@@ -7038,6 +7170,8 @@ static int patch_alc269(struct hda_codec *codec)
                break;
        case 0x10ec0257:
                spec->codec_variant = ALC269_TYPE_ALC257;
+               spec->shutup = alc256_shutup;
+               spec->init_hook = alc256_init;
                spec->gen.mixer_nid = 0;
                break;
        case 0x10ec0215:
index c33a512..9fb356d 100644 (file)
@@ -579,13 +579,6 @@ static int acp_init(void __iomem *acp_mmio, u32 asic_type)
                for (bank = 1; bank < 48; bank++)
                        acp_set_sram_bank_state(acp_mmio, bank, false);
        }
-
-       /* Stoney supports 16bit resolution */
-       if (asic_type == CHIP_STONEY) {
-               val = acp_reg_read(acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
-               val |= 0x03;
-               acp_reg_write(val, acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
-       }
        return 0;
 }
 
@@ -774,6 +767,7 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
 {
        int status;
        uint64_t size;
+       u32 val = 0;
        struct page *pg;
        struct snd_pcm_runtime *runtime;
        struct audio_substream_data *rtd;
@@ -786,6 +780,14 @@ static int acp_dma_hw_params(struct snd_pcm_substream *substream,
        if (WARN_ON(!rtd))
                return -EINVAL;
 
+       if (adata->asic_type == CHIP_STONEY) {
+               val = acp_reg_read(adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+                       val |= ACP_I2S_SP_16BIT_RESOLUTION_EN;
+               else
+                       val |= ACP_I2S_MIC_16BIT_RESOLUTION_EN;
+               acp_reg_write(val, adata->acp_mmio, mmACP_I2S_16BIT_RESOLUTION_EN);
+       }
        size = params_buffer_bytes(params);
        status = snd_pcm_lib_malloc_pages(substream, size);
        if (status < 0)
index ecb4589..9293f17 100644 (file)
@@ -70,6 +70,8 @@
 #define CAPTURE_END_DMA_DESCR_CH15 7
 
 #define mmACP_I2S_16BIT_RESOLUTION_EN       0x5209
+#define ACP_I2S_MIC_16BIT_RESOLUTION_EN 0x01
+#define ACP_I2S_SP_16BIT_RESOLUTION_EN 0x02
 enum acp_dma_priority_level {
        /* 0x0 Specifies the DMA channel is given normal priority */
        ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0,
index 5672e51..c1830cc 100644 (file)
@@ -798,12 +798,7 @@ static int hdmi_codec_probe(struct platform_device *pdev)
 
 static int hdmi_codec_remove(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct hdmi_codec_priv *hcp;
-
-       hcp = dev_get_drvdata(dev);
-       kfree(hcp->chmap_info);
-       snd_soc_unregister_codec(dev);
+       snd_soc_unregister_codec(&pdev->dev);
 
        return 0;
 }
index 831b297..45a7304 100644 (file)
@@ -1722,6 +1722,7 @@ static const struct regmap_config rt5651_regmap = {
        .num_reg_defaults = ARRAY_SIZE(rt5651_reg),
        .ranges = rt5651_ranges,
        .num_ranges = ARRAY_SIZE(rt5651_ranges),
+       .use_single_rw = true,
 };
 
 #if defined(CONFIG_OF)
index e1ab553..c5c76ab 100644 (file)
@@ -529,10 +529,15 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = {
 static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute)
 {
        struct snd_soc_codec *codec = codec_dai->codec;
-       u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT;
+       u16 i2s_pwr = SGTL5000_I2S_IN_POWERUP;
 
-       snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
-                       adcdac_ctrl, mute ? adcdac_ctrl : 0);
+       /*
+        * During 'digital mute' do not mute DAC
+        * because LINE_IN would be muted aswell. We want to mute
+        * only I2S block - this can be done by powering it off
+        */
+       snd_soc_update_bits(codec, SGTL5000_CHIP_DIG_POWER,
+                       i2s_pwr, mute ? 0 : i2s_pwr);
 
        return 0;
 }
@@ -871,15 +876,26 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
 static int sgtl5000_set_bias_level(struct snd_soc_codec *codec,
                                   enum snd_soc_bias_level level)
 {
+       struct sgtl5000_priv *sgtl = snd_soc_codec_get_drvdata(codec);
+       int ret;
+
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
        case SND_SOC_BIAS_STANDBY:
+               regcache_cache_only(sgtl->regmap, false);
+               ret = regcache_sync(sgtl->regmap);
+               if (ret) {
+                       regcache_cache_only(sgtl->regmap, true);
+                       return ret;
+               }
+
                snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                                    SGTL5000_REFTOP_POWERUP,
                                    SGTL5000_REFTOP_POWERUP);
                break;
        case SND_SOC_BIAS_OFF:
+               regcache_cache_only(sgtl->regmap, true);
                snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
                                    SGTL5000_REFTOP_POWERUP, 0);
                break;
@@ -1237,6 +1253,10 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
         */
        snd_soc_write(codec, SGTL5000_DAP_CTRL, 0);
 
+       /* Unmute DAC after start */
+       snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL,
+               SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT, 0);
+
        return 0;
 
 err:
index 66e32f5..989d093 100644 (file)
@@ -1204,12 +1204,14 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl)
                kcontrol->put = wm_coeff_put_acked;
                break;
        default:
-               kcontrol->get = wm_coeff_get;
-               kcontrol->put = wm_coeff_put;
-
-               ctl->bytes_ext.max = ctl->len;
-               ctl->bytes_ext.get = wm_coeff_tlv_get;
-               ctl->bytes_ext.put = wm_coeff_tlv_put;
+               if (kcontrol->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
+                       ctl->bytes_ext.max = ctl->len;
+                       ctl->bytes_ext.get = wm_coeff_tlv_get;
+                       ctl->bytes_ext.put = wm_coeff_tlv_put;
+               } else {
+                       kcontrol->get = wm_coeff_get;
+                       kcontrol->put = wm_coeff_put;
+               }
                break;
        }
 
index dca1143..a4aa931 100644 (file)
 
 #define SUN8I_I2S_CHAN_CFG_REG         0x30
 #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK    GENMASK(6, 4)
-#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)   (chan - 1)
+#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan)   ((chan - 1) << 4)
 #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK    GENMASK(2, 0)
 #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan)   (chan - 1)
 
index 9afb8ab..06b2262 100644 (file)
@@ -347,17 +347,20 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
                            int validx, int *value_ret)
 {
        struct snd_usb_audio *chip = cval->head.mixer->chip;
-       unsigned char buf[4 + 3 * sizeof(__u32)]; /* enough space for one range */
+       /* enough space for one range */
+       unsigned char buf[sizeof(__u16) + 3 * sizeof(__u32)];
        unsigned char *val;
-       int idx = 0, ret, size;
+       int idx = 0, ret, val_size, size;
        __u8 bRequest;
 
+       val_size = uac2_ctl_value_size(cval->val_type);
+
        if (request == UAC_GET_CUR) {
                bRequest = UAC2_CS_CUR;
-               size = uac2_ctl_value_size(cval->val_type);
+               size = val_size;
        } else {
                bRequest = UAC2_CS_RANGE;
-               size = sizeof(buf);
+               size = sizeof(__u16) + 3 * val_size;
        }
 
        memset(buf, 0, sizeof(buf));
@@ -390,16 +393,17 @@ error:
                val = buf + sizeof(__u16);
                break;
        case UAC_GET_MAX:
-               val = buf + sizeof(__u16) * 2;
+               val = buf + sizeof(__u16) + val_size;
                break;
        case UAC_GET_RES:
-               val = buf + sizeof(__u16) * 3;
+               val = buf + sizeof(__u16) + val_size * 2;
                break;
        default:
                return -EINVAL;
        }
 
-       *value_ret = convert_signed_value(cval, snd_usb_combine_bytes(val, sizeof(__u16)));
+       *value_ret = convert_signed_value(cval,
+                                         snd_usb_combine_bytes(val, val_size));
 
        return 0;
 }
index b9c9a19..3cbfae6 100644 (file)
@@ -357,6 +357,15 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs,
 
                alts = &iface->altsetting[1];
                goto add_sync_ep;
+       case USB_ID(0x1397, 0x0002):
+               ep = 0x81;
+               iface = usb_ifnum_to_if(dev, 1);
+
+               if (!iface || iface->num_altsetting == 0)
+                       return -EINVAL;
+
+               alts = &iface->altsetting[1];
+               goto add_sync_ep;
 
        }
        if (attr == USB_ENDPOINT_SYNC_ASYNC &&
index 5025204..754e632 100644 (file)
@@ -3325,4 +3325,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
        }
 },
 
+{
+       /*
+        * Bower's & Wilkins PX headphones only support the 48 kHz sample rate
+        * even though it advertises more. The capture interface doesn't work
+        * even on windows.
+        */
+       USB_DEVICE(0x19b5, 0x0021),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = (const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_IGNORE_INTERFACE,
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = UAC_EP_CS_ATTR_FILL_MAX |
+                                               UAC_EP_CS_ATTR_SAMPLE_RATE,
+                                       .endpoint = 0x03,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) {
+                                               48000
+                                       }
+                               }
+                       },
+               }
+       }
+},
+
 #undef USB_DEVICE_VENDOR_SPEC
index a66ef57..794224e 100644 (file)
@@ -1171,6 +1171,7 @@ static bool is_teac_dsd_dac(unsigned int id)
        switch (id) {
        case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */
        case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */
+       case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */
                return true;
        }
        return false;
@@ -1363,8 +1364,11 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
                        return SNDRV_PCM_FMTBIT_DSD_U32_BE;
                break;
 
-       /* Amanero Combo384 USB interface with native DSD support */
-       case USB_ID(0x16d0, 0x071a):
+       /* Amanero Combo384 USB based DACs with native DSD support */
+       case USB_ID(0x16d0, 0x071a):  /* Amanero - Combo384 */
+       case USB_ID(0x2ab6, 0x0004):  /* T+A DAC8DSD-V2.0, MP1000E-V2.0, MP2000R-V2.0, MP2500R-V2.0, MP3100HV-V2.0 */
+       case USB_ID(0x2ab6, 0x0005):  /* T+A USB HD Audio 1 */
+       case USB_ID(0x2ab6, 0x0006):  /* T+A USB HD Audio 2 */
                if (fp->altsetting == 2) {
                        switch (le16_to_cpu(chip->dev->descriptor.bcdDevice)) {
                        case 0x199:
index a095150..4ed9d0c 100644 (file)
@@ -50,6 +50,7 @@
 /*standard module options for ALSA. This module supports only one card*/
 static int hdmi_card_index = SNDRV_DEFAULT_IDX1;
 static char *hdmi_card_id = SNDRV_DEFAULT_STR1;
+static bool single_port;
 
 module_param_named(index, hdmi_card_index, int, 0444);
 MODULE_PARM_DESC(index,
@@ -57,6 +58,9 @@ MODULE_PARM_DESC(index,
 module_param_named(id, hdmi_card_id, charp, 0444);
 MODULE_PARM_DESC(id,
                "ID string for INTEL Intel HDMI Audio controller.");
+module_param(single_port, bool, 0444);
+MODULE_PARM_DESC(single_port,
+               "Single-port mode (for compatibility)");
 
 /*
  * ELD SA bits in the CEA Speaker Allocation data block
@@ -1579,7 +1583,11 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
 static void notify_audio_lpe(struct platform_device *pdev, int port)
 {
        struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev);
-       struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
+       struct snd_intelhad *ctx;
+
+       ctx = &card_ctx->pcm_ctx[single_port ? 0 : port];
+       if (single_port)
+               ctx->port = port;
 
        schedule_work(&ctx->hdmi_audio_wq);
 }
@@ -1743,6 +1751,7 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 {
        struct snd_card *card;
        struct snd_intelhad_card *card_ctx;
+       struct snd_intelhad *ctx;
        struct snd_pcm *pcm;
        struct intel_hdmi_lpe_audio_pdata *pdata;
        int irq;
@@ -1787,6 +1796,21 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, card_ctx);
 
+       card_ctx->num_pipes = pdata->num_pipes;
+       card_ctx->num_ports = single_port ? 1 : pdata->num_ports;
+
+       for_each_port(card_ctx, port) {
+               ctx = &card_ctx->pcm_ctx[port];
+               ctx->card_ctx = card_ctx;
+               ctx->dev = card_ctx->dev;
+               ctx->port = single_port ? -1 : port;
+               ctx->pipe = -1;
+
+               spin_lock_init(&ctx->had_spinlock);
+               mutex_init(&ctx->mutex);
+               INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
+       }
+
        dev_dbg(&pdev->dev, "%s: mmio_start = 0x%x, mmio_end = 0x%x\n",
                __func__, (unsigned int)res_mmio->start,
                (unsigned int)res_mmio->end);
@@ -1816,19 +1840,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
        init_channel_allocations();
 
        card_ctx->num_pipes = pdata->num_pipes;
-       card_ctx->num_ports = pdata->num_ports;
+       card_ctx->num_ports = single_port ? 1 : pdata->num_ports;
 
        for_each_port(card_ctx, port) {
-               struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
                int i;
 
-               ctx->card_ctx = card_ctx;
-               ctx->dev = card_ctx->dev;
-               ctx->port = port;
-               ctx->pipe = -1;
-
-               INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
-
+               ctx = &card_ctx->pcm_ctx[port];
                ret = snd_pcm_new(card, INTEL_HAD, port, MAX_PB_STREAMS,
                                  MAX_CAP_STREAMS, &pcm);
                if (ret)
index 637b726..833ed9a 100644 (file)
@@ -632,6 +632,8 @@ struct kvm_ppc_cpu_char {
 #define KVM_REG_PPC_TIDR       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbc)
 #define KVM_REG_PPC_PSSCR      (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd)
 
+#define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe)
+
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
  */
diff --git a/tools/arch/s390/include/uapi/asm/unistd.h b/tools/arch/s390/include/uapi/asm/unistd.h
deleted file mode 100644 (file)
index 7251209..0000000
+++ /dev/null
@@ -1,412 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
-/*
- *  S390 version
- *
- *  Derived from "include/asm-i386/unistd.h"
- */
-
-#ifndef _UAPI_ASM_S390_UNISTD_H_
-#define _UAPI_ASM_S390_UNISTD_H_
-
-/*
- * This file contains the system call numbers.
- */
-
-#define __NR_exit                 1
-#define __NR_fork                 2
-#define __NR_read                 3
-#define __NR_write                4
-#define __NR_open                 5
-#define __NR_close                6
-#define __NR_restart_syscall     7
-#define __NR_creat                8
-#define __NR_link                 9
-#define __NR_unlink              10
-#define __NR_execve              11
-#define __NR_chdir               12
-#define __NR_mknod               14
-#define __NR_chmod               15
-#define __NR_lseek               19
-#define __NR_getpid              20
-#define __NR_mount               21
-#define __NR_umount              22
-#define __NR_ptrace              26
-#define __NR_alarm               27
-#define __NR_pause               29
-#define __NR_utime               30
-#define __NR_access              33
-#define __NR_nice                34
-#define __NR_sync                36
-#define __NR_kill                37
-#define __NR_rename              38
-#define __NR_mkdir               39
-#define __NR_rmdir               40
-#define __NR_dup                 41
-#define __NR_pipe                42
-#define __NR_times               43
-#define __NR_brk                 45
-#define __NR_signal              48
-#define __NR_acct                51
-#define __NR_umount2             52
-#define __NR_ioctl               54
-#define __NR_fcntl               55
-#define __NR_setpgid             57
-#define __NR_umask               60
-#define __NR_chroot              61
-#define __NR_ustat               62
-#define __NR_dup2                63
-#define __NR_getppid             64
-#define __NR_getpgrp             65
-#define __NR_setsid              66
-#define __NR_sigaction           67
-#define __NR_sigsuspend          72
-#define __NR_sigpending          73
-#define __NR_sethostname         74
-#define __NR_setrlimit           75
-#define __NR_getrusage           77
-#define __NR_gettimeofday        78
-#define __NR_settimeofday        79
-#define __NR_symlink             83
-#define __NR_readlink            85
-#define __NR_uselib              86
-#define __NR_swapon              87
-#define __NR_reboot              88
-#define __NR_readdir             89
-#define __NR_mmap                90
-#define __NR_munmap              91
-#define __NR_truncate            92
-#define __NR_ftruncate           93
-#define __NR_fchmod              94
-#define __NR_getpriority         96
-#define __NR_setpriority         97
-#define __NR_statfs              99
-#define __NR_fstatfs            100
-#define __NR_socketcall         102
-#define __NR_syslog             103
-#define __NR_setitimer          104
-#define __NR_getitimer          105
-#define __NR_stat               106
-#define __NR_lstat              107
-#define __NR_fstat              108
-#define __NR_lookup_dcookie     110
-#define __NR_vhangup            111
-#define __NR_idle               112
-#define __NR_wait4              114
-#define __NR_swapoff            115
-#define __NR_sysinfo            116
-#define __NR_ipc                117
-#define __NR_fsync              118
-#define __NR_sigreturn          119
-#define __NR_clone              120
-#define __NR_setdomainname      121
-#define __NR_uname              122
-#define __NR_adjtimex           124
-#define __NR_mprotect           125
-#define __NR_sigprocmask        126
-#define __NR_create_module      127
-#define __NR_init_module        128
-#define __NR_delete_module      129
-#define __NR_get_kernel_syms    130
-#define __NR_quotactl           131
-#define __NR_getpgid            132
-#define __NR_fchdir             133
-#define __NR_bdflush            134
-#define __NR_sysfs              135
-#define __NR_personality        136
-#define __NR_afs_syscall        137 /* Syscall for Andrew File System */
-#define __NR_getdents           141
-#define __NR_flock              143
-#define __NR_msync              144
-#define __NR_readv              145
-#define __NR_writev             146
-#define __NR_getsid             147
-#define __NR_fdatasync          148
-#define __NR__sysctl            149
-#define __NR_mlock              150
-#define __NR_munlock            151
-#define __NR_mlockall           152
-#define __NR_munlockall         153
-#define __NR_sched_setparam             154
-#define __NR_sched_getparam             155
-#define __NR_sched_setscheduler         156
-#define __NR_sched_getscheduler         157
-#define __NR_sched_yield                158
-#define __NR_sched_get_priority_max     159
-#define __NR_sched_get_priority_min     160
-#define __NR_sched_rr_get_interval      161
-#define __NR_nanosleep          162
-#define __NR_mremap             163
-#define __NR_query_module       167
-#define __NR_poll               168
-#define __NR_nfsservctl         169
-#define __NR_prctl              172
-#define __NR_rt_sigreturn       173
-#define __NR_rt_sigaction       174
-#define __NR_rt_sigprocmask     175
-#define __NR_rt_sigpending      176
-#define __NR_rt_sigtimedwait    177
-#define __NR_rt_sigqueueinfo    178
-#define __NR_rt_sigsuspend      179
-#define __NR_pread64            180
-#define __NR_pwrite64           181
-#define __NR_getcwd             183
-#define __NR_capget             184
-#define __NR_capset             185
-#define __NR_sigaltstack        186
-#define __NR_sendfile           187
-#define __NR_getpmsg           188
-#define __NR_putpmsg           189
-#define __NR_vfork             190
-#define __NR_pivot_root         217
-#define __NR_mincore            218
-#define __NR_madvise            219
-#define __NR_getdents64                220
-#define __NR_readahead         222
-#define __NR_setxattr          224
-#define __NR_lsetxattr         225
-#define __NR_fsetxattr         226
-#define __NR_getxattr          227
-#define __NR_lgetxattr         228
-#define __NR_fgetxattr         229
-#define __NR_listxattr         230
-#define __NR_llistxattr                231
-#define __NR_flistxattr                232
-#define __NR_removexattr       233
-#define __NR_lremovexattr      234
-#define __NR_fremovexattr      235
-#define __NR_gettid            236
-#define __NR_tkill             237
-#define __NR_futex             238
-#define __NR_sched_setaffinity 239
-#define __NR_sched_getaffinity 240
-#define __NR_tgkill            241
-/* Number 242 is reserved for tux */
-#define __NR_io_setup          243
-#define __NR_io_destroy                244
-#define __NR_io_getevents      245
-#define __NR_io_submit         246
-#define __NR_io_cancel         247
-#define __NR_exit_group                248
-#define __NR_epoll_create      249
-#define __NR_epoll_ctl         250
-#define __NR_epoll_wait                251
-#define __NR_set_tid_address   252
-#define __NR_fadvise64         253
-#define __NR_timer_create      254
-#define __NR_timer_settime     255
-#define __NR_timer_gettime     256
-#define __NR_timer_getoverrun  257
-#define __NR_timer_delete      258
-#define __NR_clock_settime     259
-#define __NR_clock_gettime     260
-#define __NR_clock_getres      261
-#define __NR_clock_nanosleep   262
-/* Number 263 is reserved for vserver */
-#define __NR_statfs64          265
-#define __NR_fstatfs64         266
-#define __NR_remap_file_pages  267
-#define __NR_mbind             268
-#define __NR_get_mempolicy     269
-#define __NR_set_mempolicy     270
-#define __NR_mq_open           271
-#define __NR_mq_unlink         272
-#define __NR_mq_timedsend      273
-#define __NR_mq_timedreceive   274
-#define __NR_mq_notify         275
-#define __NR_mq_getsetattr     276
-#define __NR_kexec_load                277
-#define __NR_add_key           278
-#define __NR_request_key       279
-#define __NR_keyctl            280
-#define __NR_waitid            281
-#define __NR_ioprio_set                282
-#define __NR_ioprio_get                283
-#define __NR_inotify_init      284
-#define __NR_inotify_add_watch 285
-#define __NR_inotify_rm_watch  286
-#define __NR_migrate_pages     287
-#define __NR_openat            288
-#define __NR_mkdirat           289
-#define __NR_mknodat           290
-#define __NR_fchownat          291
-#define __NR_futimesat         292
-#define __NR_unlinkat          294
-#define __NR_renameat          295
-#define __NR_linkat            296
-#define __NR_symlinkat         297
-#define __NR_readlinkat                298
-#define __NR_fchmodat          299
-#define __NR_faccessat         300
-#define __NR_pselect6          301
-#define __NR_ppoll             302
-#define __NR_unshare           303
-#define __NR_set_robust_list   304
-#define __NR_get_robust_list   305
-#define __NR_splice            306
-#define __NR_sync_file_range   307
-#define __NR_tee               308
-#define __NR_vmsplice          309
-#define __NR_move_pages                310
-#define __NR_getcpu            311
-#define __NR_epoll_pwait       312
-#define __NR_utimes            313
-#define __NR_fallocate         314
-#define __NR_utimensat         315
-#define __NR_signalfd          316
-#define __NR_timerfd           317
-#define __NR_eventfd           318
-#define __NR_timerfd_create    319
-#define __NR_timerfd_settime   320
-#define __NR_timerfd_gettime   321
-#define __NR_signalfd4         322
-#define __NR_eventfd2          323
-#define __NR_inotify_init1     324
-#define __NR_pipe2             325
-#define __NR_dup3              326
-#define __NR_epoll_create1     327
-#define        __NR_preadv             328
-#define        __NR_pwritev            329
-#define __NR_rt_tgsigqueueinfo 330
-#define __NR_perf_event_open   331
-#define __NR_fanotify_init     332
-#define __NR_fanotify_mark     333
-#define __NR_prlimit64         334
-#define __NR_name_to_handle_at 335
-#define __NR_open_by_handle_at 336
-#define __NR_clock_adjtime     337
-#define __NR_syncfs            338
-#define __NR_setns             339
-#define __NR_process_vm_readv  340
-#define __NR_process_vm_writev 341
-#define __NR_s390_runtime_instr 342
-#define __NR_kcmp              343
-#define __NR_finit_module      344
-#define __NR_sched_setattr     345
-#define __NR_sched_getattr     346
-#define __NR_renameat2         347
-#define __NR_seccomp           348
-#define __NR_getrandom         349
-#define __NR_memfd_create      350
-#define __NR_bpf               351
-#define __NR_s390_pci_mmio_write       352
-#define __NR_s390_pci_mmio_read                353
-#define __NR_execveat          354
-#define __NR_userfaultfd       355
-#define __NR_membarrier                356
-#define __NR_recvmmsg          357
-#define __NR_sendmmsg          358
-#define __NR_socket            359
-#define __NR_socketpair                360
-#define __NR_bind              361
-#define __NR_connect           362
-#define __NR_listen            363
-#define __NR_accept4           364
-#define __NR_getsockopt                365
-#define __NR_setsockopt                366
-#define __NR_getsockname       367
-#define __NR_getpeername       368
-#define __NR_sendto            369
-#define __NR_sendmsg           370
-#define __NR_recvfrom          371
-#define __NR_recvmsg           372
-#define __NR_shutdown          373
-#define __NR_mlock2            374
-#define __NR_copy_file_range   375
-#define __NR_preadv2           376
-#define __NR_pwritev2          377
-#define __NR_s390_guarded_storage      378
-#define __NR_statx             379
-#define __NR_s390_sthyi                380
-#define NR_syscalls 381
-
-/* 
- * There are some system calls that are not present on 64 bit, some
- * have a different name although they do the same (e.g. __NR_chown32
- * is __NR_chown on 64 bit).
- */
-#ifndef __s390x__
-
-#define __NR_time               13
-#define __NR_lchown             16
-#define __NR_setuid             23
-#define __NR_getuid             24
-#define __NR_stime              25
-#define __NR_setgid             46
-#define __NR_getgid             47
-#define __NR_geteuid            49
-#define __NR_getegid            50
-#define __NR_setreuid           70
-#define __NR_setregid           71
-#define __NR_getrlimit          76
-#define __NR_getgroups          80
-#define __NR_setgroups          81
-#define __NR_fchown             95
-#define __NR_ioperm            101
-#define __NR_setfsuid          138
-#define __NR_setfsgid          139
-#define __NR__llseek           140
-#define __NR__newselect        142
-#define __NR_setresuid         164
-#define __NR_getresuid         165
-#define __NR_setresgid         170
-#define __NR_getresgid         171
-#define __NR_chown             182
-#define __NR_ugetrlimit                191     /* SuS compliant getrlimit */
-#define __NR_mmap2             192
-#define __NR_truncate64                193
-#define __NR_ftruncate64       194
-#define __NR_stat64            195
-#define __NR_lstat64           196
-#define __NR_fstat64           197
-#define __NR_lchown32          198
-#define __NR_getuid32          199
-#define __NR_getgid32          200
-#define __NR_geteuid32         201
-#define __NR_getegid32         202
-#define __NR_setreuid32                203
-#define __NR_setregid32                204
-#define __NR_getgroups32       205
-#define __NR_setgroups32       206
-#define __NR_fchown32          207
-#define __NR_setresuid32       208
-#define __NR_getresuid32       209
-#define __NR_setresgid32       210
-#define __NR_getresgid32       211
-#define __NR_chown32           212
-#define __NR_setuid32          213
-#define __NR_setgid32          214
-#define __NR_setfsuid32                215
-#define __NR_setfsgid32                216
-#define __NR_fcntl64           221
-#define __NR_sendfile64                223
-#define __NR_fadvise64_64      264
-#define __NR_fstatat64         293
-
-#else
-
-#define __NR_select            142
-#define __NR_getrlimit         191     /* SuS compliant getrlimit */
-#define __NR_lchown            198
-#define __NR_getuid            199
-#define __NR_getgid            200
-#define __NR_geteuid           201
-#define __NR_getegid           202
-#define __NR_setreuid                  203
-#define __NR_setregid                  204
-#define __NR_getgroups         205
-#define __NR_setgroups         206
-#define __NR_fchown            207
-#define __NR_setresuid         208
-#define __NR_getresuid         209
-#define __NR_setresgid         210
-#define __NR_getresgid         211
-#define __NR_chown             212
-#define __NR_setuid            213
-#define __NR_setgid            214
-#define __NR_setfsuid                  215
-#define __NR_setfsgid                  216
-#define __NR_newfstatat                293
-
-#endif
-
-#endif /* _UAPI_ASM_S390_UNISTD_H_ */
index 1d9199e..f41079d 100644 (file)
 
 #define X86_FEATURE_MBA                        ( 7*32+18) /* Memory Bandwidth Allocation */
 #define X86_FEATURE_RSB_CTXSW          ( 7*32+19) /* "" Fill RSB on context switches */
+#define X86_FEATURE_SEV                        ( 7*32+20) /* AMD Secure Encrypted Virtualization */
 
 #define X86_FEATURE_USE_IBPB           ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */
+#define X86_FEATURE_USE_IBRS_FW                ( 7*32+22) /* "" Use IBRS during runtime firmware calls */
 
 /* Virtualization flags: Linux defined, word 8 */
 #define X86_FEATURE_TPR_SHADOW         ( 8*32+ 0) /* Intel TPR Shadow */
index 0b482c0..4659952 100644 (file)
 
 #include "main.h"
 
+#ifndef BPF_FS_MAGIC
+#define BPF_FS_MAGIC           0xcafe4a11
+#endif
+
 void p_err(const char *fmt, ...)
 {
        va_list ap;
index 3a0396d..185acfa 100644 (file)
@@ -244,7 +244,7 @@ static int do_batch(int argc, char **argv)
        }
 
        if (errno && errno != ENOENT) {
-               perror("reading batch file failed");
+               p_err("reading batch file failed: %s", strerror(errno));
                err = -1;
        } else {
                p_info("processed %d lines", lines);
index f95fa67..f509c86 100644 (file)
@@ -428,7 +428,7 @@ static int show_map_close_json(int fd, struct bpf_map_info *info)
                jsonw_string_field(json_wtr, "name", info->name);
 
        jsonw_name(json_wtr, "flags");
-       jsonw_printf(json_wtr, "%#x", info->map_flags);
+       jsonw_printf(json_wtr, "%d", info->map_flags);
 
        print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
 
index e8e2baa..e549e32 100644 (file)
@@ -774,6 +774,9 @@ static int do_dump(int argc, char **argv)
                              n < 0 ? strerror(errno) : "short write");
                        goto err_free;
                }
+
+               if (json_output)
+                       jsonw_null(json_wtr);
        } else {
                if (member_len == &info.jited_prog_len) {
                        const char *name = NULL;
index 860fa15..ffca068 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for cgroup tools
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra
 
 all: cgroup_event_listener
index 805a2c0..240eda0 100644 (file)
@@ -12,8 +12,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := lsgpio gpio-hammer gpio-event-mon
index 1139d71..5db5e62 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for Hyper-V tools
 
-CC = $(CROSS_COMPILE)gcc
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g $(shell getconf LFS_CFLAGS)
 
index a08e7a4..332ed2f 100644 (file)
@@ -12,8 +12,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := iio_event_monitor lsiio iio_generic_buffer
index ac3c650..536ee4f 100644 (file)
@@ -86,6 +86,62 @@ enum i915_mocs_table_index {
        I915_MOCS_CACHED,
 };
 
+/*
+ * Different engines serve different roles, and there may be more than one
+ * engine serving each role. enum drm_i915_gem_engine_class provides a
+ * classification of the role of the engine, which may be used when requesting
+ * operations to be performed on a certain subset of engines, or for providing
+ * information about that group.
+ */
+enum drm_i915_gem_engine_class {
+       I915_ENGINE_CLASS_RENDER        = 0,
+       I915_ENGINE_CLASS_COPY          = 1,
+       I915_ENGINE_CLASS_VIDEO         = 2,
+       I915_ENGINE_CLASS_VIDEO_ENHANCE = 3,
+
+       I915_ENGINE_CLASS_INVALID       = -1
+};
+
+/**
+ * DOC: perf_events exposed by i915 through /sys/bus/event_sources/drivers/i915
+ *
+ */
+
+enum drm_i915_pmu_engine_sample {
+       I915_SAMPLE_BUSY = 0,
+       I915_SAMPLE_WAIT = 1,
+       I915_SAMPLE_SEMA = 2
+};
+
+#define I915_PMU_SAMPLE_BITS (4)
+#define I915_PMU_SAMPLE_MASK (0xf)
+#define I915_PMU_SAMPLE_INSTANCE_BITS (8)
+#define I915_PMU_CLASS_SHIFT \
+       (I915_PMU_SAMPLE_BITS + I915_PMU_SAMPLE_INSTANCE_BITS)
+
+#define __I915_PMU_ENGINE(class, instance, sample) \
+       ((class) << I915_PMU_CLASS_SHIFT | \
+       (instance) << I915_PMU_SAMPLE_BITS | \
+       (sample))
+
+#define I915_PMU_ENGINE_BUSY(class, instance) \
+       __I915_PMU_ENGINE(class, instance, I915_SAMPLE_BUSY)
+
+#define I915_PMU_ENGINE_WAIT(class, instance) \
+       __I915_PMU_ENGINE(class, instance, I915_SAMPLE_WAIT)
+
+#define I915_PMU_ENGINE_SEMA(class, instance) \
+       __I915_PMU_ENGINE(class, instance, I915_SAMPLE_SEMA)
+
+#define __I915_PMU_OTHER(x) (__I915_PMU_ENGINE(0xff, 0xff, 0xf) + 1 + (x))
+
+#define I915_PMU_ACTUAL_FREQUENCY      __I915_PMU_OTHER(0)
+#define I915_PMU_REQUESTED_FREQUENCY   __I915_PMU_OTHER(1)
+#define I915_PMU_INTERRUPTS            __I915_PMU_OTHER(2)
+#define I915_PMU_RC6_RESIDENCY         __I915_PMU_OTHER(3)
+
+#define I915_PMU_LAST I915_PMU_RC6_RESIDENCY
+
 /* Each region is a minimum of 16k, and there are at most 255 of them.
  */
 #define I915_NR_TEX_REGIONS 255        /* table size 2k - maximum due to use
@@ -450,6 +506,27 @@ typedef struct drm_i915_irq_wait {
  */
 #define I915_PARAM_HAS_EXEC_FENCE_ARRAY  49
 
+/*
+ * Query whether every context (both per-file default and user created) is
+ * isolated (insofar as HW supports). If this parameter is not true, then
+ * freshly created contexts may inherit values from an existing context,
+ * rather than default HW values. If true, it also ensures (insofar as HW
+ * supports) that all state set by this context will not leak to any other
+ * context.
+ *
+ * As not every engine across every gen support contexts, the returned
+ * value reports the support of context isolation for individual engines by
+ * returning a bitmask of each engine class set to true if that class supports
+ * isolation.
+ */
+#define I915_PARAM_HAS_CONTEXT_ISOLATION 50
+
+/* Frequency of the command streamer timestamps given by the *_TIMESTAMP
+ * registers. This used to be fixed per platform but from CNL onwards, this
+ * might vary depending on the parts.
+ */
+#define I915_PARAM_CS_TIMESTAMP_FREQUENCY 51
+
 typedef struct drm_i915_getparam {
        __s32 param;
        /*
index 8616131..6d94477 100644 (file)
@@ -163,6 +163,7 @@ enum {
        IFLA_IF_NETNSID,
        IFLA_CARRIER_UP_COUNT,
        IFLA_CARRIER_DOWN_COUNT,
+       IFLA_NEW_IFINDEX,
        __IFLA_MAX
 };
 
index 8fb90a0..7b26d4b 100644 (file)
@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_TRACE_PAUSE           __KVM_DEPRECATED_MAIN_0x07
 #define KVM_TRACE_DISABLE         __KVM_DEPRECATED_MAIN_0x08
 #define KVM_GET_EMULATED_CPUID   _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
+#define KVM_GET_MSR_FEATURE_INDEX_LIST    _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
 
 /*
  * Extension capability list.
@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
 #define KVM_CAP_S390_AIS_MIGRATION 150
 #define KVM_CAP_PPC_GET_CPU_CHAR 151
 #define KVM_CAP_S390_BPB 152
+#define KVM_CAP_GET_MSR_FEATURES 153
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -1362,6 +1364,96 @@ struct kvm_s390_ucas_mapping {
 /* Available with KVM_CAP_S390_CMMA_MIGRATION */
 #define KVM_S390_GET_CMMA_BITS      _IOWR(KVMIO, 0xb8, struct kvm_s390_cmma_log)
 #define KVM_S390_SET_CMMA_BITS      _IOW(KVMIO, 0xb9, struct kvm_s390_cmma_log)
+/* Memory Encryption Commands */
+#define KVM_MEMORY_ENCRYPT_OP      _IOWR(KVMIO, 0xba, unsigned long)
+
+struct kvm_enc_region {
+       __u64 addr;
+       __u64 size;
+};
+
+#define KVM_MEMORY_ENCRYPT_REG_REGION    _IOR(KVMIO, 0xbb, struct kvm_enc_region)
+#define KVM_MEMORY_ENCRYPT_UNREG_REGION  _IOR(KVMIO, 0xbc, struct kvm_enc_region)
+
+/* Secure Encrypted Virtualization command */
+enum sev_cmd_id {
+       /* Guest initialization commands */
+       KVM_SEV_INIT = 0,
+       KVM_SEV_ES_INIT,
+       /* Guest launch commands */
+       KVM_SEV_LAUNCH_START,
+       KVM_SEV_LAUNCH_UPDATE_DATA,
+       KVM_SEV_LAUNCH_UPDATE_VMSA,
+       KVM_SEV_LAUNCH_SECRET,
+       KVM_SEV_LAUNCH_MEASURE,
+       KVM_SEV_LAUNCH_FINISH,
+       /* Guest migration commands (outgoing) */
+       KVM_SEV_SEND_START,
+       KVM_SEV_SEND_UPDATE_DATA,
+       KVM_SEV_SEND_UPDATE_VMSA,
+       KVM_SEV_SEND_FINISH,
+       /* Guest migration commands (incoming) */
+       KVM_SEV_RECEIVE_START,
+       KVM_SEV_RECEIVE_UPDATE_DATA,
+       KVM_SEV_RECEIVE_UPDATE_VMSA,
+       KVM_SEV_RECEIVE_FINISH,
+       /* Guest status and debug commands */
+       KVM_SEV_GUEST_STATUS,
+       KVM_SEV_DBG_DECRYPT,
+       KVM_SEV_DBG_ENCRYPT,
+       /* Guest certificates commands */
+       KVM_SEV_CERT_EXPORT,
+
+       KVM_SEV_NR_MAX,
+};
+
+struct kvm_sev_cmd {
+       __u32 id;
+       __u64 data;
+       __u32 error;
+       __u32 sev_fd;
+};
+
+struct kvm_sev_launch_start {
+       __u32 handle;
+       __u32 policy;
+       __u64 dh_uaddr;
+       __u32 dh_len;
+       __u64 session_uaddr;
+       __u32 session_len;
+};
+
+struct kvm_sev_launch_update_data {
+       __u64 uaddr;
+       __u32 len;
+};
+
+
+struct kvm_sev_launch_secret {
+       __u64 hdr_uaddr;
+       __u32 hdr_len;
+       __u64 guest_uaddr;
+       __u32 guest_len;
+       __u64 trans_uaddr;
+       __u32 trans_len;
+};
+
+struct kvm_sev_launch_measure {
+       __u64 uaddr;
+       __u32 len;
+};
+
+struct kvm_sev_guest_status {
+       __u32 handle;
+       __u32 policy;
+       __u32 state;
+};
+
+struct kvm_sev_dbg {
+       __u64 src_uaddr;
+       __u64 dst_uaddr;
+       __u32 len;
+};
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU    (1 << 0)
 #define KVM_DEV_ASSIGN_PCI_2_3         (1 << 1)
index a5684d0..5898c22 100755 (executable)
@@ -33,7 +33,7 @@ import resource
 import struct
 import re
 import subprocess
-from collections import defaultdict
+from collections import defaultdict, namedtuple
 
 VMX_EXIT_REASONS = {
     'EXCEPTION_NMI':        0,
@@ -228,6 +228,7 @@ IOCTL_NUMBERS = {
 }
 
 ENCODING = locale.getpreferredencoding(False)
+TRACE_FILTER = re.compile(r'^[^\(]*$')
 
 
 class Arch(object):
@@ -260,6 +261,11 @@ class Arch(object):
                     return ArchX86(SVM_EXIT_REASONS)
                 return
 
+    def tracepoint_is_child(self, field):
+        if (TRACE_FILTER.match(field)):
+            return None
+        return field.split('(', 1)[0]
+
 
 class ArchX86(Arch):
     def __init__(self, exit_reasons):
@@ -267,6 +273,10 @@ class ArchX86(Arch):
         self.ioctl_numbers = IOCTL_NUMBERS
         self.exit_reasons = exit_reasons
 
+    def debugfs_is_child(self, field):
+        """ Returns name of parent if 'field' is a child, None otherwise """
+        return None
+
 
 class ArchPPC(Arch):
     def __init__(self):
@@ -282,6 +292,10 @@ class ArchPPC(Arch):
         self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16
         self.exit_reasons = {}
 
+    def debugfs_is_child(self, field):
+        """ Returns name of parent if 'field' is a child, None otherwise """
+        return None
+
 
 class ArchA64(Arch):
     def __init__(self):
@@ -289,6 +303,10 @@ class ArchA64(Arch):
         self.ioctl_numbers = IOCTL_NUMBERS
         self.exit_reasons = AARCH64_EXIT_REASONS
 
+    def debugfs_is_child(self, field):
+        """ Returns name of parent if 'field' is a child, None otherwise """
+        return None
+
 
 class ArchS390(Arch):
     def __init__(self):
@@ -296,6 +314,12 @@ class ArchS390(Arch):
         self.ioctl_numbers = IOCTL_NUMBERS
         self.exit_reasons = None
 
+    def debugfs_is_child(self, field):
+        """ Returns name of parent if 'field' is a child, None otherwise """
+        if field.startswith('instruction_'):
+            return 'exit_instruction'
+
+
 ARCH = Arch.get_arch()
 
 
@@ -331,9 +355,6 @@ class perf_event_attr(ctypes.Structure):
 PERF_TYPE_TRACEPOINT = 2
 PERF_FORMAT_GROUP = 1 << 3
 
-PATH_DEBUGFS_TRACING = '/sys/kernel/debug/tracing'
-PATH_DEBUGFS_KVM = '/sys/kernel/debug/kvm'
-
 
 class Group(object):
     """Represents a perf event group."""
@@ -376,8 +397,8 @@ class Event(object):
         self.syscall = self.libc.syscall
         self.name = name
         self.fd = None
-        self.setup_event(group, trace_cpu, trace_pid, trace_point,
-                         trace_filter, trace_set)
+        self._setup_event(group, trace_cpu, trace_pid, trace_point,
+                          trace_filter, trace_set)
 
     def __del__(self):
         """Closes the event's file descriptor.
@@ -390,7 +411,7 @@ class Event(object):
         if self.fd:
             os.close(self.fd)
 
-    def perf_event_open(self, attr, pid, cpu, group_fd, flags):
+    def _perf_event_open(self, attr, pid, cpu, group_fd, flags):
         """Wrapper for the sys_perf_evt_open() syscall.
 
         Used to set up performance events, returns a file descriptor or -1
@@ -409,7 +430,7 @@ class Event(object):
                             ctypes.c_int(pid), ctypes.c_int(cpu),
                             ctypes.c_int(group_fd), ctypes.c_long(flags))
 
-    def setup_event_attribute(self, trace_set, trace_point):
+    def _setup_event_attribute(self, trace_set, trace_point):
         """Returns an initialized ctype perf_event_attr struct."""
 
         id_path = os.path.join(PATH_DEBUGFS_TRACING, 'events', trace_set,
@@ -419,8 +440,8 @@ class Event(object):
         event_attr.config = int(open(id_path).read())
         return event_attr
 
-    def setup_event(self, group, trace_cpu, trace_pid, trace_point,
-                    trace_filter, trace_set):
+    def _setup_event(self, group, trace_cpu, trace_pid, trace_point,
+                     trace_filter, trace_set):
         """Sets up the perf event in Linux.
 
         Issues the syscall to register the event in the kernel and
@@ -428,7 +449,7 @@ class Event(object):
 
         """
 
-        event_attr = self.setup_event_attribute(trace_set, trace_point)
+        event_attr = self._setup_event_attribute(trace_set, trace_point)
 
         # First event will be group leader.
         group_leader = -1
@@ -437,8 +458,8 @@ class Event(object):
         if group.events:
             group_leader = group.events[0].fd
 
-        fd = self.perf_event_open(event_attr, trace_pid,
-                                  trace_cpu, group_leader, 0)
+        fd = self._perf_event_open(event_attr, trace_pid,
+                                   trace_cpu, group_leader, 0)
         if fd == -1:
             err = ctypes.get_errno()
             raise OSError(err, os.strerror(err),
@@ -475,6 +496,10 @@ class Event(object):
 
 class Provider(object):
     """Encapsulates functionalities used by all providers."""
+    def __init__(self, pid):
+        self.child_events = False
+        self.pid = pid
+
     @staticmethod
     def is_field_wanted(fields_filter, field):
         """Indicate whether field is valid according to fields_filter."""
@@ -500,12 +525,12 @@ class TracepointProvider(Provider):
     """
     def __init__(self, pid, fields_filter):
         self.group_leaders = []
-        self.filters = self.get_filters()
+        self.filters = self._get_filters()
         self.update_fields(fields_filter)
-        self.pid = pid
+        super(TracepointProvider, self).__init__(pid)
 
     @staticmethod
-    def get_filters():
+    def _get_filters():
         """Returns a dict of trace events, their filter ids and
         the values that can be filtered.
 
@@ -521,8 +546,8 @@ class TracepointProvider(Provider):
             filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons)
         return filters
 
-    def get_available_fields(self):
-        """Returns a list of available event's of format 'event name(filter
+    def _get_available_fields(self):
+        """Returns a list of available events of format 'event name(filter
         name)'.
 
         All available events have directories under
@@ -549,11 +574,12 @@ class TracepointProvider(Provider):
 
     def update_fields(self, fields_filter):
         """Refresh fields, applying fields_filter"""
-        self.fields = [field for field in self.get_available_fields()
-                       if self.is_field_wanted(fields_filter, field)]
+        self.fields = [field for field in self._get_available_fields()
+                       if self.is_field_wanted(fields_filter, field) or
+                       ARCH.tracepoint_is_child(field)]
 
     @staticmethod
-    def get_online_cpus():
+    def _get_online_cpus():
         """Returns a list of cpu id integers."""
         def parse_int_list(list_string):
             """Returns an int list from a string of comma separated integers and
@@ -575,17 +601,17 @@ class TracepointProvider(Provider):
             cpu_string = cpu_list.readline()
             return parse_int_list(cpu_string)
 
-    def setup_traces(self):
+    def _setup_traces(self):
         """Creates all event and group objects needed to be able to retrieve
         data."""
-        fields = self.get_available_fields()
+        fields = self._get_available_fields()
         if self._pid > 0:
             # Fetch list of all threads of the monitored pid, as qemu
             # starts a thread for each vcpu.
             path = os.path.join('/proc', str(self._pid), 'task')
             groupids = self.walkdir(path)[1]
         else:
-            groupids = self.get_online_cpus()
+            groupids = self._get_online_cpus()
 
         # The constant is needed as a buffer for python libs, std
         # streams and other files that the script opens.
@@ -663,7 +689,7 @@ class TracepointProvider(Provider):
         # The garbage collector will get rid of all Event/Group
         # objects and open files after removing the references.
         self.group_leaders = []
-        self.setup_traces()
+        self._setup_traces()
         self.fields = self._fields
 
     def read(self, by_guest=0):
@@ -671,8 +697,12 @@ class TracepointProvider(Provider):
         ret = defaultdict(int)
         for group in self.group_leaders:
             for name, val in group.read().items():
-                if name in self._fields:
-                    ret[name] += val
+                if name not in self._fields:
+                    continue
+                parent = ARCH.tracepoint_is_child(name)
+                if parent:
+                    name += ' ' + parent
+                ret[name] += val
         return ret
 
     def reset(self):
@@ -690,11 +720,11 @@ class DebugfsProvider(Provider):
         self._baseline = {}
         self.do_read = True
         self.paths = []
-        self.pid = pid
+        super(DebugfsProvider, self).__init__(pid)
         if include_past:
-            self.restore()
+            self._restore()
 
-    def get_available_fields(self):
+    def _get_available_fields(self):
         """"Returns a list of available fields.
 
         The fields are all available KVM debugfs files
@@ -704,8 +734,9 @@ class DebugfsProvider(Provider):
 
     def update_fields(self, fields_filter):
         """Refresh fields, applying fields_filter"""
-        self._fields = [field for field in self.get_available_fields()
-                        if self.is_field_wanted(fields_filter, field)]
+        self._fields = [field for field in self._get_available_fields()
+                        if self.is_field_wanted(fields_filter, field) or
+                        ARCH.debugfs_is_child(field)]
 
     @property
     def fields(self):
@@ -758,7 +789,7 @@ class DebugfsProvider(Provider):
                     paths.append(dir)
         for path in paths:
             for field in self._fields:
-                value = self.read_field(field, path)
+                value = self._read_field(field, path)
                 key = path + field
                 if reset == 1:
                     self._baseline[key] = value
@@ -766,20 +797,21 @@ class DebugfsProvider(Provider):
                     self._baseline[key] = 0
                 if self._baseline.get(key, -1) == -1:
                     self._baseline[key] = value
-                increment = (results.get(field, 0) + value -
-                             self._baseline.get(key, 0))
-                if by_guest:
-                    pid = key.split('-')[0]
-                    if pid in results:
-                        results[pid] += increment
-                    else:
-                        results[pid] = increment
+                parent = ARCH.debugfs_is_child(field)
+                if parent:
+                    field = field + ' ' + parent
+                else:
+                    if by_guest:
+                        field = key.split('-')[0]    # set 'field' to 'pid'
+                increment = value - self._baseline.get(key, 0)
+                if field in results:
+                    results[field] += increment
                 else:
                     results[field] = increment
 
         return results
 
-    def read_field(self, field, path):
+    def _read_field(self, field, path):
         """Returns the value of a single field from a specific VM."""
         try:
             return int(open(os.path.join(PATH_DEBUGFS_KVM,
@@ -794,12 +826,15 @@ class DebugfsProvider(Provider):
         self._baseline = {}
         self.read(1)
 
-    def restore(self):
+    def _restore(self):
         """Reset field counters"""
         self._baseline = {}
         self.read(2)
 
 
+EventStat = namedtuple('EventStat', ['value', 'delta'])
+
+
 class Stats(object):
     """Manages the data providers and the data they provide.
 
@@ -808,13 +843,13 @@ class Stats(object):
 
     """
     def __init__(self, options):
-        self.providers = self.get_providers(options)
+        self.providers = self._get_providers(options)
         self._pid_filter = options.pid
         self._fields_filter = options.fields
         self.values = {}
+        self._child_events = False
 
-    @staticmethod
-    def get_providers(options):
+    def _get_providers(self, options):
         """Returns a list of data providers depending on the passed options."""
         providers = []
 
@@ -826,7 +861,7 @@ class Stats(object):
 
         return providers
 
-    def update_provider_filters(self):
+    def _update_provider_filters(self):
         """Propagates fields filters to providers."""
         # As we reset the counters when updating the fields we can
         # also clear the cache of old values.
@@ -847,7 +882,7 @@ class Stats(object):
     def fields_filter(self, fields_filter):
         if fields_filter != self._fields_filter:
             self._fields_filter = fields_filter
-            self.update_provider_filters()
+            self._update_provider_filters()
 
     @property
     def pid_filter(self):
@@ -861,16 +896,33 @@ class Stats(object):
             for provider in self.providers:
                 provider.pid = self._pid_filter
 
+    @property
+    def child_events(self):
+        return self._child_events
+
+    @child_events.setter
+    def child_events(self, val):
+        self._child_events = val
+        for provider in self.providers:
+            provider.child_events = val
+
     def get(self, by_guest=0):
         """Returns a dict with field -> (value, delta to last value) of all
-        provider data."""
+        provider data.
+        Key formats:
+          * plain: 'key' is event name
+          * child-parent: 'key' is in format '<child> <parent>'
+          * pid: 'key' is the pid of the guest, and the record contains the
+               aggregated event data
+        These formats are generated by the providers, and handled in class TUI.
+        """
         for provider in self.providers:
             new = provider.read(by_guest=by_guest)
-            for key in new if by_guest else provider.fields:
-                oldval = self.values.get(key, (0, 0))[0]
+            for key in new:
+                oldval = self.values.get(key, EventStat(0, 0)).value
                 newval = new.get(key, 0)
                 newdelta = newval - oldval
-                self.values[key] = (newval, newdelta)
+                self.values[key] = EventStat(newval, newdelta)
         return self.values
 
     def toggle_display_guests(self, to_pid):
@@ -899,10 +951,10 @@ class Stats(object):
         self.get(to_pid)
         return 0
 
+
 DELAY_DEFAULT = 3.0
 MAX_GUEST_NAME_LEN = 48
 MAX_REGEX_LEN = 44
-DEFAULT_REGEX = r'^[^\(]*$'
 SORT_DEFAULT = 0
 
 
@@ -969,7 +1021,7 @@ class Tui(object):
 
         return res
 
-    def print_all_gnames(self, row):
+    def _print_all_gnames(self, row):
         """Print a list of all running guests along with their pids."""
         self.screen.addstr(row, 2, '%8s  %-60s' %
                            ('Pid', 'Guest Name (fuzzy list, might be '
@@ -1032,19 +1084,13 @@ class Tui(object):
 
         return name
 
-    def update_drilldown(self):
-        """Sets or removes a filter that only allows fields without braces."""
-        if not self.stats.fields_filter:
-            self.stats.fields_filter = DEFAULT_REGEX
-
-        elif self.stats.fields_filter == DEFAULT_REGEX:
-            self.stats.fields_filter = None
-
-    def update_pid(self, pid):
+    def _update_pid(self, pid):
         """Propagates pid selection to stats object."""
+        self.screen.addstr(4, 1, 'Updating pid filter...')
+        self.screen.refresh()
         self.stats.pid_filter = pid
 
-    def refresh_header(self, pid=None):
+    def _refresh_header(self, pid=None):
         """Refreshes the header."""
         if pid is None:
             pid = self.stats.pid_filter
@@ -1059,8 +1105,7 @@ class Tui(object):
                                .format(pid, gname), curses.A_BOLD)
         else:
             self.screen.addstr(0, 0, 'kvm statistics - summary', curses.A_BOLD)
-        if self.stats.fields_filter and self.stats.fields_filter \
-           != DEFAULT_REGEX:
+        if self.stats.fields_filter:
             regex = self.stats.fields_filter
             if len(regex) > MAX_REGEX_LEN:
                 regex = regex[:MAX_REGEX_LEN] + '...'
@@ -1075,56 +1120,99 @@ class Tui(object):
         self.screen.addstr(4, 1, 'Collecting data...')
         self.screen.refresh()
 
-    def refresh_body(self, sleeptime):
+    def _refresh_body(self, sleeptime):
+        def is_child_field(field):
+            return field.find('(') != -1
+
+        def insert_child(sorted_items, child, values, parent):
+            num = len(sorted_items)
+            for i in range(0, num):
+                # only add child if parent is present
+                if parent.startswith(sorted_items[i][0]):
+                    sorted_items.insert(i + 1, ('  ' + child, values))
+
+        def get_sorted_events(self, stats):
+            """ separate parent and child events """
+            if self._sorting == SORT_DEFAULT:
+                def sortkey((_k, v)):
+                    # sort by (delta value, overall value)
+                    return (v.delta, v.value)
+            else:
+                def sortkey((_k, v)):
+                    # sort by overall value
+                    return v.value
+
+            childs = []
+            sorted_items = []
+            # we can't rule out child events to appear prior to parents even
+            # when sorted - separate out all children first, and add in later
+            for key, values in sorted(stats.items(), key=sortkey,
+                                      reverse=True):
+                if values == (0, 0):
+                    continue
+                if key.find(' ') != -1:
+                    if not self.stats.child_events:
+                        continue
+                    childs.insert(0, (key, values))
+                else:
+                    sorted_items.append((key, values))
+            if self.stats.child_events:
+                for key, values in childs:
+                    (child, parent) = key.split(' ')
+                    insert_child(sorted_items, child, values, parent)
+
+            return sorted_items
+
         row = 3
         self.screen.move(row, 0)
         self.screen.clrtobot()
         stats = self.stats.get(self._display_guests)
-
-        def sortCurAvg(x):
-            # sort by current events if available
-            if stats[x][1]:
-                return (-stats[x][1], -stats[x][0])
+        total = 0.
+        ctotal = 0.
+        for key, values in stats.items():
+            if self._display_guests:
+                if self.get_gname_from_pid(key):
+                    total += values.value
+                continue
+            if not key.find(' ') != -1:
+                total += values.value
             else:
-                return (0, -stats[x][0])
+                ctotal += values.value
+        if total == 0.:
+            # we don't have any fields, or all non-child events are filtered
+            total = ctotal
 
-        def sortTotal(x):
-            # sort by totals
-            return (0, -stats[x][0])
-        total = 0.
-        for key in stats.keys():
-            if key.find('(') is -1:
-                total += stats[key][0]
-        if self._sorting == SORT_DEFAULT:
-            sortkey = sortCurAvg
-        else:
-            sortkey = sortTotal
+        # print events
         tavg = 0
-        for key in sorted(stats.keys(), key=sortkey):
-            if row >= self.screen.getmaxyx()[0] - 1:
-                break
-            values = stats[key]
-            if not values[0] and not values[1]:
+        tcur = 0
+        for key, values in get_sorted_events(self, stats):
+            if row >= self.screen.getmaxyx()[0] - 1 or values == (0, 0):
                 break
-            if values[0] is not None:
-                cur = int(round(values[1] / sleeptime)) if values[1] else ''
-                if self._display_guests:
-                    key = self.get_gname_from_pid(key)
-                self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' %
-                                   (key, values[0], values[0] * 100 / total,
-                                    cur))
-                if cur is not '' and key.find('(') is -1:
-                    tavg += cur
+            if self._display_guests:
+                key = self.get_gname_from_pid(key)
+                if not key:
+                    continue
+            cur = int(round(values.delta / sleeptime)) if values.delta else ''
+            if key[0] != ' ':
+                if values.delta:
+                    tcur += values.delta
+                ptotal = values.value
+                ltotal = total
+            else:
+                ltotal = ptotal
+            self.screen.addstr(row, 1, '%-40s %10d%7.1f %8s' % (key,
+                               values.value,
+                               values.value * 100 / float(ltotal), cur))
             row += 1
         if row == 3:
             self.screen.addstr(4, 1, 'No matching events reported yet')
-        else:
+        if row > 4:
+            tavg = int(round(tcur / sleeptime)) if tcur > 0 else ''
             self.screen.addstr(row, 1, '%-40s %10d        %8s' %
-                               ('Total', total, tavg if tavg else ''),
-                               curses.A_BOLD)
+                               ('Total', total, tavg), curses.A_BOLD)
         self.screen.refresh()
 
-    def show_msg(self, text):
+    def _show_msg(self, text):
         """Display message centered text and exit on key press"""
         hint = 'Press any key to continue'
         curses.cbreak()
@@ -1139,16 +1227,16 @@ class Tui(object):
                            curses.A_STANDOUT)
         self.screen.getkey()
 
-    def show_help_interactive(self):
+    def _show_help_interactive(self):
         """Display help with list of interactive commands"""
         msg = ('   b     toggle events by guests (debugfs only, honors'
                ' filters)',
                '   c     clear filter',
                '   f     filter by regular expression',
-               '   g     filter by guest name',
+               '   g     filter by guest name/PID',
                '   h     display interactive commands reference',
                '   o     toggle sorting order (Total vs CurAvg/s)',
-               '   p     filter by PID',
+               '   p     filter by guest name/PID',
                '   q     quit',
                '   r     reset stats',
                '   s     set update interval',
@@ -1165,14 +1253,15 @@ class Tui(object):
             self.screen.addstr(row, 0, line)
             row += 1
         self.screen.getkey()
-        self.refresh_header()
+        self._refresh_header()
 
-    def show_filter_selection(self):
+    def _show_filter_selection(self):
         """Draws filter selection mask.
 
         Asks for a valid regex and sets the fields filter accordingly.
 
         """
+        msg = ''
         while True:
             self.screen.erase()
             self.screen.addstr(0, 0,
@@ -1181,61 +1270,25 @@ class Tui(object):
             self.screen.addstr(2, 0,
                                "Current regex: {0}"
                                .format(self.stats.fields_filter))
+            self.screen.addstr(5, 0, msg)
             self.screen.addstr(3, 0, "New regex: ")
             curses.echo()
             regex = self.screen.getstr().decode(ENCODING)
             curses.noecho()
             if len(regex) == 0:
-                self.stats.fields_filter = DEFAULT_REGEX
-                self.refresh_header()
+                self.stats.fields_filter = ''
+                self._refresh_header()
                 return
             try:
                 re.compile(regex)
                 self.stats.fields_filter = regex
-                self.refresh_header()
+                self._refresh_header()
                 return
             except re.error:
+                msg = '"' + regex + '": Not a valid regular expression'
                 continue
 
-    def show_vm_selection_by_pid(self):
-        """Draws PID selection mask.
-
-        Asks for a pid until a valid pid or 0 has been entered.
-
-        """
-        msg = ''
-        while True:
-            self.screen.erase()
-            self.screen.addstr(0, 0,
-                               'Show statistics for specific pid.',
-                               curses.A_BOLD)
-            self.screen.addstr(1, 0,
-                               'This might limit the shown data to the trace '
-                               'statistics.')
-            self.screen.addstr(5, 0, msg)
-            self.print_all_gnames(7)
-
-            curses.echo()
-            self.screen.addstr(3, 0, "Pid [0 or pid]: ")
-            pid = self.screen.getstr().decode(ENCODING)
-            curses.noecho()
-
-            try:
-                if len(pid) > 0:
-                    pid = int(pid)
-                    if pid != 0 and not os.path.isdir(os.path.join('/proc/',
-                                                                   str(pid))):
-                        msg = '"' + str(pid) + '": Not a running process'
-                        continue
-                else:
-                    pid = 0
-                self.refresh_header(pid)
-                self.update_pid(pid)
-                break
-            except ValueError:
-                msg = '"' + str(pid) + '": Not a valid pid'
-
-    def show_set_update_interval(self):
+    def _show_set_update_interval(self):
         """Draws update interval selection mask."""
         msg = ''
         while True:
@@ -1265,60 +1318,67 @@ class Tui(object):
 
             except ValueError:
                 msg = '"' + str(val) + '": Invalid value'
-        self.refresh_header()
+        self._refresh_header()
 
-    def show_vm_selection_by_guest_name(self):
+    def _show_vm_selection_by_guest(self):
         """Draws guest selection mask.
 
-        Asks for a guest name until a valid guest name or '' is entered.
+        Asks for a guest name or pid until a valid guest name or '' is entered.
 
         """
         msg = ''
         while True:
             self.screen.erase()
             self.screen.addstr(0, 0,
-                               'Show statistics for specific guest.',
+                               'Show statistics for specific guest or pid.',
                                curses.A_BOLD)
             self.screen.addstr(1, 0,
                                'This might limit the shown data to the trace '
                                'statistics.')
             self.screen.addstr(5, 0, msg)
-            self.print_all_gnames(7)
+            self._print_all_gnames(7)
             curses.echo()
-            self.screen.addstr(3, 0, "Guest [ENTER or guest]: ")
-            gname = self.screen.getstr().decode(ENCODING)
+            curses.curs_set(1)
+            self.screen.addstr(3, 0, "Guest or pid [ENTER exits]: ")
+            guest = self.screen.getstr().decode(ENCODING)
             curses.noecho()
 
-            if not gname:
-                self.refresh_header(0)
-                self.update_pid(0)
+            pid = 0
+            if not guest or guest == '0':
                 break
-            else:
-                pids = []
-                try:
-                    pids = self.get_pid_from_gname(gname)
-                except:
-                    msg = '"' + gname + '": Internal error while searching, ' \
-                          'use pid filter instead'
-                    continue
-                if len(pids) == 0:
-                    msg = '"' + gname + '": Not an active guest'
+            if guest.isdigit():
+                if not os.path.isdir(os.path.join('/proc/', guest)):
+                    msg = '"' + guest + '": Not a running process'
                     continue
-                if len(pids) > 1:
-                    msg = '"' + gname + '": Multiple matches found, use pid ' \
-                          'filter instead'
-                    continue
-                self.refresh_header(pids[0])
-                self.update_pid(pids[0])
+                pid = int(guest)
                 break
+            pids = []
+            try:
+                pids = self.get_pid_from_gname(guest)
+            except:
+                msg = '"' + guest + '": Internal error while searching, ' \
+                      'use pid filter instead'
+                continue
+            if len(pids) == 0:
+                msg = '"' + guest + '": Not an active guest'
+                continue
+            if len(pids) > 1:
+                msg = '"' + guest + '": Multiple matches found, use pid ' \
+                      'filter instead'
+                continue
+            pid = pids[0]
+            break
+        curses.curs_set(0)
+        self._refresh_header(pid)
+        self._update_pid(pid)
 
     def show_stats(self):
         """Refreshes the screen and processes user input."""
         sleeptime = self._delay_initial
-        self.refresh_header()
+        self._refresh_header()
         start = 0.0  # result based on init value never appears on screen
         while True:
-            self.refresh_body(time.time() - start)
+            self._refresh_body(time.time() - start)
             curses.halfdelay(int(sleeptime * 10))
             start = time.time()
             sleeptime = self._delay_regular
@@ -1327,47 +1387,39 @@ class Tui(object):
                 if char == 'b':
                     self._display_guests = not self._display_guests
                     if self.stats.toggle_display_guests(self._display_guests):
-                        self.show_msg(['Command not available with tracepoints'
-                                       ' enabled', 'Restart with debugfs only '
-                                       '(see option \'-d\') and try again!'])
+                        self._show_msg(['Command not available with '
+                                        'tracepoints enabled', 'Restart with '
+                                        'debugfs only (see option \'-d\') and '
+                                        'try again!'])
                         self._display_guests = not self._display_guests
-                    self.refresh_header()
+                    self._refresh_header()
                 if char == 'c':
-                    self.stats.fields_filter = DEFAULT_REGEX
-                    self.refresh_header(0)
-                    self.update_pid(0)
+                    self.stats.fields_filter = ''
+                    self._refresh_header(0)
+                    self._update_pid(0)
                 if char == 'f':
                     curses.curs_set(1)
-                    self.show_filter_selection()
+                    self._show_filter_selection()
                     curses.curs_set(0)
                     sleeptime = self._delay_initial
-                if char == 'g':
-                    curses.curs_set(1)
-                    self.show_vm_selection_by_guest_name()
-                    curses.curs_set(0)
+                if char == 'g' or char == 'p':
+                    self._show_vm_selection_by_guest()
                     sleeptime = self._delay_initial
                 if char == 'h':
-                    self.show_help_interactive()
+                    self._show_help_interactive()
                 if char == 'o':
                     self._sorting = not self._sorting
-                if char == 'p':
-                    curses.curs_set(1)
-                    self.show_vm_selection_by_pid()
-                    curses.curs_set(0)
-                    sleeptime = self._delay_initial
                 if char == 'q':
                     break
                 if char == 'r':
                     self.stats.reset()
                 if char == 's':
                     curses.curs_set(1)
-                    self.show_set_update_interval()
+                    self._show_set_update_interval()
                     curses.curs_set(0)
                     sleeptime = self._delay_initial
                 if char == 'x':
-                    self.update_drilldown()
-                    # prevents display of current values on next refresh
-                    self.stats.get(self._display_guests)
+                    self.stats.child_events = not self.stats.child_events
             except KeyboardInterrupt:
                 break
             except curses.error:
@@ -1380,9 +1432,9 @@ def batch(stats):
         s = stats.get()
         time.sleep(1)
         s = stats.get()
-        for key in sorted(s.keys()):
-            values = s[key]
-            print('%-42s%10d%10d' % (key, values[0], values[1]))
+        for key, values in sorted(s.items()):
+            print('%-42s%10d%10d' % (key.split(' ')[0], values.value,
+                  values.delta))
     except KeyboardInterrupt:
         pass
 
@@ -1392,14 +1444,14 @@ def log(stats):
     keys = sorted(stats.get().keys())
 
     def banner():
-        for k in keys:
-            print(k, end=' ')
+        for key in keys:
+            print(key.split(' ')[0], end=' ')
         print()
 
     def statline():
         s = stats.get()
-        for k in keys:
-            print(' %9d' % s[k][1], end=' ')
+        for key in keys:
+            print(' %9d' % s[key].delta, end=' ')
         print()
     line = 0
     banner_repeat = 20
@@ -1504,7 +1556,7 @@ Press any other key to refresh statistics immediately.
                          )
     optparser.add_option('-f', '--fields',
                          action='store',
-                         default=DEFAULT_REGEX,
+                         default='',
                          dest='fields',
                          help='''fields to display (regex)
                                  "-f help" for a list of available events''',
@@ -1539,17 +1591,6 @@ Press any other key to refresh statistics immediately.
 
 def check_access(options):
     """Exits if the current user can't access all needed directories."""
-    if not os.path.exists('/sys/kernel/debug'):
-        sys.stderr.write('Please enable CONFIG_DEBUG_FS in your kernel.')
-        sys.exit(1)
-
-    if not os.path.exists(PATH_DEBUGFS_KVM):
-        sys.stderr.write("Please make sure, that debugfs is mounted and "
-                         "readable by the current user:\n"
-                         "('mount -t debugfs debugfs /sys/kernel/debug')\n"
-                         "Also ensure, that the kvm modules are loaded.\n")
-        sys.exit(1)
-
     if not os.path.exists(PATH_DEBUGFS_TRACING) and (options.tracepoints or
                                                      not options.debugfs):
         sys.stderr.write("Please enable CONFIG_TRACING in your kernel "
@@ -1567,7 +1608,33 @@ def check_access(options):
     return options
 
 
+def assign_globals():
+    global PATH_DEBUGFS_KVM
+    global PATH_DEBUGFS_TRACING
+
+    debugfs = ''
+    for line in file('/proc/mounts'):
+        if line.split(' ')[0] == 'debugfs':
+            debugfs = line.split(' ')[1]
+            break
+    if debugfs == '':
+        sys.stderr.write("Please make sure that CONFIG_DEBUG_FS is enabled in "
+                         "your kernel, mounted and\nreadable by the current "
+                         "user:\n"
+                         "('mount -t debugfs debugfs /sys/kernel/debug')\n")
+        sys.exit(1)
+
+    PATH_DEBUGFS_KVM = os.path.join(debugfs, 'kvm')
+    PATH_DEBUGFS_TRACING = os.path.join(debugfs, 'tracing')
+
+    if not os.path.exists(PATH_DEBUGFS_KVM):
+        sys.stderr.write("Please make sure that CONFIG_KVM is enabled in "
+                         "your kernel and that the modules are loaded.\n")
+        sys.exit(1)
+
+
 def main():
+    assign_globals()
     options = get_options()
     options = check_access(options)
 
index b5b3810..0811d86 100644 (file)
@@ -35,13 +35,13 @@ INTERACTIVE COMMANDS
 
 *f*::  filter by regular expression
 
-*g*::  filter by guest name
+*g*::  filter by guest name/PID
 
 *h*::  display interactive commands reference
 
 *o*::   toggle sorting order (Total vs CurAvg/s)
 
-*p*::  filter by PID
+*p*::  filter by guest name/PID
 
 *q*::  quit
 
index 5f758c4..b572d94 100644 (file)
@@ -2,7 +2,6 @@
 PREFIX ?= /usr
 SBINDIR ?= sbin
 INSTALL ?= install
-CC = $(CROSS_COMPILE)gcc
 
 TARGET = freefall
 
index c379af0..7b6bed1 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for LEDs tools
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -g -I../../include/uapi
 
 all: uledmon led_hw_brightness_mon
index 97073d6..5bbbf28 100644 (file)
@@ -1060,11 +1060,12 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
                prog->insns = new_insn;
                prog->main_prog_cnt = prog->insns_cnt;
                prog->insns_cnt = new_cnt;
+               pr_debug("added %zd insn from %s to prog %s\n",
+                        text->insns_cnt, text->section_name,
+                        prog->section_name);
        }
        insn = &prog->insns[relo->insn_idx];
        insn->imm += prog->main_prog_cnt - relo->insn_idx;
-       pr_debug("added %zd insn from %s to prog %s\n",
-                text->insns_cnt, text->section_name, prog->section_name);
        return 0;
 }
 
index f0796a4..90bb4aa 100644 (file)
@@ -30,6 +30,10 @@ OPTIONS for 'convert'
 -i::
        Specify input perf data file path.
 
+-f::
+--force::
+       Don't complain, do it.
+
 -v::
 --verbose::
         Be more verbose (show counter open errors, etc).
index 954ea9e..cf9f404 100644 (file)
@@ -8,7 +8,7 @@ perf-kallsyms - Searches running kernel for symbols
 SYNOPSIS
 --------
 [verse]
-'perf kallsyms <options> symbol_name[,symbol_name...]'
+'perf kallsyms' [<options>] symbol_name[,symbol_name...]
 
 DESCRIPTION
 -----------
index 9b0351d..0123280 100644 (file)
@@ -146,12 +146,6 @@ define allow-override
     $(eval $(1) = $(2)))
 endef
 
-# Allow setting CC and AR and LD, or setting CROSS_COMPILE as a prefix.
-$(call allow-override,CC,$(CROSS_COMPILE)gcc)
-$(call allow-override,AR,$(CROSS_COMPILE)ar)
-$(call allow-override,LD,$(CROSS_COMPILE)ld)
-$(call allow-override,CXX,$(CROSS_COMPILE)g++)
-
 LD += $(EXTRA_LDFLAGS)
 
 HOSTCC  ?= gcc
index 48228de..dfa6e31 100644 (file)
@@ -10,15 +10,19 @@ PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1
 
 out    := $(OUTPUT)arch/s390/include/generated/asm
 header := $(out)/syscalls_64.c
-sysdef := $(srctree)/tools/arch/s390/include/uapi/asm/unistd.h
-sysprf := $(srctree)/tools/perf/arch/s390/entry/syscalls/
+syskrn := $(srctree)/arch/s390/kernel/syscalls/syscall.tbl
+sysprf := $(srctree)/tools/perf/arch/s390/entry/syscalls
+sysdef := $(sysprf)/syscall.tbl
 systbl := $(sysprf)/mksyscalltbl
 
 # Create output directory if not already present
 _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)')
 
 $(header): $(sysdef) $(systbl)
-       $(Q)$(SHELL) '$(systbl)' '$(CC)' $(sysdef) > $@
+       @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \
+        (diff -B $(sysdef) $(syskrn) >/dev/null) \
+        || echo "Warning: Kernel ABI header at '$(sysdef)' differs from latest version at '$(syskrn)'" >&2 )) || true
+       $(Q)$(SHELL) '$(systbl)' $(sysdef) > $@
 
 clean::
        $(call QUIET_CLEAN, s390) $(RM) $(header)
index 7fa0d0a..72ecbb6 100755 (executable)
@@ -3,25 +3,23 @@
 #
 # Generate system call table for perf
 #
-#
-# Copyright IBM Corp. 2017
+# Copyright IBM Corp. 2017, 2018
 # Author(s):  Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
 #
 
-gcc=$1
-input=$2
+SYSCALL_TBL=$1
 
-if ! test -r $input; then
+if ! test -r $SYSCALL_TBL; then
        echo "Could not read input file" >&2
        exit 1
 fi
 
 create_table()
 {
-       local max_nr
+       local max_nr nr abi sc discard
 
        echo 'static const char *syscalltbl_s390_64[] = {'
-       while read sc nr; do
+       while read nr abi sc discard; do
                printf '\t[%d] = "%s",\n' $nr $sc
                max_nr=$nr
        done
@@ -29,8 +27,6 @@ create_table()
        echo "#define SYSCALLTBL_S390_64_MAX_ID $max_nr"
 }
 
-
-$gcc -m64 -E -dM -x c  $input         \
-       |sed -ne 's/^#define __NR_//p' \
-       |sort -t' ' -k2 -nu            \
+grep -E "^[[:digit:]]+[[:space:]]+(common|64)" $SYSCALL_TBL    \
+       |sort -k1 -n                                    \
        |create_table
diff --git a/tools/perf/arch/s390/entry/syscalls/syscall.tbl b/tools/perf/arch/s390/entry/syscalls/syscall.tbl
new file mode 100644 (file)
index 0000000..b38d484
--- /dev/null
@@ -0,0 +1,390 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# System call table for s390
+#
+# Format:
+#
+# <nr> <abi> <syscall> <entry-64bit> <compat-entry>
+#
+# where <abi> can be common, 64, or 32
+
+1    common    exit                    sys_exit                        sys_exit
+2    common    fork                    sys_fork                        sys_fork
+3    common    read                    sys_read                        compat_sys_s390_read
+4    common    write                   sys_write                       compat_sys_s390_write
+5    common    open                    sys_open                        compat_sys_open
+6    common    close                   sys_close                       sys_close
+7    common    restart_syscall         sys_restart_syscall             sys_restart_syscall
+8    common    creat                   sys_creat                       compat_sys_creat
+9    common    link                    sys_link                        compat_sys_link
+10   common    unlink                  sys_unlink                      compat_sys_unlink
+11   common    execve                  sys_execve                      compat_sys_execve
+12   common    chdir                   sys_chdir                       compat_sys_chdir
+13   32                time                    -                               compat_sys_time
+14   common    mknod                   sys_mknod                       compat_sys_mknod
+15   common    chmod                   sys_chmod                       compat_sys_chmod
+16   32                lchown                  -                               compat_sys_s390_lchown16
+19   common    lseek                   sys_lseek                       compat_sys_lseek
+20   common    getpid                  sys_getpid                      sys_getpid
+21   common    mount                   sys_mount                       compat_sys_mount
+22   common    umount                  sys_oldumount                   compat_sys_oldumount
+23   32                setuid                  -                               compat_sys_s390_setuid16
+24   32                getuid                  -                               compat_sys_s390_getuid16
+25   32                stime                   -                               compat_sys_stime
+26   common    ptrace                  sys_ptrace                      compat_sys_ptrace
+27   common    alarm                   sys_alarm                       sys_alarm
+29   common    pause                   sys_pause                       sys_pause
+30   common    utime                   sys_utime                       compat_sys_utime
+33   common    access                  sys_access                      compat_sys_access
+34   common    nice                    sys_nice                        sys_nice
+36   common    sync                    sys_sync                        sys_sync
+37   common    kill                    sys_kill                        sys_kill
+38   common    rename                  sys_rename                      compat_sys_rename
+39   common    mkdir                   sys_mkdir                       compat_sys_mkdir
+40   common    rmdir                   sys_rmdir                       compat_sys_rmdir
+41   common    dup                     sys_dup                         sys_dup
+42   common    pipe                    sys_pipe                        compat_sys_pipe
+43   common    times                   sys_times                       compat_sys_times
+45   common    brk                     sys_brk                         compat_sys_brk
+46   32                setgid                  -                               compat_sys_s390_setgid16
+47   32                getgid                  -                               compat_sys_s390_getgid16
+48   common    signal                  sys_signal                      compat_sys_signal
+49   32                geteuid                 -                               compat_sys_s390_geteuid16
+50   32                getegid                 -                               compat_sys_s390_getegid16
+51   common    acct                    sys_acct                        compat_sys_acct
+52   common    umount2                 sys_umount                      compat_sys_umount
+54   common    ioctl                   sys_ioctl                       compat_sys_ioctl
+55   common    fcntl                   sys_fcntl                       compat_sys_fcntl
+57   common    setpgid                 sys_setpgid                     sys_setpgid
+60   common    umask                   sys_umask                       sys_umask
+61   common    chroot                  sys_chroot                      compat_sys_chroot
+62   common    ustat                   sys_ustat                       compat_sys_ustat
+63   common    dup2                    sys_dup2                        sys_dup2
+64   common    getppid                 sys_getppid                     sys_getppid
+65   common    getpgrp                 sys_getpgrp                     sys_getpgrp
+66   common    setsid                  sys_setsid                      sys_setsid
+67   common    sigaction               sys_sigaction                   compat_sys_sigaction
+70   32                setreuid                -                               compat_sys_s390_setreuid16
+71   32                setregid                -                               compat_sys_s390_setregid16
+72   common    sigsuspend              sys_sigsuspend                  compat_sys_sigsuspend
+73   common    sigpending              sys_sigpending                  compat_sys_sigpending
+74   common    sethostname             sys_sethostname                 compat_sys_sethostname
+75   common    setrlimit               sys_setrlimit                   compat_sys_setrlimit
+76   32                getrlimit               -                               compat_sys_old_getrlimit
+77   common    getrusage               sys_getrusage                   compat_sys_getrusage
+78   common    gettimeofday            sys_gettimeofday                compat_sys_gettimeofday
+79   common    settimeofday            sys_settimeofday                compat_sys_settimeofday
+80   32                getgroups               -                               compat_sys_s390_getgroups16
+81   32                setgroups               -                               compat_sys_s390_setgroups16
+83   common    symlink                 sys_symlink                     compat_sys_symlink
+85   common    readlink                sys_readlink                    compat_sys_readlink
+86   common    uselib                  sys_uselib                      compat_sys_uselib
+87   common    swapon                  sys_swapon                      compat_sys_swapon
+88   common    reboot                  sys_reboot                      compat_sys_reboot
+89   common    readdir                 -                               compat_sys_old_readdir
+90   common    mmap                    sys_old_mmap                    compat_sys_s390_old_mmap
+91   common    munmap                  sys_munmap                      compat_sys_munmap
+92   common    truncate                sys_truncate                    compat_sys_truncate
+93   common    ftruncate               sys_ftruncate                   compat_sys_ftruncate
+94   common    fchmod                  sys_fchmod                      sys_fchmod
+95   32                fchown                  -                               compat_sys_s390_fchown16
+96   common    getpriority             sys_getpriority                 sys_getpriority
+97   common    setpriority             sys_setpriority                 sys_setpriority
+99   common    statfs                  sys_statfs                      compat_sys_statfs
+100  common    fstatfs                 sys_fstatfs                     compat_sys_fstatfs
+101  32                ioperm                  -                               -
+102  common    socketcall              sys_socketcall                  compat_sys_socketcall
+103  common    syslog                  sys_syslog                      compat_sys_syslog
+104  common    setitimer               sys_setitimer                   compat_sys_setitimer
+105  common    getitimer               sys_getitimer                   compat_sys_getitimer
+106  common    stat                    sys_newstat                     compat_sys_newstat
+107  common    lstat                   sys_newlstat                    compat_sys_newlstat
+108  common    fstat                   sys_newfstat                    compat_sys_newfstat
+110  common    lookup_dcookie          sys_lookup_dcookie              compat_sys_lookup_dcookie
+111  common    vhangup                 sys_vhangup                     sys_vhangup
+112  common    idle                    -                               -
+114  common    wait4                   sys_wait4                       compat_sys_wait4
+115  common    swapoff                 sys_swapoff                     compat_sys_swapoff
+116  common    sysinfo                 sys_sysinfo                     compat_sys_sysinfo
+117  common    ipc                     sys_s390_ipc                    compat_sys_s390_ipc
+118  common    fsync                   sys_fsync                       sys_fsync
+119  common    sigreturn               sys_sigreturn                   compat_sys_sigreturn
+120  common    clone                   sys_clone                       compat_sys_clone
+121  common    setdomainname           sys_setdomainname               compat_sys_setdomainname
+122  common    uname                   sys_newuname                    compat_sys_newuname
+124  common    adjtimex                sys_adjtimex                    compat_sys_adjtimex
+125  common    mprotect                sys_mprotect                    compat_sys_mprotect
+126  common    sigprocmask             sys_sigprocmask                 compat_sys_sigprocmask
+127  common    create_module           -                               -
+128  common    init_module             sys_init_module                 compat_sys_init_module
+129  common    delete_module           sys_delete_module               compat_sys_delete_module
+130  common    get_kernel_syms         -                               -
+131  common    quotactl                sys_quotactl                    compat_sys_quotactl
+132  common    getpgid                 sys_getpgid                     sys_getpgid
+133  common    fchdir                  sys_fchdir                      sys_fchdir
+134  common    bdflush                 sys_bdflush                     compat_sys_bdflush
+135  common    sysfs                   sys_sysfs                       compat_sys_sysfs
+136  common    personality             sys_s390_personality            sys_s390_personality
+137  common    afs_syscall             -                               -
+138  32                setfsuid                -                               compat_sys_s390_setfsuid16
+139  32                setfsgid                -                               compat_sys_s390_setfsgid16
+140  32                _llseek                 -                               compat_sys_llseek
+141  common    getdents                sys_getdents                    compat_sys_getdents
+142  32                _newselect              -                               compat_sys_select
+142  64                select                  sys_select                      -
+143  common    flock                   sys_flock                       sys_flock
+144  common    msync                   sys_msync                       compat_sys_msync
+145  common    readv                   sys_readv                       compat_sys_readv
+146  common    writev                  sys_writev                      compat_sys_writev
+147  common    getsid                  sys_getsid                      sys_getsid
+148  common    fdatasync               sys_fdatasync                   sys_fdatasync
+149  common    _sysctl                 sys_sysctl                      compat_sys_sysctl
+150  common    mlock                   sys_mlock                       compat_sys_mlock
+151  common    munlock                 sys_munlock                     compat_sys_munlock
+152  common    mlockall                sys_mlockall                    sys_mlockall
+153  common    munlockall              sys_munlockall                  sys_munlockall
+154  common    sched_setparam          sys_sched_setparam              compat_sys_sched_setparam
+155  common    sched_getparam          sys_sched_getparam              compat_sys_sched_getparam
+156  common    sched_setscheduler      sys_sched_setscheduler          compat_sys_sched_setscheduler
+157  common    sched_getscheduler      sys_sched_getscheduler          sys_sched_getscheduler
+158  common    sched_yield             sys_sched_yield                 sys_sched_yield
+159  common    sched_get_priority_max  sys_sched_get_priority_max      sys_sched_get_priority_max
+160  common    sched_get_priority_min  sys_sched_get_priority_min      sys_sched_get_priority_min
+161  common    sched_rr_get_interval   sys_sched_rr_get_interval       compat_sys_sched_rr_get_interval
+162  common    nanosleep               sys_nanosleep                   compat_sys_nanosleep
+163  common    mremap                  sys_mremap                      compat_sys_mremap
+164  32                setresuid               -                               compat_sys_s390_setresuid16
+165  32                getresuid               -                               compat_sys_s390_getresuid16
+167  common    query_module            -                               -
+168  common    poll                    sys_poll                        compat_sys_poll
+169  common    nfsservctl              -                               -
+170  32                setresgid               -                               compat_sys_s390_setresgid16
+171  32                getresgid               -                               compat_sys_s390_getresgid16
+172  common    prctl                   sys_prctl                       compat_sys_prctl
+173  common    rt_sigreturn            sys_rt_sigreturn                compat_sys_rt_sigreturn
+174  common    rt_sigaction            sys_rt_sigaction                compat_sys_rt_sigaction
+175  common    rt_sigprocmask          sys_rt_sigprocmask              compat_sys_rt_sigprocmask
+176  common    rt_sigpending           sys_rt_sigpending               compat_sys_rt_sigpending
+177  common    rt_sigtimedwait         sys_rt_sigtimedwait             compat_sys_rt_sigtimedwait
+178  common    rt_sigqueueinfo         sys_rt_sigqueueinfo             compat_sys_rt_sigqueueinfo
+179  common    rt_sigsuspend           sys_rt_sigsuspend               compat_sys_rt_sigsuspend
+180  common    pread64                 sys_pread64                     compat_sys_s390_pread64
+181  common    pwrite64                sys_pwrite64                    compat_sys_s390_pwrite64
+182  32                chown                   -                               compat_sys_s390_chown16
+183  common    getcwd                  sys_getcwd                      compat_sys_getcwd
+184  common    capget                  sys_capget                      compat_sys_capget
+185  common    capset                  sys_capset                      compat_sys_capset
+186  common    sigaltstack             sys_sigaltstack                 compat_sys_sigaltstack
+187  common    sendfile                sys_sendfile64                  compat_sys_sendfile
+188  common    getpmsg                 -                               -
+189  common    putpmsg                 -                               -
+190  common    vfork                   sys_vfork                       sys_vfork
+191  32                ugetrlimit              -                               compat_sys_getrlimit
+191  64                getrlimit               sys_getrlimit                   -
+192  32                mmap2                   -                               compat_sys_s390_mmap2
+193  32                truncate64              -                               compat_sys_s390_truncate64
+194  32                ftruncate64             -                               compat_sys_s390_ftruncate64
+195  32                stat64                  -                               compat_sys_s390_stat64
+196  32                lstat64                 -                               compat_sys_s390_lstat64
+197  32                fstat64                 -                               compat_sys_s390_fstat64
+198  32                lchown32                -                               compat_sys_lchown
+198  64                lchown                  sys_lchown                      -
+199  32                getuid32                -                               sys_getuid
+199  64                getuid                  sys_getuid                      -
+200  32                getgid32                -                               sys_getgid
+200  64                getgid                  sys_getgid                      -
+201  32                geteuid32               -                               sys_geteuid
+201  64                geteuid                 sys_geteuid                     -
+202  32                getegid32               -                               sys_getegid
+202  64                getegid                 sys_getegid                     -
+203  32                setreuid32              -                               sys_setreuid
+203  64                setreuid                sys_setreuid                    -
+204  32                setregid32              -                               sys_setregid
+204  64                setregid                sys_setregid                    -
+205  32                getgroups32             -                               compat_sys_getgroups
+205  64                getgroups               sys_getgroups                   -
+206  32                setgroups32             -                               compat_sys_setgroups
+206  64                setgroups               sys_setgroups                   -
+207  32                fchown32                -                               sys_fchown
+207  64                fchown                  sys_fchown                      -
+208  32                setresuid32             -                               sys_setresuid
+208  64                setresuid               sys_setresuid                   -
+209  32                getresuid32             -                               compat_sys_getresuid
+209  64                getresuid               sys_getresuid                   -
+210  32                setresgid32             -                               sys_setresgid
+210  64                setresgid               sys_setresgid                   -
+211  32                getresgid32             -                               compat_sys_getresgid
+211  64                getresgid               sys_getresgid                   -
+212  32                chown32                 -                               compat_sys_chown
+212  64                chown                   sys_chown                       -
+213  32                setuid32                -                               sys_setuid
+213  64                setuid                  sys_setuid                      -
+214  32                setgid32                -                               sys_setgid
+214  64                setgid                  sys_setgid                      -
+215  32                setfsuid32              -                               sys_setfsuid
+215  64                setfsuid                sys_setfsuid                    -
+216  32                setfsgid32              -                               sys_setfsgid
+216  64                setfsgid                sys_setfsgid                    -
+217  common    pivot_root              sys_pivot_root                  compat_sys_pivot_root
+218  common    mincore                 sys_mincore                     compat_sys_mincore
+219  common    madvise                 sys_madvise                     compat_sys_madvise
+220  common    getdents64              sys_getdents64                  compat_sys_getdents64
+221  32                fcntl64                 -                               compat_sys_fcntl64
+222  common    readahead               sys_readahead                   compat_sys_s390_readahead
+223  32                sendfile64              -                               compat_sys_sendfile64
+224  common    setxattr                sys_setxattr                    compat_sys_setxattr
+225  common    lsetxattr               sys_lsetxattr                   compat_sys_lsetxattr
+226  common    fsetxattr               sys_fsetxattr                   compat_sys_fsetxattr
+227  common    getxattr                sys_getxattr                    compat_sys_getxattr
+228  common    lgetxattr               sys_lgetxattr                   compat_sys_lgetxattr
+229  common    fgetxattr               sys_fgetxattr                   compat_sys_fgetxattr
+230  common    listxattr               sys_listxattr                   compat_sys_listxattr
+231  common    llistxattr              sys_llistxattr                  compat_sys_llistxattr
+232  common    flistxattr              sys_flistxattr                  compat_sys_flistxattr
+233  common    removexattr             sys_removexattr                 compat_sys_removexattr
+234  common    lremovexattr            sys_lremovexattr                compat_sys_lremovexattr
+235  common    fremovexattr            sys_fremovexattr                compat_sys_fremovexattr
+236  common    gettid                  sys_gettid                      sys_gettid
+237  common    tkill                   sys_tkill                       sys_tkill
+238  common    futex                   sys_futex                       compat_sys_futex
+239  common    sched_setaffinity       sys_sched_setaffinity           compat_sys_sched_setaffinity
+240  common    sched_getaffinity       sys_sched_getaffinity           compat_sys_sched_getaffinity
+241  common    tgkill                  sys_tgkill                      sys_tgkill
+243  common    io_setup                sys_io_setup                    compat_sys_io_setup
+244  common    io_destroy              sys_io_destroy                  compat_sys_io_destroy
+245  common    io_getevents            sys_io_getevents                compat_sys_io_getevents
+246  common    io_submit               sys_io_submit                   compat_sys_io_submit
+247  common    io_cancel               sys_io_cancel                   compat_sys_io_cancel
+248  common    exit_group              sys_exit_group                  sys_exit_group
+249  common    epoll_create            sys_epoll_create                sys_epoll_create
+250  common    epoll_ctl               sys_epoll_ctl                   compat_sys_epoll_ctl
+251  common    epoll_wait              sys_epoll_wait                  compat_sys_epoll_wait
+252  common    set_tid_address         sys_set_tid_address             compat_sys_set_tid_address
+253  common    fadvise64               sys_fadvise64_64                compat_sys_s390_fadvise64
+254  common    timer_create            sys_timer_create                compat_sys_timer_create
+255  common    timer_settime           sys_timer_settime               compat_sys_timer_settime
+256  common    timer_gettime           sys_timer_gettime               compat_sys_timer_gettime
+257  common    timer_getoverrun        sys_timer_getoverrun            sys_timer_getoverrun
+258  common    timer_delete            sys_timer_delete                sys_timer_delete
+259  common    clock_settime           sys_clock_settime               compat_sys_clock_settime
+260  common    clock_gettime           sys_clock_gettime               compat_sys_clock_gettime
+261  common    clock_getres            sys_clock_getres                compat_sys_clock_getres
+262  common    clock_nanosleep         sys_clock_nanosleep             compat_sys_clock_nanosleep
+264  32                fadvise64_64            -                               compat_sys_s390_fadvise64_64
+265  common    statfs64                sys_statfs64                    compat_sys_statfs64
+266  common    fstatfs64               sys_fstatfs64                   compat_sys_fstatfs64
+267  common    remap_file_pages        sys_remap_file_pages            compat_sys_remap_file_pages
+268  common    mbind                   sys_mbind                       compat_sys_mbind
+269  common    get_mempolicy           sys_get_mempolicy               compat_sys_get_mempolicy
+270  common    set_mempolicy           sys_set_mempolicy               compat_sys_set_mempolicy
+271  common    mq_open                 sys_mq_open                     compat_sys_mq_open
+272  common    mq_unlink               sys_mq_unlink                   compat_sys_mq_unlink
+273  common    mq_timedsend            sys_mq_timedsend                compat_sys_mq_timedsend
+274  common    mq_timedreceive         sys_mq_timedreceive             compat_sys_mq_timedreceive
+275  common    mq_notify               sys_mq_notify                   compat_sys_mq_notify
+276  common    mq_getsetattr           sys_mq_getsetattr               compat_sys_mq_getsetattr
+277  common    kexec_load              sys_kexec_load                  compat_sys_kexec_load
+278  common    add_key                 sys_add_key                     compat_sys_add_key
+279  common    request_key             sys_request_key                 compat_sys_request_key
+280  common    keyctl                  sys_keyctl                      compat_sys_keyctl
+281  common    waitid                  sys_waitid                      compat_sys_waitid
+282  common    ioprio_set              sys_ioprio_set                  sys_ioprio_set
+283  common    ioprio_get              sys_ioprio_get                  sys_ioprio_get
+284  common    inotify_init            sys_inotify_init                sys_inotify_init
+285  common    inotify_add_watch       sys_inotify_add_watch           compat_sys_inotify_add_watch
+286  common    inotify_rm_watch        sys_inotify_rm_watch            sys_inotify_rm_watch
+287  common    migrate_pages           sys_migrate_pages               compat_sys_migrate_pages
+288  common    openat                  sys_openat                      compat_sys_openat
+289  common    mkdirat                 sys_mkdirat                     compat_sys_mkdirat
+290  common    mknodat                 sys_mknodat                     compat_sys_mknodat
+291  common    fchownat                sys_fchownat                    compat_sys_fchownat
+292  common    futimesat               sys_futimesat                   compat_sys_futimesat
+293  32                fstatat64               -                               compat_sys_s390_fstatat64
+293  64                newfstatat              sys_newfstatat                  -
+294  common    unlinkat                sys_unlinkat                    compat_sys_unlinkat
+295  common    renameat                sys_renameat                    compat_sys_renameat
+296  common    linkat                  sys_linkat                      compat_sys_linkat
+297  common    symlinkat               sys_symlinkat                   compat_sys_symlinkat
+298  common    readlinkat              sys_readlinkat                  compat_sys_readlinkat
+299  common    fchmodat                sys_fchmodat                    compat_sys_fchmodat
+300  common    faccessat               sys_faccessat                   compat_sys_faccessat
+301  common    pselect6                sys_pselect6                    compat_sys_pselect6
+302  common    ppoll                   sys_ppoll                       compat_sys_ppoll
+303  common    unshare                 sys_unshare                     compat_sys_unshare
+304  common    set_robust_list         sys_set_robust_list             compat_sys_set_robust_list
+305  common    get_robust_list         sys_get_robust_list             compat_sys_get_robust_list
+306  common    splice                  sys_splice                      compat_sys_splice
+307  common    sync_file_range         sys_sync_file_range             compat_sys_s390_sync_file_range
+308  common    tee                     sys_tee                         compat_sys_tee
+309  common    vmsplice                sys_vmsplice                    compat_sys_vmsplice
+310  common    move_pages              sys_move_pages                  compat_sys_move_pages
+311  common    getcpu                  sys_getcpu                      compat_sys_getcpu
+312  common    epoll_pwait             sys_epoll_pwait                 compat_sys_epoll_pwait
+313  common    utimes                  sys_utimes                      compat_sys_utimes
+314  common    fallocate               sys_fallocate                   compat_sys_s390_fallocate
+315  common    utimensat               sys_utimensat                   compat_sys_utimensat
+316  common    signalfd                sys_signalfd                    compat_sys_signalfd
+317  common    timerfd                 -                               -
+318  common    eventfd                 sys_eventfd                     sys_eventfd
+319  common    timerfd_create          sys_timerfd_create              sys_timerfd_create
+320  common    timerfd_settime         sys_timerfd_settime             compat_sys_timerfd_settime
+321  common    timerfd_gettime         sys_timerfd_gettime             compat_sys_timerfd_gettime
+322  common    signalfd4               sys_signalfd4                   compat_sys_signalfd4
+323  common    eventfd2                sys_eventfd2                    sys_eventfd2
+324  common    inotify_init1           sys_inotify_init1               sys_inotify_init1
+325  common    pipe2                   sys_pipe2                       compat_sys_pipe2
+326  common    dup3                    sys_dup3                        sys_dup3
+327  common    epoll_create1           sys_epoll_create1               sys_epoll_create1
+328  common    preadv                  sys_preadv                      compat_sys_preadv
+329  common    pwritev                 sys_pwritev                     compat_sys_pwritev
+330  common    rt_tgsigqueueinfo       sys_rt_tgsigqueueinfo           compat_sys_rt_tgsigqueueinfo
+331  common    perf_event_open         sys_perf_event_open             compat_sys_perf_event_open
+332  common    fanotify_init           sys_fanotify_init               sys_fanotify_init
+333  common    fanotify_mark           sys_fanotify_mark               compat_sys_fanotify_mark
+334  common    prlimit64               sys_prlimit64                   compat_sys_prlimit64
+335  common    name_to_handle_at       sys_name_to_handle_at           compat_sys_name_to_handle_at
+336  common    open_by_handle_at       sys_open_by_handle_at           compat_sys_open_by_handle_at
+337  common    clock_adjtime           sys_clock_adjtime               compat_sys_clock_adjtime
+338  common    syncfs                  sys_syncfs                      sys_syncfs
+339  common    setns                   sys_setns                       sys_setns
+340  common    process_vm_readv        sys_process_vm_readv            compat_sys_process_vm_readv
+341  common    process_vm_writev       sys_process_vm_writev           compat_sys_process_vm_writev
+342  common    s390_runtime_instr      sys_s390_runtime_instr          sys_s390_runtime_instr
+343  common    kcmp                    sys_kcmp                        compat_sys_kcmp
+344  common    finit_module            sys_finit_module                compat_sys_finit_module
+345  common    sched_setattr           sys_sched_setattr               compat_sys_sched_setattr
+346  common    sched_getattr           sys_sched_getattr               compat_sys_sched_getattr
+347  common    renameat2               sys_renameat2                   compat_sys_renameat2
+348  common    seccomp                 sys_seccomp                     compat_sys_seccomp
+349  common    getrandom               sys_getrandom                   compat_sys_getrandom
+350  common    memfd_create            sys_memfd_create                compat_sys_memfd_create
+351  common    bpf                     sys_bpf                         compat_sys_bpf
+352  common    s390_pci_mmio_write     sys_s390_pci_mmio_write         compat_sys_s390_pci_mmio_write
+353  common    s390_pci_mmio_read      sys_s390_pci_mmio_read          compat_sys_s390_pci_mmio_read
+354  common    execveat                sys_execveat                    compat_sys_execveat
+355  common    userfaultfd             sys_userfaultfd                 sys_userfaultfd
+356  common    membarrier              sys_membarrier                  sys_membarrier
+357  common    recvmmsg                sys_recvmmsg                    compat_sys_recvmmsg
+358  common    sendmmsg                sys_sendmmsg                    compat_sys_sendmmsg
+359  common    socket                  sys_socket                      sys_socket
+360  common    socketpair              sys_socketpair                  compat_sys_socketpair
+361  common    bind                    sys_bind                        compat_sys_bind
+362  common    connect                 sys_connect                     compat_sys_connect
+363  common    listen                  sys_listen                      sys_listen
+364  common    accept4                 sys_accept4                     compat_sys_accept4
+365  common    getsockopt              sys_getsockopt                  compat_sys_getsockopt
+366  common    setsockopt              sys_setsockopt                  compat_sys_setsockopt
+367  common    getsockname             sys_getsockname                 compat_sys_getsockname
+368  common    getpeername             sys_getpeername                 compat_sys_getpeername
+369  common    sendto                  sys_sendto                      compat_sys_sendto
+370  common    sendmsg                 sys_sendmsg                     compat_sys_sendmsg
+371  common    recvfrom                sys_recvfrom                    compat_sys_recvfrom
+372  common    recvmsg                 sys_recvmsg                     compat_sys_recvmsg
+373  common    shutdown                sys_shutdown                    sys_shutdown
+374  common    mlock2                  sys_mlock2                      compat_sys_mlock2
+375  common    copy_file_range         sys_copy_file_range             compat_sys_copy_file_range
+376  common    preadv2                 sys_preadv2                     compat_sys_preadv2
+377  common    pwritev2                sys_pwritev2                    compat_sys_pwritev2
+378  common    s390_guarded_storage    sys_s390_guarded_storage        compat_sys_s390_guarded_storage
+379  common    statx                   sys_statx                       compat_sys_statx
+380  common    s390_sthyi              sys_s390_sthyi                  compat_sys_s390_sthyi
index c0815a3..539c3d4 100644 (file)
@@ -2245,7 +2245,7 @@ static int perf_c2c__browse_cacheline(struct hist_entry *he)
        c2c_browser__update_nr_entries(browser);
 
        while (1) {
-               key = hist_browser__run(browser, "? - help");
+               key = hist_browser__run(browser, "? - help", true);
 
                switch (key) {
                case 's':
@@ -2314,7 +2314,7 @@ static int perf_c2c__hists_browse(struct hists *hists)
        c2c_browser__update_nr_entries(browser);
 
        while (1) {
-               key = hist_browser__run(browser, "? - help");
+               key = hist_browser__run(browser, "? - help", true);
 
                switch (key) {
                case 'q':
index bf4ca74..a217623 100644 (file)
@@ -881,6 +881,15 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
                }
        }
 
+       /*
+        * If we have just single event and are sending data
+        * through pipe, we need to force the ids allocation,
+        * because we synthesize event name through the pipe
+        * and need the id for that.
+        */
+       if (data->is_pipe && rec->evlist->nr_entries == 1)
+               rec->opts.sample_id = true;
+
        if (record__open(rec) != 0) {
                err = -1;
                goto out_child;
index 42a52dc..4ad5dc6 100644 (file)
@@ -530,7 +530,8 @@ static int report__browse_hists(struct report *rep)
        case 1:
                ret = perf_evlist__tui_browse_hists(evlist, help, NULL,
                                                    rep->min_percent,
-                                                   &session->header.env);
+                                                   &session->header.env,
+                                                   true);
                /*
                 * Usually "ret" is the last pressed key, and we only
                 * care if the key notifies us to switch data file.
index 98bf9d3..54a4c15 100644 (file)
@@ -917,7 +917,7 @@ static void print_metric_csv(void *ctx,
        char buf[64], *vals, *ends;
 
        if (unit == NULL || fmt == NULL) {
-               fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep);
+               fprintf(out, "%s%s", csv_sep, csv_sep);
                return;
        }
        snprintf(buf, sizeof(buf), fmt, val);
index c6ccda5..35ac016 100644 (file)
@@ -283,8 +283,9 @@ static void perf_top__print_sym_table(struct perf_top *top)
 
        printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
 
-       if (hists->stats.nr_lost_warned !=
-           hists->stats.nr_events[PERF_RECORD_LOST]) {
+       if (!top->record_opts.overwrite &&
+           (hists->stats.nr_lost_warned !=
+           hists->stats.nr_events[PERF_RECORD_LOST])) {
                hists->stats.nr_lost_warned =
                              hists->stats.nr_events[PERF_RECORD_LOST];
                color_fprintf(stdout, PERF_COLOR_RED,
@@ -611,7 +612,8 @@ static void *display_thread_tui(void *arg)
 
        perf_evlist__tui_browse_hists(top->evlist, help, &hbt,
                                      top->min_percent,
-                                     &top->session->header.env);
+                                     &top->session->header.env,
+                                     !top->record_opts.overwrite);
 
        done = 1;
        return NULL;
@@ -807,15 +809,23 @@ static void perf_event__process_sample(struct perf_tool *tool,
 
 static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
 {
+       struct record_opts *opts = &top->record_opts;
+       struct perf_evlist *evlist = top->evlist;
        struct perf_sample sample;
        struct perf_evsel *evsel;
+       struct perf_mmap *md;
        struct perf_session *session = top->session;
        union perf_event *event;
        struct machine *machine;
+       u64 end, start;
        int ret;
 
-       while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
-               ret = perf_evlist__parse_sample(top->evlist, event, &sample);
+       md = opts->overwrite ? &evlist->overwrite_mmap[idx] : &evlist->mmap[idx];
+       if (perf_mmap__read_init(md, opts->overwrite, &start, &end) < 0)
+               return;
+
+       while ((event = perf_mmap__read_event(md, opts->overwrite, &start, end)) != NULL) {
+               ret = perf_evlist__parse_sample(evlist, event, &sample);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
                        goto next_event;
@@ -869,16 +879,120 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
                } else
                        ++session->evlist->stats.nr_unknown_events;
 next_event:
-               perf_evlist__mmap_consume(top->evlist, idx);
+               perf_mmap__consume(md, opts->overwrite);
        }
+
+       perf_mmap__read_done(md);
 }
 
 static void perf_top__mmap_read(struct perf_top *top)
 {
+       bool overwrite = top->record_opts.overwrite;
+       struct perf_evlist *evlist = top->evlist;
+       unsigned long long start, end;
        int i;
 
+       start = rdclock();
+       if (overwrite)
+               perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_DATA_PENDING);
+
        for (i = 0; i < top->evlist->nr_mmaps; i++)
                perf_top__mmap_read_idx(top, i);
+
+       if (overwrite) {
+               perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_EMPTY);
+               perf_evlist__toggle_bkw_mmap(evlist, BKW_MMAP_RUNNING);
+       }
+       end = rdclock();
+
+       if ((end - start) > (unsigned long long)top->delay_secs * NSEC_PER_SEC)
+               ui__warning("Too slow to read ring buffer.\n"
+                           "Please try increasing the period (-c) or\n"
+                           "decreasing the freq (-F) or\n"
+                           "limiting the number of CPUs (-C)\n");
+}
+
+/*
+ * Check per-event overwrite term.
+ * perf top should support consistent term for all events.
+ * - All events don't have per-event term
+ *   E.g. "cpu/cpu-cycles/,cpu/instructions/"
+ *   Nothing change, return 0.
+ * - All events have same per-event term
+ *   E.g. "cpu/cpu-cycles,no-overwrite/,cpu/instructions,no-overwrite/
+ *   Using the per-event setting to replace the opts->overwrite if
+ *   they are different, then return 0.
+ * - Events have different per-event term
+ *   E.g. "cpu/cpu-cycles,overwrite/,cpu/instructions,no-overwrite/"
+ *   Return -1
+ * - Some of the event set per-event term, but some not.
+ *   E.g. "cpu/cpu-cycles/,cpu/instructions,no-overwrite/"
+ *   Return -1
+ */
+static int perf_top__overwrite_check(struct perf_top *top)
+{
+       struct record_opts *opts = &top->record_opts;
+       struct perf_evlist *evlist = top->evlist;
+       struct perf_evsel_config_term *term;
+       struct list_head *config_terms;
+       struct perf_evsel *evsel;
+       int set, overwrite = -1;
+
+       evlist__for_each_entry(evlist, evsel) {
+               set = -1;
+               config_terms = &evsel->config_terms;
+               list_for_each_entry(term, config_terms, list) {
+                       if (term->type == PERF_EVSEL__CONFIG_TERM_OVERWRITE)
+                               set = term->val.overwrite ? 1 : 0;
+               }
+
+               /* no term for current and previous event (likely) */
+               if ((overwrite < 0) && (set < 0))
+                       continue;
+
+               /* has term for both current and previous event, compare */
+               if ((overwrite >= 0) && (set >= 0) && (overwrite != set))
+                       return -1;
+
+               /* no term for current event but has term for previous one */
+               if ((overwrite >= 0) && (set < 0))
+                       return -1;
+
+               /* has term for current event */
+               if ((overwrite < 0) && (set >= 0)) {
+                       /* if it's first event, set overwrite */
+                       if (evsel == perf_evlist__first(evlist))
+                               overwrite = set;
+                       else
+                               return -1;
+               }
+       }
+
+       if ((overwrite >= 0) && (opts->overwrite != overwrite))
+               opts->overwrite = overwrite;
+
+       return 0;
+}
+
+static int perf_top_overwrite_fallback(struct perf_top *top,
+                                      struct perf_evsel *evsel)
+{
+       struct record_opts *opts = &top->record_opts;
+       struct perf_evlist *evlist = top->evlist;
+       struct perf_evsel *counter;
+
+       if (!opts->overwrite)
+               return 0;
+
+       /* only fall back when first event fails */
+       if (evsel != perf_evlist__first(evlist))
+               return 0;
+
+       evlist__for_each_entry(evlist, counter)
+               counter->attr.write_backward = false;
+       opts->overwrite = false;
+       pr_debug2("fall back to non-overwrite mode\n");
+       return 1;
 }
 
 static int perf_top__start_counters(struct perf_top *top)
@@ -888,12 +1002,33 @@ static int perf_top__start_counters(struct perf_top *top)
        struct perf_evlist *evlist = top->evlist;
        struct record_opts *opts = &top->record_opts;
 
+       if (perf_top__overwrite_check(top)) {
+               ui__error("perf top only support consistent per-event "
+                         "overwrite setting for all events\n");
+               goto out_err;
+       }
+
        perf_evlist__config(evlist, opts, &callchain_param);
 
        evlist__for_each_entry(evlist, counter) {
 try_again:
                if (perf_evsel__open(counter, top->evlist->cpus,
                                     top->evlist->threads) < 0) {
+
+                       /*
+                        * Specially handle overwrite fall back.
+                        * Because perf top is the only tool which has
+                        * overwrite mode by default, support
+                        * both overwrite and non-overwrite mode, and
+                        * require consistent mode for all events.
+                        *
+                        * May move it to generic code with more tools
+                        * have similar attribute.
+                        */
+                       if (perf_missing_features.write_backward &&
+                           perf_top_overwrite_fallback(top, counter))
+                               goto try_again;
+
                        if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) {
                                if (verbose > 0)
                                        ui__warning("%s\n", msg);
@@ -1033,7 +1168,7 @@ static int __cmd_top(struct perf_top *top)
 
                perf_top__mmap_read(top);
 
-               if (hits == top->samples)
+               if (opts->overwrite || (hits == top->samples))
                        ret = perf_evlist__poll(top->evlist, 100);
 
                if (resize) {
@@ -1127,6 +1262,7 @@ int cmd_top(int argc, const char **argv)
                                .uses_mmap   = true,
                        },
                        .proc_map_timeout    = 500,
+                       .overwrite      = 1,
                },
                .max_stack           = sysctl_perf_event_max_stack,
                .sym_pcnt_filter     = 5,
index 51abdb0..790ec25 100755 (executable)
@@ -33,7 +33,6 @@ arch/s390/include/uapi/asm/kvm.h
 arch/s390/include/uapi/asm/kvm_perf.h
 arch/s390/include/uapi/asm/ptrace.h
 arch/s390/include/uapi/asm/sie.h
-arch/s390/include/uapi/asm/unistd.h
 arch/arm/include/uapi/asm/kvm.h
 arch/arm64/include/uapi/asm/kvm.h
 arch/alpha/include/uapi/asm/errno.h
index cfe4623..57b9b34 100644 (file)
@@ -61,6 +61,7 @@ struct record_opts {
        bool         tail_synthesize;
        bool         overwrite;
        bool         ignore_missing_thread;
+       bool         sample_id;
        unsigned int freq;
        unsigned int mmap_pages;
        unsigned int auxtrace_mmap_pages;
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/branch.json
new file mode 100644 (file)
index 0000000..3b62087
--- /dev/null
@@ -0,0 +1,27 @@
+[
+  {,
+    "EventCode": "0x7A",
+    "EventName": "BR_INDIRECT_SPEC",
+    "BriefDescription": "Branch speculatively executed - Indirect branch"
+  },
+  {,
+    "EventCode": "0xC9",
+    "EventName": "BR_COND",
+    "BriefDescription": "Conditional branch executed"
+  },
+  {,
+    "EventCode": "0xCA",
+    "EventName": "BR_INDIRECT_MISPRED",
+    "BriefDescription": "Indirect branch mispredicted"
+  },
+  {,
+    "EventCode": "0xCB",
+    "EventName": "BR_INDIRECT_MISPRED_ADDR",
+    "BriefDescription": "Indirect branch mispredicted because of address miscompare"
+  },
+  {,
+    "EventCode": "0xCC",
+    "EventName": "BR_COND_MISPRED",
+    "BriefDescription": "Conditional branch mispredicted"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/bus.json
new file mode 100644 (file)
index 0000000..480d9f7
--- /dev/null
@@ -0,0 +1,22 @@
+[
+  {,
+    "EventCode": "0x60",
+    "EventName": "BUS_ACCESS_LD",
+    "BriefDescription": "Bus access - Read"
+  },
+  {,
+    "EventCode": "0x61",
+    "EventName": "BUS_ACCESS_ST",
+    "BriefDescription": "Bus access - Write"
+  },
+  {,
+    "EventCode": "0xC0",
+    "EventName": "EXT_MEM_REQ",
+    "BriefDescription": "External memory request"
+  },
+  {,
+    "EventCode": "0xC1",
+    "EventName": "EXT_MEM_REQ_NC",
+    "BriefDescription": "Non-cacheable external memory request"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/cache.json
new file mode 100644 (file)
index 0000000..11baad6
--- /dev/null
@@ -0,0 +1,27 @@
+[
+  {,
+    "EventCode": "0xC2",
+    "EventName": "PREFETCH_LINEFILL",
+    "BriefDescription": "Linefill because of prefetch"
+  },
+  {,
+    "EventCode": "0xC3",
+    "EventName": "PREFETCH_LINEFILL_DROP",
+    "BriefDescription": "Instruction Cache Throttle occurred"
+  },
+  {,
+    "EventCode": "0xC4",
+    "EventName": "READ_ALLOC_ENTER",
+    "BriefDescription": "Entering read allocate mode"
+  },
+  {,
+    "EventCode": "0xC5",
+    "EventName": "READ_ALLOC",
+    "BriefDescription": "Read allocate mode"
+  },
+  {,
+    "EventCode": "0xC8",
+    "EventName": "EXT_SNOOP",
+    "BriefDescription": "SCU Snooped data from another CPU for this CPU"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/memory.json
new file mode 100644 (file)
index 0000000..480d9f7
--- /dev/null
@@ -0,0 +1,22 @@
+[
+  {,
+    "EventCode": "0x60",
+    "EventName": "BUS_ACCESS_LD",
+    "BriefDescription": "Bus access - Read"
+  },
+  {,
+    "EventCode": "0x61",
+    "EventName": "BUS_ACCESS_ST",
+    "BriefDescription": "Bus access - Write"
+  },
+  {,
+    "EventCode": "0xC0",
+    "EventName": "EXT_MEM_REQ",
+    "BriefDescription": "External memory request"
+  },
+  {,
+    "EventCode": "0xC1",
+    "EventName": "EXT_MEM_REQ_NC",
+    "BriefDescription": "Non-cacheable external memory request"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/other.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/other.json
new file mode 100644 (file)
index 0000000..73a2240
--- /dev/null
@@ -0,0 +1,32 @@
+[
+  {,
+    "EventCode": "0x86",
+    "EventName": "EXC_IRQ",
+    "BriefDescription": "Exception taken, IRQ"
+  },
+  {,
+    "EventCode": "0x87",
+    "EventName": "EXC_FIQ",
+    "BriefDescription": "Exception taken, FIQ"
+  },
+  {,
+    "EventCode": "0xC6",
+    "EventName": "PRE_DECODE_ERR",
+    "BriefDescription": "Pre-decode error"
+  },
+  {,
+    "EventCode": "0xD0",
+    "EventName": "L1I_CACHE_ERR",
+    "BriefDescription": "L1 Instruction Cache (data or tag) memory error"
+  },
+  {,
+    "EventCode": "0xD1",
+    "EventName": "L1D_CACHE_ERR",
+    "BriefDescription": "L1 Data Cache (data, tag or dirty) memory error, correctable or non-correctable"
+  },
+  {,
+    "EventCode": "0xD2",
+    "EventName": "TLB_ERR",
+    "BriefDescription": "TLB memory error"
+  }
+]
diff --git a/tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json b/tools/perf/pmu-events/arch/arm64/cortex-a53/pipeline.json
new file mode 100644 (file)
index 0000000..3149fb9
--- /dev/null
@@ -0,0 +1,52 @@
+[
+  {,
+    "EventCode": "0xC7",
+    "EventName": "STALL_SB_FULL",
+    "BriefDescription": "Data Write operation that stalls the pipeline because the store buffer is full"
+  },
+  {,
+    "EventCode": "0xE0",
+    "EventName": "OTHER_IQ_DEP_STALL",
+    "BriefDescription": "Cycles that the DPU IQ is empty and that is not because of a recent micro-TLB miss, instruction cache miss or pre-decode error"
+  },
+  {,
+    "EventCode": "0xE1",
+    "EventName": "IC_DEP_STALL",
+    "BriefDescription": "Cycles the DPU IQ is empty and there is an instruction cache miss being processed"
+  },
+  {,
+    "EventCode": "0xE2",
+    "EventName": "IUTLB_DEP_STALL",
+    "BriefDescription": "Cycles the DPU IQ is empty and there is an instruction micro-TLB miss being processed"
+  },
+  {,
+    "EventCode": "0xE3",
+    "EventName": "DECODE_DEP_STALL",
+    "BriefDescription": "Cycles the DPU IQ is empty and there is a pre-decode error being processed"
+  },
+  {,
+    "EventCode": "0xE4",
+    "EventName": "OTHER_INTERLOCK_STALL",
+    "BriefDescription": "Cycles there is an interlock other than  Advanced SIMD/Floating-point instructions or load/store instruction"
+  },
+  {,
+    "EventCode": "0xE5",
+    "EventName": "AGU_DEP_STALL",
+    "BriefDescription": "Cycles there is an interlock for a load/store instruction waiting for data to calculate the address in the AGU"
+  },
+  {,
+    "EventCode": "0xE6",
+    "EventName": "SIMD_DEP_STALL",
+    "BriefDescription": "Cycles there is an interlock for an Advanced SIMD/Floating-point operation."
+  },
+  {,
+    "EventCode": "0xE7",
+    "EventName": "LD_DEP_STALL",
+    "BriefDescription": "Cycles there is a stall in the Wr stage because of a load miss"
+  },
+  {,
+    "EventCode": "0xE8",
+    "EventName": "ST_DEP_STALL",
+    "BriefDescription": "Cycles there is a stall in the Wr stage because of a store"
+  }
+]
index 219d675..e61c9ca 100644 (file)
@@ -13,3 +13,4 @@
 #
 #Family-model,Version,Filename,EventType
 0x00000000420f5160,v1,cavium,core
+0x00000000410fd03[[:xdigit:]],v1,cortex-a53,core
index 4035d43..e0b1b41 100644 (file)
@@ -31,10 +31,12 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count,
        int i;
 
        for (i = 0; i < evlist->nr_mmaps; i++) {
+               struct perf_mmap *map = &evlist->overwrite_mmap[i];
                union perf_event *event;
+               u64 start, end;
 
-               perf_mmap__read_catchup(&evlist->overwrite_mmap[i]);
-               while ((event = perf_mmap__read_backward(&evlist->overwrite_mmap[i])) != NULL) {
+               perf_mmap__read_init(map, true, &start, &end);
+               while ((event = perf_mmap__read_event(map, true, &start, end)) != NULL) {
                        const u32 type = event->header.type;
 
                        switch (type) {
@@ -49,6 +51,7 @@ static int count_samples(struct perf_evlist *evlist, int *sample_count,
                                return TEST_FAIL;
                        }
                }
+               perf_mmap__read_done(map);
        }
        return TEST_OK;
 }
index 8b3da21..c446c89 100755 (executable)
@@ -22,10 +22,23 @@ trace_libc_inet_pton_backtrace() {
        expected[4]="rtt min.*"
        expected[5]="[0-9]+\.[0-9]+[[:space:]]+probe_libc:inet_pton:\([[:xdigit:]]+\)"
        expected[6]=".*inet_pton[[:space:]]\($libc\)$"
-       expected[7]="getaddrinfo[[:space:]]\($libc\)$"
-       expected[8]=".*\(.*/bin/ping.*\)$"
-
-       perf trace --no-syscalls -e probe_libc:inet_pton/max-stack=3/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do
+       case "$(uname -m)" in
+       s390x)
+               eventattr='call-graph=dwarf'
+               expected[7]="gaih_inet[[:space:]]\(inlined\)$"
+               expected[8]="__GI_getaddrinfo[[:space:]]\(inlined\)$"
+               expected[9]="main[[:space:]]\(.*/bin/ping.*\)$"
+               expected[10]="__libc_start_main[[:space:]]\($libc\)$"
+               expected[11]="_start[[:space:]]\(.*/bin/ping.*\)$"
+               ;;
+       *)
+               eventattr='max-stack=3'
+               expected[7]="getaddrinfo[[:space:]]\($libc\)$"
+               expected[8]=".*\(.*/bin/ping.*\)$"
+               ;;
+       esac
+
+       perf trace --no-syscalls -e probe_libc:inet_pton/$eventattr/ ping -6 -c 1 ::1 2>&1 | grep -v ^$ | while read line ; do
                echo $line
                echo "$line" | egrep -q "${expected[$idx]}"
                if [ $? -ne 0 ] ; then
@@ -33,7 +46,7 @@ trace_libc_inet_pton_backtrace() {
                        exit 1
                fi
                let idx+=1
-               [ $idx -eq 9 ] && break
+               [ -z "${expected[$idx]}" ] && break
        done
 }
 
index 2864279..fbf927c 100644 (file)
@@ -327,7 +327,32 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
        if (!disasm_line__is_valid_jump(cursor, sym))
                return;
 
+       /*
+        * This first was seen with a gcc function, _cpp_lex_token, that
+        * has the usual jumps:
+        *
+        *  â”‚1159e6c: â†“ jne    115aa32 <_cpp_lex_token@@Base+0xf92>
+        *
+        * I.e. jumps to a label inside that function (_cpp_lex_token), and
+        * those works, but also this kind:
+        *
+        *  â”‚1159e8b: â†“ jne    c469be <cpp_named_operator2name@@Base+0xa72>
+        *
+        *  I.e. jumps to another function, outside _cpp_lex_token, which
+        *  are not being correctly handled generating as a side effect references
+        *  to ab->offset[] entries that are set to NULL, so to make this code
+        *  more robust, check that here.
+        *
+        *  A proper fix for will be put in place, looking at the function
+        *  name right after the '<' token and probably treating this like a
+        *  'call' instruction.
+        */
        target = ab->offsets[cursor->ops.target.offset];
+       if (target == NULL) {
+               ui_helpline__printf("WARN: jump target inconsistency, press 'o', ab->offsets[%#x] = NULL\n",
+                                   cursor->ops.target.offset);
+               return;
+       }
 
        bcursor = browser_line(&cursor->al);
        btarget = browser_line(target);
index 68146f4..6495ee5 100644 (file)
@@ -608,7 +608,8 @@ static int hist_browser__title(struct hist_browser *browser, char *bf, size_t si
        return browser->title ? browser->title(browser, bf, size) : 0;
 }
 
-int hist_browser__run(struct hist_browser *browser, const char *help)
+int hist_browser__run(struct hist_browser *browser, const char *help,
+                     bool warn_lost_event)
 {
        int key;
        char title[160];
@@ -638,8 +639,9 @@ int hist_browser__run(struct hist_browser *browser, const char *help)
                        nr_entries = hist_browser__nr_entries(browser);
                        ui_browser__update_nr_entries(&browser->b, nr_entries);
 
-                       if (browser->hists->stats.nr_lost_warned !=
-                           browser->hists->stats.nr_events[PERF_RECORD_LOST]) {
+                       if (warn_lost_event &&
+                           (browser->hists->stats.nr_lost_warned !=
+                           browser->hists->stats.nr_events[PERF_RECORD_LOST])) {
                                browser->hists->stats.nr_lost_warned =
                                        browser->hists->stats.nr_events[PERF_RECORD_LOST];
                                ui_browser__warn_lost_events(&browser->b);
@@ -2763,7 +2765,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
                                    bool left_exits,
                                    struct hist_browser_timer *hbt,
                                    float min_pcnt,
-                                   struct perf_env *env)
+                                   struct perf_env *env,
+                                   bool warn_lost_event)
 {
        struct hists *hists = evsel__hists(evsel);
        struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env);
@@ -2844,7 +2847,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
                nr_options = 0;
 
-               key = hist_browser__run(browser, helpline);
+               key = hist_browser__run(browser, helpline,
+                                       warn_lost_event);
 
                if (browser->he_selection != NULL) {
                        thread = hist_browser__selected_thread(browser);
@@ -3184,7 +3188,8 @@ static void perf_evsel_menu__write(struct ui_browser *browser,
 
 static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
                                int nr_events, const char *help,
-                               struct hist_browser_timer *hbt)
+                               struct hist_browser_timer *hbt,
+                               bool warn_lost_event)
 {
        struct perf_evlist *evlist = menu->b.priv;
        struct perf_evsel *pos;
@@ -3203,7 +3208,9 @@ static int perf_evsel_menu__run(struct perf_evsel_menu *menu,
                case K_TIMER:
                        hbt->timer(hbt->arg);
 
-                       if (!menu->lost_events_warned && menu->lost_events) {
+                       if (!menu->lost_events_warned &&
+                           menu->lost_events &&
+                           warn_lost_event) {
                                ui_browser__warn_lost_events(&menu->b);
                                menu->lost_events_warned = true;
                        }
@@ -3224,7 +3231,8 @@ browse_hists:
                        key = perf_evsel__hists_browse(pos, nr_events, help,
                                                       true, hbt,
                                                       menu->min_pcnt,
-                                                      menu->env);
+                                                      menu->env,
+                                                      warn_lost_event);
                        ui_browser__show_title(&menu->b, title);
                        switch (key) {
                        case K_TAB:
@@ -3282,7 +3290,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                                           int nr_entries, const char *help,
                                           struct hist_browser_timer *hbt,
                                           float min_pcnt,
-                                          struct perf_env *env)
+                                          struct perf_env *env,
+                                          bool warn_lost_event)
 {
        struct perf_evsel *pos;
        struct perf_evsel_menu menu = {
@@ -3309,13 +3318,15 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
                        menu.b.width = line_len;
        }
 
-       return perf_evsel_menu__run(&menu, nr_entries, help, hbt);
+       return perf_evsel_menu__run(&menu, nr_entries, help,
+                                   hbt, warn_lost_event);
 }
 
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  struct hist_browser_timer *hbt,
                                  float min_pcnt,
-                                 struct perf_env *env)
+                                 struct perf_env *env,
+                                 bool warn_lost_event)
 {
        int nr_entries = evlist->nr_entries;
 
@@ -3325,7 +3336,7 @@ single_entry:
 
                return perf_evsel__hists_browse(first, nr_entries, help,
                                                false, hbt, min_pcnt,
-                                               env);
+                                               env, warn_lost_event);
        }
 
        if (symbol_conf.event_group) {
@@ -3342,5 +3353,6 @@ single_entry:
        }
 
        return __perf_evlist__tui_browse_hists(evlist, nr_entries, help,
-                                              hbt, min_pcnt, env);
+                                              hbt, min_pcnt, env,
+                                              warn_lost_event);
 }
index ba43177..9428bee 100644 (file)
@@ -28,7 +28,8 @@ struct hist_browser {
 
 struct hist_browser *hist_browser__new(struct hists *hists);
 void hist_browser__delete(struct hist_browser *browser);
-int hist_browser__run(struct hist_browser *browser, const char *help);
+int hist_browser__run(struct hist_browser *browser, const char *help,
+                     bool warn_lost_event);
 void hist_browser__init(struct hist_browser *browser,
                        struct hists *hists);
 #endif /* _PERF_UI_BROWSER_HISTS_H_ */
index 9faf3b5..6470ea2 100644 (file)
 #include "sane_ctype.h"
 #include "symbol/kallsyms.h"
 
+static bool auxtrace__dont_decode(struct perf_session *session)
+{
+       return !session->itrace_synth_opts ||
+              session->itrace_synth_opts->dont_decode;
+}
+
 int auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
                        struct auxtrace_mmap_params *mp,
                        void *userpg, int fd)
@@ -762,6 +768,9 @@ int auxtrace_queues__process_index(struct auxtrace_queues *queues,
        size_t i;
        int err;
 
+       if (auxtrace__dont_decode(session))
+               return 0;
+
        list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) {
                for (i = 0; i < auxtrace_index->nr; i++) {
                        ent = &auxtrace_index->entries[i];
@@ -892,12 +901,6 @@ out_free:
        return err;
 }
 
-static bool auxtrace__dont_decode(struct perf_session *session)
-{
-       return !session->itrace_synth_opts ||
-              session->itrace_synth_opts->dont_decode;
-}
-
 int perf_event__process_auxtrace_info(struct perf_tool *tool __maybe_unused,
                                      union perf_event *event,
                                      struct perf_session *session)
index ac35cd2..e5fc14e 100644 (file)
@@ -715,28 +715,11 @@ union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist, int
        return perf_mmap__read_forward(md);
 }
 
-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx)
-{
-       struct perf_mmap *md = &evlist->mmap[idx];
-
-       /*
-        * No need to check messup for backward ring buffer:
-        * We can always read arbitrary long data from a backward
-        * ring buffer unless we forget to pause it before reading.
-        */
-       return perf_mmap__read_backward(md);
-}
-
 union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx)
 {
        return perf_evlist__mmap_read_forward(evlist, idx);
 }
 
-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx)
-{
-       perf_mmap__read_catchup(&evlist->mmap[idx]);
-}
-
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx)
 {
        perf_mmap__consume(&evlist->mmap[idx], false);
index 75f8e0a..336b838 100644 (file)
@@ -133,10 +133,6 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx);
 
 union perf_event *perf_evlist__mmap_read_forward(struct perf_evlist *evlist,
                                                 int idx);
-union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist,
-                                                 int idx);
-void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx);
-
 void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx);
 
 int perf_evlist__open(struct perf_evlist *evlist);
index ff359c9..ef35168 100644 (file)
 
 #include "sane_ctype.h"
 
-static struct {
-       bool sample_id_all;
-       bool exclude_guest;
-       bool mmap2;
-       bool cloexec;
-       bool clockid;
-       bool clockid_wrong;
-       bool lbr_flags;
-       bool write_backward;
-       bool group_read;
-} perf_missing_features;
+struct perf_missing_features perf_missing_features;
 
 static clockid_t clockid;
 
index 846e416..a7487c6 100644 (file)
@@ -149,6 +149,20 @@ union u64_swap {
        u32 val32[2];
 };
 
+struct perf_missing_features {
+       bool sample_id_all;
+       bool exclude_guest;
+       bool mmap2;
+       bool cloexec;
+       bool clockid;
+       bool clockid_wrong;
+       bool lbr_flags;
+       bool write_backward;
+       bool group_read;
+};
+
+extern struct perf_missing_features perf_missing_features;
+
 struct cpu_map;
 struct target;
 struct thread_map;
index f6630cb..02721b5 100644 (file)
@@ -430,7 +430,8 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
 int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
                                  struct hist_browser_timer *hbt,
                                  float min_pcnt,
-                                 struct perf_env *env);
+                                 struct perf_env *env,
+                                 bool warn_lost_event);
 int script_browse(const char *script_opt);
 #else
 static inline
@@ -438,7 +439,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
                                  const char *help __maybe_unused,
                                  struct hist_browser_timer *hbt __maybe_unused,
                                  float min_pcnt __maybe_unused,
-                                 struct perf_env *env __maybe_unused)
+                                 struct perf_env *env __maybe_unused,
+                                 bool warn_lost_event __maybe_unused)
 {
        return 0;
 }
index 05076e6..91531a7 100644 (file)
@@ -22,29 +22,27 @@ size_t perf_mmap__mmap_len(struct perf_mmap *map)
 
 /* When check_messup is true, 'end' must points to a good entry */
 static union perf_event *perf_mmap__read(struct perf_mmap *map,
-                                        u64 start, u64 end, u64 *prev)
+                                        u64 *startp, u64 end)
 {
        unsigned char *data = map->base + page_size;
        union perf_event *event = NULL;
-       int diff = end - start;
+       int diff = end - *startp;
 
        if (diff >= (int)sizeof(event->header)) {
                size_t size;
 
-               event = (union perf_event *)&data[start & map->mask];
+               event = (union perf_event *)&data[*startp & map->mask];
                size = event->header.size;
 
-               if (size < sizeof(event->header) || diff < (int)size) {
-                       event = NULL;
-                       goto broken_event;
-               }
+               if (size < sizeof(event->header) || diff < (int)size)
+                       return NULL;
 
                /*
                 * Event straddles the mmap boundary -- header should always
                 * be inside due to u64 alignment of output.
                 */
-               if ((start & map->mask) + size != ((start + size) & map->mask)) {
-                       unsigned int offset = start;
+               if ((*startp & map->mask) + size != ((*startp + size) & map->mask)) {
+                       unsigned int offset = *startp;
                        unsigned int len = min(sizeof(*event), size), cpy;
                        void *dst = map->event_copy;
 
@@ -59,20 +57,19 @@ static union perf_event *perf_mmap__read(struct perf_mmap *map,
                        event = (union perf_event *)map->event_copy;
                }
 
-               start += size;
+               *startp += size;
        }
 
-broken_event:
-       if (prev)
-               *prev = start;
-
        return event;
 }
 
+/*
+ * legacy interface for mmap read.
+ * Don't use it. Use perf_mmap__read_event().
+ */
 union perf_event *perf_mmap__read_forward(struct perf_mmap *map)
 {
        u64 head;
-       u64 old = map->prev;
 
        /*
         * Check if event was unmapped due to a POLLHUP/POLLERR.
@@ -82,13 +79,26 @@ union perf_event *perf_mmap__read_forward(struct perf_mmap *map)
 
        head = perf_mmap__read_head(map);
 
-       return perf_mmap__read(map, old, head, &map->prev);
+       return perf_mmap__read(map, &map->prev, head);
 }
 
-union perf_event *perf_mmap__read_backward(struct perf_mmap *map)
+/*
+ * Read event from ring buffer one by one.
+ * Return one event for each call.
+ *
+ * Usage:
+ * perf_mmap__read_init()
+ * while(event = perf_mmap__read_event()) {
+ *     //process the event
+ *     perf_mmap__consume()
+ * }
+ * perf_mmap__read_done()
+ */
+union perf_event *perf_mmap__read_event(struct perf_mmap *map,
+                                       bool overwrite,
+                                       u64 *startp, u64 end)
 {
-       u64 head, end;
-       u64 start = map->prev;
+       union perf_event *event;
 
        /*
         * Check if event was unmapped due to a POLLHUP/POLLERR.
@@ -96,40 +106,19 @@ union perf_event *perf_mmap__read_backward(struct perf_mmap *map)
        if (!refcount_read(&map->refcnt))
                return NULL;
 
-       head = perf_mmap__read_head(map);
-       if (!head)
+       if (startp == NULL)
                return NULL;
 
-       /*
-        * 'head' pointer starts from 0. Kernel minus sizeof(record) form
-        * it each time when kernel writes to it, so in fact 'head' is
-        * negative. 'end' pointer is made manually by adding the size of
-        * the ring buffer to 'head' pointer, means the validate data can
-        * read is the whole ring buffer. If 'end' is positive, the ring
-        * buffer has not fully filled, so we must adjust 'end' to 0.
-        *
-        * However, since both 'head' and 'end' is unsigned, we can't
-        * simply compare 'end' against 0. Here we compare '-head' and
-        * the size of the ring buffer, where -head is the number of bytes
-        * kernel write to the ring buffer.
-        */
-       if (-head < (u64)(map->mask + 1))
-               end = 0;
-       else
-               end = head + map->mask + 1;
-
-       return perf_mmap__read(map, start, end, &map->prev);
-}
+       /* non-overwirte doesn't pause the ringbuffer */
+       if (!overwrite)
+               end = perf_mmap__read_head(map);
 
-void perf_mmap__read_catchup(struct perf_mmap *map)
-{
-       u64 head;
+       event = perf_mmap__read(map, startp, end);
 
-       if (!refcount_read(&map->refcnt))
-               return;
+       if (!overwrite)
+               map->prev = *startp;
 
-       head = perf_mmap__read_head(map);
-       map->prev = head;
+       return event;
 }
 
 static bool perf_mmap__empty(struct perf_mmap *map)
@@ -267,41 +256,60 @@ static int overwrite_rb_find_range(void *buf, int mask, u64 head, u64 *start, u6
        return -1;
 }
 
-int perf_mmap__push(struct perf_mmap *md, bool overwrite,
-                   void *to, int push(void *to, void *buf, size_t size))
+/*
+ * Report the start and end of the available data in ringbuffer
+ */
+int perf_mmap__read_init(struct perf_mmap *md, bool overwrite,
+                        u64 *startp, u64 *endp)
 {
        u64 head = perf_mmap__read_head(md);
        u64 old = md->prev;
-       u64 end = head, start = old;
        unsigned char *data = md->base + page_size;
        unsigned long size;
-       void *buf;
-       int rc = 0;
 
-       start = overwrite ? head : old;
-       end = overwrite ? old : head;
+       *startp = overwrite ? head : old;
+       *endp = overwrite ? old : head;
 
-       if (start == end)
-               return 0;
+       if (*startp == *endp)
+               return -EAGAIN;
 
-       size = end - start;
+       size = *endp - *startp;
        if (size > (unsigned long)(md->mask) + 1) {
                if (!overwrite) {
                        WARN_ONCE(1, "failed to keep up with mmap data. (warn only once)\n");
 
                        md->prev = head;
                        perf_mmap__consume(md, overwrite);
-                       return 0;
+                       return -EAGAIN;
                }
 
                /*
                 * Backward ring buffer is full. We still have a chance to read
                 * most of data from it.
                 */
-               if (overwrite_rb_find_range(data, md->mask, head, &start, &end))
-                       return -1;
+               if (overwrite_rb_find_range(data, md->mask, head, startp, endp))
+                       return -EINVAL;
        }
 
+       return 0;
+}
+
+int perf_mmap__push(struct perf_mmap *md, bool overwrite,
+                   void *to, int push(void *to, void *buf, size_t size))
+{
+       u64 head = perf_mmap__read_head(md);
+       u64 end, start;
+       unsigned char *data = md->base + page_size;
+       unsigned long size;
+       void *buf;
+       int rc = 0;
+
+       rc = perf_mmap__read_init(md, overwrite, &start, &end);
+       if (rc < 0)
+               return (rc == -EAGAIN) ? 0 : -1;
+
+       size = end - start;
+
        if ((start & md->mask) + size != (end & md->mask)) {
                buf = &data[start & md->mask];
                size = md->mask + 1 - (start & md->mask);
@@ -327,3 +335,14 @@ int perf_mmap__push(struct perf_mmap *md, bool overwrite,
 out:
        return rc;
 }
+
+/*
+ * Mandatory for overwrite mode
+ * The direction of overwrite mode is backward.
+ * The last perf_mmap__read() will set tail to map->prev.
+ * Need to correct the map->prev to head which is the end of next read.
+ */
+void perf_mmap__read_done(struct perf_mmap *map)
+{
+       map->prev = perf_mmap__read_head(map);
+}
index e43d7b5..ec7d3a2 100644 (file)
@@ -65,8 +65,6 @@ void perf_mmap__put(struct perf_mmap *map);
 
 void perf_mmap__consume(struct perf_mmap *map, bool overwrite);
 
-void perf_mmap__read_catchup(struct perf_mmap *md);
-
 static inline u64 perf_mmap__read_head(struct perf_mmap *mm)
 {
        struct perf_event_mmap_page *pc = mm->base;
@@ -87,11 +85,17 @@ static inline void perf_mmap__write_tail(struct perf_mmap *md, u64 tail)
 }
 
 union perf_event *perf_mmap__read_forward(struct perf_mmap *map);
-union perf_event *perf_mmap__read_backward(struct perf_mmap *map);
+
+union perf_event *perf_mmap__read_event(struct perf_mmap *map,
+                                       bool overwrite,
+                                       u64 *startp, u64 end);
 
 int perf_mmap__push(struct perf_mmap *md, bool backward,
                    void *to, int push(void *to, void *buf, size_t size));
 
 size_t perf_mmap__mmap_len(struct perf_mmap *map);
 
+int perf_mmap__read_init(struct perf_mmap *md, bool overwrite,
+                        u64 *startp, u64 *endp);
+void perf_mmap__read_done(struct perf_mmap *map);
 #endif /*__PERF_MMAP_H */
index 1e97937..6f09e49 100644 (file)
@@ -137,6 +137,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
        struct perf_evsel *evsel;
        bool use_sample_identifier = false;
        bool use_comm_exec;
+       bool sample_id = opts->sample_id;
 
        /*
         * Set the evsel leader links before we configure attributes,
@@ -163,8 +164,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
                 * match the id.
                 */
                use_sample_identifier = perf_can_sample_identifier();
-               evlist__for_each_entry(evlist, evsel)
-                       perf_evsel__set_sample_id(evsel, use_sample_identifier);
+               sample_id = true;
        } else if (evlist->nr_entries > 1) {
                struct perf_evsel *first = perf_evlist__first(evlist);
 
@@ -174,6 +174,10 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
                        use_sample_identifier = perf_can_sample_identifier();
                        break;
                }
+               sample_id = true;
+       }
+
+       if (sample_id) {
                evlist__for_each_entry(evlist, evsel)
                        perf_evsel__set_sample_id(evsel, use_sample_identifier);
        }
index 370138e..88223bc 100644 (file)
@@ -12,7 +12,7 @@
  * States and transits:
  *
  *
- *  OFF--(on)--> READY --(hit)--> HIT
+ *  OFF--> ON --> READY --(hit)--> HIT
  *                 ^               |
  *                 |            (ready)
  *                 |               |
@@ -27,8 +27,9 @@ struct trigger {
        volatile enum {
                TRIGGER_ERROR           = -2,
                TRIGGER_OFF             = -1,
-               TRIGGER_READY           = 0,
-               TRIGGER_HIT             = 1,
+               TRIGGER_ON              = 0,
+               TRIGGER_READY           = 1,
+               TRIGGER_HIT             = 2,
        } state;
        const char *name;
 };
@@ -50,7 +51,7 @@ static inline bool trigger_is_error(struct trigger *t)
 static inline void trigger_on(struct trigger *t)
 {
        TRIGGER_WARN_ONCE(t, TRIGGER_OFF);
-       t->state = TRIGGER_READY;
+       t->state = TRIGGER_ON;
 }
 
 static inline void trigger_ready(struct trigger *t)
index 443892d..1019bbc 100644 (file)
@@ -340,35 +340,15 @@ size_t hex_width(u64 v)
        return n;
 }
 
-static int hex(char ch)
-{
-       if ((ch >= '0') && (ch <= '9'))
-               return ch - '0';
-       if ((ch >= 'a') && (ch <= 'f'))
-               return ch - 'a' + 10;
-       if ((ch >= 'A') && (ch <= 'F'))
-               return ch - 'A' + 10;
-       return -1;
-}
-
 /*
  * While we find nice hex chars, build a long_val.
  * Return number of chars processed.
  */
 int hex2u64(const char *ptr, u64 *long_val)
 {
-       const char *p = ptr;
-       *long_val = 0;
-
-       while (*p) {
-               const int hex_val = hex(*p);
+       char *p;
 
-               if (hex_val < 0)
-                       break;
-
-               *long_val = (*long_val << 4) | hex_val;
-               p++;
-       }
+       *long_val = strtoull(ptr, &p, 16);
 
        return p - ptr;
 }
index a1883bb..2cccbba 100644 (file)
@@ -56,9 +56,6 @@ INSTALL_SCRIPT = ${INSTALL_PROGRAM}
 # to compile vs uClibc, that can be done here as well.
 CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc-
 CROSS_COMPILE ?= $(CROSS)
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)gcc
-STRIP = $(CROSS_COMPILE)strip
 HOSTCC = gcc
 
 # check if compiler option is supported
index fcb3ed0..dd61446 100644 (file)
@@ -42,6 +42,24 @@ EXTRA_WARNINGS += -Wformat
 
 CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
 
+# Makefiles suck: This macro sets a default value of $(2) for the
+# variable named by $(1), unless the variable has been set by
+# environment or command line. This is necessary for CC and AR
+# because make sets default values, so the simpler ?= approach
+# won't work as expected.
+define allow-override
+  $(if $(or $(findstring environment,$(origin $(1))),\
+            $(findstring command line,$(origin $(1)))),,\
+    $(eval $(1) = $(2)))
+endef
+
+# Allow setting various cross-compile vars or setting CROSS_COMPILE as a prefix.
+$(call allow-override,CC,$(CROSS_COMPILE)gcc)
+$(call allow-override,AR,$(CROSS_COMPILE)ar)
+$(call allow-override,LD,$(CROSS_COMPILE)ld)
+$(call allow-override,CXX,$(CROSS_COMPILE)g++)
+$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
+
 ifeq ($(CC_NO_CLANG), 1)
 EXTRA_WARNINGS += -Wstrict-aliasing=3
 endif
index 90615e1..815d155 100644 (file)
@@ -11,8 +11,6 @@ endif
 # (this improves performance and avoids hard-to-debug behaviour);
 MAKEFLAGS += -r
 
-CC = $(CROSS_COMPILE)gcc
-LD = $(CROSS_COMPILE)ld
 CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include
 
 ALL_TARGETS := spidev_test spidev_fdx
index 44ef9eb..6c645eb 100644 (file)
@@ -178,6 +178,55 @@ void idr_get_next_test(int base)
        idr_destroy(&idr);
 }
 
+int idr_u32_cb(int id, void *ptr, void *data)
+{
+       BUG_ON(id < 0);
+       BUG_ON(ptr != DUMMY_PTR);
+       return 0;
+}
+
+void idr_u32_test1(struct idr *idr, u32 handle)
+{
+       static bool warned = false;
+       u32 id = handle;
+       int sid = 0;
+       void *ptr;
+
+       BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL));
+       BUG_ON(id != handle);
+       BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL) != -ENOSPC);
+       BUG_ON(id != handle);
+       if (!warned && id > INT_MAX)
+               printk("vvv Ignore these warnings\n");
+       ptr = idr_get_next(idr, &sid);
+       if (id > INT_MAX) {
+               BUG_ON(ptr != NULL);
+               BUG_ON(sid != 0);
+       } else {
+               BUG_ON(ptr != DUMMY_PTR);
+               BUG_ON(sid != id);
+       }
+       idr_for_each(idr, idr_u32_cb, NULL);
+       if (!warned && id > INT_MAX) {
+               printk("^^^ Warnings over\n");
+               warned = true;
+       }
+       BUG_ON(idr_remove(idr, id) != DUMMY_PTR);
+       BUG_ON(!idr_is_empty(idr));
+}
+
+void idr_u32_test(int base)
+{
+       DEFINE_IDR(idr);
+       idr_init_base(&idr, base);
+       idr_u32_test1(&idr, 10);
+       idr_u32_test1(&idr, 0x7fffffff);
+       idr_u32_test1(&idr, 0x80000000);
+       idr_u32_test1(&idr, 0x80000001);
+       idr_u32_test1(&idr, 0xffe00000);
+       idr_u32_test1(&idr, 0xffffffff);
+}
+
 void idr_checks(void)
 {
        unsigned long i;
@@ -248,6 +297,9 @@ void idr_checks(void)
        idr_get_next_test(0);
        idr_get_next_test(1);
        idr_get_next_test(4);
+       idr_u32_test(4);
+       idr_u32_test(1);
+       idr_u32_test(0);
 }
 
 /*
index 6903ccf..44a0d1a 100644 (file)
@@ -29,7 +29,7 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, int flags)
 {
        struct radix_tree_node *node;
 
-       if (flags & __GFP_NOWARN)
+       if (!(flags & __GFP_DIRECT_RECLAIM))
                return NULL;
 
        pthread_mutex_lock(&cachep->lock);
@@ -73,10 +73,17 @@ void kmem_cache_free(struct kmem_cache *cachep, void *objp)
 
 void *kmalloc(size_t size, gfp_t gfp)
 {
-       void *ret = malloc(size);
+       void *ret;
+
+       if (!(gfp & __GFP_DIRECT_RECLAIM))
+               return NULL;
+
+       ret = malloc(size);
        uatomic_inc(&nr_allocated);
        if (kmalloc_verbose)
                printf("Allocating %p from malloc\n", ret);
+       if (gfp & __GFP_ZERO)
+               memset(ret, 0, size);
        return ret;
 }
 
diff --git a/tools/testing/radix-tree/linux/compiler_types.h b/tools/testing/radix-tree/linux/compiler_types.h
new file mode 100644 (file)
index 0000000..e69de29
index e9fff59..e3201cc 100644 (file)
@@ -11,6 +11,7 @@
 #define __GFP_IO               0x40u
 #define __GFP_FS               0x80u
 #define __GFP_NOWARN           0x200u
+#define __GFP_ZERO             0x8000u
 #define __GFP_ATOMIC           0x80000u
 #define __GFP_ACCOUNT          0x100000u
 #define __GFP_DIRECT_RECLAIM   0x400000u
index 979baee..a037def 100644 (file)
@@ -3,6 +3,7 @@
 #define SLAB_H
 
 #include <linux/types.h>
+#include <linux/gfp.h>
 
 #define SLAB_HWCACHE_ALIGN 1
 #define SLAB_PANIC 2
 void *kmalloc(size_t size, gfp_t);
 void kfree(void *);
 
+static inline void *kzalloc(size_t size, gfp_t gfp)
+{
+        return kmalloc(size, gfp | __GFP_ZERO);
+}
+
 void *kmem_cache_alloc(struct kmem_cache *cachep, int flags);
 void kmem_cache_free(struct kmem_cache *cachep, void *objp);
 
index 1a74922..f6304d2 100644 (file)
@@ -11,11 +11,11 @@ all:
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
                make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
-               #SUBDIR test prog name should be in the form: SUBDIR_test.sh
+               #SUBDIR test prog name should be in the form: SUBDIR_test.sh \
                TEST=$$DIR"_test.sh"; \
-               if [ -e $$DIR/$$TEST ]; then
-                       rsync -a $$DIR/$$TEST $$BUILD_TARGET/;
-               fi
+               if [ -e $$DIR/$$TEST ]; then \
+                       rsync -a $$DIR/$$TEST $$BUILD_TARGET/; \
+               fi \
        done
 
 override define RUN_TESTS
index cc15af2..9cf83f8 100644 (file)
@@ -11,3 +11,4 @@ test_progs
 test_tcpbpf_user
 test_verifier_log
 feature
+test_libbpf_open
index 436c4c7..9e03a4c 100644 (file)
@@ -126,6 +126,8 @@ static void test_hashmap_sizes(int task, void *data)
                        fd = bpf_create_map(BPF_MAP_TYPE_HASH, i, j,
                                            2, map_flags);
                        if (fd < 0) {
+                               if (errno == ENOMEM)
+                                       return;
                                printf("Failed to create hashmap key=%d value=%d '%s'\n",
                                       i, j, strerror(errno));
                                exit(1);
index 57119ad..3e645ee 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
 #include <linux/ip.h>
-#include <linux/in6.h>
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/tcp.h>
index c0f16e9..437c0b1 100644 (file)
@@ -2587,6 +2587,32 @@ static struct bpf_test tests[] = {
                .result = ACCEPT,
        },
        {
+               "runtime/jit: pass negative index to tail_call",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_3, -1),
+                       BPF_LD_MAP_FD(BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_tail_call),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_prog = { 1 },
+               .result = ACCEPT,
+       },
+       {
+               "runtime/jit: pass > 32bit index to tail_call",
+               .insns = {
+                       BPF_LD_IMM64(BPF_REG_3, 0x100000000ULL),
+                       BPF_LD_MAP_FD(BPF_REG_2, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_tail_call),
+                       BPF_MOV64_IMM(BPF_REG_0, 0),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_prog = { 2 },
+               .result = ACCEPT,
+       },
+       {
                "stack pointer arithmetic",
                .insns = {
                        BPF_MOV64_IMM(BPF_REG_1, 4),
@@ -11137,6 +11163,64 @@ static struct bpf_test tests[] = {
                .result = REJECT,
                .prog_type = BPF_PROG_TYPE_TRACEPOINT,
        },
+       {
+               "xadd/w check unaligned stack",
+               .insns = {
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
+                       BPF_STX_XADD(BPF_W, BPF_REG_10, BPF_REG_0, -7),
+                       BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8),
+                       BPF_EXIT_INSN(),
+               },
+               .result = REJECT,
+               .errstr = "misaligned stack access off",
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       },
+       {
+               "xadd/w check unaligned map",
+               .insns = {
+                       BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
+                       BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),
+                       BPF_LD_MAP_FD(BPF_REG_1, 0),
+                       BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0,
+                                    BPF_FUNC_map_lookup_elem),
+                       BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
+                       BPF_EXIT_INSN(),
+                       BPF_MOV64_IMM(BPF_REG_1, 1),
+                       BPF_STX_XADD(BPF_W, BPF_REG_0, BPF_REG_1, 3),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3),
+                       BPF_EXIT_INSN(),
+               },
+               .fixup_map1 = { 3 },
+               .result = REJECT,
+               .errstr = "misaligned value access off",
+               .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       },
+       {
+               "xadd/w check unaligned pkt",
+               .insns = {
+                       BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1,
+                                   offsetof(struct xdp_md, data)),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1,
+                                   offsetof(struct xdp_md, data_end)),
+                       BPF_MOV64_REG(BPF_REG_1, BPF_REG_2),
+                       BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8),
+                       BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 2),
+                       BPF_MOV64_IMM(BPF_REG_0, 99),
+                       BPF_JMP_IMM(BPF_JA, 0, 0, 6),
+                       BPF_MOV64_IMM(BPF_REG_0, 1),
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0),
+                       BPF_ST_MEM(BPF_W, BPF_REG_2, 3, 0),
+                       BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 1),
+                       BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 2),
+                       BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 1),
+                       BPF_EXIT_INSN(),
+               },
+               .result = REJECT,
+               .errstr = "BPF_XADD stores into R2 packet",
+               .prog_type = BPF_PROG_TYPE_XDP,
+       },
 };
 
 static int probe_filter_length(const struct bpf_insn *fp)
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc
new file mode 100644 (file)
index 0000000..5ba7303
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event string type argument
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+echo 0 > events/enable
+echo > kprobe_events
+
+case `uname -m` in
+x86_64)
+  ARG2=%si
+  OFFS=8
+;;
+i[3456]86)
+  ARG2=%cx
+  OFFS=4
+;;
+aarch64)
+  ARG2=%x1
+  OFFS=8
+;;
+arm*)
+  ARG2=%r1
+  OFFS=4
+;;
+*)
+  echo "Please implement other architecture here"
+  exit_untested
+esac
+
+: "Test get argument (1)"
+echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\""
+
+echo 0 > events/kprobes/testprobe/enable
+: "Test get argument (2)"
+echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events
+echo 1 > events/kprobes/testprobe/enable
+! echo test1 test2 >> kprobe_events
+tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\""
+
+echo 0 > events/enable
+echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc
new file mode 100644 (file)
index 0000000..231bcd2
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe event argument syntax
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue
+
+echo 0 > events/enable
+echo > kprobe_events
+
+PROBEFUNC="vfs_read"
+GOODREG=
+BADREG=
+GOODSYM="_sdata"
+if ! grep -qw ${GOODSYM} /proc/kallsyms ; then
+  GOODSYM=$PROBEFUNC
+fi
+BADSYM="deaqswdefr"
+SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "`
+GOODTYPE="x16"
+BADTYPE="y16"
+
+case `uname -m` in
+x86_64|i[3456]86)
+  GOODREG=%ax
+  BADREG=%ex
+;;
+aarch64)
+  GOODREG=%x0
+  BADREG=%ax
+;;
+arm*)
+  GOODREG=%r0
+  BADREG=%ax
+;;
+esac
+
+test_goodarg() # Good-args
+{
+  while [ "$1" ]; do
+    echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+test_badarg() # Bad-args
+{
+  while [ "$1" ]; do
+    ! echo "p ${PROBEFUNC} $1" > kprobe_events
+    shift 1
+  done;
+}
+
+echo > kprobe_events
+
+: "Register access"
+test_goodarg ${GOODREG}
+test_badarg ${BADREG}
+
+: "Symbol access"
+test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10"
+test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \
+           "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10"
+
+: "Stack access"
+test_goodarg "\$stack" "\$stack0" "\$stack1"
+test_badarg "\$stackp" "\$stack0+10" "\$stack1-10"
+
+: "Retval access"
+echo "r ${PROBEFUNC} \$retval" > kprobe_events
+! echo "p ${PROBEFUNC} \$retval" > kprobe_events
+
+: "Comm access"
+test_goodarg "\$comm"
+
+: "Indirect memory access"
+test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \
+       "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))"
+test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \
+       "+10(\$comm)" "+0(${GOODREG})+10"
+
+: "Name assignment"
+test_goodarg "varname=${GOODREG}"
+test_badarg "varname=varname2=${GOODREG}"
+
+: "Type syntax"
+test_goodarg "${GOODREG}:${GOODTYPE}"
+test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \
+       "${GOODTYPE}:${GOODREG}"
+
+: "Combination check"
+
+test_goodarg "\$comm:string" "+0(\$stack):string"
+test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string"
+
+echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc
new file mode 100644 (file)
index 0000000..4fda01a
--- /dev/null
@@ -0,0 +1,43 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: Kprobe events - probe points
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+
+TARGET_FUNC=create_trace_kprobe
+
+dec_addr() { # hexaddr
+  printf "%d" "0x"`echo $1 | tail -c 8`
+}
+
+set_offs() { # prev target next
+  A1=`dec_addr $1`
+  A2=`dec_addr $2`
+  A3=`dec_addr $3`
+  TARGET="0x$2" # an address
+  PREV=`expr $A1 - $A2` # offset to previous symbol
+  NEXT=+`expr $A3 - $A2` # offset to next symbol
+  OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol
+}
+
+# We have to decode symbol addresses to get correct offsets.
+# If the offset is not an instruction boundary, it cause -EILSEQ.
+set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs`
+
+UINT_TEST=no
+# printf "%x" -1 returns (unsigned long)-1.
+if [ `printf "%x" -1 | wc -c` != 9 ]; then
+  UINT_TEST=yes
+fi
+
+echo 0 > events/enable
+echo > kprobe_events
+echo "p:testprobe ${TARGET_FUNC}" > kprobe_events
+echo "p:testprobe ${TARGET}" > kprobe_events
+echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events
+! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events
+if [ "${UINT_TEST}" = yes ]; then
+! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events
+fi
+echo > kprobe_events
+clear_trace
index cea4adc..a63e845 100644 (file)
@@ -12,9 +12,9 @@ all:
                BUILD_TARGET=$(OUTPUT)/$$DIR;   \
                mkdir $$BUILD_TARGET  -p;       \
                make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\
-               if [ -e $$DIR/$(TEST_PROGS) ]; then
-                       rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/;
-               fi
+               if [ -e $$DIR/$(TEST_PROGS) ]; then \
+                       rsync -a $$DIR/$(TEST_PROGS) $$BUILD_TARGET/; \
+               fi \
        done
 
 override define RUN_TESTS
index a5276a9..0862e6f 100644 (file)
@@ -5,6 +5,7 @@ CFLAGS += -I../../../../include/
 CFLAGS += -I../../../../usr/include/
 
 TEST_PROGS := run_tests.sh
+TEST_FILES := run_fuse_test.sh
 TEST_GEN_FILES := memfd_test fuse_mnt fuse_test
 
 fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags)
diff --git a/tools/testing/selftests/memfd/config b/tools/testing/selftests/memfd/config
new file mode 100644 (file)
index 0000000..835c7f4
--- /dev/null
@@ -0,0 +1 @@
+CONFIG_FUSE_FS=m
index 86636d2..686da51 100644 (file)
@@ -4,8 +4,9 @@ all:
 include ../lib.mk
 
 TEST_PROGS := mem-on-off-test.sh
-override RUN_TESTS := ./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
-override EMIT_TESTS := echo "$(RUN_TESTS)"
+override RUN_TESTS := @./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]"
+
+override EMIT_TESTS := echo "$(subst @,,$(RUN_TESTS))"
 
 run_full_test:
        @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]"
index 35ade74..3ae77ba 100644 (file)
@@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size)
        return 0;
 }
 
+static int syscall_available(void)
+{
+       int rc;
+
+       errno = 0;
+       rc = syscall(__NR_subpage_prot, 0, 0, 0);
+
+       return rc == 0 || (errno != ENOENT && errno != ENOSYS);
+}
+
 int test_anon(void)
 {
        unsigned long align;
@@ -145,6 +155,8 @@ int test_anon(void)
        void *mallocblock;
        unsigned long mallocsize;
 
+       SKIP_IF(!syscall_available());
+
        if (getpagesize() != 0x10000) {
                fprintf(stderr, "Kernel page size must be 64K!\n");
                return 1;
@@ -180,6 +192,8 @@ int test_file(void)
        off_t filesize;
        int fd;
 
+       SKIP_IF(!syscall_available());
+
        fd = open(file_name, O_RDWR);
        if (fd == -1) {
                perror("failed to open file");
index a234539..5c72ff9 100644 (file)
@@ -16,7 +16,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S
 $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include
 $(OUTPUT)/tm-tmspr: CFLAGS += -pthread
 $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64
-$(OUTPUT)/tm-resched-dscr: ../pmu/lib.o
+$(OUTPUT)/tm-resched-dscr: ../pmu/lib.c
 $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx
 $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64
 
index 5d92c23..179d592 100644 (file)
@@ -255,6 +255,8 @@ int tm_trap_test(void)
 
        struct sigaction trap_sa;
 
+       SKIP_IF(!have_htm());
+
        trap_sa.sa_flags = SA_SIGINFO;
        trap_sa.sa_sigaction = trap_signal_handler;
        sigaction(SIGTRAP, &trap_sa, NULL);
index 6a8e5a9..d148f9f 100644 (file)
@@ -2,3 +2,4 @@ CONFIG_MISC_FILESYSTEMS=y
 CONFIG_PSTORE=y
 CONFIG_PSTORE_PMSG=y
 CONFIG_PSTORE_CONSOLE=y
+CONFIG_PSTORE_RAM=m
index 0b457e8..5df6099 100644 (file)
@@ -141,6 +141,15 @@ struct seccomp_data {
 #define SECCOMP_FILTER_FLAG_LOG 2
 #endif
 
+#ifndef PTRACE_SECCOMP_GET_METADATA
+#define PTRACE_SECCOMP_GET_METADATA    0x420d
+
+struct seccomp_metadata {
+       __u64 filter_off;       /* Input: which filter */
+       __u64 flags;             /* Output: filter's flags */
+};
+#endif
+
 #ifndef seccomp
 int seccomp(unsigned int op, unsigned int flags, void *args)
 {
@@ -2845,6 +2854,58 @@ TEST(get_action_avail)
        EXPECT_EQ(errno, EOPNOTSUPP);
 }
 
+TEST(get_metadata)
+{
+       pid_t pid;
+       int pipefd[2];
+       char buf;
+       struct seccomp_metadata md;
+
+       ASSERT_EQ(0, pipe(pipefd));
+
+       pid = fork();
+       ASSERT_GE(pid, 0);
+       if (pid == 0) {
+               struct sock_filter filter[] = {
+                       BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+               };
+               struct sock_fprog prog = {
+                       .len = (unsigned short)ARRAY_SIZE(filter),
+                       .filter = filter,
+               };
+
+               /* one with log, one without */
+               ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER,
+                                    SECCOMP_FILTER_FLAG_LOG, &prog));
+               ASSERT_EQ(0, seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog));
+
+               ASSERT_EQ(0, close(pipefd[0]));
+               ASSERT_EQ(1, write(pipefd[1], "1", 1));
+               ASSERT_EQ(0, close(pipefd[1]));
+
+               while (1)
+                       sleep(100);
+       }
+
+       ASSERT_EQ(0, close(pipefd[1]));
+       ASSERT_EQ(1, read(pipefd[0], &buf, 1));
+
+       ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid));
+       ASSERT_EQ(pid, waitpid(pid, NULL, 0));
+
+       md.filter_off = 0;
+       ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md));
+       EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG);
+       EXPECT_EQ(md.filter_off, 0);
+
+       md.filter_off = 1;
+       ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md));
+       EXPECT_EQ(md.flags, 0);
+       EXPECT_EQ(md.filter_off, 1);
+
+       ASSERT_EQ(0, kill(pid, SIGKILL));
+}
+
 /*
  * TODO:
  * - add microbenchmarks
index b3c8ba3..d0121a8 100644 (file)
@@ -30,7 +30,7 @@ $(TEST_CUSTOM_PROGS): $(TESTS) $(OBJS)
        $(CC) -o $(TEST_CUSTOM_PROGS) $(OBJS) $(TESTS) $(CFLAGS) $(LDFLAGS)
 
 $(OBJS): $(OUTPUT)/%.o: %.c
-       $(CC) -c $^ -o $@
+       $(CC) -c $^ -o $@ $(CFLAGS)
 
 $(TESTS): $(OUTPUT)/%.o: %.c
        $(CC) -c $^ -o $@
index e340750..90bba48 100644 (file)
         "cmdUnderTest": "$TC actions ls action skbmod",
         "expExitCode": "0",
         "verifyCmd": "$TC actions get action skbmod index 4",
-        "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x0031",
+        "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x31",
         "matchCount": "1",
         "teardown": [
             "$TC actions flush action skbmod"
index 3d5a62f..f5d7a78 100644 (file)
@@ -1,4 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
+include ../lib.mk
+
 ifndef CROSS_COMPILE
 CFLAGS := -std=gnu99
 CFLAGS_vdso_standalone_test_x86 := -nostdlib -fno-asynchronous-unwind-tables -fno-stack-protector
@@ -6,16 +8,14 @@ ifeq ($(CONFIG_X86_32),y)
 LDLIBS += -lgcc_s
 endif
 
-TEST_PROGS := vdso_test vdso_standalone_test_x86
+TEST_PROGS := $(OUTPUT)/vdso_test $(OUTPUT)/vdso_standalone_test_x86
 
 all: $(TEST_PROGS)
-vdso_test: parse_vdso.c vdso_test.c
-vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
+$(OUTPUT)/vdso_test: parse_vdso.c vdso_test.c
+$(OUTPUT)/vdso_standalone_test_x86: vdso_standalone_test_x86.c parse_vdso.c
        $(CC) $(CFLAGS) $(CFLAGS_vdso_standalone_test_x86) \
                vdso_standalone_test_x86.c parse_vdso.c \
-               -o vdso_standalone_test_x86
+               -o $@
 
-include ../lib.mk
-clean:
-       rm -fr $(TEST_PROGS)
+EXTRA_CLEAN := $(TEST_PROGS)
 endif
index 63c94d7..342c7bc 100644 (file)
@@ -11,3 +11,4 @@ mlock-intersect-test
 mlock-random-test
 virtual_address_range
 gup_benchmark
+va_128TBswitch
index d256189..22d5646 100755 (executable)
@@ -2,25 +2,33 @@
 # SPDX-License-Identifier: GPL-2.0
 #please run as root
 
-#we need 256M, below is the size in kB
-needmem=262144
 mnt=./huge
 exitcode=0
 
-#get pagesize and freepages from /proc/meminfo
+#get huge pagesize and freepages from /proc/meminfo
 while read name size unit; do
        if [ "$name" = "HugePages_Free:" ]; then
                freepgs=$size
        fi
        if [ "$name" = "Hugepagesize:" ]; then
-               pgsize=$size
+               hpgsize_KB=$size
        fi
 done < /proc/meminfo
 
+# Simple hugetlbfs tests have a hardcoded minimum requirement of
+# huge pages totaling 256MB (262144KB) in size.  The userfaultfd
+# hugetlb test requires a minimum of 2 * nr_cpus huge pages.  Take
+# both of these requirements into account and attempt to increase
+# number of huge pages available.
+nr_cpus=$(nproc)
+hpgsize_MB=$((hpgsize_KB / 1024))
+half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128))
+needmem_KB=$((half_ufd_size_MB * 2 * 1024))
+
 #set proper nr_hugepages
-if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
+if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then
        nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
-       needpgs=`expr $needmem / $pgsize`
+       needpgs=$((needmem_KB / hpgsize_KB))
        tries=2
        while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do
                lackpgs=$(( $needpgs - $freepgs ))
@@ -107,8 +115,9 @@ fi
 echo "---------------------------"
 echo "running userfaultfd_hugetlb"
 echo "---------------------------"
-# 256MB total huge pages == 128MB src and 128MB dst
-./userfaultfd hugetlb 128 32 $mnt/ufd_test_file
+# Test requires source and destination huge pages.  Size of source
+# (half_ufd_size_MB) is passed as argument to test.
+./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
        exitcode=1
index 4e65060..01d758d 100644 (file)
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for USB tools
 
-CC = $(CROSS_COMPILE)gcc
 PTHREAD_LIBS = -lpthread
 WARNINGS = -Wall -Wextra
 CFLAGS = $(WARNINGS) -g -I../include
index be320b9..20f6cf0 100644 (file)
@@ -6,7 +6,6 @@ TARGETS=page-types slabinfo page_owner_sort
 LIB_DIR = ../lib/api
 LIBS = $(LIB_DIR)/libapi.a
 
-CC = $(CROSS_COMPILE)gcc
 CFLAGS = -Wall -Wextra -I../lib/
 LDFLAGS = $(LIBS)
 
index e664f11..e0e8723 100644 (file)
@@ -2,7 +2,6 @@ PREFIX ?= /usr
 SBINDIR ?= sbin
 INSTALL ?= install
 CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
-CC = $(CROSS_COMPILE)gcc
 
 TARGET = dell-smbios-example
 
index 70268c0..282389e 100644 (file)
@@ -36,6 +36,8 @@ static struct timecounter *timecounter;
 static unsigned int host_vtimer_irq;
 static u32 host_vtimer_irq_flags;
 
+static DEFINE_STATIC_KEY_FALSE(has_gic_active_state);
+
 static const struct kvm_irq_level default_ptimer_irq = {
        .irq    = 30,
        .level  = 1,
@@ -56,6 +58,12 @@ u64 kvm_phys_timer_read(void)
        return timecounter->cc->read(timecounter->cc);
 }
 
+static inline bool userspace_irqchip(struct kvm *kvm)
+{
+       return static_branch_unlikely(&userspace_irqchip_in_use) &&
+               unlikely(!irqchip_in_kernel(kvm));
+}
+
 static void soft_timer_start(struct hrtimer *hrt, u64 ns)
 {
        hrtimer_start(hrt, ktime_add_ns(ktime_get(), ns),
@@ -69,25 +77,6 @@ static void soft_timer_cancel(struct hrtimer *hrt, struct work_struct *work)
                cancel_work_sync(work);
 }
 
-static void kvm_vtimer_update_mask_user(struct kvm_vcpu *vcpu)
-{
-       struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
-
-       /*
-        * When using a userspace irqchip with the architected timers, we must
-        * prevent continuously exiting from the guest, and therefore mask the
-        * physical interrupt by disabling it on the host interrupt controller
-        * when the virtual level is high, such that the guest can make
-        * forward progress.  Once we detect the output level being
-        * de-asserted, we unmask the interrupt again so that we exit from the
-        * guest when the timer fires.
-        */
-       if (vtimer->irq.level)
-               disable_percpu_irq(host_vtimer_irq);
-       else
-               enable_percpu_irq(host_vtimer_irq, 0);
-}
-
 static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
 {
        struct kvm_vcpu *vcpu = *(struct kvm_vcpu **)dev_id;
@@ -106,9 +95,9 @@ static irqreturn_t kvm_arch_timer_handler(int irq, void *dev_id)
        if (kvm_timer_should_fire(vtimer))
                kvm_timer_update_irq(vcpu, true, vtimer);
 
-       if (static_branch_unlikely(&userspace_irqchip_in_use) &&
-           unlikely(!irqchip_in_kernel(vcpu->kvm)))
-               kvm_vtimer_update_mask_user(vcpu);
+       if (userspace_irqchip(vcpu->kvm) &&
+           !static_branch_unlikely(&has_gic_active_state))
+               disable_percpu_irq(host_vtimer_irq);
 
        return IRQ_HANDLED;
 }
@@ -290,8 +279,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
        trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_ctx->irq.irq,
                                   timer_ctx->irq.level);
 
-       if (!static_branch_unlikely(&userspace_irqchip_in_use) ||
-           likely(irqchip_in_kernel(vcpu->kvm))) {
+       if (!userspace_irqchip(vcpu->kvm)) {
                ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu->vcpu_id,
                                          timer_ctx->irq.irq,
                                          timer_ctx->irq.level,
@@ -350,12 +338,6 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
        phys_timer_emulate(vcpu);
 }
 
-static void __timer_snapshot_state(struct arch_timer_context *timer)
-{
-       timer->cnt_ctl = read_sysreg_el0(cntv_ctl);
-       timer->cnt_cval = read_sysreg_el0(cntv_cval);
-}
-
 static void vtimer_save_state(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
@@ -367,8 +349,10 @@ static void vtimer_save_state(struct kvm_vcpu *vcpu)
        if (!vtimer->loaded)
                goto out;
 
-       if (timer->enabled)
-               __timer_snapshot_state(vtimer);
+       if (timer->enabled) {
+               vtimer->cnt_ctl = read_sysreg_el0(cntv_ctl);
+               vtimer->cnt_cval = read_sysreg_el0(cntv_cval);
+       }
 
        /* Disable the virtual timer */
        write_sysreg_el0(0, cntv_ctl);
@@ -460,23 +444,43 @@ static void set_cntvoff(u64 cntvoff)
        kvm_call_hyp(__kvm_timer_set_cntvoff, low, high);
 }
 
-static void kvm_timer_vcpu_load_vgic(struct kvm_vcpu *vcpu)
+static inline void set_vtimer_irq_phys_active(struct kvm_vcpu *vcpu, bool active)
+{
+       int r;
+       r = irq_set_irqchip_state(host_vtimer_irq, IRQCHIP_STATE_ACTIVE, active);
+       WARN_ON(r);
+}
+
+static void kvm_timer_vcpu_load_gic(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
        bool phys_active;
-       int ret;
-
-       phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
 
-       ret = irq_set_irqchip_state(host_vtimer_irq,
-                                   IRQCHIP_STATE_ACTIVE,
-                                   phys_active);
-       WARN_ON(ret);
+       if (irqchip_in_kernel(vcpu->kvm))
+               phys_active = kvm_vgic_map_is_active(vcpu, vtimer->irq.irq);
+       else
+               phys_active = vtimer->irq.level;
+       set_vtimer_irq_phys_active(vcpu, phys_active);
 }
 
-static void kvm_timer_vcpu_load_user(struct kvm_vcpu *vcpu)
+static void kvm_timer_vcpu_load_nogic(struct kvm_vcpu *vcpu)
 {
-       kvm_vtimer_update_mask_user(vcpu);
+       struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
+
+       /*
+        * When using a userspace irqchip with the architected timers and a
+        * host interrupt controller that doesn't support an active state, we
+        * must still prevent continuously exiting from the guest, and
+        * therefore mask the physical interrupt by disabling it on the host
+        * interrupt controller when the virtual level is high, such that the
+        * guest can make forward progress.  Once we detect the output level
+        * being de-asserted, we unmask the interrupt again so that we exit
+        * from the guest when the timer fires.
+        */
+       if (vtimer->irq.level)
+               disable_percpu_irq(host_vtimer_irq);
+       else
+               enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
 }
 
 void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
@@ -487,10 +491,10 @@ void kvm_timer_vcpu_load(struct kvm_vcpu *vcpu)
        if (unlikely(!timer->enabled))
                return;
 
-       if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
-               kvm_timer_vcpu_load_user(vcpu);
+       if (static_branch_likely(&has_gic_active_state))
+               kvm_timer_vcpu_load_gic(vcpu);
        else
-               kvm_timer_vcpu_load_vgic(vcpu);
+               kvm_timer_vcpu_load_nogic(vcpu);
 
        set_cntvoff(vtimer->cntvoff);
 
@@ -555,22 +559,29 @@ static void unmask_vtimer_irq_user(struct kvm_vcpu *vcpu)
 {
        struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
 
-       if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
-               __timer_snapshot_state(vtimer);
-               if (!kvm_timer_should_fire(vtimer)) {
-                       kvm_timer_update_irq(vcpu, false, vtimer);
-                       kvm_vtimer_update_mask_user(vcpu);
-               }
+       if (!kvm_timer_should_fire(vtimer)) {
+               kvm_timer_update_irq(vcpu, false, vtimer);
+               if (static_branch_likely(&has_gic_active_state))
+                       set_vtimer_irq_phys_active(vcpu, false);
+               else
+                       enable_percpu_irq(host_vtimer_irq, host_vtimer_irq_flags);
        }
 }
 
 void kvm_timer_sync_hwstate(struct kvm_vcpu *vcpu)
 {
-       unmask_vtimer_irq_user(vcpu);
+       struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+
+       if (unlikely(!timer->enabled))
+               return;
+
+       if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
+               unmask_vtimer_irq_user(vcpu);
 }
 
 int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
 {
+       struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
        struct arch_timer_context *vtimer = vcpu_vtimer(vcpu);
        struct arch_timer_context *ptimer = vcpu_ptimer(vcpu);
 
@@ -584,6 +595,9 @@ int kvm_timer_vcpu_reset(struct kvm_vcpu *vcpu)
        ptimer->cnt_ctl = 0;
        kvm_timer_update_state(vcpu);
 
+       if (timer->enabled && irqchip_in_kernel(vcpu->kvm))
+               kvm_vgic_reset_mapped_irq(vcpu, vtimer->irq.irq);
+
        return 0;
 }
 
@@ -753,9 +767,11 @@ int kvm_timer_hyp_init(bool has_gic)
                        kvm_err("kvm_arch_timer: error setting vcpu affinity\n");
                        goto out_free_irq;
                }
+
+               static_branch_enable(&has_gic_active_state);
        }
 
-       kvm_info("virtual timer IRQ%d\n", host_vtimer_irq);
+       kvm_debug("virtual timer IRQ%d\n", host_vtimer_irq);
 
        cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
                          "kvm/arm/timer:starting", kvm_timer_starting_cpu,
index 86941f6..5357230 100644 (file)
@@ -384,14 +384,11 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
                                    struct kvm_mp_state *mp_state)
 {
-       vcpu_load(vcpu);
-
        if (vcpu->arch.power_off)
                mp_state->mp_state = KVM_MP_STATE_STOPPED;
        else
                mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
 
-       vcpu_put(vcpu);
        return 0;
 }
 
@@ -400,8 +397,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
 {
        int ret = 0;
 
-       vcpu_load(vcpu);
-
        switch (mp_state->mp_state) {
        case KVM_MP_STATE_RUNNABLE:
                vcpu->arch.power_off = false;
@@ -413,7 +408,6 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
                ret = -EINVAL;
        }
 
-       vcpu_put(vcpu);
        return ret;
 }
 
@@ -1036,8 +1030,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        struct kvm_device_attr attr;
        long r;
 
-       vcpu_load(vcpu);
-
        switch (ioctl) {
        case KVM_ARM_VCPU_INIT: {
                struct kvm_vcpu_init init;
@@ -1114,7 +1106,6 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
                r = -EINVAL;
        }
 
-       vcpu_put(vcpu);
        return r;
 }
 
index f5c3d6d..b89ce54 100644 (file)
@@ -215,7 +215,8 @@ void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
         * are now visible to the system register interface.
         */
        if (!cpu_if->vgic_sre) {
-               dsb(st);
+               dsb(sy);
+               isb();
                cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
        }
 
index ec62d1c..b960acd 100644 (file)
@@ -1810,9 +1810,9 @@ int kvm_mmu_init(void)
         */
        BUG_ON((hyp_idmap_start ^ (hyp_idmap_end - 1)) & PAGE_MASK);
 
-       kvm_info("IDMAP page: %lx\n", hyp_idmap_start);
-       kvm_info("HYP VA range: %lx:%lx\n",
-                kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
+       kvm_debug("IDMAP page: %lx\n", hyp_idmap_start);
+       kvm_debug("HYP VA range: %lx:%lx\n",
+                 kern_hyp_va(PAGE_OFFSET), kern_hyp_va(~0UL));
 
        if (hyp_idmap_start >= kern_hyp_va(PAGE_OFFSET) &&
            hyp_idmap_start <  kern_hyp_va(~0UL) &&
index 83d82bd..dbe99d6 100644 (file)
@@ -113,9 +113,12 @@ unsigned long vgic_mmio_read_pending(struct kvm_vcpu *vcpu,
        /* Loop over all IRQs affected by this read */
        for (i = 0; i < len * 8; i++) {
                struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
+               unsigned long flags;
 
+               spin_lock_irqsave(&irq->irq_lock, flags);
                if (irq_is_pending(irq))
                        value |= (1U << i);
+               spin_unlock_irqrestore(&irq->irq_lock, flags);
 
                vgic_put_irq(vcpu->kvm, irq);
        }
index c32d7b9..29556f7 100644 (file)
@@ -37,6 +37,13 @@ void vgic_v2_init_lrs(void)
                vgic_v2_write_lr(i, 0);
 }
 
+void vgic_v2_set_npie(struct kvm_vcpu *vcpu)
+{
+       struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
+
+       cpuif->vgic_hcr |= GICH_HCR_NPIE;
+}
+
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu)
 {
        struct vgic_v2_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v2;
@@ -64,7 +71,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu)
        int lr;
        unsigned long flags;
 
-       cpuif->vgic_hcr &= ~GICH_HCR_UIE;
+       cpuif->vgic_hcr &= ~(GICH_HCR_UIE | GICH_HCR_NPIE);
 
        for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
                u32 val = cpuif->vgic_lr[lr];
@@ -410,7 +417,7 @@ int vgic_v2_probe(const struct gic_kvm_info *info)
        kvm_vgic_global_state.type = VGIC_V2;
        kvm_vgic_global_state.max_gic_vcpus = VGIC_V2_MAX_CPUS;
 
-       kvm_info("vgic-v2@%llx\n", info->vctrl.start);
+       kvm_debug("vgic-v2@%llx\n", info->vctrl.start);
 
        return 0;
 out:
index 6b32941..0ff2006 100644 (file)
@@ -26,6 +26,13 @@ static bool group1_trap;
 static bool common_trap;
 static bool gicv4_enable;
 
+void vgic_v3_set_npie(struct kvm_vcpu *vcpu)
+{
+       struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
+
+       cpuif->vgic_hcr |= ICH_HCR_NPIE;
+}
+
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu)
 {
        struct vgic_v3_cpu_if *cpuif = &vcpu->arch.vgic_cpu.vgic_v3;
@@ -47,7 +54,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu)
        int lr;
        unsigned long flags;
 
-       cpuif->vgic_hcr &= ~ICH_HCR_UIE;
+       cpuif->vgic_hcr &= ~(ICH_HCR_UIE | ICH_HCR_NPIE);
 
        for (lr = 0; lr < vgic_cpu->used_lrs; lr++) {
                u64 val = cpuif->vgic_lr[lr];
index c7c5ef1..8201899 100644 (file)
@@ -495,6 +495,32 @@ int kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu, unsigned int host_irq,
        return ret;
 }
 
+/**
+ * kvm_vgic_reset_mapped_irq - Reset a mapped IRQ
+ * @vcpu: The VCPU pointer
+ * @vintid: The INTID of the interrupt
+ *
+ * Reset the active and pending states of a mapped interrupt.  Kernel
+ * subsystems injecting mapped interrupts should reset their interrupt lines
+ * when we are doing a reset of the VM.
+ */
+void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid)
+{
+       struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, vintid);
+       unsigned long flags;
+
+       if (!irq->hw)
+               goto out;
+
+       spin_lock_irqsave(&irq->irq_lock, flags);
+       irq->active = false;
+       irq->pending_latch = false;
+       irq->line_level = false;
+       spin_unlock_irqrestore(&irq->irq_lock, flags);
+out:
+       vgic_put_irq(vcpu->kvm, irq);
+}
+
 int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, unsigned int vintid)
 {
        struct vgic_irq *irq;
@@ -684,22 +710,37 @@ static inline void vgic_set_underflow(struct kvm_vcpu *vcpu)
                vgic_v3_set_underflow(vcpu);
 }
 
+static inline void vgic_set_npie(struct kvm_vcpu *vcpu)
+{
+       if (kvm_vgic_global_state.type == VGIC_V2)
+               vgic_v2_set_npie(vcpu);
+       else
+               vgic_v3_set_npie(vcpu);
+}
+
 /* Requires the ap_list_lock to be held. */
-static int compute_ap_list_depth(struct kvm_vcpu *vcpu)
+static int compute_ap_list_depth(struct kvm_vcpu *vcpu,
+                                bool *multi_sgi)
 {
        struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
        struct vgic_irq *irq;
        int count = 0;
 
+       *multi_sgi = false;
+
        DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
 
        list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
                spin_lock(&irq->irq_lock);
                /* GICv2 SGIs can count for more than one... */
-               if (vgic_irq_is_sgi(irq->intid) && irq->source)
-                       count += hweight8(irq->source);
-               else
+               if (vgic_irq_is_sgi(irq->intid) && irq->source) {
+                       int w = hweight8(irq->source);
+
+                       count += w;
+                       *multi_sgi |= (w > 1);
+               } else {
                        count++;
+               }
                spin_unlock(&irq->irq_lock);
        }
        return count;
@@ -710,28 +751,43 @@ static void vgic_flush_lr_state(struct kvm_vcpu *vcpu)
 {
        struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
        struct vgic_irq *irq;
-       int count = 0;
+       int count;
+       bool npie = false;
+       bool multi_sgi;
+       u8 prio = 0xff;
 
        DEBUG_SPINLOCK_BUG_ON(!spin_is_locked(&vgic_cpu->ap_list_lock));
 
-       if (compute_ap_list_depth(vcpu) > kvm_vgic_global_state.nr_lr)
+       count = compute_ap_list_depth(vcpu, &multi_sgi);
+       if (count > kvm_vgic_global_state.nr_lr || multi_sgi)
                vgic_sort_ap_list(vcpu);
 
+       count = 0;
+
        list_for_each_entry(irq, &vgic_cpu->ap_list_head, ap_list) {
                spin_lock(&irq->irq_lock);
 
-               if (unlikely(vgic_target_oracle(irq) != vcpu))
-                       goto next;
-
                /*
-                * If we get an SGI with multiple sources, try to get
-                * them in all at once.
+                * If we have multi-SGIs in the pipeline, we need to
+                * guarantee that they are all seen before any IRQ of
+                * lower priority. In that case, we need to filter out
+                * these interrupts by exiting early. This is easy as
+                * the AP list has been sorted already.
                 */
-               do {
+               if (multi_sgi && irq->priority > prio) {
+                       spin_unlock(&irq->irq_lock);
+                       break;
+               }
+
+               if (likely(vgic_target_oracle(irq) == vcpu)) {
                        vgic_populate_lr(vcpu, irq, count++);
-               } while (irq->source && count < kvm_vgic_global_state.nr_lr);
 
-next:
+                       if (irq->source) {
+                               npie = true;
+                               prio = irq->priority;
+                       }
+               }
+
                spin_unlock(&irq->irq_lock);
 
                if (count == kvm_vgic_global_state.nr_lr) {
@@ -742,6 +798,9 @@ next:
                }
        }
 
+       if (npie)
+               vgic_set_npie(vcpu);
+
        vcpu->arch.vgic_cpu.used_lrs = count;
 
        /* Nuke remaining LRs */
index 12c37b8..f5b8519 100644 (file)
@@ -96,6 +96,7 @@
 /* we only support 64 kB translation table page size */
 #define KVM_ITS_L1E_ADDR_MASK          GENMASK_ULL(51, 16)
 
+/* Requires the irq_lock to be held by the caller. */
 static inline bool irq_is_pending(struct vgic_irq *irq)
 {
        if (irq->config == VGIC_CONFIG_EDGE)
@@ -159,6 +160,7 @@ void vgic_v2_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v2_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v2_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v2_set_underflow(struct kvm_vcpu *vcpu);
+void vgic_v2_set_npie(struct kvm_vcpu *vcpu);
 int vgic_v2_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
 int vgic_v2_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,
                         int offset, u32 *val);
@@ -188,6 +190,7 @@ void vgic_v3_fold_lr_state(struct kvm_vcpu *vcpu);
 void vgic_v3_populate_lr(struct kvm_vcpu *vcpu, struct vgic_irq *irq, int lr);
 void vgic_v3_clear_lr(struct kvm_vcpu *vcpu, int lr);
 void vgic_v3_set_underflow(struct kvm_vcpu *vcpu);
+void vgic_v3_set_npie(struct kvm_vcpu *vcpu);
 void vgic_v3_set_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_get_vmcr(struct kvm_vcpu *vcpu, struct vgic_vmcr *vmcr);
 void vgic_v3_enable(struct kvm_vcpu *vcpu);
index 4501e65..65dea3f 100644 (file)
@@ -969,8 +969,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
                /* Check for overlaps */
                r = -EEXIST;
                kvm_for_each_memslot(slot, __kvm_memslots(kvm, as_id)) {
-                       if ((slot->id >= KVM_USER_MEM_SLOTS) ||
-                           (slot->id == id))
+                       if (slot->id == id)
                                continue;
                        if (!((base_gfn + npages <= slot->base_gfn) ||
                              (base_gfn >= slot->base_gfn + slot->npages)))