Merge tag 'soc-fixes-5.17-3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 10 Mar 2022 19:43:01 +0000 (11:43 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 10 Mar 2022 19:43:01 +0000 (11:43 -0800)
Pull ARM SoC fixes from Arnd Bergmann:
 "Here is a third set of fixes for the soc tree, well within the
  expected set of changes.

  Maintainer list changes:
   - Krzysztof Kozlowski and Jisheng Zhang both have new email addresses
   - Broadcom iProc has a new git tree

  Regressions:
   - Robert Foss sends a revert for a Mediatek DPI bridge patch that
     caused an inadvertent break in the DT binding
   - mstar timers need to be included in Kconfig

  Devicetree fixes for:
   - Aspeed ast2600 spi pinmux
   - Tegra eDP panels on Nyan FHD
   - Tegra display IOMMU
   - Qualcomm sm8350 UFS clocks
   - minor DT changes for Marvell Armada, Qualcomm sdx65, Qualcomm
     sm8450, and Broadcom BCM2711"

* tag 'soc-fixes-5.17-3' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc:
  arm64: dts: marvell: armada-37xx: Remap IO space to bus address 0x0
  MAINTAINERS: Update Jisheng's email address
  Revert "arm64: dts: mt8183: jacuzzi: Fix bus properties in anx's DSI endpoint"
  dt-bindings: drm/bridge: anx7625: Revert DPI support
  ARM: dts: aspeed: Fix AST2600 quad spi group
  MAINTAINERS: update Krzysztof Kozlowski's email
  MAINTAINERS: Update git tree for Broadcom iProc SoCs
  ARM: tegra: Move Nyan FHD panels to AUX bus
  arm64: dts: armada-3720-turris-mox: Add missing ethernet0 alias
  ARM: mstar: Select HAVE_ARM_ARCH_TIMER
  soc: mediatek: mt8192-mmsys: Fix dither to dsi0 path's input sel
  arm64: dts: mt8183: jacuzzi: Fix bus properties in anx's DSI endpoint
  ARM: boot: dts: bcm2711: Fix HVS register range
  arm64: dts: qcom: c630: disable crypto due to serror
  arm64: dts: qcom: sm8450: fix apps_smmu interrupts
  arm64: dts: qcom: sm8450: enable GCC_USB3_0_CLKREF_EN for usb
  arm64: dts: qcom: sm8350: Correct UFS symbol clocks
  arm64: tegra: Disable ISO SMMU for Tegra194
  Revert "dt-bindings: arm: qcom: Document SDX65 platform and boards"

340 files changed:
CREDITS
Documentation/admin-guide/hw-vuln/spectre.rst
Documentation/admin-guide/kernel-parameters.txt
Documentation/admin-guide/mm/pagemap.rst
Documentation/core-api/dma-attributes.rst
Documentation/devicetree/bindings/arm/atmel-at91.yaml
Documentation/devicetree/bindings/arm/freescale/fsl,layerscape-dcfg.txt
Documentation/devicetree/bindings/clock/qoriq-clock.txt
Documentation/devicetree/bindings/mfd/brcm,cru.yaml
Documentation/devicetree/bindings/mfd/cirrus,lochnagar.yaml
Documentation/devicetree/bindings/phy/ti,tcan104x-can.yaml
Documentation/devicetree/bindings/pinctrl/cirrus,madera.yaml
Documentation/devicetree/bindings/usb/dwc2.yaml
MAINTAINERS
Makefile
arch/arm/boot/dts/omap3-devkit8000-common.dtsi
arch/arm/boot/dts/omap3-devkit8000.dts
arch/arm/boot/dts/rk322x.dtsi
arch/arm/boot/dts/rk3288.dtsi
arch/arm/include/asm/assembler.h
arch/arm/include/asm/spectre.h [new file with mode: 0644]
arch/arm/include/asm/vmlinux.lds.h
arch/arm/kernel/Makefile
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/kgdb.c
arch/arm/kernel/spectre.c [new file with mode: 0644]
arch/arm/kernel/traps.c
arch/arm/mm/Kconfig
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-bugs.c
arch/arm64/Kconfig
arch/arm64/boot/dts/arm/juno-base.dtsi
arch/arm64/boot/dts/freescale/imx8mm.dtsi
arch/arm64/boot/dts/freescale/imx8ulp.dtsi
arch/arm64/boot/dts/intel/socfpga_agilex.dtsi
arch/arm64/boot/dts/rockchip/px30.dtsi
arch/arm64/boot/dts/rockchip/rk3328.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru.dtsi
arch/arm64/boot/dts/rockchip/rk3399-puma-haikou.dts
arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
arch/arm64/boot/dts/rockchip/rk3568.dtsi
arch/arm64/boot/dts/rockchip/rk356x.dtsi
arch/arm64/include/asm/assembler.h
arch/arm64/include/asm/cpufeature.h
arch/arm64/include/asm/cputype.h
arch/arm64/include/asm/fixmap.h
arch/arm64/include/asm/insn.h
arch/arm64/include/asm/kvm_host.h
arch/arm64/include/asm/mte-kasan.h
arch/arm64/include/asm/pgtable-prot.h
arch/arm64/include/asm/pgtable.h
arch/arm64/include/asm/rwonce.h
arch/arm64/include/asm/sections.h
arch/arm64/include/asm/spectre.h
arch/arm64/include/asm/sysreg.h
arch/arm64/include/asm/vectors.h [new file with mode: 0644]
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kernel/cpu_errata.c
arch/arm64/kernel/cpufeature.c
arch/arm64/kernel/entry.S
arch/arm64/kernel/image-vars.h
arch/arm64/kernel/proton-pack.c
arch/arm64/kernel/vmlinux.lds.S
arch/arm64/kvm/arm.c
arch/arm64/kvm/hyp/hyp-entry.S
arch/arm64/kvm/hyp/nvhe/mm.c
arch/arm64/kvm/hyp/vhe/switch.c
arch/arm64/kvm/hypercalls.c
arch/arm64/kvm/psci.c
arch/arm64/mm/mmap.c
arch/arm64/mm/mmu.c
arch/arm64/tools/cpucaps
arch/mips/kernel/setup.c
arch/mips/kernel/smp.c
arch/mips/ralink/mt7621.c
arch/powerpc/include/asm/book3s/64/mmu.h
arch/powerpc/include/asm/kexec_ranges.h
arch/riscv/boot/dts/canaan/k210.dtsi
arch/riscv/include/asm/page.h
arch/riscv/include/asm/pgtable.h
arch/riscv/mm/Makefile
arch/riscv/mm/init.c
arch/riscv/mm/kasan_init.c
arch/riscv/mm/physaddr.c
arch/s390/include/asm/extable.h
arch/s390/include/asm/ftrace.h
arch/s390/include/asm/ptrace.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/mcount.S
arch/s390/kernel/setup.c
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/nospec-branch.h
arch/x86/kernel/alternative.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/kvm.c
arch/x86/kernel/kvmclock.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/x86.c
arch/x86/lib/retpoline.S
arch/x86/net/bpf_jit_comp.c
drivers/atm/firestream.c
drivers/auxdisplay/lcd2s.c
drivers/block/virtio_blk.c
drivers/block/xen-blkfront.c
drivers/char/virtio_console.c
drivers/clk/Kconfig
drivers/clk/qcom/dispcc-sc7180.c
drivers/clk/qcom/dispcc-sc7280.c
drivers/clk/qcom/dispcc-sm8250.c
drivers/clk/qcom/gdsc.c
drivers/clk/qcom/gdsc.h
drivers/clocksource/timer-ti-dm-systimer.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/efi/libstub/riscv-stub.c
drivers/firmware/efi/vars.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-tegra186.c
drivers/gpio/gpio-ts4900.c
drivers/gpio/gpiolib-acpi.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
drivers/gpu/drm/arm/Kconfig
drivers/gpu/drm/bridge/ti-sn65dsi86.c
drivers/gpu/drm/drm_connector.c
drivers/gpu/drm/exynos/exynos7_drm_decon.c
drivers/gpu/drm/exynos/exynos_drm_dsi.c
drivers/gpu/drm/exynos/exynos_drm_fimc.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_gsc.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
drivers/gpu/drm/i915/intel_pch.c
drivers/gpu/drm/i915/intel_pch.h
drivers/hid/hid-debug.c
drivers/hid/hid-elo.c
drivers/hid/hid-input.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-nintendo.c
drivers/hid/hid-thrustmaster.c
drivers/hid/hid-vivaldi.c
drivers/input/keyboard/Kconfig
drivers/input/mouse/elan_i2c_core.c
drivers/input/touchscreen/goodix.c
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/amd_iommu_types.h
drivers/iommu/amd/init.c
drivers/iommu/amd/io_pgtable.c
drivers/iommu/amd/iommu.c
drivers/iommu/intel/iommu.c
drivers/iommu/tegra-smmu.c
drivers/mtd/nand/raw/Kconfig
drivers/net/arcnet/com20020-pci.c
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/usb/etas_es58x/es58x_core.c
drivers/net/can/usb/etas_es58x/es58x_core.h
drivers/net/can/usb/gs_usb.c
drivers/net/ethernet/broadcom/bnx2.c
drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h
drivers/net/ethernet/intel/e1000e/hw.h
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c
drivers/net/ethernet/intel/igc/igc_phy.c
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c
drivers/net/ethernet/microchip/sparx5/sparx5_main.h
drivers/net/ethernet/microchip/sparx5/sparx5_vlan.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/sfc/mcdi.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ipa/Kconfig
drivers/net/wireless/intel/Makefile
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/vendor-cmd.c
drivers/net/xen-netfront.c
drivers/ntb/hw/intel/ntb_hw_gen4.c
drivers/ntb/hw/intel/ntb_hw_gen4.h
drivers/ntb/msi.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/ptp/ptp_ocp.c
drivers/scsi/xen-scsifront.c
drivers/soc/fsl/guts.c
drivers/soc/fsl/qe/qe.c
drivers/soc/fsl/qe/qe_io.c
drivers/soc/imx/gpcv2.c
drivers/spi/spi.c
drivers/tee/optee/ffa_abi.c
drivers/tee/optee/smc_abi.c
drivers/thermal/thermal_netlink.c
drivers/usb/host/xen-hcd.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/vdpa.c
drivers/vdpa/vdpa_user/iova_domain.c
drivers/vdpa/virtio_pci/vp_vdpa.c
drivers/vhost/iotlb.c
drivers/vhost/vdpa.c
drivers/vhost/vhost.c
drivers/virtio/Kconfig
drivers/virtio/virtio.c
drivers/virtio/virtio_vdpa.c
drivers/xen/gntalloc.c
drivers/xen/grant-table.c
drivers/xen/pvcalls-front.c
drivers/xen/xenbus/xenbus_client.c
fs/binfmt_elf.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/qgroup.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/subpage.c
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-checker.c
fs/btrfs/tree-log.c
fs/cachefiles/interface.c
fs/erofs/internal.h
fs/fuse/dev.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/fuse/ioctl.c
fs/proc/task_mmu.c
fs/userfaultfd.c
include/linux/arm-smccc.h
include/linux/bpf.h
include/linux/dma-mapping.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/netfilter_netdev.h
include/linux/rfkill.h
include/linux/vdpa.h
include/linux/virtio.h
include/linux/virtio_config.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci_core.h
include/net/ndisc.h
include/net/netfilter/nf_flow_table.h
include/net/netfilter/nf_queue.h
include/net/xfrm.h
include/soc/fsl/dpaa2-fd.h
include/soc/fsl/qe/immap_qe.h
include/soc/fsl/qe/qe_tdm.h
include/soc/fsl/qe/ucc_fast.h
include/soc/fsl/qe/ucc_slow.h
include/uapi/linux/input-event-codes.h
include/uapi/linux/magic.h
include/uapi/linux/xfrm.h
include/xen/grant_table.h
kernel/configs/debug.config
kernel/dma/swiotlb.c
kernel/fork.c
kernel/sys.c
kernel/sysctl.c
kernel/trace/blktrace.c
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
kernel/trace/trace_kprobe.c
kernel/user_namespace.c
lib/Kconfig
mm/gup.c
mm/madvise.c
mm/memfd.c
mm/mempolicy.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/util.c
net/9p/trans_xen.c
net/batman-adv/hard-interface.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sync.c
net/bluetooth/mgmt.c
net/bluetooth/mgmt_util.c
net/core/skbuff.c
net/core/skmsg.c
net/dcb/dcbnl.c
net/dsa/dsa2.c
net/ipv4/esp4.c
net/ipv4/tcp.c
net/ipv6/addrconf.c
net/ipv6/esp6.c
net/ipv6/ip6_output.c
net/ipv6/mcast.c
net/key/af_key.c
net/mac80211/agg-tx.c
net/mac80211/ieee80211_i.h
net/mac80211/mlme.c
net/mac80211/rx.c
net/mptcp/protocol.c
net/netfilter/core.c
net/netfilter/nf_flow_table_offload.c
net/netfilter/nf_queue.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink_queue.c
net/sched/act_ct.c
net/smc/af_smc.c
net/smc/smc_core.c
net/wireless/Makefile
net/wireless/nl80211.c
net/xfrm/xfrm_device.c
net/xfrm/xfrm_interface.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
sound/soc/codecs/cs4265.c
sound/soc/soc-ops.c
sound/x86/intel_hdmi_audio.c
tools/arch/x86/include/asm/cpufeatures.h
tools/testing/selftests/drivers/net/mlxsw/spectrum/resource_scale.sh
tools/testing/selftests/drivers/net/mlxsw/tc_police_scale.sh
tools/testing/selftests/kvm/aarch64/arch_timer.c
tools/testing/selftests/kvm/aarch64/vgic_irq.c
tools/testing/selftests/kvm/lib/aarch64/vgic.c
tools/testing/selftests/net/mptcp/mptcp_connect.sh
tools/testing/selftests/netfilter/.gitignore
tools/testing/selftests/netfilter/Makefile
tools/testing/selftests/netfilter/connect_close.c [new file with mode: 0644]
tools/testing/selftests/netfilter/nft_queue.sh
tools/testing/selftests/vm/hugepage-mremap.c
tools/testing/selftests/vm/run_vmtests.sh
tools/testing/selftests/vm/userfaultfd.c
tools/virtio/linux/mm_types.h [new file with mode: 0644]
tools/virtio/virtio_test.c

diff --git a/CREDITS b/CREDITS
index b97256d..7e85a53 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -895,6 +895,12 @@ S: 3000 FORE Drive
 S: Warrendale, Pennsylvania 15086
 S: USA
 
+N: Ludovic Desroches
+E: ludovic.desroches@microchip.com
+D: Maintainer for ARM/Microchip (AT91) SoC support
+D: Author of ADC, pinctrl, XDMA and SDHCI drivers for this platform
+S: France
+
 N: Martin Devera
 E: devik@cdi.cz
 W: http://luxik.cdi.cz/~devik/qos/
index a2b22d5..9e95568 100644 (file)
@@ -60,8 +60,8 @@ privileged data touched during the speculative execution.
 Spectre variant 1 attacks take advantage of speculative execution of
 conditional branches, while Spectre variant 2 attacks use speculative
 execution of indirect branches to leak privileged memory.
-See :ref:`[1] <spec_ref1>` :ref:`[5] <spec_ref5>` :ref:`[7] <spec_ref7>`
-:ref:`[10] <spec_ref10>` :ref:`[11] <spec_ref11>`.
+See :ref:`[1] <spec_ref1>` :ref:`[5] <spec_ref5>` :ref:`[6] <spec_ref6>`
+:ref:`[7] <spec_ref7>` :ref:`[10] <spec_ref10>` :ref:`[11] <spec_ref11>`.
 
 Spectre variant 1 (Bounds Check Bypass)
 ---------------------------------------
@@ -131,6 +131,19 @@ steer its indirect branch speculations to gadget code, and measure the
 speculative execution's side effects left in level 1 cache to infer the
 victim's data.
 
+Yet another variant 2 attack vector is for the attacker to poison the
+Branch History Buffer (BHB) to speculatively steer an indirect branch
+to a specific Branch Target Buffer (BTB) entry, even if the entry isn't
+associated with the source address of the indirect branch. Specifically,
+the BHB might be shared across privilege levels even in the presence of
+Enhanced IBRS.
+
+Currently the only known real-world BHB attack vector is via
+unprivileged eBPF. Therefore, it's highly recommended to not enable
+unprivileged eBPF, especially when eIBRS is used (without retpolines).
+For a full mitigation against BHB attacks, it's recommended to use
+retpolines (or eIBRS combined with retpolines).
+
 Attack scenarios
 ----------------
 
@@ -364,13 +377,15 @@ The possible values in this file are:
 
   - Kernel status:
 
-  ====================================  =================================
-  'Not affected'                        The processor is not vulnerable
-  'Vulnerable'                          Vulnerable, no mitigation
-  'Mitigation: Full generic retpoline'  Software-focused mitigation
-  'Mitigation: Full AMD retpoline'      AMD-specific software mitigation
-  'Mitigation: Enhanced IBRS'           Hardware-focused mitigation
-  ====================================  =================================
+  ========================================  =================================
+  'Not affected'                            The processor is not vulnerable
+  'Mitigation: None'                        Vulnerable, no mitigation
+  'Mitigation: Retpolines'                  Use Retpoline thunks
+  'Mitigation: LFENCE'                      Use LFENCE instructions
+  'Mitigation: Enhanced IBRS'               Hardware-focused mitigation
+  'Mitigation: Enhanced IBRS + Retpolines'  Hardware-focused + Retpolines
+  'Mitigation: Enhanced IBRS + LFENCE'      Hardware-focused + LFENCE
+  ========================================  =================================
 
   - Firmware status: Show if Indirect Branch Restricted Speculation (IBRS) is
     used to protect against Spectre variant 2 attacks when calling firmware (x86 only).
@@ -583,12 +598,13 @@ kernel command line.
 
                Specific mitigations can also be selected manually:
 
-               retpoline
-                                       replace indirect branches
-               retpoline,generic
-                                       google's original retpoline
-               retpoline,amd
-                                       AMD-specific minimal thunk
+                retpoline               auto pick between generic,lfence
+                retpoline,generic       Retpolines
+                retpoline,lfence        LFENCE; indirect branch
+                retpoline,amd           alias for retpoline,lfence
+                eibrs                   enhanced IBRS
+                eibrs,retpoline         enhanced IBRS + Retpolines
+                eibrs,lfence            enhanced IBRS + LFENCE
 
                Not specifying this option is equivalent to
                spectre_v2=auto.
@@ -599,7 +615,7 @@ kernel command line.
                spectre_v2=off. Spectre variant 1 mitigations
                cannot be disabled.
 
-For spectre_v2_user see :doc:`/admin-guide/kernel-parameters`.
+For spectre_v2_user see Documentation/admin-guide/kernel-parameters.txt
 
 Mitigation selection guide
 --------------------------
@@ -681,7 +697,7 @@ AMD white papers:
 
 .. _spec_ref6:
 
-[6] `Software techniques for managing speculation on AMD processors <https://developer.amd.com/wp-content/resources/90343-B_SoftwareTechniquesforManagingSpeculation_WP_7-18Update_FNL.pdf>`_.
+[6] `Software techniques for managing speculation on AMD processors <https://developer.amd.com/wp-content/resources/Managing-Speculation-on-AMD-Processors.pdf>`_.
 
 ARM white papers:
 
index f5a27f0..7123524 100644 (file)
                        Specific mitigations can also be selected manually:
 
                        retpoline         - replace indirect branches
-                       retpoline,generic - google's original retpoline
-                       retpoline,amd     - AMD-specific minimal thunk
+                       retpoline,generic - Retpolines
+                       retpoline,lfence  - LFENCE; indirect branch
+                       retpoline,amd     - alias for retpoline,lfence
+                       eibrs             - enhanced IBRS
+                       eibrs,retpoline   - enhanced IBRS + Retpolines
+                       eibrs,lfence      - enhanced IBRS + LFENCE
 
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
index bfc2870..6e2e416 100644 (file)
@@ -23,7 +23,7 @@ There are four components to pagemap:
     * Bit  56    page exclusively mapped (since 4.2)
     * Bit  57    pte is uffd-wp write-protected (since 5.13) (see
       :ref:`Documentation/admin-guide/mm/userfaultfd.rst <userfaultfd>`)
-    * Bits 57-60 zero
+    * Bits 58-60 zero
     * Bit  61    page is file-page or shared-anon (since 3.5)
     * Bit  62    page swapped
     * Bit  63    page present
index 17706dc..1887d92 100644 (file)
@@ -130,11 +130,3 @@ accesses to DMA buffers in both privileged "supervisor" and unprivileged
 subsystem that the buffer is fully accessible at the elevated privilege
 level (and ideally inaccessible or at least read-only at the
 lesser-privileged levels).
-
-DMA_ATTR_OVERWRITE
-------------------
-
-This is a hint to the DMA-mapping subsystem that the device is expected to
-overwrite the entire mapped size, thus the caller does not require any of the
-previous buffer contents to be preserved. This allows bounce-buffering
-implementations to optimise DMA_FROM_DEVICE transfers.
index c612e1f..ff91df0 100644 (file)
@@ -8,7 +8,8 @@ title: Atmel AT91 device tree bindings.
 
 maintainers:
   - Alexandre Belloni <alexandre.belloni@bootlin.com>
-  - Ludovic Desroches <ludovic.desroches@microchip.com>
+  - Claudiu Beznea <claudiu.beznea@microchip.com>
+  - Nicolas Ferre <nicolas.ferre@microchip.com>
 
 description: |
   Boards with a SoC of the Atmel AT91 or SMART family shall have the following
index b5cb374..10a91cc 100644 (file)
@@ -8,7 +8,7 @@ Required properties:
   - compatible: Should contain a chip-specific compatible string,
        Chip-specific strings are of the form "fsl,<chip>-dcfg",
        The following <chip>s are known to be supported:
-       ls1012a, ls1021a, ls1043a, ls1046a, ls2080a.
+       ls1012a, ls1021a, ls1043a, ls1046a, ls2080a, lx2160a
 
   - reg : should contain base address and length of DCFG memory-mapped registers
 
index f7d48f2..10119d9 100644 (file)
@@ -44,6 +44,7 @@ Required properties:
        * "fsl,ls1046a-clockgen"
        * "fsl,ls1088a-clockgen"
        * "fsl,ls2080a-clockgen"
+       * "fsl,lx2160a-clockgen"
        Chassis-version clock strings include:
        * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks
        * "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks
index be4a2df..b85819f 100644 (file)
@@ -39,7 +39,7 @@ patternProperties:
   '^phy@[a-f0-9]+$':
     $ref: ../phy/bcm-ns-usb2-phy.yaml
 
-  '^pin-controller@[a-f0-9]+$':
+  '^pinctrl@[a-f0-9]+$':
     $ref: ../pinctrl/brcm,ns-pinmux.yaml
 
   '^syscon@[a-f0-9]+$':
@@ -94,7 +94,7 @@ examples:
             reg = <0x180 0x4>;
         };
 
-        pin-controller@1c0 {
+        pinctrl@1c0 {
             compatible = "brcm,bcm4708-pinmux";
             reg = <0x1c0 0x24>;
             reg-names = "cru_gpio_control";
index c00ad3e..ad285cb 100644 (file)
@@ -126,7 +126,7 @@ properties:
       clock-frequency:
         const: 12288000
 
-  lochnagar-pinctrl:
+  pinctrl:
     type: object
     $ref: /schemas/pinctrl/cirrus,lochnagar.yaml#
 
@@ -255,7 +255,7 @@ required:
   - reg
   - reset-gpios
   - lochnagar-clk
-  - lochnagar-pinctrl
+  - pinctrl
 
 additionalProperties: false
 
@@ -293,7 +293,7 @@ examples:
                 clock-frequency = <32768>;
             };
 
-            lochnagar-pinctrl {
+            pinctrl {
                 compatible = "cirrus,lochnagar-pinctrl";
 
                 gpio-controller;
index 6107880..02b76f1 100644 (file)
@@ -37,6 +37,12 @@ properties:
       max bit rate supported in bps
     minimum: 1
 
+  mux-states:
+    description:
+      mux controller node to route the signals from controller to
+      transceiver.
+    maxItems: 1
+
 required:
   - compatible
   - '#phy-cells'
@@ -53,4 +59,5 @@ examples:
       max-bitrate = <5000000>;
       standby-gpios = <&wakeup_gpio1 16 GPIO_ACTIVE_LOW>;
       enable-gpios = <&main_gpio1 67 GPIO_ACTIVE_HIGH>;
+      mux-states = <&mux0 1>;
     };
index c85f759..8a90d82 100644 (file)
@@ -107,9 +107,6 @@ properties:
 
     additionalProperties: false
 
-allOf:
-  - $ref: "pinctrl.yaml#"
-
 required:
   - pinctrl-0
   - pinctrl-names
index f00867e..481aaa0 100644 (file)
@@ -53,6 +53,7 @@ properties:
           - const: st,stm32mp15-hsotg
           - const: snps,dwc2
       - const: samsung,s3c6400-hsotg
+      - const: intel,socfpga-agilex-hsotg
 
   reg:
     maxItems: 1
index d53eb15..e127c2f 100644 (file)
@@ -2254,7 +2254,7 @@ F:        drivers/phy/mediatek/
 ARM/Microchip (AT91) SoC support
 M:     Nicolas Ferre <nicolas.ferre@microchip.com>
 M:     Alexandre Belloni <alexandre.belloni@bootlin.com>
-M:     Ludovic Desroches <ludovic.desroches@microchip.com>
+M:     Claudiu Beznea <claudiu.beznea@microchip.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 W:     http://www.linux4sam.org
@@ -7744,8 +7744,7 @@ M:        Qiang Zhao <qiang.zhao@nxp.com>
 L:     linuxppc-dev@lists.ozlabs.org
 S:     Maintained
 F:     drivers/soc/fsl/qe/
-F:     include/soc/fsl/*qe*.h
-F:     include/soc/fsl/*ucc*.h
+F:     include/soc/fsl/qe/
 
 FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
 M:     Li Yang <leoyang.li@nxp.com>
@@ -7776,6 +7775,7 @@ F:        Documentation/devicetree/bindings/misc/fsl,dpaa2-console.yaml
 F:     Documentation/devicetree/bindings/soc/fsl/
 F:     drivers/soc/fsl/
 F:     include/linux/fsl/
+F:     include/soc/fsl/
 
 FREESCALE SOC FS_ENET DRIVER
 M:     Pantelis Antoniou <pantelis.antoniou@gmail.com>
@@ -13699,7 +13699,7 @@ F:      scripts/nsdeps
 NTB AMD DRIVER
 M:     Sanjay R Mehta <sanju.mehta@amd.com>
 M:     Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
-L:     linux-ntb@googlegroups.com
+L:     ntb@lists.linux.dev
 S:     Supported
 F:     drivers/ntb/hw/amd/
 
@@ -13707,7 +13707,7 @@ NTB DRIVER CORE
 M:     Jon Mason <jdmason@kudzu.us>
 M:     Dave Jiang <dave.jiang@intel.com>
 M:     Allen Hubbe <allenbh@gmail.com>
-L:     linux-ntb@googlegroups.com
+L:     ntb@lists.linux.dev
 S:     Supported
 W:     https://github.com/jonmason/ntb/wiki
 T:     git git://github.com/jonmason/ntb.git
@@ -13719,13 +13719,13 @@ F:    tools/testing/selftests/ntb/
 
 NTB IDT DRIVER
 M:     Serge Semin <fancer.lancer@gmail.com>
-L:     linux-ntb@googlegroups.com
+L:     ntb@lists.linux.dev
 S:     Supported
 F:     drivers/ntb/hw/idt/
 
 NTB INTEL DRIVER
 M:     Dave Jiang <dave.jiang@intel.com>
-L:     linux-ntb@googlegroups.com
+L:     ntb@lists.linux.dev
 S:     Supported
 W:     https://github.com/davejiang/linux/wiki
 T:     git https://github.com/davejiang/linux.git
@@ -21468,7 +21468,6 @@ THE REST
 M:     Linus Torvalds <torvalds@linux-foundation.org>
 L:     linux-kernel@vger.kernel.org
 S:     Buried alive in reporters
-Q:     http://patchwork.kernel.org/project/LKML/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
 F:     *
 F:     */
index daeb5c8..87f6724 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 17
 SUBLEVEL = 0
-EXTRAVERSION = -rc6
+EXTRAVERSION = -rc7
 NAME = Superb Owl
 
 # *DOCUMENTATION*
index 5e55198..54cd373 100644 (file)
        status = "disabled";
 };
 
+/* Unusable as clockevent because if unreliable oscillator, allow to idle */
+&timer1_target {
+       /delete-property/ti,no-reset-on-init;
+       /delete-property/ti,no-idle;
+       timer@0 {
+               /delete-property/ti,timer-alwon;
+       };
+};
+
+/* Preferred timer for clockevent */
+&timer12_target {
+       ti,no-reset-on-init;
+       ti,no-idle;
+       timer@0 {
+               /* Always clocked by secure_32k_fck */
+       };
+};
+
 &twl_gpio {
        ti,use-leds;
        /*
index c2995a2..162d072 100644 (file)
                display2 = &tv0;
        };
 };
-
-/* Unusable as clocksource because of unreliable oscillator */
-&counter32k {
-       status = "disabled";
-};
-
-/* Unusable as clockevent because if unreliable oscillator, allow to idle */
-&timer1_target {
-       /delete-property/ti,no-reset-on-init;
-       /delete-property/ti,no-idle;
-       timer@0 {
-               /delete-property/ti,timer-alwon;
-       };
-};
-
-/* Preferred always-on timer for clocksource */
-&timer12_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               /* Always clocked by secure_32k_fck */
-       };
-};
-
-/* Preferred timer for clockevent */
-&timer2_target {
-       ti,no-reset-on-init;
-       ti,no-idle;
-       timer@0 {
-               assigned-clocks = <&gpt2_fck>;
-               assigned-clock-parents = <&sys_ck>;
-       };
-};
index 8eed9e3..5868eb5 100644 (file)
                interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
                assigned-clocks = <&cru SCLK_HDMI_PHY>;
                assigned-clock-parents = <&hdmi_phy>;
-               clocks = <&cru SCLK_HDMI_HDCP>, <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_CEC>;
-               clock-names = "isfr", "iahb", "cec";
+               clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>, <&cru SCLK_HDMI_CEC>;
+               clock-names = "iahb", "isfr", "cec";
                pinctrl-names = "default";
                pinctrl-0 = <&hdmii2c_xfer &hdmi_hpd &hdmi_cec>;
                resets = <&cru SRST_HDMI_P>;
index aaaa618..45a9d9b 100644 (file)
                status = "disabled";
        };
 
-       crypto: cypto-controller@ff8a0000 {
+       crypto: crypto@ff8a0000 {
                compatible = "rockchip,rk3288-crypto";
                reg = <0x0 0xff8a0000 0x0 0x4000>;
                interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
index 6fe6796..aee73ef 100644 (file)
        .endm
 #endif
 
+#if __LINUX_ARM_ARCH__ < 7
+       .macro  dsb, args
+       mcr     p15, 0, r0, c7, c10, 4
+       .endm
+
+       .macro  isb, args
+       mcr     p15, 0, r0, c7, c5, 4
+       .endm
+#endif
+
        .macro asm_trace_hardirqs_off, save=1
 #if defined(CONFIG_TRACE_IRQFLAGS)
        .if \save
diff --git a/arch/arm/include/asm/spectre.h b/arch/arm/include/asm/spectre.h
new file mode 100644 (file)
index 0000000..d1fa560
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_SPECTRE_H
+#define __ASM_SPECTRE_H
+
+enum {
+       SPECTRE_UNAFFECTED,
+       SPECTRE_MITIGATED,
+       SPECTRE_VULNERABLE,
+};
+
+enum {
+       __SPECTRE_V2_METHOD_BPIALL,
+       __SPECTRE_V2_METHOD_ICIALLU,
+       __SPECTRE_V2_METHOD_SMC,
+       __SPECTRE_V2_METHOD_HVC,
+       __SPECTRE_V2_METHOD_LOOP8,
+};
+
+enum {
+       SPECTRE_V2_METHOD_BPIALL = BIT(__SPECTRE_V2_METHOD_BPIALL),
+       SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
+       SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
+       SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
+       SPECTRE_V2_METHOD_LOOP8 = BIT(__SPECTRE_V2_METHOD_LOOP8),
+};
+
+void spectre_v2_update_state(unsigned int state, unsigned int methods);
+
+int spectre_bhb_update_vectors(unsigned int method);
+
+#endif
index 4a91428..fad45c8 100644 (file)
 #define ARM_MMU_DISCARD(x)     x
 #endif
 
+/*
+ * ld.lld does not support NOCROSSREFS:
+ * https://github.com/ClangBuiltLinux/linux/issues/1609
+ */
+#ifdef CONFIG_LD_IS_LLD
+#define NOCROSSREFS
+#endif
+
+/* Set start/end symbol names to the LMA for the section */
+#define ARM_LMA(sym, section)                                          \
+       sym##_start = LOADADDR(section);                                \
+       sym##_end = LOADADDR(section) + SIZEOF(section)
+
 #define PROC_INFO                                                      \
                . = ALIGN(4);                                           \
                __proc_info_begin = .;                                  \
  * only thing that matters is their relative offsets
  */
 #define ARM_VECTORS                                                    \
-       __vectors_start = .;                                            \
-       .vectors 0xffff0000 : AT(__vectors_start) {                     \
-               *(.vectors)                                             \
+       __vectors_lma = .;                                              \
+       OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) {            \
+               .vectors {                                              \
+                       *(.vectors)                                     \
+               }                                                       \
+               .vectors.bhb.loop8 {                                    \
+                       *(.vectors.bhb.loop8)                           \
+               }                                                       \
+               .vectors.bhb.bpiall {                                   \
+                       *(.vectors.bhb.bpiall)                          \
+               }                                                       \
        }                                                               \
-       . = __vectors_start + SIZEOF(.vectors);                         \
-       __vectors_end = .;                                              \
+       ARM_LMA(__vectors, .vectors);                                   \
+       ARM_LMA(__vectors_bhb_loop8, .vectors.bhb.loop8);               \
+       ARM_LMA(__vectors_bhb_bpiall, .vectors.bhb.bpiall);             \
+       . = __vectors_lma + SIZEOF(.vectors) +                          \
+               SIZEOF(.vectors.bhb.loop8) +                            \
+               SIZEOF(.vectors.bhb.bpiall);                            \
                                                                        \
-       __stubs_start = .;                                              \
-       .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) {            \
+       __stubs_lma = .;                                                \
+       .stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) {              \
                *(.stubs)                                               \
        }                                                               \
-       . = __stubs_start + SIZEOF(.stubs);                             \
-       __stubs_end = .;                                                \
+       ARM_LMA(__stubs, .stubs);                                       \
+       . = __stubs_lma + SIZEOF(.stubs);                               \
                                                                        \
        PROVIDE(vector_fiq_offset = vector_fiq - ADDR(.vectors));
 
index ae295a3..6ef3b53 100644 (file)
@@ -106,4 +106,6 @@ endif
 
 obj-$(CONFIG_HAVE_ARM_SMCCC)   += smccc-call.o
 
+obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += spectre.o
+
 extra-y := $(head-y) vmlinux.lds
index 5cd0578..676703c 100644 (file)
@@ -1002,12 +1002,11 @@ vector_\name:
        sub     lr, lr, #\correction
        .endif
 
-       @
-       @ Save r0, lr_<exception> (parent PC) and spsr_<exception>
-       @ (parent CPSR)
-       @
+       @ Save r0, lr_<exception> (parent PC)
        stmia   sp, {r0, lr}            @ save r0, lr
-       mrs     lr, spsr
+
+       @ Save spsr_<exception> (parent CPSR)
+2:     mrs     lr, spsr
        str     lr, [sp, #8]            @ save spsr
 
        @
@@ -1028,6 +1027,44 @@ vector_\name:
        movs    pc, lr                  @ branch to handler in SVC mode
 ENDPROC(vector_\name)
 
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+       .subsection 1
+       .align 5
+vector_bhb_loop8_\name:
+       .if \correction
+       sub     lr, lr, #\correction
+       .endif
+
+       @ Save r0, lr_<exception> (parent PC)
+       stmia   sp, {r0, lr}
+
+       @ bhb workaround
+       mov     r0, #8
+1:     b       . + 4
+       subs    r0, r0, #1
+       bne     1b
+       dsb
+       isb
+       b       2b
+ENDPROC(vector_bhb_loop8_\name)
+
+vector_bhb_bpiall_\name:
+       .if \correction
+       sub     lr, lr, #\correction
+       .endif
+
+       @ Save r0, lr_<exception> (parent PC)
+       stmia   sp, {r0, lr}
+
+       @ bhb workaround
+       mcr     p15, 0, r0, c7, c5, 6   @ BPIALL
+       @ isb not needed due to "movs pc, lr" in the vector stub
+       @ which gives a "context synchronisation".
+       b       2b
+ENDPROC(vector_bhb_bpiall_\name)
+       .previous
+#endif
+
        .align  2
        @ handler addresses follow this label
 1:
@@ -1036,6 +1073,10 @@ ENDPROC(vector_\name)
        .section .stubs, "ax", %progbits
        @ This must be the first word
        .word   vector_swi
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+       .word   vector_bhb_loop8_swi
+       .word   vector_bhb_bpiall_swi
+#endif
 
 vector_rst:
  ARM(  swi     SYS_ERROR0      )
@@ -1150,8 +1191,10 @@ vector_addrexcptn:
  * FIQ "NMI" handler
  *-----------------------------------------------------------------------------
  * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
- * systems.
+ * systems. This must be the last vector stub, so lets place it in its own
+ * subsection.
  */
+       .subsection 2
        vector_stub     fiq, FIQ_MODE, 4
 
        .long   __fiq_usr                       @  0  (USR_26 / USR_32)
@@ -1184,6 +1227,30 @@ vector_addrexcptn:
        W(b)    vector_irq
        W(b)    vector_fiq
 
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+       .section .vectors.bhb.loop8, "ax", %progbits
+.L__vectors_bhb_loop8_start:
+       W(b)    vector_rst
+       W(b)    vector_bhb_loop8_und
+       W(ldr)  pc, .L__vectors_bhb_loop8_start + 0x1004
+       W(b)    vector_bhb_loop8_pabt
+       W(b)    vector_bhb_loop8_dabt
+       W(b)    vector_addrexcptn
+       W(b)    vector_bhb_loop8_irq
+       W(b)    vector_bhb_loop8_fiq
+
+       .section .vectors.bhb.bpiall, "ax", %progbits
+.L__vectors_bhb_bpiall_start:
+       W(b)    vector_rst
+       W(b)    vector_bhb_bpiall_und
+       W(ldr)  pc, .L__vectors_bhb_bpiall_start + 0x1008
+       W(b)    vector_bhb_bpiall_pabt
+       W(b)    vector_bhb_bpiall_dabt
+       W(b)    vector_addrexcptn
+       W(b)    vector_bhb_bpiall_irq
+       W(b)    vector_bhb_bpiall_fiq
+#endif
+
        .data
        .align  2
 
index ac86c34..dbc1913 100644 (file)
@@ -153,6 +153,29 @@ ENDPROC(ret_from_fork)
  *-----------------------------------------------------------------------------
  */
 
+       .align  5
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+ENTRY(vector_bhb_loop8_swi)
+       sub     sp, sp, #PT_REGS_SIZE
+       stmia   sp, {r0 - r12}
+       mov     r8, #8
+1:     b       2f
+2:     subs    r8, r8, #1
+       bne     1b
+       dsb
+       isb
+       b       3f
+ENDPROC(vector_bhb_loop8_swi)
+
+       .align  5
+ENTRY(vector_bhb_bpiall_swi)
+       sub     sp, sp, #PT_REGS_SIZE
+       stmia   sp, {r0 - r12}
+       mcr     p15, 0, r8, c7, c5, 6   @ BPIALL
+       isb
+       b       3f
+ENDPROC(vector_bhb_bpiall_swi)
+#endif
        .align  5
 ENTRY(vector_swi)
 #ifdef CONFIG_CPU_V7M
@@ -160,6 +183,7 @@ ENTRY(vector_swi)
 #else
        sub     sp, sp, #PT_REGS_SIZE
        stmia   sp, {r0 - r12}                  @ Calling r0 - r12
+3:
  ARM(  add     r8, sp, #S_PC           )
  ARM(  stmdb   r8, {sp, lr}^           )       @ Calling sp, lr
  THUMB(        mov     r8, sp                  )
index 7bd30c0..22f937e 100644 (file)
@@ -154,22 +154,38 @@ static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
        return 0;
 }
 
-static struct undef_hook kgdb_brkpt_hook = {
+static struct undef_hook kgdb_brkpt_arm_hook = {
        .instr_mask             = 0xffffffff,
        .instr_val              = KGDB_BREAKINST,
-       .cpsr_mask              = MODE_MASK,
+       .cpsr_mask              = PSR_T_BIT | MODE_MASK,
        .cpsr_val               = SVC_MODE,
        .fn                     = kgdb_brk_fn
 };
 
-static struct undef_hook kgdb_compiled_brkpt_hook = {
+static struct undef_hook kgdb_brkpt_thumb_hook = {
+       .instr_mask             = 0xffff,
+       .instr_val              = KGDB_BREAKINST & 0xffff,
+       .cpsr_mask              = PSR_T_BIT | MODE_MASK,
+       .cpsr_val               = PSR_T_BIT | SVC_MODE,
+       .fn                     = kgdb_brk_fn
+};
+
+static struct undef_hook kgdb_compiled_brkpt_arm_hook = {
        .instr_mask             = 0xffffffff,
        .instr_val              = KGDB_COMPILED_BREAK,
-       .cpsr_mask              = MODE_MASK,
+       .cpsr_mask              = PSR_T_BIT | MODE_MASK,
        .cpsr_val               = SVC_MODE,
        .fn                     = kgdb_compiled_brk_fn
 };
 
+static struct undef_hook kgdb_compiled_brkpt_thumb_hook = {
+       .instr_mask             = 0xffff,
+       .instr_val              = KGDB_COMPILED_BREAK & 0xffff,
+       .cpsr_mask              = PSR_T_BIT | MODE_MASK,
+       .cpsr_val               = PSR_T_BIT | SVC_MODE,
+       .fn                     = kgdb_compiled_brk_fn
+};
+
 static int __kgdb_notify(struct die_args *args, unsigned long cmd)
 {
        struct pt_regs *regs = args->regs;
@@ -210,8 +226,10 @@ int kgdb_arch_init(void)
        if (ret != 0)
                return ret;
 
-       register_undef_hook(&kgdb_brkpt_hook);
-       register_undef_hook(&kgdb_compiled_brkpt_hook);
+       register_undef_hook(&kgdb_brkpt_arm_hook);
+       register_undef_hook(&kgdb_brkpt_thumb_hook);
+       register_undef_hook(&kgdb_compiled_brkpt_arm_hook);
+       register_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
 
        return 0;
 }
@@ -224,8 +242,10 @@ int kgdb_arch_init(void)
  */
 void kgdb_arch_exit(void)
 {
-       unregister_undef_hook(&kgdb_brkpt_hook);
-       unregister_undef_hook(&kgdb_compiled_brkpt_hook);
+       unregister_undef_hook(&kgdb_brkpt_arm_hook);
+       unregister_undef_hook(&kgdb_brkpt_thumb_hook);
+       unregister_undef_hook(&kgdb_compiled_brkpt_arm_hook);
+       unregister_undef_hook(&kgdb_compiled_brkpt_thumb_hook);
        unregister_die_notifier(&kgdb_notifier);
 }
 
diff --git a/arch/arm/kernel/spectre.c b/arch/arm/kernel/spectre.c
new file mode 100644 (file)
index 0000000..0dcefc3
--- /dev/null
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/bpf.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+
+#include <asm/spectre.h>
+
+static bool _unprivileged_ebpf_enabled(void)
+{
+#ifdef CONFIG_BPF_SYSCALL
+       return !sysctl_unprivileged_bpf_disabled;
+#else
+       return false;
+#endif
+}
+
+ssize_t cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       return sprintf(buf, "Mitigation: __user pointer sanitization\n");
+}
+
+static unsigned int spectre_v2_state;
+static unsigned int spectre_v2_methods;
+
+void spectre_v2_update_state(unsigned int state, unsigned int method)
+{
+       if (state > spectre_v2_state)
+               spectre_v2_state = state;
+       spectre_v2_methods |= method;
+}
+
+ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
+                           char *buf)
+{
+       const char *method;
+
+       if (spectre_v2_state == SPECTRE_UNAFFECTED)
+               return sprintf(buf, "%s\n", "Not affected");
+
+       if (spectre_v2_state != SPECTRE_MITIGATED)
+               return sprintf(buf, "%s\n", "Vulnerable");
+
+       if (_unprivileged_ebpf_enabled())
+               return sprintf(buf, "Vulnerable: Unprivileged eBPF enabled\n");
+
+       switch (spectre_v2_methods) {
+       case SPECTRE_V2_METHOD_BPIALL:
+               method = "Branch predictor hardening";
+               break;
+
+       case SPECTRE_V2_METHOD_ICIALLU:
+               method = "I-cache invalidation";
+               break;
+
+       case SPECTRE_V2_METHOD_SMC:
+       case SPECTRE_V2_METHOD_HVC:
+               method = "Firmware call";
+               break;
+
+       case SPECTRE_V2_METHOD_LOOP8:
+               method = "History overwrite";
+               break;
+
+       default:
+               method = "Multiple mitigations";
+               break;
+       }
+
+       return sprintf(buf, "Mitigation: %s\n", method);
+}
index da04ed8..cae4a74 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/exception.h>
+#include <asm/spectre.h>
 #include <asm/unistd.h>
 #include <asm/traps.h>
 #include <asm/ptrace.h>
@@ -789,10 +790,59 @@ static inline void __init kuser_init(void *vectors)
 }
 #endif
 
+#ifndef CONFIG_CPU_V7M
+static void copy_from_lma(void *vma, void *lma_start, void *lma_end)
+{
+       memcpy(vma, lma_start, lma_end - lma_start);
+}
+
+static void flush_vectors(void *vma, size_t offset, size_t size)
+{
+       unsigned long start = (unsigned long)vma + offset;
+       unsigned long end = start + size;
+
+       flush_icache_range(start, end);
+}
+
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+int spectre_bhb_update_vectors(unsigned int method)
+{
+       extern char __vectors_bhb_bpiall_start[], __vectors_bhb_bpiall_end[];
+       extern char __vectors_bhb_loop8_start[], __vectors_bhb_loop8_end[];
+       void *vec_start, *vec_end;
+
+       if (system_state >= SYSTEM_FREEING_INITMEM) {
+               pr_err("CPU%u: Spectre BHB workaround too late - system vulnerable\n",
+                      smp_processor_id());
+               return SPECTRE_VULNERABLE;
+       }
+
+       switch (method) {
+       case SPECTRE_V2_METHOD_LOOP8:
+               vec_start = __vectors_bhb_loop8_start;
+               vec_end = __vectors_bhb_loop8_end;
+               break;
+
+       case SPECTRE_V2_METHOD_BPIALL:
+               vec_start = __vectors_bhb_bpiall_start;
+               vec_end = __vectors_bhb_bpiall_end;
+               break;
+
+       default:
+               pr_err("CPU%u: unknown Spectre BHB state %d\n",
+                      smp_processor_id(), method);
+               return SPECTRE_VULNERABLE;
+       }
+
+       copy_from_lma(vectors_page, vec_start, vec_end);
+       flush_vectors(vectors_page, 0, vec_end - vec_start);
+
+       return SPECTRE_MITIGATED;
+}
+#endif
+
 void __init early_trap_init(void *vectors_base)
 {
-#ifndef CONFIG_CPU_V7M
-       unsigned long vectors = (unsigned long)vectors_base;
        extern char __stubs_start[], __stubs_end[];
        extern char __vectors_start[], __vectors_end[];
        unsigned i;
@@ -813,17 +863,20 @@ void __init early_trap_init(void *vectors_base)
         * into the vector page, mapped at 0xffff0000, and ensure these
         * are visible to the instruction stream.
         */
-       memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
-       memcpy((void *)vectors + 0x1000, __stubs_start, __stubs_end - __stubs_start);
+       copy_from_lma(vectors_base, __vectors_start, __vectors_end);
+       copy_from_lma(vectors_base + 0x1000, __stubs_start, __stubs_end);
 
        kuser_init(vectors_base);
 
-       flush_icache_range(vectors, vectors + PAGE_SIZE * 2);
+       flush_vectors(vectors_base, 0, PAGE_SIZE * 2);
+}
 #else /* ifndef CONFIG_CPU_V7M */
+void __init early_trap_init(void *vectors_base)
+{
        /*
         * on V7-M there is no need to copy the vector table to a dedicated
         * memory area. The address is configurable and so a table in the kernel
         * image can be used.
         */
-#endif
 }
+#endif
index 58afba3..9724c16 100644 (file)
@@ -830,6 +830,7 @@ config CPU_BPREDICT_DISABLE
 
 config CPU_SPECTRE
        bool
+       select GENERIC_CPU_VULNERABILITIES
 
 config HARDEN_BRANCH_PREDICTOR
        bool "Harden the branch predictor against aliasing attacks" if EXPERT
@@ -850,6 +851,16 @@ config HARDEN_BRANCH_PREDICTOR
 
           If unsure, say Y.
 
+config HARDEN_BRANCH_HISTORY
+       bool "Harden Spectre style attacks against branch history" if EXPERT
+       depends on CPU_SPECTRE
+       default y
+       help
+         Speculation attacks against some high-performance processors can
+         make use of branch history to influence future speculation. When
+         taking an exception, a sequence of branches overwrites the branch
+         history, or branch history is invalidated.
+
 config TLS_REG_EMUL
        bool
        select NEED_KUSER_HELPERS
index 274e4f7..5e2be37 100644 (file)
@@ -212,12 +212,14 @@ early_param("ecc", early_ecc);
 static int __init early_cachepolicy(char *p)
 {
        pr_warn("cachepolicy kernel parameter not supported without cp15\n");
+       return 0;
 }
 early_param("cachepolicy", early_cachepolicy);
 
 static int __init noalign_setup(char *__unused)
 {
        pr_warn("noalign kernel parameter not supported without cp15\n");
+       return 1;
 }
 __setup("noalign", noalign_setup);
 
index 114c05a..06dbfb9 100644 (file)
@@ -6,8 +6,35 @@
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/proc-fns.h>
+#include <asm/spectre.h>
 #include <asm/system_misc.h>
 
+#ifdef CONFIG_ARM_PSCI
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
+{
+       struct arm_smccc_res res;
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+                            ARM_SMCCC_ARCH_WORKAROUND_1, &res);
+
+       switch ((int)res.a0) {
+       case SMCCC_RET_SUCCESS:
+               return SPECTRE_MITIGATED;
+
+       case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+               return SPECTRE_UNAFFECTED;
+
+       default:
+               return SPECTRE_VULNERABLE;
+       }
+}
+#else
+static int __maybe_unused spectre_v2_get_cpu_fw_mitigation_state(void)
+{
+       return SPECTRE_VULNERABLE;
+}
+#endif
+
 #ifdef CONFIG_HARDEN_BRANCH_PREDICTOR
 DEFINE_PER_CPU(harden_branch_predictor_fn_t, harden_branch_predictor_fn);
 
@@ -36,13 +63,61 @@ static void __maybe_unused call_hvc_arch_workaround_1(void)
        arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL);
 }
 
-static void cpu_v7_spectre_init(void)
+static unsigned int spectre_v2_install_workaround(unsigned int method)
 {
        const char *spectre_v2_method = NULL;
        int cpu = smp_processor_id();
 
        if (per_cpu(harden_branch_predictor_fn, cpu))
-               return;
+               return SPECTRE_MITIGATED;
+
+       switch (method) {
+       case SPECTRE_V2_METHOD_BPIALL:
+               per_cpu(harden_branch_predictor_fn, cpu) =
+                       harden_branch_predictor_bpiall;
+               spectre_v2_method = "BPIALL";
+               break;
+
+       case SPECTRE_V2_METHOD_ICIALLU:
+               per_cpu(harden_branch_predictor_fn, cpu) =
+                       harden_branch_predictor_iciallu;
+               spectre_v2_method = "ICIALLU";
+               break;
+
+       case SPECTRE_V2_METHOD_HVC:
+               per_cpu(harden_branch_predictor_fn, cpu) =
+                       call_hvc_arch_workaround_1;
+               cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
+               spectre_v2_method = "hypervisor";
+               break;
+
+       case SPECTRE_V2_METHOD_SMC:
+               per_cpu(harden_branch_predictor_fn, cpu) =
+                       call_smc_arch_workaround_1;
+               cpu_do_switch_mm = cpu_v7_smc_switch_mm;
+               spectre_v2_method = "firmware";
+               break;
+       }
+
+       if (spectre_v2_method)
+               pr_info("CPU%u: Spectre v2: using %s workaround\n",
+                       smp_processor_id(), spectre_v2_method);
+
+       return SPECTRE_MITIGATED;
+}
+#else
+static unsigned int spectre_v2_install_workaround(unsigned int method)
+{
+       pr_info("CPU%u: Spectre V2: workarounds disabled by configuration\n",
+               smp_processor_id());
+
+       return SPECTRE_VULNERABLE;
+}
+#endif
+
+static void cpu_v7_spectre_v2_init(void)
+{
+       unsigned int state, method = 0;
 
        switch (read_cpuid_part()) {
        case ARM_CPU_PART_CORTEX_A8:
@@ -51,69 +126,133 @@ static void cpu_v7_spectre_init(void)
        case ARM_CPU_PART_CORTEX_A17:
        case ARM_CPU_PART_CORTEX_A73:
        case ARM_CPU_PART_CORTEX_A75:
-               per_cpu(harden_branch_predictor_fn, cpu) =
-                       harden_branch_predictor_bpiall;
-               spectre_v2_method = "BPIALL";
+               state = SPECTRE_MITIGATED;
+               method = SPECTRE_V2_METHOD_BPIALL;
                break;
 
        case ARM_CPU_PART_CORTEX_A15:
        case ARM_CPU_PART_BRAHMA_B15:
-               per_cpu(harden_branch_predictor_fn, cpu) =
-                       harden_branch_predictor_iciallu;
-               spectre_v2_method = "ICIALLU";
+               state = SPECTRE_MITIGATED;
+               method = SPECTRE_V2_METHOD_ICIALLU;
                break;
 
-#ifdef CONFIG_ARM_PSCI
        case ARM_CPU_PART_BRAHMA_B53:
                /* Requires no workaround */
+               state = SPECTRE_UNAFFECTED;
                break;
+
        default:
                /* Other ARM CPUs require no workaround */
-               if (read_cpuid_implementor() == ARM_CPU_IMP_ARM)
+               if (read_cpuid_implementor() == ARM_CPU_IMP_ARM) {
+                       state = SPECTRE_UNAFFECTED;
                        break;
+               }
+
                fallthrough;
-               /* Cortex A57/A72 require firmware workaround */
-       case ARM_CPU_PART_CORTEX_A57:
-       case ARM_CPU_PART_CORTEX_A72: {
-               struct arm_smccc_res res;
 
-               arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
-                                    ARM_SMCCC_ARCH_WORKAROUND_1, &res);
-               if ((int)res.a0 != 0)
-                       return;
+       /* Cortex A57/A72 require firmware workaround */
+       case ARM_CPU_PART_CORTEX_A57:
+       case ARM_CPU_PART_CORTEX_A72:
+               state = spectre_v2_get_cpu_fw_mitigation_state();
+               if (state != SPECTRE_MITIGATED)
+                       break;
 
                switch (arm_smccc_1_1_get_conduit()) {
                case SMCCC_CONDUIT_HVC:
-                       per_cpu(harden_branch_predictor_fn, cpu) =
-                               call_hvc_arch_workaround_1;
-                       cpu_do_switch_mm = cpu_v7_hvc_switch_mm;
-                       spectre_v2_method = "hypervisor";
+                       method = SPECTRE_V2_METHOD_HVC;
                        break;
 
                case SMCCC_CONDUIT_SMC:
-                       per_cpu(harden_branch_predictor_fn, cpu) =
-                               call_smc_arch_workaround_1;
-                       cpu_do_switch_mm = cpu_v7_smc_switch_mm;
-                       spectre_v2_method = "firmware";
+                       method = SPECTRE_V2_METHOD_SMC;
                        break;
 
                default:
+                       state = SPECTRE_VULNERABLE;
                        break;
                }
        }
-#endif
+
+       if (state == SPECTRE_MITIGATED)
+               state = spectre_v2_install_workaround(method);
+
+       spectre_v2_update_state(state, method);
+}
+
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
+static int spectre_bhb_method;
+
+static const char *spectre_bhb_method_name(int method)
+{
+       switch (method) {
+       case SPECTRE_V2_METHOD_LOOP8:
+               return "loop";
+
+       case SPECTRE_V2_METHOD_BPIALL:
+               return "BPIALL";
+
+       default:
+               return "unknown";
        }
+}
 
-       if (spectre_v2_method)
-               pr_info("CPU%u: Spectre v2: using %s workaround\n",
-                       smp_processor_id(), spectre_v2_method);
+static int spectre_bhb_install_workaround(int method)
+{
+       if (spectre_bhb_method != method) {
+               if (spectre_bhb_method) {
+                       pr_err("CPU%u: Spectre BHB: method disagreement, system vulnerable\n",
+                              smp_processor_id());
+
+                       return SPECTRE_VULNERABLE;
+               }
+
+               if (spectre_bhb_update_vectors(method) == SPECTRE_VULNERABLE)
+                       return SPECTRE_VULNERABLE;
+
+               spectre_bhb_method = method;
+       }
+
+       pr_info("CPU%u: Spectre BHB: using %s workaround\n",
+               smp_processor_id(), spectre_bhb_method_name(method));
+
+       return SPECTRE_MITIGATED;
 }
 #else
-static void cpu_v7_spectre_init(void)
+static int spectre_bhb_install_workaround(int method)
 {
+       return SPECTRE_VULNERABLE;
 }
 #endif
 
+static void cpu_v7_spectre_bhb_init(void)
+{
+       unsigned int state, method = 0;
+
+       switch (read_cpuid_part()) {
+       case ARM_CPU_PART_CORTEX_A15:
+       case ARM_CPU_PART_BRAHMA_B15:
+       case ARM_CPU_PART_CORTEX_A57:
+       case ARM_CPU_PART_CORTEX_A72:
+               state = SPECTRE_MITIGATED;
+               method = SPECTRE_V2_METHOD_LOOP8;
+               break;
+
+       case ARM_CPU_PART_CORTEX_A73:
+       case ARM_CPU_PART_CORTEX_A75:
+               state = SPECTRE_MITIGATED;
+               method = SPECTRE_V2_METHOD_BPIALL;
+               break;
+
+       default:
+               state = SPECTRE_UNAFFECTED;
+               break;
+       }
+
+       if (state == SPECTRE_MITIGATED)
+               state = spectre_bhb_install_workaround(method);
+
+       spectre_v2_update_state(state, method);
+}
+
 static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
                                                  u32 mask, const char *msg)
 {
@@ -142,16 +281,17 @@ static bool check_spectre_auxcr(bool *warned, u32 bit)
 void cpu_v7_ca8_ibe(void)
 {
        if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(6)))
-               cpu_v7_spectre_init();
+               cpu_v7_spectre_v2_init();
 }
 
 void cpu_v7_ca15_ibe(void)
 {
        if (check_spectre_auxcr(this_cpu_ptr(&spectre_warned), BIT(0)))
-               cpu_v7_spectre_init();
+               cpu_v7_spectre_v2_init();
 }
 
 void cpu_v7_bugs_init(void)
 {
-       cpu_v7_spectre_init();
+       cpu_v7_spectre_v2_init();
+       cpu_v7_spectre_bhb_init();
 }
index 09b885c..c842878 100644 (file)
@@ -1252,9 +1252,6 @@ config HW_PERF_EVENTS
        def_bool y
        depends on ARM_PMU
 
-config ARCH_HAS_FILTER_PGPROT
-       def_bool y
-
 # Supported by clang >= 7.0
 config CC_HAVE_SHADOW_CALL_STACK
        def_bool $(cc-option, -fsanitize=shadow-call-stack -ffixed-x18)
@@ -1383,6 +1380,15 @@ config UNMAP_KERNEL_AT_EL0
 
          If unsure, say Y.
 
+config MITIGATE_SPECTRE_BRANCH_HISTORY
+       bool "Mitigate Spectre style attacks against branch history" if EXPERT
+       default y
+       help
+         Speculation attacks against some high-performance processors can
+         make use of branch history to influence future speculation.
+         When taking an exception from user-space, a sequence of branches
+         or a firmware call overwrites the branch history.
+
 config RODATA_FULL_DEFAULT_ENABLED
        bool "Apply r/o permissions of VM areas also to their linear aliases"
        default y
index 6288e10..a2635b1 100644 (file)
                         <0x02000000 0x00 0x50000000 0x00 0x50000000 0x0 0x08000000>,
                         <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>;
                /* Standard AXI Translation entries as programmed by EDK2 */
-               dma-ranges = <0x02000000 0x0 0x2c1c0000 0x0 0x2c1c0000 0x0 0x00040000>,
-                            <0x02000000 0x0 0x80000000 0x0 0x80000000 0x0 0x80000000>,
+               dma-ranges = <0x02000000 0x0 0x80000000 0x0 0x80000000 0x0 0x80000000>,
                             <0x43000000 0x8 0x00000000 0x8 0x00000000 0x2 0x00000000>;
                #interrupt-cells = <1>;
                interrupt-map-mask = <0 0 0 7>;
index f77f90e..0c7a72c 100644 (file)
                                                clocks = <&clk IMX8MM_CLK_VPU_DEC_ROOT>;
                                                assigned-clocks = <&clk IMX8MM_CLK_VPU_BUS>;
                                                assigned-clock-parents = <&clk IMX8MM_SYS_PLL1_800M>;
-                                               resets = <&src IMX8MQ_RESET_VPU_RESET>;
                                        };
 
                                        pgc_vpu_g1: power-domain@7 {
index a987ff7..09f7364 100644 (file)
 
                        scmi_sensor: protocol@15 {
                                reg = <0x15>;
-                               #thermal-sensor-cells = <0>;
+                               #thermal-sensor-cells = <1>;
                        };
                };
        };
index 0dd2d2e..f4270cf 100644 (file)
                };
 
                usb0: usb@ffb00000 {
-                       compatible = "snps,dwc2";
+                       compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
                        reg = <0xffb00000 0x40000>;
                        interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
                        phys = <&usbphy0>;
                };
 
                usb1: usb@ffb40000 {
-                       compatible = "snps,dwc2";
+                       compatible = "intel,socfpga-agilex-hsotg", "snps,dwc2";
                        reg = <0xffb40000 0x40000>;
                        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
                        phys = <&usbphy0>;
index f972704..56dfbb2 100644 (file)
                clock-names = "pclk", "timer";
        };
 
-       dmac: dmac@ff240000 {
+       dmac: dma-controller@ff240000 {
                compatible = "arm,pl330", "arm,primecell";
                reg = <0x0 0xff240000 0x0 0x4000>;
                interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>,
index 39db0b8..b822533 100644 (file)
                status = "disabled";
        };
 
-       dmac: dmac@ff1f0000 {
+       dmac: dma-controller@ff1f0000 {
                compatible = "arm,pl330", "arm,primecell";
                reg = <0x0 0xff1f0000 0x0 0x4000>;
                interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>,
index 45a5ae5..162f08b 100644 (file)
 
        sound: sound {
                compatible = "rockchip,rk3399-gru-sound";
-               rockchip,cpu = <&i2s0 &i2s2>;
+               rockchip,cpu = <&i2s0 &spdif>;
        };
 };
 
@@ -437,10 +437,6 @@ ap_i2c_audio: &i2c8 {
        status = "okay";
 };
 
-&i2s2 {
-       status = "okay";
-};
-
 &io_domains {
        status = "okay";
 
@@ -537,6 +533,17 @@ ap_i2c_audio: &i2c8 {
        vqmmc-supply = <&ppvar_sd_card_io>;
 };
 
+&spdif {
+       status = "okay";
+
+       /*
+        * SPDIF is routed internally to DP; we either don't use these pins, or
+        * mux them to something else.
+        */
+       /delete-property/ pinctrl-0;
+       /delete-property/ pinctrl-names;
+};
+
 &spi1 {
        status = "okay";
 
index 292bb7e..3ae5d72 100644 (file)
 
 &usbdrd_dwc3_0 {
        dr_mode = "otg";
+       extcon = <&extcon_usb3>;
        status = "okay";
 };
 
index fb67db4..08fa003 100644 (file)
                };
        };
 
+       extcon_usb3: extcon-usb3 {
+               compatible = "linux,extcon-usb-gpio";
+               id-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&usb3_id>;
+       };
+
        clkin_gmac: external-gmac-clock {
                compatible = "fixed-clock";
                clock-frequency = <125000000>;
                          <4 RK_PA3 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
+
+       usb3 {
+               usb3_id: usb3-id {
+                       rockchip,pins =
+                         <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
 };
 
 &sdhci {
+       /*
+        * Signal integrity isn't great at 200MHz but 100MHz has proven stable
+        * enough.
+        */
+       max-frequency = <100000000>;
+
        bus-width = <8>;
        mmc-hs400-1_8v;
        mmc-hs400-enhanced-strobe;
index d3cdf6f..080457a 100644 (file)
                interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH 0>;
                clocks = <&cru PCLK_HDMI_CTRL>,
                         <&cru SCLK_HDMI_SFR>,
-                        <&cru PLL_VPLL>,
+                        <&cru SCLK_HDMI_CEC>,
                         <&cru PCLK_VIO_GRF>,
-                        <&cru SCLK_HDMI_CEC>;
-               clock-names = "iahb", "isfr", "vpll", "grf", "cec";
+                        <&cru PLL_VPLL>;
+               clock-names = "iahb", "isfr", "cec", "grf", "vpll";
                power-domains = <&power RK3399_PD_HDCP>;
                reg-io-width = <4>;
                rockchip,grf = <&grf>;
index 166399b..d9eb92d 100644 (file)
                        vcc_ddr: DCDC_REG3 {
                                regulator-always-on;
                                regulator-boot-on;
-                               regulator-min-microvolt = <1100000>;
-                               regulator-max-microvolt = <1100000>;
                                regulator-initial-mode = <0x2>;
                                regulator-name = "vcc_ddr";
                                regulator-state-mem {
index 2fd313a..d91df1c 100644 (file)
                clocks = <&cru SCLK_GMAC0>, <&cru SCLK_GMAC0_RX_TX>,
                         <&cru SCLK_GMAC0_RX_TX>, <&cru CLK_MAC0_REFOUT>,
                         <&cru ACLK_GMAC0>, <&cru PCLK_GMAC0>,
-                        <&cru SCLK_GMAC0_RX_TX>, <&cru CLK_GMAC0_PTP_REF>,
-                        <&cru PCLK_XPCS>;
+                        <&cru SCLK_GMAC0_RX_TX>, <&cru CLK_GMAC0_PTP_REF>;
                clock-names = "stmmaceth", "mac_clk_rx",
                              "mac_clk_tx", "clk_mac_refout",
                              "aclk_mac", "pclk_mac",
-                             "clk_mac_speed", "ptp_ref",
-                             "pclk_xpcs";
+                             "clk_mac_speed", "ptp_ref";
                resets = <&cru SRST_A_GMAC0>;
                reset-names = "stmmaceth";
                rockchip,grf = <&grf>;
index a68033a..8ccce54 100644 (file)
                status = "disabled";
        };
 
-       dmac0: dmac@fe530000 {
+       dmac0: dma-controller@fe530000 {
                compatible = "arm,pl330", "arm,primecell";
                reg = <0x0 0xfe530000 0x0 0x4000>;
                interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>,
                #dma-cells = <1>;
        };
 
-       dmac1: dmac@fe550000 {
+       dmac1: dma-controller@fe550000 {
                compatible = "arm,pl330", "arm,primecell";
                reg = <0x0 0xfe550000 0x0 0x4000>;
                interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>,
index e8bd0af..6ebdc0f 100644 (file)
        hint    #20
        .endm
 
+/*
+ * Clear Branch History instruction
+ */
+       .macro clearbhb
+       hint    #22
+       .endm
+
 /*
  * Speculation barrier
  */
@@ -850,4 +857,50 @@ alternative_endif
 
 #endif /* GNU_PROPERTY_AARCH64_FEATURE_1_DEFAULT */
 
+       .macro __mitigate_spectre_bhb_loop      tmp
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+alternative_cb  spectre_bhb_patch_loop_iter
+       mov     \tmp, #32               // Patched to correct the immediate
+alternative_cb_end
+.Lspectre_bhb_loop\@:
+       b       . + 4
+       subs    \tmp, \tmp, #1
+       b.ne    .Lspectre_bhb_loop\@
+       sb
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       .endm
+
+       .macro mitigate_spectre_bhb_loop        tmp
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+alternative_cb spectre_bhb_patch_loop_mitigation_enable
+       b       .L_spectre_bhb_loop_done\@      // Patched to NOP
+alternative_cb_end
+       __mitigate_spectre_bhb_loop     \tmp
+.L_spectre_bhb_loop_done\@:
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       .endm
+
+       /* Save/restores x0-x3 to the stack */
+       .macro __mitigate_spectre_bhb_fw
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+       stp     x0, x1, [sp, #-16]!
+       stp     x2, x3, [sp, #-16]!
+       mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_3
+alternative_cb smccc_patch_fw_mitigation_conduit
+       nop                                     // Patched to SMC/HVC #0
+alternative_cb_end
+       ldp     x2, x3, [sp], #16
+       ldp     x0, x1, [sp], #16
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       .endm
+
+       .macro mitigate_spectre_bhb_clear_insn
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+alternative_cb spectre_bhb_patch_clearbhb
+       /* Patched to NOP when not supported */
+       clearbhb
+       isb
+alternative_cb_end
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       .endm
 #endif /* __ASM_ASSEMBLER_H */
index ef6be92..a77b5f4 100644 (file)
@@ -637,6 +637,35 @@ static inline bool cpu_supports_mixed_endian_el0(void)
        return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
 }
 
+
+static inline bool supports_csv2p3(int scope)
+{
+       u64 pfr0;
+       u8 csv2_val;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               pfr0 = read_sysreg_s(SYS_ID_AA64PFR0_EL1);
+       else
+               pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
+
+       csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
+                                                       ID_AA64PFR0_CSV2_SHIFT);
+       return csv2_val == 3;
+}
+
+static inline bool supports_clearbhb(int scope)
+{
+       u64 isar2;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               isar2 = read_sysreg_s(SYS_ID_AA64ISAR2_EL1);
+       else
+               isar2 = read_sanitised_ftr_reg(SYS_ID_AA64ISAR2_EL1);
+
+       return cpuid_feature_extract_unsigned_field(isar2,
+                                                   ID_AA64ISAR2_CLEARBHB_SHIFT);
+}
+
 const struct cpumask *system_32bit_el0_cpumask(void);
 DECLARE_STATIC_KEY_FALSE(arm64_mismatched_32bit_el0);
 
index 999b914..bfbf0c4 100644 (file)
 #define ARM_CPU_PART_CORTEX_A76                0xD0B
 #define ARM_CPU_PART_NEOVERSE_N1       0xD0C
 #define ARM_CPU_PART_CORTEX_A77                0xD0D
+#define ARM_CPU_PART_NEOVERSE_V1       0xD40
+#define ARM_CPU_PART_CORTEX_A78                0xD41
+#define ARM_CPU_PART_CORTEX_X1         0xD44
 #define ARM_CPU_PART_CORTEX_A510       0xD46
 #define ARM_CPU_PART_CORTEX_A710       0xD47
 #define ARM_CPU_PART_CORTEX_X2         0xD48
 #define ARM_CPU_PART_NEOVERSE_N2       0xD49
+#define ARM_CPU_PART_CORTEX_A78C       0xD4B
 
 #define APM_CPU_PART_POTENZA           0x000
 
 #define MIDR_CORTEX_A76        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A76)
 #define MIDR_NEOVERSE_N1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N1)
 #define MIDR_CORTEX_A77        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A77)
+#define MIDR_NEOVERSE_V1       MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_V1)
+#define MIDR_CORTEX_A78        MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78)
+#define MIDR_CORTEX_X1 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X1)
 #define MIDR_CORTEX_A510 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A510)
 #define MIDR_CORTEX_A710 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A710)
 #define MIDR_CORTEX_X2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_X2)
 #define MIDR_NEOVERSE_N2 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_NEOVERSE_N2)
+#define MIDR_CORTEX_A78C       MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A78C)
 #define MIDR_THUNDERX  MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX)
 #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX)
 #define MIDR_THUNDERX_83XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_83XX)
index 4335800..daff882 100644 (file)
@@ -62,9 +62,11 @@ enum fixed_addresses {
 #endif /* CONFIG_ACPI_APEI_GHES */
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+       FIX_ENTRY_TRAMP_TEXT3,
+       FIX_ENTRY_TRAMP_TEXT2,
+       FIX_ENTRY_TRAMP_TEXT1,
        FIX_ENTRY_TRAMP_DATA,
-       FIX_ENTRY_TRAMP_TEXT,
-#define TRAMP_VALIAS           (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT))
+#define TRAMP_VALIAS           (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT1))
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
        __end_of_permanent_fixed_addresses,
 
index 6b776c8..b02f0c3 100644 (file)
@@ -65,6 +65,7 @@ enum aarch64_insn_hint_cr_op {
        AARCH64_INSN_HINT_PSB  = 0x11 << 5,
        AARCH64_INSN_HINT_TSB  = 0x12 << 5,
        AARCH64_INSN_HINT_CSDB = 0x14 << 5,
+       AARCH64_INSN_HINT_CLEARBHB = 0x16 << 5,
 
        AARCH64_INSN_HINT_BTI   = 0x20 << 5,
        AARCH64_INSN_HINT_BTIC  = 0x22 << 5,
index 5bc01e6..031e3a2 100644 (file)
@@ -714,6 +714,11 @@ static inline void kvm_init_host_cpu_context(struct kvm_cpu_context *cpu_ctxt)
        ctxt_sys_reg(cpu_ctxt, MPIDR_EL1) = read_cpuid_mpidr();
 }
 
+static inline bool kvm_system_needs_idmapped_vectors(void)
+{
+       return cpus_have_const_cap(ARM64_SPECTRE_V3A);
+}
+
 void kvm_arm_vcpu_ptrauth_trap(struct kvm_vcpu *vcpu);
 
 static inline void kvm_arch_hardware_unsetup(void) {}
index e4704a4..a857bca 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef __ASM_MTE_KASAN_H
 #define __ASM_MTE_KASAN_H
 
+#include <asm/compiler.h>
 #include <asm/mte-def.h>
 
 #ifndef __ASSEMBLY__
index 7032f04..b1e1b74 100644 (file)
@@ -92,7 +92,7 @@ extern bool arm64_use_ng_mappings;
 #define __P001  PAGE_READONLY
 #define __P010  PAGE_READONLY
 #define __P011  PAGE_READONLY
-#define __P100  PAGE_EXECONLY
+#define __P100  PAGE_READONLY_EXEC     /* PAGE_EXECONLY if Enhanced PAN */
 #define __P101  PAGE_READONLY_EXEC
 #define __P110  PAGE_READONLY_EXEC
 #define __P111  PAGE_READONLY_EXEC
@@ -101,7 +101,7 @@ extern bool arm64_use_ng_mappings;
 #define __S001  PAGE_READONLY
 #define __S010  PAGE_SHARED
 #define __S011  PAGE_SHARED
-#define __S100  PAGE_EXECONLY
+#define __S100  PAGE_READONLY_EXEC     /* PAGE_EXECONLY if Enhanced PAN */
 #define __S101  PAGE_READONLY_EXEC
 #define __S110  PAGE_SHARED_EXEC
 #define __S111  PAGE_SHARED_EXEC
index c4ba047..94e147e 100644 (file)
@@ -1017,17 +1017,6 @@ static inline bool arch_wants_old_prefaulted_pte(void)
 }
 #define arch_wants_old_prefaulted_pte  arch_wants_old_prefaulted_pte
 
-static inline pgprot_t arch_filter_pgprot(pgprot_t prot)
-{
-       if (cpus_have_const_cap(ARM64_HAS_EPAN))
-               return prot;
-
-       if (pgprot_val(prot) != pgprot_val(PAGE_EXECONLY))
-               return prot;
-
-       return PAGE_READONLY_EXEC;
-}
-
 static inline bool pud_sect_supported(void)
 {
        return PAGE_SIZE == SZ_4K;
index 1bce62f..56f7b1d 100644 (file)
@@ -5,7 +5,7 @@
 #ifndef __ASM_RWONCE_H
 #define __ASM_RWONCE_H
 
-#ifdef CONFIG_LTO
+#if defined(CONFIG_LTO) && !defined(__ASSEMBLY__)
 
 #include <linux/compiler_types.h>
 #include <asm/alternative-macros.h>
@@ -66,7 +66,7 @@
 })
 
 #endif /* !BUILD_VDSO */
-#endif /* CONFIG_LTO */
+#endif /* CONFIG_LTO && !__ASSEMBLY__ */
 
 #include <asm-generic/rwonce.h>
 
index 152cb35..40971ac 100644 (file)
@@ -23,4 +23,9 @@ extern char __mmuoff_data_start[], __mmuoff_data_end[];
 extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
 extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
 
+static inline size_t entry_tramp_text_size(void)
+{
+       return __entry_tramp_text_end - __entry_tramp_text_start;
+}
+
 #endif /* __ASM_SECTIONS_H */
index f62ca39..86e0cc9 100644 (file)
@@ -93,5 +93,9 @@ void spectre_v4_enable_task_mitigation(struct task_struct *tsk);
 
 enum mitigation_state arm64_get_meltdown_state(void);
 
+enum mitigation_state arm64_get_spectre_bhb_state(void);
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry, int scope);
+u8 spectre_bhb_loop_affected(int scope);
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *__unused);
 #endif /* __ASSEMBLY__ */
 #endif /* __ASM_SPECTRE_H */
index 898bee0..932d45b 100644 (file)
 #define ID_AA64ISAR1_GPI_IMP_DEF               0x1
 
 /* id_aa64isar2 */
+#define ID_AA64ISAR2_CLEARBHB_SHIFT    28
 #define ID_AA64ISAR2_RPRES_SHIFT       4
 #define ID_AA64ISAR2_WFXT_SHIFT                0
 
 #endif
 
 /* id_aa64mmfr1 */
+#define ID_AA64MMFR1_ECBHB_SHIFT       60
 #define ID_AA64MMFR1_AFP_SHIFT         44
 #define ID_AA64MMFR1_ETS_SHIFT         36
 #define ID_AA64MMFR1_TWED_SHIFT                32
diff --git a/arch/arm64/include/asm/vectors.h b/arch/arm64/include/asm/vectors.h
new file mode 100644 (file)
index 0000000..f64613a
--- /dev/null
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2022 ARM Ltd.
+ */
+#ifndef __ASM_VECTORS_H
+#define __ASM_VECTORS_H
+
+#include <linux/bug.h>
+#include <linux/percpu.h>
+
+#include <asm/fixmap.h>
+
+extern char vectors[];
+extern char tramp_vectors[];
+extern char __bp_harden_el1_vectors[];
+
+/*
+ * Note: the order of this enum corresponds to two arrays in entry.S:
+ * tramp_vecs and __bp_harden_el1_vectors. By default the canonical
+ * 'full fat' vectors are used directly.
+ */
+enum arm64_bp_harden_el1_vectors {
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+       /*
+        * Perform the BHB loop mitigation, before branching to the canonical
+        * vectors.
+        */
+       EL1_VECTOR_BHB_LOOP,
+
+       /*
+        * Make the SMC call for firmware mitigation, before branching to the
+        * canonical vectors.
+        */
+       EL1_VECTOR_BHB_FW,
+
+       /*
+        * Use the ClearBHB instruction, before branching to the canonical
+        * vectors.
+        */
+       EL1_VECTOR_BHB_CLEAR_INSN,
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+
+       /*
+        * Remap the kernel before branching to the canonical vectors.
+        */
+       EL1_VECTOR_KPTI,
+};
+
+#ifndef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+#define EL1_VECTOR_BHB_LOOP            -1
+#define EL1_VECTOR_BHB_FW              -1
+#define EL1_VECTOR_BHB_CLEAR_INSN      -1
+#endif /* !CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+
+/* The vectors to use on return from EL0. e.g. to remap the kernel */
+DECLARE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector);
+
+#ifndef CONFIG_UNMAP_KERNEL_AT_EL0
+#define TRAMP_VALIAS   0
+#endif
+
+static inline const char *
+arm64_get_bp_hardening_vector(enum arm64_bp_harden_el1_vectors slot)
+{
+       if (arm64_kernel_unmapped_at_el0())
+               return (char *)TRAMP_VALIAS + SZ_2K * slot;
+
+       WARN_ON_ONCE(slot == EL1_VECTOR_KPTI);
+
+       return __bp_harden_el1_vectors + SZ_2K * slot;
+}
+
+#endif /* __ASM_VECTORS_H */
index b3edde6..323e251 100644 (file)
@@ -281,6 +281,11 @@ struct kvm_arm_copy_mte_tags {
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_REQUIRED       3
 #define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_ENABLED            (1U << 4)
 
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3    KVM_REG_ARM_FW_REG(3)
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL          0
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL              1
+#define KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED       2
+
 /* SVE registers */
 #define KVM_REG_ARM64_SVE              (0x15 << KVM_REG_ARM_COPROC_SHIFT)
 
index b217941..a401180 100644 (file)
@@ -502,6 +502,13 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
                .matches = has_spectre_v4,
                .cpu_enable = spectre_v4_enable_mitigation,
        },
+       {
+               .desc = "Spectre-BHB",
+               .capability = ARM64_SPECTRE_BHB,
+               .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
+               .matches = is_spectre_bhb_affected,
+               .cpu_enable = spectre_bhb_enable_mitigation,
+       },
 #ifdef CONFIG_ARM64_ERRATUM_1418040
        {
                .desc = "ARM erratum 1418040",
index e5f23da..d336876 100644 (file)
@@ -73,6 +73,8 @@
 #include <linux/mm.h>
 #include <linux/cpu.h>
 #include <linux/kasan.h>
+#include <linux/percpu.h>
+
 #include <asm/cpu.h>
 #include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
@@ -85,6 +87,7 @@
 #include <asm/smp.h>
 #include <asm/sysreg.h>
 #include <asm/traps.h>
+#include <asm/vectors.h>
 #include <asm/virt.h>
 
 /* Kernel representation of AT_HWCAP and AT_HWCAP2 */
@@ -110,6 +113,8 @@ DECLARE_BITMAP(boot_capabilities, ARM64_NPATCHABLE);
 bool arm64_use_ng_mappings = false;
 EXPORT_SYMBOL(arm64_use_ng_mappings);
 
+DEFINE_PER_CPU_READ_MOSTLY(const char *, this_cpu_vector) = vectors;
+
 /*
  * Permit PER_LINUX32 and execve() of 32-bit binaries even if not all CPUs
  * support it?
@@ -226,6 +231,7 @@ static const struct arm64_ftr_bits ftr_id_aa64isar1[] = {
 };
 
 static const struct arm64_ftr_bits ftr_id_aa64isar2[] = {
+       ARM64_FTR_BITS(FTR_HIDDEN, FTR_STRICT, FTR_HIGHER_SAFE, ID_AA64ISAR2_CLEARBHB_SHIFT, 4, 0),
        ARM64_FTR_BITS(FTR_VISIBLE, FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64ISAR2_RPRES_SHIFT, 4, 0),
        ARM64_FTR_END,
 };
@@ -1590,6 +1596,12 @@ kpti_install_ng_mappings(const struct arm64_cpu_capabilities *__unused)
 
        int cpu = smp_processor_id();
 
+       if (__this_cpu_read(this_cpu_vector) == vectors) {
+               const char *v = arm64_get_bp_hardening_vector(EL1_VECTOR_KPTI);
+
+               __this_cpu_write(this_cpu_vector, v);
+       }
+
        /*
         * We don't need to rewrite the page-tables if either we've done
         * it already or we have KASLR enabled and therefore have not
index 772ec2e..4a3a653 100644 (file)
 
        .macro kernel_ventry, el:req, ht:req, regsize:req, label:req
        .align 7
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+.Lventry_start\@:
        .if     \el == 0
-alternative_if ARM64_UNMAP_KERNEL_AT_EL0
+       /*
+        * This must be the first instruction of the EL0 vector entries. It is
+        * skipped by the trampoline vectors, to trigger the cleanup.
+        */
+       b       .Lskip_tramp_vectors_cleanup\@
        .if     \regsize == 64
        mrs     x30, tpidrro_el0
        msr     tpidrro_el0, xzr
        .else
        mov     x30, xzr
        .endif
-alternative_else_nop_endif
+.Lskip_tramp_vectors_cleanup\@:
        .endif
-#endif
 
        sub     sp, sp, #PT_REGS_SIZE
 #ifdef CONFIG_VMAP_STACK
@@ -95,11 +98,15 @@ alternative_else_nop_endif
        mrs     x0, tpidrro_el0
 #endif
        b       el\el\ht\()_\regsize\()_\label
+.org .Lventry_start\@ + 128    // Did we overflow the ventry slot?
        .endm
 
-       .macro tramp_alias, dst, sym
+       .macro tramp_alias, dst, sym, tmp
        mov_q   \dst, TRAMP_VALIAS
-       add     \dst, \dst, #(\sym - .entry.tramp.text)
+       adr_l   \tmp, \sym
+       add     \dst, \dst, \tmp
+       adr_l   \tmp, .entry.tramp.text
+       sub     \dst, \dst, \tmp
        .endm
 
        /*
@@ -116,7 +123,7 @@ alternative_cb_end
        tbnz    \tmp2, #TIF_SSBD, .L__asm_ssbd_skip\@
        mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_2
        mov     w1, #\state
-alternative_cb spectre_v4_patch_fw_mitigation_conduit
+alternative_cb smccc_patch_fw_mitigation_conduit
        nop                                     // Patched to SMC/HVC #0
 alternative_cb_end
 .L__asm_ssbd_skip\@:
@@ -413,21 +420,26 @@ alternative_else_nop_endif
        ldp     x24, x25, [sp, #16 * 12]
        ldp     x26, x27, [sp, #16 * 13]
        ldp     x28, x29, [sp, #16 * 14]
-       ldr     lr, [sp, #S_LR]
-       add     sp, sp, #PT_REGS_SIZE           // restore sp
 
        .if     \el == 0
-alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0
+alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
+       ldr     lr, [sp, #S_LR]
+       add     sp, sp, #PT_REGS_SIZE           // restore sp
+       eret
+alternative_else_nop_endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
        bne     4f
-       msr     far_el1, x30
-       tramp_alias     x30, tramp_exit_native
+       msr     far_el1, x29
+       tramp_alias     x30, tramp_exit_native, x29
        br      x30
 4:
-       tramp_alias     x30, tramp_exit_compat
+       tramp_alias     x30, tramp_exit_compat, x29
        br      x30
 #endif
        .else
+       ldr     lr, [sp, #S_LR]
+       add     sp, sp, #PT_REGS_SIZE           // restore sp
+
        /* Ensure any device/NC reads complete */
        alternative_insn nop, "dmb sy", ARM64_WORKAROUND_1508412
 
@@ -594,12 +606,6 @@ SYM_CODE_END(ret_to_user)
 
        .popsection                             // .entry.text
 
-#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-/*
- * Exception vectors trampoline.
- */
-       .pushsection ".entry.tramp.text", "ax"
-
        // Move from tramp_pg_dir to swapper_pg_dir
        .macro tramp_map_kernel, tmp
        mrs     \tmp, ttbr1_el1
@@ -633,12 +639,47 @@ alternative_else_nop_endif
         */
        .endm
 
-       .macro tramp_ventry, regsize = 64
+       .macro tramp_data_page  dst
+       adr_l   \dst, .entry.tramp.text
+       sub     \dst, \dst, PAGE_SIZE
+       .endm
+
+       .macro tramp_data_read_var      dst, var
+#ifdef CONFIG_RANDOMIZE_BASE
+       tramp_data_page         \dst
+       add     \dst, \dst, #:lo12:__entry_tramp_data_\var
+       ldr     \dst, [\dst]
+#else
+       ldr     \dst, =\var
+#endif
+       .endm
+
+#define BHB_MITIGATION_NONE    0
+#define BHB_MITIGATION_LOOP    1
+#define BHB_MITIGATION_FW      2
+#define BHB_MITIGATION_INSN    3
+
+       .macro tramp_ventry, vector_start, regsize, kpti, bhb
        .align  7
 1:
        .if     \regsize == 64
        msr     tpidrro_el0, x30        // Restored in kernel_ventry
        .endif
+
+       .if     \bhb == BHB_MITIGATION_LOOP
+       /*
+        * This sequence must appear before the first indirect branch. i.e. the
+        * ret out of tramp_ventry. It appears here because x30 is free.
+        */
+       __mitigate_spectre_bhb_loop     x30
+       .endif // \bhb == BHB_MITIGATION_LOOP
+
+       .if     \bhb == BHB_MITIGATION_INSN
+       clearbhb
+       isb
+       .endif // \bhb == BHB_MITIGATION_INSN
+
+       .if     \kpti == 1
        /*
         * Defend against branch aliasing attacks by pushing a dummy
         * entry onto the return stack and using a RET instruction to
@@ -648,46 +689,75 @@ alternative_else_nop_endif
        b       .
 2:
        tramp_map_kernel        x30
-#ifdef CONFIG_RANDOMIZE_BASE
-       adr     x30, tramp_vectors + PAGE_SIZE
 alternative_insn isb, nop, ARM64_WORKAROUND_QCOM_FALKOR_E1003
-       ldr     x30, [x30]
-#else
-       ldr     x30, =vectors
-#endif
+       tramp_data_read_var     x30, vectors
 alternative_if_not ARM64_WORKAROUND_CAVIUM_TX2_219_PRFM
-       prfm    plil1strm, [x30, #(1b - tramp_vectors)]
+       prfm    plil1strm, [x30, #(1b - \vector_start)]
 alternative_else_nop_endif
+
        msr     vbar_el1, x30
-       add     x30, x30, #(1b - tramp_vectors)
        isb
+       .else
+       ldr     x30, =vectors
+       .endif // \kpti == 1
+
+       .if     \bhb == BHB_MITIGATION_FW
+       /*
+        * The firmware sequence must appear before the first indirect branch.
+        * i.e. the ret out of tramp_ventry. But it also needs the stack to be
+        * mapped to save/restore the registers the SMC clobbers.
+        */
+       __mitigate_spectre_bhb_fw
+       .endif // \bhb == BHB_MITIGATION_FW
+
+       add     x30, x30, #(1b - \vector_start + 4)
        ret
+.org 1b + 128  // Did we overflow the ventry slot?
        .endm
 
        .macro tramp_exit, regsize = 64
-       adr     x30, tramp_vectors
+       tramp_data_read_var     x30, this_cpu_vector
+       get_this_cpu_offset x29
+       ldr     x30, [x30, x29]
+
        msr     vbar_el1, x30
-       tramp_unmap_kernel      x30
+       ldr     lr, [sp, #S_LR]
+       tramp_unmap_kernel      x29
        .if     \regsize == 64
-       mrs     x30, far_el1
+       mrs     x29, far_el1
        .endif
+       add     sp, sp, #PT_REGS_SIZE           // restore sp
        eret
        sb
        .endm
 
-       .align  11
-SYM_CODE_START_NOALIGN(tramp_vectors)
+       .macro  generate_tramp_vector,  kpti, bhb
+.Lvector_start\@:
        .space  0x400
 
-       tramp_ventry
-       tramp_ventry
-       tramp_ventry
-       tramp_ventry
+       .rept   4
+       tramp_ventry    .Lvector_start\@, 64, \kpti, \bhb
+       .endr
+       .rept   4
+       tramp_ventry    .Lvector_start\@, 32, \kpti, \bhb
+       .endr
+       .endm
 
-       tramp_ventry    32
-       tramp_ventry    32
-       tramp_ventry    32
-       tramp_ventry    32
+#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
+/*
+ * Exception vectors trampoline.
+ * The order must match __bp_harden_el1_vectors and the
+ * arm64_bp_harden_el1_vectors enum.
+ */
+       .pushsection ".entry.tramp.text", "ax"
+       .align  11
+SYM_CODE_START_NOALIGN(tramp_vectors)
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+       generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_LOOP
+       generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_FW
+       generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_INSN
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+       generate_tramp_vector   kpti=1, bhb=BHB_MITIGATION_NONE
 SYM_CODE_END(tramp_vectors)
 
 SYM_CODE_START(tramp_exit_native)
@@ -704,12 +774,56 @@ SYM_CODE_END(tramp_exit_compat)
        .pushsection ".rodata", "a"
        .align PAGE_SHIFT
 SYM_DATA_START(__entry_tramp_data_start)
+__entry_tramp_data_vectors:
        .quad   vectors
+#ifdef CONFIG_ARM_SDE_INTERFACE
+__entry_tramp_data___sdei_asm_handler:
+       .quad   __sdei_asm_handler
+#endif /* CONFIG_ARM_SDE_INTERFACE */
+__entry_tramp_data_this_cpu_vector:
+       .quad   this_cpu_vector
 SYM_DATA_END(__entry_tramp_data_start)
        .popsection                             // .rodata
 #endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
+/*
+ * Exception vectors for spectre mitigations on entry from EL1 when
+ * kpti is not in use.
+ */
+       .macro generate_el1_vector, bhb
+.Lvector_start\@:
+       kernel_ventry   1, t, 64, sync          // Synchronous EL1t
+       kernel_ventry   1, t, 64, irq           // IRQ EL1t
+       kernel_ventry   1, t, 64, fiq           // FIQ EL1h
+       kernel_ventry   1, t, 64, error         // Error EL1t
+
+       kernel_ventry   1, h, 64, sync          // Synchronous EL1h
+       kernel_ventry   1, h, 64, irq           // IRQ EL1h
+       kernel_ventry   1, h, 64, fiq           // FIQ EL1h
+       kernel_ventry   1, h, 64, error         // Error EL1h
+
+       .rept   4
+       tramp_ventry    .Lvector_start\@, 64, 0, \bhb
+       .endr
+       .rept 4
+       tramp_ventry    .Lvector_start\@, 32, 0, \bhb
+       .endr
+       .endm
+
+/* The order must match tramp_vecs and the arm64_bp_harden_el1_vectors enum. */
+       .pushsection ".entry.text", "ax"
+       .align  11
+SYM_CODE_START(__bp_harden_el1_vectors)
+#ifdef CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY
+       generate_el1_vector     bhb=BHB_MITIGATION_LOOP
+       generate_el1_vector     bhb=BHB_MITIGATION_FW
+       generate_el1_vector     bhb=BHB_MITIGATION_INSN
+#endif /* CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY */
+SYM_CODE_END(__bp_harden_el1_vectors)
+       .popsection
+
+
 /*
  * Register switch for AArch64. The callee-saved registers need to be saved
  * and restored. On entry:
@@ -835,14 +949,7 @@ SYM_CODE_START(__sdei_asm_entry_trampoline)
         * Remember whether to unmap the kernel on exit.
         */
 1:     str     x4, [x1, #(SDEI_EVENT_INTREGS + S_SDEI_TTBR1)]
-
-#ifdef CONFIG_RANDOMIZE_BASE
-       adr     x4, tramp_vectors + PAGE_SIZE
-       add     x4, x4, #:lo12:__sdei_asm_trampoline_next_handler
-       ldr     x4, [x4]
-#else
-       ldr     x4, =__sdei_asm_handler
-#endif
+       tramp_data_read_var     x4, __sdei_asm_handler
        br      x4
 SYM_CODE_END(__sdei_asm_entry_trampoline)
 NOKPROBE(__sdei_asm_entry_trampoline)
@@ -865,13 +972,6 @@ SYM_CODE_END(__sdei_asm_exit_trampoline)
 NOKPROBE(__sdei_asm_exit_trampoline)
        .ltorg
 .popsection            // .entry.tramp.text
-#ifdef CONFIG_RANDOMIZE_BASE
-.pushsection ".rodata", "a"
-SYM_DATA_START(__sdei_asm_trampoline_next_handler)
-       .quad   __sdei_asm_handler
-SYM_DATA_END(__sdei_asm_trampoline_next_handler)
-.popsection            // .rodata
-#endif /* CONFIG_RANDOMIZE_BASE */
 #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
 /*
@@ -981,7 +1081,7 @@ alternative_if_not ARM64_UNMAP_KERNEL_AT_EL0
 alternative_else_nop_endif
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-       tramp_alias     dst=x5, sym=__sdei_asm_exit_trampoline
+       tramp_alias     dst=x5, sym=__sdei_asm_exit_trampoline, tmp=x3
        br      x5
 #endif
 SYM_CODE_END(__sdei_asm_handler)
index 7eaf1f7..55a1ced 100644 (file)
@@ -66,6 +66,10 @@ KVM_NVHE_ALIAS(kvm_patch_vector_branch);
 KVM_NVHE_ALIAS(kvm_update_va_mask);
 KVM_NVHE_ALIAS(kvm_get_kimage_voffset);
 KVM_NVHE_ALIAS(kvm_compute_final_ctr_el0);
+KVM_NVHE_ALIAS(spectre_bhb_patch_loop_iter);
+KVM_NVHE_ALIAS(spectre_bhb_patch_loop_mitigation_enable);
+KVM_NVHE_ALIAS(spectre_bhb_patch_wa3);
+KVM_NVHE_ALIAS(spectre_bhb_patch_clearbhb);
 
 /* Global kernel state accessed by nVHE hyp code. */
 KVM_NVHE_ALIAS(kvm_vgic_global_state);
index 902e408..6d45c63 100644 (file)
  */
 
 #include <linux/arm-smccc.h>
+#include <linux/bpf.h>
 #include <linux/cpu.h>
 #include <linux/device.h>
 #include <linux/nospec.h>
 #include <linux/prctl.h>
 #include <linux/sched/task_stack.h>
 
+#include <asm/debug-monitors.h>
 #include <asm/insn.h>
 #include <asm/spectre.h>
 #include <asm/traps.h>
+#include <asm/vectors.h>
 #include <asm/virt.h>
 
 /*
@@ -96,14 +99,51 @@ static bool spectre_v2_mitigations_off(void)
        return ret;
 }
 
+static const char *get_bhb_affected_string(enum mitigation_state bhb_state)
+{
+       switch (bhb_state) {
+       case SPECTRE_UNAFFECTED:
+               return "";
+       default:
+       case SPECTRE_VULNERABLE:
+               return ", but not BHB";
+       case SPECTRE_MITIGATED:
+               return ", BHB";
+       }
+}
+
+static bool _unprivileged_ebpf_enabled(void)
+{
+#ifdef CONFIG_BPF_SYSCALL
+       return !sysctl_unprivileged_bpf_disabled;
+#else
+       return false;
+#endif
+}
+
 ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
+       enum mitigation_state bhb_state = arm64_get_spectre_bhb_state();
+       const char *bhb_str = get_bhb_affected_string(bhb_state);
+       const char *v2_str = "Branch predictor hardening";
+
        switch (spectre_v2_state) {
        case SPECTRE_UNAFFECTED:
-               return sprintf(buf, "Not affected\n");
+               if (bhb_state == SPECTRE_UNAFFECTED)
+                       return sprintf(buf, "Not affected\n");
+
+               /*
+                * Platforms affected by Spectre-BHB can't report
+                * "Not affected" for Spectre-v2.
+                */
+               v2_str = "CSV2";
+               fallthrough;
        case SPECTRE_MITIGATED:
-               return sprintf(buf, "Mitigation: Branch predictor hardening\n");
+               if (bhb_state == SPECTRE_MITIGATED && _unprivileged_ebpf_enabled())
+                       return sprintf(buf, "Vulnerable: Unprivileged eBPF enabled\n");
+
+               return sprintf(buf, "Mitigation: %s%s\n", v2_str, bhb_str);
        case SPECTRE_VULNERABLE:
                fallthrough;
        default:
@@ -554,9 +594,9 @@ void __init spectre_v4_patch_fw_mitigation_enable(struct alt_instr *alt,
  * Patch a NOP in the Spectre-v4 mitigation code with an SMC/HVC instruction
  * to call into firmware to adjust the mitigation state.
  */
-void __init spectre_v4_patch_fw_mitigation_conduit(struct alt_instr *alt,
-                                                  __le32 *origptr,
-                                                  __le32 *updptr, int nr_inst)
+void __init smccc_patch_fw_mitigation_conduit(struct alt_instr *alt,
+                                              __le32 *origptr,
+                                              __le32 *updptr, int nr_inst)
 {
        u32 insn;
 
@@ -770,3 +810,344 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
                return -ENODEV;
        }
 }
+
+/*
+ * Spectre BHB.
+ *
+ * A CPU is either:
+ * - Mitigated by a branchy loop a CPU specific number of times, and listed
+ *   in our "loop mitigated list".
+ * - Mitigated in software by the firmware Spectre v2 call.
+ * - Has the ClearBHB instruction to perform the mitigation.
+ * - Has the 'Exception Clears Branch History Buffer' (ECBHB) feature, so no
+ *   software mitigation in the vectors is needed.
+ * - Has CSV2.3, so is unaffected.
+ */
+static enum mitigation_state spectre_bhb_state;
+
+enum mitigation_state arm64_get_spectre_bhb_state(void)
+{
+       return spectre_bhb_state;
+}
+
+enum bhb_mitigation_bits {
+       BHB_LOOP,
+       BHB_FW,
+       BHB_HW,
+       BHB_INSN,
+};
+static unsigned long system_bhb_mitigations;
+
+/*
+ * This must be called with SCOPE_LOCAL_CPU for each type of CPU, before any
+ * SCOPE_SYSTEM call will give the right answer.
+ */
+u8 spectre_bhb_loop_affected(int scope)
+{
+       u8 k = 0;
+       static u8 max_bhb_k;
+
+       if (scope == SCOPE_LOCAL_CPU) {
+               static const struct midr_range spectre_bhb_k32_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A78),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A78C),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_X1),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A710),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_X2),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N2),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_V1),
+                       {},
+               };
+               static const struct midr_range spectre_bhb_k24_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A76),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A77),
+                       MIDR_ALL_VERSIONS(MIDR_NEOVERSE_N1),
+                       {},
+               };
+               static const struct midr_range spectre_bhb_k8_list[] = {
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A72),
+                       MIDR_ALL_VERSIONS(MIDR_CORTEX_A57),
+                       {},
+               };
+
+               if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k32_list))
+                       k = 32;
+               else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k24_list))
+                       k = 24;
+               else if (is_midr_in_range_list(read_cpuid_id(), spectre_bhb_k8_list))
+                       k =  8;
+
+               max_bhb_k = max(max_bhb_k, k);
+       } else {
+               k = max_bhb_k;
+       }
+
+       return k;
+}
+
+static enum mitigation_state spectre_bhb_get_cpu_fw_mitigation_state(void)
+{
+       int ret;
+       struct arm_smccc_res res;
+
+       arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
+                            ARM_SMCCC_ARCH_WORKAROUND_3, &res);
+
+       ret = res.a0;
+       switch (ret) {
+       case SMCCC_RET_SUCCESS:
+               return SPECTRE_MITIGATED;
+       case SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED:
+               return SPECTRE_UNAFFECTED;
+       default:
+               fallthrough;
+       case SMCCC_RET_NOT_SUPPORTED:
+               return SPECTRE_VULNERABLE;
+       }
+}
+
+static bool is_spectre_bhb_fw_affected(int scope)
+{
+       static bool system_affected;
+       enum mitigation_state fw_state;
+       bool has_smccc = arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_NONE;
+       static const struct midr_range spectre_bhb_firmware_mitigated_list[] = {
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A73),
+               MIDR_ALL_VERSIONS(MIDR_CORTEX_A75),
+               {},
+       };
+       bool cpu_in_list = is_midr_in_range_list(read_cpuid_id(),
+                                        spectre_bhb_firmware_mitigated_list);
+
+       if (scope != SCOPE_LOCAL_CPU)
+               return system_affected;
+
+       fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+       if (cpu_in_list || (has_smccc && fw_state == SPECTRE_MITIGATED)) {
+               system_affected = true;
+               return true;
+       }
+
+       return false;
+}
+
+static bool supports_ecbhb(int scope)
+{
+       u64 mmfr1;
+
+       if (scope == SCOPE_LOCAL_CPU)
+               mmfr1 = read_sysreg_s(SYS_ID_AA64MMFR1_EL1);
+       else
+               mmfr1 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR1_EL1);
+
+       return cpuid_feature_extract_unsigned_field(mmfr1,
+                                                   ID_AA64MMFR1_ECBHB_SHIFT);
+}
+
+bool is_spectre_bhb_affected(const struct arm64_cpu_capabilities *entry,
+                            int scope)
+{
+       WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
+
+       if (supports_csv2p3(scope))
+               return false;
+
+       if (supports_clearbhb(scope))
+               return true;
+
+       if (spectre_bhb_loop_affected(scope))
+               return true;
+
+       if (is_spectre_bhb_fw_affected(scope))
+               return true;
+
+       return false;
+}
+
+static void this_cpu_set_vectors(enum arm64_bp_harden_el1_vectors slot)
+{
+       const char *v = arm64_get_bp_hardening_vector(slot);
+
+       if (slot < 0)
+               return;
+
+       __this_cpu_write(this_cpu_vector, v);
+
+       /*
+        * When KPTI is in use, the vectors are switched when exiting to
+        * user-space.
+        */
+       if (arm64_kernel_unmapped_at_el0())
+               return;
+
+       write_sysreg(v, vbar_el1);
+       isb();
+}
+
+void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
+{
+       bp_hardening_cb_t cpu_cb;
+       enum mitigation_state fw_state, state = SPECTRE_VULNERABLE;
+       struct bp_hardening_data *data = this_cpu_ptr(&bp_hardening_data);
+
+       if (!is_spectre_bhb_affected(entry, SCOPE_LOCAL_CPU))
+               return;
+
+       if (arm64_get_spectre_v2_state() == SPECTRE_VULNERABLE) {
+               /* No point mitigating Spectre-BHB alone. */
+       } else if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY)) {
+               pr_info_once("spectre-bhb mitigation disabled by compile time option\n");
+       } else if (cpu_mitigations_off()) {
+               pr_info_once("spectre-bhb mitigation disabled by command line option\n");
+       } else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
+               state = SPECTRE_MITIGATED;
+               set_bit(BHB_HW, &system_bhb_mitigations);
+       } else if (supports_clearbhb(SCOPE_LOCAL_CPU)) {
+               /*
+                * Ensure KVM uses the indirect vector which will have ClearBHB
+                * added.
+                */
+               if (!data->slot)
+                       data->slot = HYP_VECTOR_INDIRECT;
+
+               this_cpu_set_vectors(EL1_VECTOR_BHB_CLEAR_INSN);
+               state = SPECTRE_MITIGATED;
+               set_bit(BHB_INSN, &system_bhb_mitigations);
+       } else if (spectre_bhb_loop_affected(SCOPE_LOCAL_CPU)) {
+               /*
+                * Ensure KVM uses the indirect vector which will have the
+                * branchy-loop added. A57/A72-r0 will already have selected
+                * the spectre-indirect vector, which is sufficient for BHB
+                * too.
+                */
+               if (!data->slot)
+                       data->slot = HYP_VECTOR_INDIRECT;
+
+               this_cpu_set_vectors(EL1_VECTOR_BHB_LOOP);
+               state = SPECTRE_MITIGATED;
+               set_bit(BHB_LOOP, &system_bhb_mitigations);
+       } else if (is_spectre_bhb_fw_affected(SCOPE_LOCAL_CPU)) {
+               fw_state = spectre_bhb_get_cpu_fw_mitigation_state();
+               if (fw_state == SPECTRE_MITIGATED) {
+                       /*
+                        * Ensure KVM uses one of the spectre bp_hardening
+                        * vectors. The indirect vector doesn't include the EL3
+                        * call, so needs upgrading to
+                        * HYP_VECTOR_SPECTRE_INDIRECT.
+                        */
+                       if (!data->slot || data->slot == HYP_VECTOR_INDIRECT)
+                               data->slot += 1;
+
+                       this_cpu_set_vectors(EL1_VECTOR_BHB_FW);
+
+                       /*
+                        * The WA3 call in the vectors supersedes the WA1 call
+                        * made during context-switch. Uninstall any firmware
+                        * bp_hardening callback.
+                        */
+                       cpu_cb = spectre_v2_get_sw_mitigation_cb();
+                       if (__this_cpu_read(bp_hardening_data.fn) != cpu_cb)
+                               __this_cpu_write(bp_hardening_data.fn, NULL);
+
+                       state = SPECTRE_MITIGATED;
+                       set_bit(BHB_FW, &system_bhb_mitigations);
+               }
+       }
+
+       update_mitigation_state(&spectre_bhb_state, state);
+}
+
+/* Patched to NOP when enabled */
+void noinstr spectre_bhb_patch_loop_mitigation_enable(struct alt_instr *alt,
+                                                    __le32 *origptr,
+                                                     __le32 *updptr, int nr_inst)
+{
+       BUG_ON(nr_inst != 1);
+
+       if (test_bit(BHB_LOOP, &system_bhb_mitigations))
+               *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
+/* Patched to NOP when enabled */
+void noinstr spectre_bhb_patch_fw_mitigation_enabled(struct alt_instr *alt,
+                                                  __le32 *origptr,
+                                                  __le32 *updptr, int nr_inst)
+{
+       BUG_ON(nr_inst != 1);
+
+       if (test_bit(BHB_FW, &system_bhb_mitigations))
+               *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
+/* Patched to correct the immediate */
+void noinstr spectre_bhb_patch_loop_iter(struct alt_instr *alt,
+                                  __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+       u8 rd;
+       u32 insn;
+       u16 loop_count = spectre_bhb_loop_affected(SCOPE_SYSTEM);
+
+       BUG_ON(nr_inst != 1); /* MOV -> MOV */
+
+       if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY))
+               return;
+
+       insn = le32_to_cpu(*origptr);
+       rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
+       insn = aarch64_insn_gen_movewide(rd, loop_count, 0,
+                                        AARCH64_INSN_VARIANT_64BIT,
+                                        AARCH64_INSN_MOVEWIDE_ZERO);
+       *updptr++ = cpu_to_le32(insn);
+}
+
+/* Patched to mov WA3 when supported */
+void noinstr spectre_bhb_patch_wa3(struct alt_instr *alt,
+                                  __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+       u8 rd;
+       u32 insn;
+
+       BUG_ON(nr_inst != 1); /* MOV -> MOV */
+
+       if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY) ||
+           !test_bit(BHB_FW, &system_bhb_mitigations))
+               return;
+
+       insn = le32_to_cpu(*origptr);
+       rd = aarch64_insn_decode_register(AARCH64_INSN_REGTYPE_RD, insn);
+
+       insn = aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_ORR,
+                                                 AARCH64_INSN_VARIANT_32BIT,
+                                                 AARCH64_INSN_REG_ZR, rd,
+                                                 ARM_SMCCC_ARCH_WORKAROUND_3);
+       if (WARN_ON_ONCE(insn == AARCH64_BREAK_FAULT))
+               return;
+
+       *updptr++ = cpu_to_le32(insn);
+}
+
+/* Patched to NOP when not supported */
+void __init spectre_bhb_patch_clearbhb(struct alt_instr *alt,
+                                  __le32 *origptr, __le32 *updptr, int nr_inst)
+{
+       BUG_ON(nr_inst != 2);
+
+       if (test_bit(BHB_INSN, &system_bhb_mitigations))
+               return;
+
+       *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
+       *updptr++ = cpu_to_le32(aarch64_insn_gen_nop());
+}
+
+#ifdef CONFIG_BPF_SYSCALL
+#define EBPF_WARN "Unprivileged eBPF is enabled, data leaks possible via Spectre v2 BHB attacks!\n"
+void unpriv_ebpf_notify(int new_state)
+{
+       if (spectre_v2_state == SPECTRE_VULNERABLE ||
+           spectre_bhb_state != SPECTRE_MITIGATED)
+               return;
+
+       if (!new_state)
+               pr_err("WARNING: %s", EBPF_WARN);
+}
+#endif
index 50bab18..edaf0fa 100644 (file)
@@ -341,7 +341,7 @@ ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1))
        <= SZ_4K, "Hibernate exit text too big or misaligned")
 #endif
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
-ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE,
+ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) <= 3*PAGE_SIZE,
        "Entry trampoline text too big")
 #endif
 #ifdef CONFIG_KVM
index ecc5958..4dca6ff 100644 (file)
@@ -1491,10 +1491,7 @@ static int kvm_init_vector_slots(void)
        base = kern_hyp_va(kvm_ksym_ref(__bp_harden_hyp_vecs));
        kvm_init_vector_slot(base, HYP_VECTOR_SPECTRE_DIRECT);
 
-       if (!cpus_have_const_cap(ARM64_SPECTRE_V3A))
-               return 0;
-
-       if (!has_vhe()) {
+       if (kvm_system_needs_idmapped_vectors() && !has_vhe()) {
                err = create_hyp_exec_mappings(__pa_symbol(__bp_harden_hyp_vecs),
                                               __BP_HARDEN_HYP_VECS_SZ, &base);
                if (err)
index b6b6801..7839d07 100644 (file)
@@ -62,6 +62,10 @@ el1_sync:                            // Guest trapped into EL2
        /* ARM_SMCCC_ARCH_WORKAROUND_2 handling */
        eor     w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_1 ^ \
                          ARM_SMCCC_ARCH_WORKAROUND_2)
+       cbz     w1, wa_epilogue
+
+       eor     w1, w1, #(ARM_SMCCC_ARCH_WORKAROUND_2 ^ \
+                         ARM_SMCCC_ARCH_WORKAROUND_3)
        cbnz    w1, el1_trap
 
 wa_epilogue:
@@ -192,7 +196,10 @@ SYM_CODE_END(__kvm_hyp_vector)
        sub     sp, sp, #(8 * 4)
        stp     x2, x3, [sp, #(8 * 0)]
        stp     x0, x1, [sp, #(8 * 2)]
+       alternative_cb spectre_bhb_patch_wa3
+       /* Patched to mov WA3 when supported */
        mov     w0, #ARM_SMCCC_ARCH_WORKAROUND_1
+       alternative_cb_end
        smc     #0
        ldp     x2, x3, [sp, #(8 * 0)]
        add     sp, sp, #(8 * 2)
@@ -205,6 +212,8 @@ SYM_CODE_END(__kvm_hyp_vector)
        spectrev2_smccc_wa1_smc
        .else
        stp     x0, x1, [sp, #-16]!
+       mitigate_spectre_bhb_loop       x0
+       mitigate_spectre_bhb_clear_insn
        .endif
        .if \indirect != 0
        alternative_cb  kvm_patch_vector_branch
index 526a7d6..cdbe8e2 100644 (file)
@@ -148,8 +148,10 @@ int hyp_map_vectors(void)
        phys_addr_t phys;
        void *bp_base;
 
-       if (!cpus_have_const_cap(ARM64_SPECTRE_V3A))
+       if (!kvm_system_needs_idmapped_vectors()) {
+               __hyp_bp_vect_base = __bp_harden_hyp_vecs;
                return 0;
+       }
 
        phys = __hyp_pa(__bp_harden_hyp_vecs);
        bp_base = (void *)__pkvm_create_private_mapping(phys,
index 11d053f..54af470 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kvm_host.h>
 #include <linux/types.h>
 #include <linux/jump_label.h>
+#include <linux/percpu.h>
 #include <uapi/linux/psci.h>
 
 #include <kvm/arm_psci.h>
@@ -24,6 +25,8 @@
 #include <asm/fpsimd.h>
 #include <asm/debug-monitors.h>
 #include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/vectors.h>
 
 /* VHE specific context */
 DEFINE_PER_CPU(struct kvm_host_data, kvm_host_data);
@@ -67,7 +70,7 @@ NOKPROBE_SYMBOL(__activate_traps);
 
 static void __deactivate_traps(struct kvm_vcpu *vcpu)
 {
-       extern char vectors[];  /* kernel exception vectors */
+       const char *host_vectors = vectors;
 
        ___deactivate_traps(vcpu);
 
@@ -81,7 +84,10 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
        asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));
 
        write_sysreg(CPACR_EL1_DEFAULT, cpacr_el1);
-       write_sysreg(vectors, vbar_el1);
+
+       if (!arm64_kernel_unmapped_at_el0())
+               host_vectors = __this_cpu_read(this_cpu_vector);
+       write_sysreg(host_vectors, vbar_el1);
 }
 NOKPROBE_SYMBOL(__deactivate_traps);
 
index 30da78f..202b8c4 100644 (file)
@@ -107,6 +107,18 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
                                break;
                        }
                        break;
+               case ARM_SMCCC_ARCH_WORKAROUND_3:
+                       switch (arm64_get_spectre_bhb_state()) {
+                       case SPECTRE_VULNERABLE:
+                               break;
+                       case SPECTRE_MITIGATED:
+                               val[0] = SMCCC_RET_SUCCESS;
+                               break;
+                       case SPECTRE_UNAFFECTED:
+                               val[0] = SMCCC_ARCH_WORKAROUND_RET_UNAFFECTED;
+                               break;
+                       }
+                       break;
                case ARM_SMCCC_HV_PV_TIME_FEATURES:
                        val[0] = SMCCC_RET_SUCCESS;
                        break;
index 3eae328..5918095 100644 (file)
@@ -46,8 +46,7 @@ static unsigned long kvm_psci_vcpu_suspend(struct kvm_vcpu *vcpu)
         * specification (ARM DEN 0022A). This means all suspend states
         * for KVM will preserve the register state.
         */
-       kvm_vcpu_halt(vcpu);
-       kvm_clear_request(KVM_REQ_UNHALT, vcpu);
+       kvm_vcpu_wfi(vcpu);
 
        return PSCI_RET_SUCCESS;
 }
@@ -406,7 +405,7 @@ int kvm_psci_call(struct kvm_vcpu *vcpu)
 
 int kvm_arm_get_fw_num_regs(struct kvm_vcpu *vcpu)
 {
-       return 3;               /* PSCI version and two workaround registers */
+       return 4;               /* PSCI version and three workaround registers */
 }
 
 int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
@@ -420,6 +419,9 @@ int kvm_arm_copy_fw_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
        if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2, uindices++))
                return -EFAULT;
 
+       if (put_user(KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3, uindices++))
+               return -EFAULT;
+
        return 0;
 }
 
@@ -459,6 +461,17 @@ static int get_kernel_wa_level(u64 regid)
                case SPECTRE_VULNERABLE:
                        return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2_NOT_AVAIL;
                }
+               break;
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
+               switch (arm64_get_spectre_bhb_state()) {
+               case SPECTRE_VULNERABLE:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
+               case SPECTRE_MITIGATED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_AVAIL;
+               case SPECTRE_UNAFFECTED:
+                       return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_REQUIRED;
+               }
+               return KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3_NOT_AVAIL;
        }
 
        return -EINVAL;
@@ -475,6 +488,7 @@ int kvm_arm_get_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
                break;
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_2:
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
                val = get_kernel_wa_level(reg->id) & KVM_REG_FEATURE_LEVEL_MASK;
                break;
        default:
@@ -520,6 +534,7 @@ int kvm_arm_set_fw_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg)
        }
 
        case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_1:
+       case KVM_REG_ARM_SMCCC_ARCH_WORKAROUND_3:
                if (val & ~KVM_REG_FEATURE_LEVEL_MASK)
                        return -EINVAL;
 
index a38f54c..77ada00 100644 (file)
@@ -7,8 +7,10 @@
 
 #include <linux/io.h>
 #include <linux/memblock.h>
+#include <linux/mm.h>
 #include <linux/types.h>
 
+#include <asm/cpufeature.h>
 #include <asm/page.h>
 
 /*
@@ -38,3 +40,18 @@ int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
 {
        return !(((pfn << PAGE_SHIFT) + size) & ~PHYS_MASK);
 }
+
+static int __init adjust_protection_map(void)
+{
+       /*
+        * With Enhanced PAN we can honour the execute-only permissions as
+        * there is no PAN override with such mappings.
+        */
+       if (cpus_have_const_cap(ARM64_HAS_EPAN)) {
+               protection_map[VM_EXEC] = PAGE_EXECONLY;
+               protection_map[VM_EXEC | VM_SHARED] = PAGE_EXECONLY;
+       }
+
+       return 0;
+}
+arch_initcall(adjust_protection_map);
index acfae9b..49abbf4 100644 (file)
@@ -617,6 +617,8 @@ early_param("rodata", parse_rodata);
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 static int __init map_entry_trampoline(void)
 {
+       int i;
+
        pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
        phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start);
 
@@ -625,11 +627,15 @@ static int __init map_entry_trampoline(void)
 
        /* Map only the text into the trampoline page table */
        memset(tramp_pg_dir, 0, PGD_SIZE);
-       __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE,
-                            prot, __pgd_pgtable_alloc, 0);
+       __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS,
+                            entry_tramp_text_size(), prot,
+                            __pgd_pgtable_alloc, NO_BLOCK_MAPPINGS);
 
        /* Map both the text and data into the kernel page table */
-       __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot);
+       for (i = 0; i < DIV_ROUND_UP(entry_tramp_text_size(), PAGE_SIZE); i++)
+               __set_fixmap(FIX_ENTRY_TRAMP_TEXT1 - i,
+                            pa_start + i * PAGE_SIZE, prot);
+
        if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
                extern char __entry_tramp_data_start[];
 
index 9c65b1e..cea7533 100644 (file)
@@ -44,6 +44,7 @@ MTE_ASYMM
 SPECTRE_V2
 SPECTRE_V3A
 SPECTRE_V4
+SPECTRE_BHB
 SSBS
 SVE
 UNMAP_KERNEL_AT_EL0
index f979adf..ef73ba1 100644 (file)
@@ -803,7 +803,7 @@ early_param("coherentio", setcoherentio);
 
 static int __init setnocoherentio(char *str)
 {
-       dma_default_coherent = true;
+       dma_default_coherent = false;
        pr_info("Software DMA cache coherency (command line)\n");
        return 0;
 }
index d542fb7..1986d13 100644 (file)
@@ -351,6 +351,9 @@ asmlinkage void start_secondary(void)
        cpu = smp_processor_id();
        cpu_data[cpu].udelay_val = loops_per_jiffy;
 
+       set_cpu_sibling_map(cpu);
+       set_cpu_core_map(cpu);
+
        cpumask_set_cpu(cpu, &cpu_coherent_mask);
        notify_cpu_starting(cpu);
 
@@ -362,9 +365,6 @@ asmlinkage void start_secondary(void)
        /* The CPU is running and counters synchronised, now mark it online */
        set_cpu_online(cpu, true);
 
-       set_cpu_sibling_map(cpu);
-       set_cpu_core_map(cpu);
-
        calculate_cpu_foreign_map();
 
        /*
index d6efffd..fb0565b 100644 (file)
@@ -22,7 +22,9 @@
 
 #include "common.h"
 
-static void *detect_magic __initdata = detect_memory_region;
+#define MT7621_MEM_TEST_PATTERN         0xaa5555aa
+
+static u32 detect_magic __initdata;
 
 int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
 {
@@ -58,24 +60,32 @@ phys_addr_t mips_cpc_default_phys_base(void)
        panic("Cannot detect cpc address");
 }
 
+static bool __init mt7621_addr_wraparound_test(phys_addr_t size)
+{
+       void *dm = (void *)KSEG1ADDR(&detect_magic);
+
+       if (CPHYSADDR(dm + size) >= MT7621_LOWMEM_MAX_SIZE)
+               return true;
+       __raw_writel(MT7621_MEM_TEST_PATTERN, dm);
+       if (__raw_readl(dm) != __raw_readl(dm + size))
+               return false;
+       __raw_writel(~MT7621_MEM_TEST_PATTERN, dm);
+       return __raw_readl(dm) == __raw_readl(dm + size);
+}
+
 static void __init mt7621_memory_detect(void)
 {
-       void *dm = &detect_magic;
        phys_addr_t size;
 
-       for (size = 32 * SZ_1M; size < 256 * SZ_1M; size <<= 1) {
-               if (!__builtin_memcmp(dm, dm + size, sizeof(detect_magic)))
-                       break;
+       for (size = 32 * SZ_1M; size <= 256 * SZ_1M; size <<= 1) {
+               if (mt7621_addr_wraparound_test(size)) {
+                       memblock_add(MT7621_LOWMEM_BASE, size);
+                       return;
+               }
        }
 
-       if ((size == 256 * SZ_1M) &&
-           (CPHYSADDR(dm + size) < MT7621_LOWMEM_MAX_SIZE) &&
-           __builtin_memcmp(dm, dm + size, sizeof(detect_magic))) {
-               memblock_add(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE);
-               memblock_add(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE);
-       } else {
-               memblock_add(MT7621_LOWMEM_BASE, size);
-       }
+       memblock_add(MT7621_LOWMEM_BASE, MT7621_LOWMEM_MAX_SIZE);
+       memblock_add(MT7621_HIGHMEM_BASE, MT7621_HIGHMEM_SIZE);
 }
 
 void __init ralink_of_remap(void)
index ba5b1be..006cbec 100644 (file)
@@ -202,7 +202,6 @@ static inline struct subpage_prot_table *mm_ctx_subpage_prot(mm_context_t *ctx)
 /*
  * The current system page and segment sizes
  */
-extern int mmu_linear_psize;
 extern int mmu_virtual_psize;
 extern int mmu_vmalloc_psize;
 extern int mmu_io_psize;
@@ -213,6 +212,7 @@ extern int mmu_io_psize;
 #define mmu_virtual_psize MMU_PAGE_4K
 #endif
 #endif
+extern int mmu_linear_psize;
 extern int mmu_vmemmap_psize;
 
 /* MMU initialization */
index 7a90000..f83866a 100644 (file)
@@ -9,7 +9,7 @@ struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
 int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
 int add_tce_mem_ranges(struct crash_mem **mem_ranges);
 int add_initrd_mem_range(struct crash_mem **mem_ranges);
-#ifdef CONFIG_PPC_BOOK3S_64
+#ifdef CONFIG_PPC_64S_HASH_MMU
 int add_htab_mem_range(struct crash_mem **mem_ranges);
 #else
 static inline int add_htab_mem_range(struct crash_mem **mem_ranges)
index 56f5711..44d3385 100644 (file)
                        compatible = "canaan,k210-plic", "sifive,plic-1.0.0";
                        reg = <0xC000000 0x4000000>;
                        interrupt-controller;
-                       interrupts-extended = <&cpu0_intc 11>, <&cpu1_intc 11>;
+                       interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>,
+                                             <&cpu1_intc 11>, <&cpu1_intc 9>;
                        riscv,ndev = <65>;
                };
 
index 160e3a1..004372f 100644 (file)
@@ -119,7 +119,7 @@ extern phys_addr_t phys_ram_base;
        ((x) >= kernel_map.virt_addr && (x) < (kernel_map.virt_addr + kernel_map.size))
 
 #define is_linear_mapping(x)   \
-       ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < kernel_map.virt_addr))
+       ((x) >= PAGE_OFFSET && (!IS_ENABLED(CONFIG_64BIT) || (x) < PAGE_OFFSET + KERN_VIRT_SIZE))
 
 #define linear_mapping_pa_to_va(x)     ((void *)((unsigned long)(x) + kernel_map.va_pa_offset))
 #define kernel_mapping_pa_to_va(y)     ({                                              \
index 7e949f2..e3549e5 100644 (file)
@@ -13,6 +13,7 @@
 
 #ifndef CONFIG_MMU
 #define KERNEL_LINK_ADDR       PAGE_OFFSET
+#define KERN_VIRT_SIZE         (UL(-1))
 #else
 
 #define ADDRESS_SPACE_END      (UL(-1))
index 7ebaef1..ac7a252 100644 (file)
@@ -24,6 +24,9 @@ obj-$(CONFIG_KASAN)   += kasan_init.o
 ifdef CONFIG_KASAN
 KASAN_SANITIZE_kasan_init.o := n
 KASAN_SANITIZE_init.o := n
+ifdef CONFIG_DEBUG_VIRTUAL
+KASAN_SANITIZE_physaddr.o := n
+endif
 endif
 
 obj-$(CONFIG_DEBUG_VIRTUAL) += physaddr.o
index c272941..0d58803 100644 (file)
@@ -125,7 +125,6 @@ void __init mem_init(void)
        else
                swiotlb_force = SWIOTLB_NO_FORCE;
 #endif
-       high_memory = (void *)(__va(PFN_PHYS(max_low_pfn)));
        memblock_free_all();
 
        print_vm_layout();
@@ -195,6 +194,7 @@ static void __init setup_bootmem(void)
 
        min_low_pfn = PFN_UP(phys_ram_base);
        max_low_pfn = max_pfn = PFN_DOWN(phys_ram_end);
+       high_memory = (void *)(__va(PFN_PHYS(max_low_pfn)));
 
        dma32_phys_limit = min(4UL * SZ_1G, (unsigned long)PFN_PHYS(max_low_pfn));
        set_max_mapnr(max_low_pfn - ARCH_PFN_OFFSET);
index f61f7ca..cd1a145 100644 (file)
@@ -113,8 +113,11 @@ static void __init kasan_populate_pud(pgd_t *pgd,
                base_pud = pt_ops.get_pud_virt(pfn_to_phys(_pgd_pfn(*pgd)));
        } else {
                base_pud = (pud_t *)pgd_page_vaddr(*pgd);
-               if (base_pud == lm_alias(kasan_early_shadow_pud))
+               if (base_pud == lm_alias(kasan_early_shadow_pud)) {
                        base_pud = memblock_alloc(PTRS_PER_PUD * sizeof(pud_t), PAGE_SIZE);
+                       memcpy(base_pud, (void *)kasan_early_shadow_pud,
+                              sizeof(pud_t) * PTRS_PER_PUD);
+               }
        }
 
        pudp = base_pud + pud_index(vaddr);
@@ -202,8 +205,7 @@ asmlinkage void __init kasan_early_init(void)
 
        for (i = 0; i < PTRS_PER_PTE; ++i)
                set_pte(kasan_early_shadow_pte + i,
-                       mk_pte(virt_to_page(kasan_early_shadow_page),
-                              PAGE_KERNEL));
+                       pfn_pte(virt_to_pfn(kasan_early_shadow_page), PAGE_KERNEL));
 
        for (i = 0; i < PTRS_PER_PMD; ++i)
                set_pmd(kasan_early_shadow_pmd + i,
index e7fd0c2..19cf25a 100644 (file)
@@ -8,12 +8,10 @@
 
 phys_addr_t __virt_to_phys(unsigned long x)
 {
-       phys_addr_t y = x - PAGE_OFFSET;
-
        /*
         * Boundary checking aginst the kernel linear mapping space.
         */
-       WARN(y >= KERN_VIRT_SIZE,
+       WARN(!is_linear_mapping(x) && !is_kernel_mapping(x),
             "virt_to_phys used for non-linear address: %pK (%pS)\n",
             (void *)x, (void *)x);
 
index 16dc57d..8511f0e 100644 (file)
@@ -69,8 +69,13 @@ static inline void swap_ex_entry_fixup(struct exception_table_entry *a,
 {
        a->fixup = b->fixup + delta;
        b->fixup = tmp.fixup - delta;
-       a->handler = b->handler + delta;
-       b->handler = tmp.handler - delta;
+       a->handler = b->handler;
+       if (a->handler)
+               a->handler += delta;
+       b->handler = tmp.handler;
+       if (b->handler)
+               b->handler -= delta;
 }
+#define swap_ex_entry_fixup swap_ex_entry_fixup
 
 #endif
index 267f70f..6f80ec9 100644 (file)
@@ -47,15 +47,17 @@ struct ftrace_regs {
 
 static __always_inline struct pt_regs *arch_ftrace_get_regs(struct ftrace_regs *fregs)
 {
-       return &fregs->regs;
+       struct pt_regs *regs = &fregs->regs;
+
+       if (test_pt_regs_flag(regs, PIF_FTRACE_FULL_REGS))
+               return regs;
+       return NULL;
 }
 
 static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *fregs,
                                                           unsigned long ip)
 {
-       struct pt_regs *regs = arch_ftrace_get_regs(fregs);
-
-       regs->psw.addr = ip;
+       fregs->regs.psw.addr = ip;
 }
 
 /*
index 4ffa8e7..ddb70fb 100644 (file)
 #define PIF_EXECVE_PGSTE_RESTART       1       /* restart execve for PGSTE binaries */
 #define PIF_SYSCALL_RET_SET            2       /* return value was set via ptrace */
 #define PIF_GUEST_FAULT                        3       /* indicates program check in sie64a */
+#define PIF_FTRACE_FULL_REGS           4       /* all register contents valid (ftrace) */
 
 #define _PIF_SYSCALL                   BIT(PIF_SYSCALL)
 #define _PIF_EXECVE_PGSTE_RESTART      BIT(PIF_EXECVE_PGSTE_RESTART)
 #define _PIF_SYSCALL_RET_SET           BIT(PIF_SYSCALL_RET_SET)
 #define _PIF_GUEST_FAULT               BIT(PIF_GUEST_FAULT)
+#define _PIF_FTRACE_FULL_REGS          BIT(PIF_FTRACE_FULL_REGS)
 
 #ifndef __ASSEMBLY__
 
index 21d62d8..89c0870 100644 (file)
@@ -159,9 +159,38 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec)
        return 0;
 }
 
+static struct ftrace_hotpatch_trampoline *ftrace_get_trampoline(struct dyn_ftrace *rec)
+{
+       struct ftrace_hotpatch_trampoline *trampoline;
+       struct ftrace_insn insn;
+       s64 disp;
+       u16 opc;
+
+       if (copy_from_kernel_nofault(&insn, (void *)rec->ip, sizeof(insn)))
+               return ERR_PTR(-EFAULT);
+       disp = (s64)insn.disp * 2;
+       trampoline = (void *)(rec->ip + disp);
+       if (get_kernel_nofault(opc, &trampoline->brasl_opc))
+               return ERR_PTR(-EFAULT);
+       if (opc != 0xc015)
+               return ERR_PTR(-EINVAL);
+       return trampoline;
+}
+
 int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
                       unsigned long addr)
 {
+       struct ftrace_hotpatch_trampoline *trampoline;
+       u64 old;
+
+       trampoline = ftrace_get_trampoline(rec);
+       if (IS_ERR(trampoline))
+               return PTR_ERR(trampoline);
+       if (get_kernel_nofault(old, &trampoline->interceptor))
+               return -EFAULT;
+       if (old != old_addr)
+               return -EINVAL;
+       s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
        return 0;
 }
 
@@ -188,6 +217,12 @@ static void brcl_enable(void *brcl)
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
+       struct ftrace_hotpatch_trampoline *trampoline;
+
+       trampoline = ftrace_get_trampoline(rec);
+       if (IS_ERR(trampoline))
+               return PTR_ERR(trampoline);
+       s390_kernel_write(&trampoline->interceptor, &addr, sizeof(addr));
        brcl_enable((void *)rec->ip);
        return 0;
 }
@@ -291,7 +326,7 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
 
        regs = ftrace_get_regs(fregs);
        p = get_kprobe((kprobe_opcode_t *)ip);
-       if (unlikely(!p) || kprobe_disabled(p))
+       if (!regs || unlikely(!p) || kprobe_disabled(p))
                goto out;
 
        if (kprobe_running()) {
index 39bcc0e..a24177d 100644 (file)
@@ -27,6 +27,7 @@ ENDPROC(ftrace_stub)
 #define STACK_PTREGS_GPRS      (STACK_PTREGS + __PT_GPRS)
 #define STACK_PTREGS_PSW       (STACK_PTREGS + __PT_PSW)
 #define STACK_PTREGS_ORIG_GPR2 (STACK_PTREGS + __PT_ORIG_GPR2)
+#define STACK_PTREGS_FLAGS     (STACK_PTREGS + __PT_FLAGS)
 #ifdef __PACK_STACK
 /* allocate just enough for r14, r15 and backchain */
 #define TRACED_FUNC_FRAME_SIZE 24
@@ -57,6 +58,14 @@ ENDPROC(ftrace_stub)
        .if \allregs == 1
        stg     %r14,(STACK_PTREGS_PSW)(%r15)
        stosm   (STACK_PTREGS_PSW)(%r15),0
+#ifdef CONFIG_HAVE_MARCH_Z10_FEATURES
+       mvghi   STACK_PTREGS_FLAGS(%r15),_PIF_FTRACE_FULL_REGS
+#else
+       lghi    %r14,_PIF_FTRACE_FULL_REGS
+       stg     %r14,STACK_PTREGS_FLAGS(%r15)
+#endif
+       .else
+       xc      STACK_PTREGS_FLAGS(8,%r15),STACK_PTREGS_FLAGS(%r15)
        .endif
 
        lg      %r14,(__SF_GPRS+8*8)(%r1)       # restore original return address
index f2c25d1..05327be 100644 (file)
@@ -800,6 +800,8 @@ static void __init check_initrd(void)
 static void __init reserve_kernel(void)
 {
        memblock_reserve(0, STARTUP_NORMAL_OFFSET);
+       memblock_reserve(OLDMEM_BASE, sizeof(unsigned long));
+       memblock_reserve(OLDMEM_SIZE, sizeof(unsigned long));
        memblock_reserve(__amode31_base, __eamode31 - __samode31);
        memblock_reserve(__pa(sclp_early_sccb), EXT_SCCB_READ_SCP);
        memblock_reserve(__pa(_stext), _end - _stext);
index 6db4e29..65d1479 100644 (file)
 /* FREE!                                ( 7*32+10) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
 #define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_AMD      ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
index cc74dc5..acbaeaf 100644 (file)
@@ -84,7 +84,7 @@
 #ifdef CONFIG_RETPOLINE
        ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
                      __stringify(jmp __x86_indirect_thunk_\reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), X86_FEATURE_RETPOLINE_AMD
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), X86_FEATURE_RETPOLINE_LFENCE
 #else
        jmp     *%\reg
 #endif
@@ -94,7 +94,7 @@
 #ifdef CONFIG_RETPOLINE
        ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *%\reg), \
                      __stringify(call __x86_indirect_thunk_\reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *%\reg), X86_FEATURE_RETPOLINE_AMD
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *%\reg), X86_FEATURE_RETPOLINE_LFENCE
 #else
        call    *%\reg
 #endif
@@ -146,7 +146,7 @@ extern retpoline_thunk_t __x86_indirect_thunk_array[];
        "lfence;\n"                                             \
        ANNOTATE_RETPOLINE_SAFE                                 \
        "call *%[thunk_target]\n",                              \
-       X86_FEATURE_RETPOLINE_AMD)
+       X86_FEATURE_RETPOLINE_LFENCE)
 
 # define THUNK_TARGET(addr) [thunk_target] "r" (addr)
 
@@ -176,7 +176,7 @@ extern retpoline_thunk_t __x86_indirect_thunk_array[];
        "lfence;\n"                                             \
        ANNOTATE_RETPOLINE_SAFE                                 \
        "call *%[thunk_target]\n",                              \
-       X86_FEATURE_RETPOLINE_AMD)
+       X86_FEATURE_RETPOLINE_LFENCE)
 
 # define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
 #endif
@@ -188,9 +188,11 @@ extern retpoline_thunk_t __x86_indirect_thunk_array[];
 /* The Spectre V2 mitigation variants */
 enum spectre_v2_mitigation {
        SPECTRE_V2_NONE,
-       SPECTRE_V2_RETPOLINE_GENERIC,
-       SPECTRE_V2_RETPOLINE_AMD,
-       SPECTRE_V2_IBRS_ENHANCED,
+       SPECTRE_V2_RETPOLINE,
+       SPECTRE_V2_LFENCE,
+       SPECTRE_V2_EIBRS,
+       SPECTRE_V2_EIBRS_RETPOLINE,
+       SPECTRE_V2_EIBRS_LFENCE,
 };
 
 /* The indirect branch speculation control variants */
index 5007c3f..b4470ea 100644 (file)
@@ -389,7 +389,7 @@ static int emit_indirect(int op, int reg, u8 *bytes)
  *
  *   CALL *%\reg
  *
- * It also tries to inline spectre_v2=retpoline,amd when size permits.
+ * It also tries to inline spectre_v2=retpoline,lfence when size permits.
  */
 static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
 {
@@ -407,7 +407,7 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
        BUG_ON(reg == 4);
 
        if (cpu_feature_enabled(X86_FEATURE_RETPOLINE) &&
-           !cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD))
+           !cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE))
                return -1;
 
        op = insn->opcode.bytes[0];
@@ -438,9 +438,9 @@ static int patch_retpoline(void *addr, struct insn *insn, u8 *bytes)
        }
 
        /*
-        * For RETPOLINE_AMD: prepend the indirect CALL/JMP with an LFENCE.
+        * For RETPOLINE_LFENCE: prepend the indirect CALL/JMP with an LFENCE.
         */
-       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD)) {
+       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                bytes[i++] = 0x0f;
                bytes[i++] = 0xae;
                bytes[i++] = 0xe8; /* LFENCE */
index 1c1f218..6296e1e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/prctl.h>
 #include <linux/sched/smt.h>
 #include <linux/pgtable.h>
+#include <linux/bpf.h>
 
 #include <asm/spec-ctrl.h>
 #include <asm/cmdline.h>
@@ -650,6 +651,32 @@ static inline const char *spectre_v2_module_string(void)
 static inline const char *spectre_v2_module_string(void) { return ""; }
 #endif
 
+#define SPECTRE_V2_LFENCE_MSG "WARNING: LFENCE mitigation is not recommended for this CPU, data leaks possible!\n"
+#define SPECTRE_V2_EIBRS_EBPF_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS on, data leaks possible via Spectre v2 BHB attacks!\n"
+#define SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG "WARNING: Unprivileged eBPF is enabled with eIBRS+LFENCE mitigation and SMT, data leaks possible via Spectre v2 BHB attacks!\n"
+
+#ifdef CONFIG_BPF_SYSCALL
+void unpriv_ebpf_notify(int new_state)
+{
+       if (new_state)
+               return;
+
+       /* Unprivileged eBPF is enabled */
+
+       switch (spectre_v2_enabled) {
+       case SPECTRE_V2_EIBRS:
+               pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+               break;
+       case SPECTRE_V2_EIBRS_LFENCE:
+               if (sched_smt_active())
+                       pr_err(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+               break;
+       default:
+               break;
+       }
+}
+#endif
+
 static inline bool match_option(const char *arg, int arglen, const char *opt)
 {
        int len = strlen(opt);
@@ -664,7 +691,10 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_FORCE,
        SPECTRE_V2_CMD_RETPOLINE,
        SPECTRE_V2_CMD_RETPOLINE_GENERIC,
-       SPECTRE_V2_CMD_RETPOLINE_AMD,
+       SPECTRE_V2_CMD_RETPOLINE_LFENCE,
+       SPECTRE_V2_CMD_EIBRS,
+       SPECTRE_V2_CMD_EIBRS_RETPOLINE,
+       SPECTRE_V2_CMD_EIBRS_LFENCE,
 };
 
 enum spectre_v2_user_cmd {
@@ -737,6 +767,13 @@ spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
        return SPECTRE_V2_USER_CMD_AUTO;
 }
 
+static inline bool spectre_v2_in_eibrs_mode(enum spectre_v2_mitigation mode)
+{
+       return (mode == SPECTRE_V2_EIBRS ||
+               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+               mode == SPECTRE_V2_EIBRS_LFENCE);
+}
+
 static void __init
 spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
 {
@@ -804,7 +841,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+           spectre_v2_in_eibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -824,9 +861,11 @@ set_mode:
 
 static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_NONE]                       = "Vulnerable",
-       [SPECTRE_V2_RETPOLINE_GENERIC]          = "Mitigation: Full generic retpoline",
-       [SPECTRE_V2_RETPOLINE_AMD]              = "Mitigation: Full AMD retpoline",
-       [SPECTRE_V2_IBRS_ENHANCED]              = "Mitigation: Enhanced IBRS",
+       [SPECTRE_V2_RETPOLINE]                  = "Mitigation: Retpolines",
+       [SPECTRE_V2_LFENCE]                     = "Mitigation: LFENCE",
+       [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
+       [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
+       [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
 };
 
 static const struct {
@@ -837,8 +876,12 @@ static const struct {
        { "off",                SPECTRE_V2_CMD_NONE,              false },
        { "on",                 SPECTRE_V2_CMD_FORCE,             true  },
        { "retpoline",          SPECTRE_V2_CMD_RETPOLINE,         false },
-       { "retpoline,amd",      SPECTRE_V2_CMD_RETPOLINE_AMD,     false },
+       { "retpoline,amd",      SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
+       { "retpoline,lfence",   SPECTRE_V2_CMD_RETPOLINE_LFENCE,  false },
        { "retpoline,generic",  SPECTRE_V2_CMD_RETPOLINE_GENERIC, false },
+       { "eibrs",              SPECTRE_V2_CMD_EIBRS,             false },
+       { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
+       { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
 };
 
@@ -875,10 +918,30 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
        }
 
        if ((cmd == SPECTRE_V2_CMD_RETPOLINE ||
-            cmd == SPECTRE_V2_CMD_RETPOLINE_AMD ||
-            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC) &&
+            cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+            cmd == SPECTRE_V2_CMD_RETPOLINE_GENERIC ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
            !IS_ENABLED(CONFIG_RETPOLINE)) {
-               pr_err("%s selected but not compiled in. Switching to AUTO select\n", mitigation_options[i].option);
+               pr_err("%s selected but not compiled in. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if ((cmd == SPECTRE_V2_CMD_EIBRS ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_RETPOLINE) &&
+           !boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
+               pr_err("%s selected but CPU doesn't have eIBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if ((cmd == SPECTRE_V2_CMD_RETPOLINE_LFENCE ||
+            cmd == SPECTRE_V2_CMD_EIBRS_LFENCE) &&
+           !boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
+               pr_err("%s selected, but CPU doesn't have a serializing LFENCE. Switching to AUTO select\n",
+                      mitigation_options[i].option);
                return SPECTRE_V2_CMD_AUTO;
        }
 
@@ -887,6 +950,16 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
        return cmd;
 }
 
+static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
+{
+       if (!IS_ENABLED(CONFIG_RETPOLINE)) {
+               pr_err("Kernel not compiled with retpoline; no mitigation available!");
+               return SPECTRE_V2_NONE;
+       }
+
+       return SPECTRE_V2_RETPOLINE;
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -907,49 +980,64 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_CMD_FORCE:
        case SPECTRE_V2_CMD_AUTO:
                if (boot_cpu_has(X86_FEATURE_IBRS_ENHANCED)) {
-                       mode = SPECTRE_V2_IBRS_ENHANCED;
-                       /* Force it so VMEXIT will restore correctly */
-                       x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
-                       goto specv2_set_mode;
+                       mode = SPECTRE_V2_EIBRS;
+                       break;
                }
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_auto;
+
+               mode = spectre_v2_select_retpoline();
                break;
-       case SPECTRE_V2_CMD_RETPOLINE_AMD:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_amd;
+
+       case SPECTRE_V2_CMD_RETPOLINE_LFENCE:
+               pr_err(SPECTRE_V2_LFENCE_MSG);
+               mode = SPECTRE_V2_LFENCE;
                break;
+
        case SPECTRE_V2_CMD_RETPOLINE_GENERIC:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_generic;
+               mode = SPECTRE_V2_RETPOLINE;
                break;
+
        case SPECTRE_V2_CMD_RETPOLINE:
-               if (IS_ENABLED(CONFIG_RETPOLINE))
-                       goto retpoline_auto;
+               mode = spectre_v2_select_retpoline();
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS:
+               mode = SPECTRE_V2_EIBRS;
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS_LFENCE:
+               mode = SPECTRE_V2_EIBRS_LFENCE;
+               break;
+
+       case SPECTRE_V2_CMD_EIBRS_RETPOLINE:
+               mode = SPECTRE_V2_EIBRS_RETPOLINE;
                break;
        }
-       pr_err("Spectre mitigation: kernel not compiled with retpoline; no mitigation available!");
-       return;
 
-retpoline_auto:
-       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
-           boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
-       retpoline_amd:
-               if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
-                       pr_err("Spectre mitigation: LFENCE not serializing, switching to generic retpoline\n");
-                       goto retpoline_generic;
-               }
-               mode = SPECTRE_V2_RETPOLINE_AMD;
-               setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
-               setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
-       } else {
-       retpoline_generic:
-               mode = SPECTRE_V2_RETPOLINE_GENERIC;
+       if (mode == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+               pr_err(SPECTRE_V2_EIBRS_EBPF_MSG);
+
+       if (spectre_v2_in_eibrs_mode(mode)) {
+               /* Force it so VMEXIT will restore correctly */
+               x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
+               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+       }
+
+       switch (mode) {
+       case SPECTRE_V2_NONE:
+       case SPECTRE_V2_EIBRS:
+               break;
+
+       case SPECTRE_V2_LFENCE:
+       case SPECTRE_V2_EIBRS_LFENCE:
+               setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
+               fallthrough;
+
+       case SPECTRE_V2_RETPOLINE:
+       case SPECTRE_V2_EIBRS_RETPOLINE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+               break;
        }
 
-specv2_set_mode:
        spectre_v2_enabled = mode;
        pr_info("%s\n", spectre_v2_strings[mode]);
 
@@ -975,7 +1063,7 @@ specv2_set_mode:
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && mode != SPECTRE_V2_IBRS_ENHANCED) {
+       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
@@ -1045,6 +1133,10 @@ void cpu_bugs_smt_update(void)
 {
        mutex_lock(&spec_ctrl_mutex);
 
+       if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+           spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+               pr_warn_once(SPECTRE_V2_EIBRS_LFENCE_EBPF_SMT_MSG);
+
        switch (spectre_v2_user_stibp) {
        case SPECTRE_V2_USER_NONE:
                break;
@@ -1684,7 +1776,7 @@ static ssize_t tsx_async_abort_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
+       if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {
@@ -1714,6 +1806,27 @@ static char *ibpb_state(void)
        return "";
 }
 
+static ssize_t spectre_v2_show_state(char *buf)
+{
+       if (spectre_v2_enabled == SPECTRE_V2_LFENCE)
+               return sprintf(buf, "Vulnerable: LFENCE\n");
+
+       if (spectre_v2_enabled == SPECTRE_V2_EIBRS && unprivileged_ebpf_enabled())
+               return sprintf(buf, "Vulnerable: eIBRS with unprivileged eBPF\n");
+
+       if (sched_smt_active() && unprivileged_ebpf_enabled() &&
+           spectre_v2_enabled == SPECTRE_V2_EIBRS_LFENCE)
+               return sprintf(buf, "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT\n");
+
+       return sprintf(buf, "%s%s%s%s%s%s\n",
+                      spectre_v2_strings[spectre_v2_enabled],
+                      ibpb_state(),
+                      boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
+                      stibp_state(),
+                      boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
+                      spectre_v2_module_string());
+}
+
 static ssize_t srbds_show_state(char *buf)
 {
        return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
@@ -1739,12 +1852,7 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
                return sprintf(buf, "%s\n", spectre_v1_strings[spectre_v1_mitigation]);
 
        case X86_BUG_SPECTRE_V2:
-               return sprintf(buf, "%s%s%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled],
-                              ibpb_state(),
-                              boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "",
-                              stibp_state(),
-                              boot_cpu_has(X86_FEATURE_RSB_CTXSW) ? ", RSB filling" : "",
-                              spectre_v2_module_string());
+               return spectre_v2_show_state(buf);
 
        case X86_BUG_SPEC_STORE_BYPASS:
                return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
index f734e3b..d77481e 100644 (file)
@@ -463,6 +463,7 @@ static bool pv_tlb_flush_supported(void)
        return (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&
                !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
                kvm_para_has_feature(KVM_FEATURE_STEAL_TIME) &&
+               !boot_cpu_has(X86_FEATURE_MWAIT) &&
                (num_possible_cpus() != 1));
 }
 
@@ -477,6 +478,7 @@ static bool pv_sched_yield_supported(void)
        return (kvm_para_has_feature(KVM_FEATURE_PV_SCHED_YIELD) &&
                !kvm_para_has_hint(KVM_HINTS_REALTIME) &&
            kvm_para_has_feature(KVM_FEATURE_STEAL_TIME) &&
+           !boot_cpu_has(X86_FEATURE_MWAIT) &&
            (num_possible_cpus() != 1));
 }
 
@@ -622,7 +624,7 @@ static void kvm_smp_send_call_func_ipi(const struct cpumask *mask)
 
        /* Make sure other vCPUs get a chance to run if they need to. */
        for_each_cpu(cpu, mask) {
-               if (vcpu_is_preempted(cpu)) {
+               if (!idle_cpu(cpu) && vcpu_is_preempted(cpu)) {
                        kvm_hypercall1(KVM_HC_SCHED_YIELD, per_cpu(x86_cpu_to_apicid, cpu));
                        break;
                }
index a35cbf9..c5caa73 100644 (file)
@@ -239,6 +239,9 @@ static void __init kvmclock_init_mem(void)
 
 static int __init kvm_setup_vsyscall_timeinfo(void)
 {
+       if (!kvm_para_available() || !kvmclock)
+               return 0;
+
        kvmclock_init_mem();
 
 #ifdef CONFIG_X86_64
index 8e24f73..5628d0b 100644 (file)
@@ -3565,7 +3565,7 @@ set_root_pgd:
 out_unlock:
        write_unlock(&vcpu->kvm->mmu_lock);
 
-       return 0;
+       return r;
 }
 
 static int mmu_alloc_special_roots(struct kvm_vcpu *vcpu)
index ba34e94..dc822a1 100644 (file)
@@ -246,8 +246,7 @@ static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx,
        src = &prev->host_state;
        dest = &vmx->loaded_vmcs->host_state;
 
-       vmx_set_vmcs_host_state(dest, src->cr3, src->fs_sel, src->gs_sel,
-                               src->fs_base, src->gs_base);
+       vmx_set_host_fs_gs(dest, src->fs_sel, src->gs_sel, src->fs_base, src->gs_base);
        dest->ldt_sel = src->ldt_sel;
 #ifdef CONFIG_X86_64
        dest->ds_sel = src->ds_sel;
@@ -3056,7 +3055,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
 static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       unsigned long cr4;
+       unsigned long cr3, cr4;
        bool vm_fail;
 
        if (!nested_early_check)
@@ -3079,6 +3078,12 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
         */
        vmcs_writel(GUEST_RFLAGS, 0);
 
+       cr3 = __get_current_cr3_fast();
+       if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) {
+               vmcs_writel(HOST_CR3, cr3);
+               vmx->loaded_vmcs->host_state.cr3 = cr3;
+       }
+
        cr4 = cr4_read_shadow();
        if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) {
                vmcs_writel(HOST_CR4, cr4);
index efda5e4..b730d79 100644 (file)
@@ -1080,14 +1080,9 @@ static void pt_guest_exit(struct vcpu_vmx *vmx)
                wrmsrl(MSR_IA32_RTIT_CTL, vmx->pt_desc.host.ctl);
 }
 
-void vmx_set_vmcs_host_state(struct vmcs_host_state *host, unsigned long cr3,
-                            u16 fs_sel, u16 gs_sel,
-                            unsigned long fs_base, unsigned long gs_base)
+void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
+                       unsigned long fs_base, unsigned long gs_base)
 {
-       if (unlikely(cr3 != host->cr3)) {
-               vmcs_writel(HOST_CR3, cr3);
-               host->cr3 = cr3;
-       }
        if (unlikely(fs_sel != host->fs_sel)) {
                if (!(fs_sel & 7))
                        vmcs_write16(HOST_FS_SELECTOR, fs_sel);
@@ -1182,9 +1177,7 @@ void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
        gs_base = segment_base(gs_sel);
 #endif
 
-       vmx_set_vmcs_host_state(host_state, __get_current_cr3_fast(),
-                               fs_sel, gs_sel, fs_base, gs_base);
-
+       vmx_set_host_fs_gs(host_state, fs_sel, gs_sel, fs_base, gs_base);
        vmx->guest_state_loaded = true;
 }
 
@@ -6791,7 +6784,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       unsigned long cr4;
+       unsigned long cr3, cr4;
 
        /* Record the guest's net vcpu time for enforced NMI injections. */
        if (unlikely(!enable_vnmi &&
@@ -6834,6 +6827,19 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
                vmcs_writel(GUEST_RIP, vcpu->arch.regs[VCPU_REGS_RIP]);
        vcpu->arch.regs_dirty = 0;
 
+       /*
+        * Refresh vmcs.HOST_CR3 if necessary.  This must be done immediately
+        * prior to VM-Enter, as the kernel may load a new ASID (PCID) any time
+        * it switches back to the current->mm, which can occur in KVM context
+        * when switching to a temporary mm to patch kernel code, e.g. if KVM
+        * toggles a static key while handling a VM-Exit.
+        */
+       cr3 = __get_current_cr3_fast();
+       if (unlikely(cr3 != vmx->loaded_vmcs->host_state.cr3)) {
+               vmcs_writel(HOST_CR3, cr3);
+               vmx->loaded_vmcs->host_state.cr3 = cr3;
+       }
+
        cr4 = cr4_read_shadow();
        if (unlikely(cr4 != vmx->loaded_vmcs->host_state.cr4)) {
                vmcs_writel(HOST_CR4, cr4);
index 7f2c82e..9c6bfcd 100644 (file)
@@ -374,9 +374,8 @@ int allocate_vpid(void);
 void free_vpid(int vpid);
 void vmx_set_constant_host_state(struct vcpu_vmx *vmx);
 void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu);
-void vmx_set_vmcs_host_state(struct vmcs_host_state *host, unsigned long cr3,
-                            u16 fs_sel, u16 gs_sel,
-                            unsigned long fs_base, unsigned long gs_base);
+void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel,
+                       unsigned long fs_base, unsigned long gs_base);
 int vmx_get_cpl(struct kvm_vcpu *vcpu);
 bool vmx_emulation_required(struct kvm_vcpu *vcpu);
 unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu);
index 82a9dcd..eb40296 100644 (file)
@@ -9180,6 +9180,7 @@ static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
                likely(!pic_in_kernel(vcpu->kvm));
 }
 
+/* Called within kvm->srcu read side.  */
 static void post_kvm_run_save(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *kvm_run = vcpu->run;
@@ -9188,16 +9189,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
        kvm_run->cr8 = kvm_get_cr8(vcpu);
        kvm_run->apic_base = kvm_get_apic_base(vcpu);
 
-       /*
-        * The call to kvm_ready_for_interrupt_injection() may end up in
-        * kvm_xen_has_interrupt() which may require the srcu lock to be
-        * held, to protect against changes in the vcpu_info address.
-        */
-       vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
        kvm_run->ready_for_interrupt_injection =
                pic_in_kernel(vcpu->kvm) ||
                kvm_vcpu_ready_for_interrupt_injection(vcpu);
-       srcu_read_unlock(&vcpu->kvm->srcu, vcpu->srcu_idx);
 
        if (is_smm(vcpu))
                kvm_run->flags |= KVM_RUN_X86_SMM;
@@ -9815,6 +9809,7 @@ void __kvm_request_immediate_exit(struct kvm_vcpu *vcpu)
 EXPORT_SYMBOL_GPL(__kvm_request_immediate_exit);
 
 /*
+ * Called within kvm->srcu read side.
  * Returns 1 to let vcpu_run() continue the guest execution loop without
  * exiting to the userspace.  Otherwise, the value will be returned to the
  * userspace.
@@ -10193,6 +10188,7 @@ out:
        return r;
 }
 
+/* Called within kvm->srcu read side.  */
 static inline int vcpu_block(struct kvm *kvm, struct kvm_vcpu *vcpu)
 {
        bool hv_timer;
@@ -10252,12 +10248,12 @@ static inline bool kvm_vcpu_running(struct kvm_vcpu *vcpu)
                !vcpu->arch.apf.halted);
 }
 
+/* Called within kvm->srcu read side.  */
 static int vcpu_run(struct kvm_vcpu *vcpu)
 {
        int r;
        struct kvm *kvm = vcpu->kvm;
 
-       vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
        vcpu->arch.l1tf_flush_l1d = true;
 
        for (;;) {
@@ -10285,14 +10281,12 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
                if (__xfer_to_guest_mode_work_pending()) {
                        srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
                        r = xfer_to_guest_mode_handle_work(vcpu);
+                       vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
                        if (r)
                                return r;
-                       vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
                }
        }
 
-       srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
-
        return r;
 }
 
@@ -10398,6 +10392,7 @@ static void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 {
        struct kvm_run *kvm_run = vcpu->run;
+       struct kvm *kvm = vcpu->kvm;
        int r;
 
        vcpu_load(vcpu);
@@ -10405,6 +10400,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
        kvm_run->flags = 0;
        kvm_load_guest_fpu(vcpu);
 
+       vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
        if (unlikely(vcpu->arch.mp_state == KVM_MP_STATE_UNINITIALIZED)) {
                if (kvm_run->immediate_exit) {
                        r = -EINTR;
@@ -10415,7 +10411,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
                 * use before KVM has ever run the vCPU.
                 */
                WARN_ON_ONCE(kvm_lapic_hv_timer_in_use(vcpu));
+
+               srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
                kvm_vcpu_block(vcpu);
+               vcpu->srcu_idx = srcu_read_lock(&kvm->srcu);
+
                if (kvm_apic_accept_events(vcpu) < 0) {
                        r = 0;
                        goto out;
@@ -10475,8 +10475,9 @@ out:
        if (kvm_run->kvm_valid_regs)
                store_regs(vcpu);
        post_kvm_run_save(vcpu);
-       kvm_sigset_deactivate(vcpu);
+       srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx);
 
+       kvm_sigset_deactivate(vcpu);
        vcpu_put(vcpu);
        return r;
 }
index 89b3fb2..afbdda5 100644 (file)
@@ -34,7 +34,7 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
 
        ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), \
                      __stringify(RETPOLINE \reg), X86_FEATURE_RETPOLINE, \
-                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_AMD
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE
 
 .endm
 
index 2b1e266..0ecb140 100644 (file)
@@ -394,7 +394,7 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
        u8 *prog = *pprog;
 
 #ifdef CONFIG_RETPOLINE
-       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_AMD)) {
+       if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                EMIT_LFENCE();
                EMIT2(0xFF, 0xE0 + reg);
        } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
index 3bc3c31..4f67404 100644 (file)
@@ -1676,6 +1676,8 @@ static int fs_init(struct fs_dev *dev)
        dev->hw_base = pci_resource_start(pci_dev, 0);
 
        dev->base = ioremap(dev->hw_base, 0x1000);
+       if (!dev->base)
+               return 1;
 
        reset_chip (dev);
   
index 38ba086..2578b2d 100644 (file)
@@ -238,7 +238,7 @@ static int lcd2s_redefine_char(struct charlcd *lcd, char *esc)
        if (buf[1] > 7)
                return 1;
 
-       i = 0;
+       i = 2;
        shift = 0;
        value = 0;
        while (*esc && i < LCD2S_CHARACTER_SIZE + 2) {
@@ -298,6 +298,10 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c,
                        I2C_FUNC_SMBUS_WRITE_BLOCK_DATA))
                return -EIO;
 
+       lcd2s = devm_kzalloc(&i2c->dev, sizeof(*lcd2s), GFP_KERNEL);
+       if (!lcd2s)
+               return -ENOMEM;
+
        /* Test, if the display is responding */
        err = lcd2s_i2c_smbus_write_byte(i2c, LCD2S_CMD_DISPLAY_OFF);
        if (err < 0)
@@ -307,12 +311,6 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c,
        if (!lcd)
                return -ENOMEM;
 
-       lcd2s = kzalloc(sizeof(struct lcd2s_data), GFP_KERNEL);
-       if (!lcd2s) {
-               err = -ENOMEM;
-               goto fail1;
-       }
-
        lcd->drvdata = lcd2s;
        lcd2s->i2c = i2c;
        lcd2s->charlcd = lcd;
@@ -321,26 +319,24 @@ static int lcd2s_i2c_probe(struct i2c_client *i2c,
        err = device_property_read_u32(&i2c->dev, "display-height-chars",
                        &lcd->height);
        if (err)
-               goto fail2;
+               goto fail1;
 
        err = device_property_read_u32(&i2c->dev, "display-width-chars",
                        &lcd->width);
        if (err)
-               goto fail2;
+               goto fail1;
 
        lcd->ops = &lcd2s_ops;
 
        err = charlcd_register(lcd2s->charlcd);
        if (err)
-               goto fail2;
+               goto fail1;
 
        i2c_set_clientdata(i2c, lcd2s);
        return 0;
 
-fail2:
-       kfree(lcd2s);
 fail1:
-       kfree(lcd);
+       charlcd_free(lcd2s->charlcd);
        return err;
 }
 
@@ -349,7 +345,7 @@ static int lcd2s_i2c_remove(struct i2c_client *i2c)
        struct lcd2s_data *lcd2s = i2c_get_clientdata(i2c);
 
        charlcd_unregister(lcd2s->charlcd);
-       kfree(lcd2s->charlcd);
+       charlcd_free(lcd2s->charlcd);
        return 0;
 }
 
index c443cd6..8c415be 100644 (file)
@@ -76,9 +76,6 @@ struct virtio_blk {
         */
        refcount_t refs;
 
-       /* What host tells us, plus 2 for header & tailer. */
-       unsigned int sg_elems;
-
        /* Ida index - used to track minor number allocations. */
        int index;
 
@@ -322,8 +319,6 @@ static blk_status_t virtio_queue_rq(struct blk_mq_hw_ctx *hctx,
        blk_status_t status;
        int err;
 
-       BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
-
        status = virtblk_setup_cmd(vblk->vdev, req, vbr);
        if (unlikely(status))
                return status;
@@ -783,8 +778,6 @@ static int virtblk_probe(struct virtio_device *vdev)
        /* Prevent integer overflows and honor max vq size */
        sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
 
-       /* We need extra sg elements at head and tail. */
-       sg_elems += 2;
        vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
        if (!vblk) {
                err = -ENOMEM;
@@ -796,7 +789,6 @@ static int virtblk_probe(struct virtio_device *vdev)
        mutex_init(&vblk->vdev_mutex);
 
        vblk->vdev = vdev;
-       vblk->sg_elems = sg_elems;
 
        INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
 
@@ -853,7 +845,7 @@ static int virtblk_probe(struct virtio_device *vdev)
                set_disk_ro(vblk->disk, 1);
 
        /* We can handle whatever the host told us to handle. */
-       blk_queue_max_segments(q, vblk->sg_elems-2);
+       blk_queue_max_segments(q, sg_elems);
 
        /* No real sector limit. */
        blk_queue_max_hw_sectors(q, -1U);
@@ -925,9 +917,15 @@ static int virtblk_probe(struct virtio_device *vdev)
 
                virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
                             &v);
+
+               /*
+                * max_discard_seg == 0 is out of spec but we always
+                * handled it.
+                */
+               if (!v)
+                       v = sg_elems;
                blk_queue_max_discard_segments(q,
-                                              min_not_zero(v,
-                                                           MAX_DISCARD_SEGMENTS));
+                                              min(v, MAX_DISCARD_SEGMENTS));
 
                blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
        }
index ca71a05..03b5fb3 100644 (file)
@@ -1288,7 +1288,8 @@ free_shadow:
                        rinfo->ring_ref[i] = GRANT_INVALID_REF;
                }
        }
-       free_pages((unsigned long)rinfo->ring.sring, get_order(info->nr_ring_pages * XEN_PAGE_SIZE));
+       free_pages_exact(rinfo->ring.sring,
+                        info->nr_ring_pages * XEN_PAGE_SIZE);
        rinfo->ring.sring = NULL;
 
        if (rinfo->irq)
@@ -1372,9 +1373,15 @@ static int blkif_get_final_status(enum blk_req_status s1,
        return BLKIF_RSP_OKAY;
 }
 
-static bool blkif_completion(unsigned long *id,
-                            struct blkfront_ring_info *rinfo,
-                            struct blkif_response *bret)
+/*
+ * Return values:
+ *  1 response processed.
+ *  0 missing further responses.
+ * -1 error while processing.
+ */
+static int blkif_completion(unsigned long *id,
+                           struct blkfront_ring_info *rinfo,
+                           struct blkif_response *bret)
 {
        int i = 0;
        struct scatterlist *sg;
@@ -1397,7 +1404,7 @@ static bool blkif_completion(unsigned long *id,
 
                /* Wait the second response if not yet here. */
                if (s2->status < REQ_DONE)
-                       return false;
+                       return 0;
 
                bret->status = blkif_get_final_status(s->status,
                                                      s2->status);
@@ -1448,42 +1455,43 @@ static bool blkif_completion(unsigned long *id,
        }
        /* Add the persistent grant into the list of free grants */
        for (i = 0; i < num_grant; i++) {
-               if (gnttab_query_foreign_access(s->grants_used[i]->gref)) {
+               if (!gnttab_try_end_foreign_access(s->grants_used[i]->gref)) {
                        /*
                         * If the grant is still mapped by the backend (the
                         * backend has chosen to make this grant persistent)
                         * we add it at the head of the list, so it will be
                         * reused first.
                         */
-                       if (!info->feature_persistent)
-                               pr_alert_ratelimited("backed has not unmapped grant: %u\n",
-                                                    s->grants_used[i]->gref);
+                       if (!info->feature_persistent) {
+                               pr_alert("backed has not unmapped grant: %u\n",
+                                        s->grants_used[i]->gref);
+                               return -1;
+                       }
                        list_add(&s->grants_used[i]->node, &rinfo->grants);
                        rinfo->persistent_gnts_c++;
                } else {
                        /*
-                        * If the grant is not mapped by the backend we end the
-                        * foreign access and add it to the tail of the list,
-                        * so it will not be picked again unless we run out of
-                        * persistent grants.
+                        * If the grant is not mapped by the backend we add it
+                        * to the tail of the list, so it will not be picked
+                        * again unless we run out of persistent grants.
                         */
-                       gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
                        s->grants_used[i]->gref = GRANT_INVALID_REF;
                        list_add_tail(&s->grants_used[i]->node, &rinfo->grants);
                }
        }
        if (s->req.operation == BLKIF_OP_INDIRECT) {
                for (i = 0; i < INDIRECT_GREFS(num_grant); i++) {
-                       if (gnttab_query_foreign_access(s->indirect_grants[i]->gref)) {
-                               if (!info->feature_persistent)
-                                       pr_alert_ratelimited("backed has not unmapped grant: %u\n",
-                                                            s->indirect_grants[i]->gref);
+                       if (!gnttab_try_end_foreign_access(s->indirect_grants[i]->gref)) {
+                               if (!info->feature_persistent) {
+                                       pr_alert("backed has not unmapped grant: %u\n",
+                                                s->indirect_grants[i]->gref);
+                                       return -1;
+                               }
                                list_add(&s->indirect_grants[i]->node, &rinfo->grants);
                                rinfo->persistent_gnts_c++;
                        } else {
                                struct page *indirect_page;
 
-                               gnttab_end_foreign_access(s->indirect_grants[i]->gref, 0, 0UL);
                                /*
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
@@ -1498,7 +1506,7 @@ static bool blkif_completion(unsigned long *id,
                }
        }
 
-       return true;
+       return 1;
 }
 
 static irqreturn_t blkif_interrupt(int irq, void *dev_id)
@@ -1564,12 +1572,17 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
                }
 
                if (bret.operation != BLKIF_OP_DISCARD) {
+                       int ret;
+
                        /*
                         * We may need to wait for an extra response if the
                         * I/O request is split in 2
                         */
-                       if (!blkif_completion(&id, rinfo, &bret))
+                       ret = blkif_completion(&id, rinfo, &bret);
+                       if (!ret)
                                continue;
+                       if (unlikely(ret < 0))
+                               goto err;
                }
 
                if (add_id_to_freelist(rinfo, id)) {
@@ -1676,8 +1689,7 @@ static int setup_blkring(struct xenbus_device *dev,
        for (i = 0; i < info->nr_ring_pages; i++)
                rinfo->ring_ref[i] = GRANT_INVALID_REF;
 
-       sring = (struct blkif_sring *)__get_free_pages(GFP_NOIO | __GFP_HIGH,
-                                                      get_order(ring_size));
+       sring = alloc_pages_exact(ring_size, GFP_NOIO);
        if (!sring) {
                xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
                return -ENOMEM;
@@ -1687,7 +1699,7 @@ static int setup_blkring(struct xenbus_device *dev,
 
        err = xenbus_grant_ring(dev, rinfo->ring.sring, info->nr_ring_pages, gref);
        if (err < 0) {
-               free_pages((unsigned long)sring, get_order(ring_size));
+               free_pages_exact(sring, ring_size);
                rinfo->ring.sring = NULL;
                goto fail;
        }
@@ -2532,11 +2544,10 @@ static void purge_persistent_grants(struct blkfront_info *info)
                list_for_each_entry_safe(gnt_list_entry, tmp, &rinfo->grants,
                                         node) {
                        if (gnt_list_entry->gref == GRANT_INVALID_REF ||
-                           gnttab_query_foreign_access(gnt_list_entry->gref))
+                           !gnttab_try_end_foreign_access(gnt_list_entry->gref))
                                continue;
 
                        list_del(&gnt_list_entry->node);
-                       gnttab_end_foreign_access(gnt_list_entry->gref, 0, 0UL);
                        rinfo->persistent_gnts_c--;
                        gnt_list_entry->gref = GRANT_INVALID_REF;
                        list_add_tail(&gnt_list_entry->node, &rinfo->grants);
index 2359889..e3c4305 100644 (file)
@@ -1957,6 +1957,13 @@ static void virtcons_remove(struct virtio_device *vdev)
        list_del(&portdev->list);
        spin_unlock_irq(&pdrvdata_lock);
 
+       /* Device is going away, exit any polling for buffers */
+       virtio_break_device(vdev);
+       if (use_multiport(portdev))
+               flush_work(&portdev->control_work);
+       else
+               flush_work(&portdev->config_work);
+
        /* Disable interrupts for vqs */
        virtio_reset_device(vdev);
        /* Finish up work that's lined up */
index ad4256d..d4d67fb 100644 (file)
@@ -231,6 +231,8 @@ config COMMON_CLK_GEMINI
 
 config COMMON_CLK_LAN966X
        bool "Generic Clock Controller driver for LAN966X SoC"
+       depends on HAS_IOMEM
+       depends on OF
        help
          This driver provides support for Generic Clock Controller(GCK) on
          LAN966X SoC. GCK generates and supplies clock to various peripherals
index 538e496..5d2ae29 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2019, 2022, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/clk-provider.h>
@@ -625,6 +625,9 @@ static struct clk_branch disp_cc_mdss_vsync_clk = {
 
 static struct gdsc mdss_gdsc = {
        .gdscr = 0x3000,
+       .en_rest_wait_val = 0x2,
+       .en_few_wait_val = 0x2,
+       .clk_dis_wait_val = 0xf,
        .pd = {
                .name = "mdss_gdsc",
        },
index 4ef4ae2..ad596d5 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2021-2022, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/clk-provider.h>
@@ -787,6 +787,9 @@ static struct clk_branch disp_cc_sleep_clk = {
 
 static struct gdsc disp_cc_mdss_core_gdsc = {
        .gdscr = 0x1004,
+       .en_rest_wait_val = 0x2,
+       .en_few_wait_val = 0x2,
+       .clk_dis_wait_val = 0xf,
        .pd = {
                .name = "disp_cc_mdss_core_gdsc",
        },
index 566fdfa..db93796 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 /*
- * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, 2022, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/clk-provider.h>
@@ -1126,6 +1126,9 @@ static struct clk_branch disp_cc_mdss_vsync_clk = {
 
 static struct gdsc mdss_gdsc = {
        .gdscr = 0x3000,
+       .en_rest_wait_val = 0x2,
+       .en_few_wait_val = 0x2,
+       .clk_dis_wait_val = 0xf,
        .pd = {
                .name = "mdss_gdsc",
        },
index 7e1dd8c..44520ef 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/bitops.h>
 #define CFG_GDSCR_OFFSET               0x4
 
 /* Wait 2^n CXO cycles between all states. Here, n=2 (4 cycles). */
-#define EN_REST_WAIT_VAL       (0x2 << 20)
-#define EN_FEW_WAIT_VAL                (0x8 << 16)
-#define CLK_DIS_WAIT_VAL       (0x2 << 12)
+#define EN_REST_WAIT_VAL       0x2
+#define EN_FEW_WAIT_VAL                0x8
+#define CLK_DIS_WAIT_VAL       0x2
+
+/* Transition delay shifts */
+#define EN_REST_WAIT_SHIFT     20
+#define EN_FEW_WAIT_SHIFT      16
+#define CLK_DIS_WAIT_SHIFT     12
 
 #define RETAIN_MEM             BIT(14)
 #define RETAIN_PERIPH          BIT(13)
@@ -380,7 +385,18 @@ static int gdsc_init(struct gdsc *sc)
         */
        mask = HW_CONTROL_MASK | SW_OVERRIDE_MASK |
               EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK;
-       val = EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
+
+       if (!sc->en_rest_wait_val)
+               sc->en_rest_wait_val = EN_REST_WAIT_VAL;
+       if (!sc->en_few_wait_val)
+               sc->en_few_wait_val = EN_FEW_WAIT_VAL;
+       if (!sc->clk_dis_wait_val)
+               sc->clk_dis_wait_val = CLK_DIS_WAIT_VAL;
+
+       val = sc->en_rest_wait_val << EN_REST_WAIT_SHIFT |
+               sc->en_few_wait_val << EN_FEW_WAIT_SHIFT |
+               sc->clk_dis_wait_val << CLK_DIS_WAIT_SHIFT;
+
        ret = regmap_update_bits(sc->regmap, sc->gdscr, mask, val);
        if (ret)
                return ret;
index d7cc4c2..ad313d7 100644 (file)
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015, 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, 2017-2018, 2022, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __QCOM_GDSC_H__
@@ -22,6 +22,9 @@ struct reset_controller_dev;
  * @cxcs: offsets of branch registers to toggle mem/periph bits in
  * @cxc_count: number of @cxcs
  * @pwrsts: Possible powerdomain power states
+ * @en_rest_wait_val: transition delay value for receiving enr ack signal
+ * @en_few_wait_val: transition delay value for receiving enf ack signal
+ * @clk_dis_wait_val: transition delay value for halting clock
  * @resets: ids of resets associated with this gdsc
  * @reset_count: number of @resets
  * @rcdev: reset controller
@@ -36,6 +39,9 @@ struct gdsc {
        unsigned int                    clamp_io_ctrl;
        unsigned int                    *cxcs;
        unsigned int                    cxc_count;
+       unsigned int                    en_rest_wait_val;
+       unsigned int                    en_few_wait_val;
+       unsigned int                    clk_dis_wait_val;
        const u8                        pwrsts;
 /* Powerdomain allowable state bitfields */
 #define PWRSTS_OFF             BIT(0)
index 5c40ca1..1fccb45 100644 (file)
@@ -241,8 +241,7 @@ static void __init dmtimer_systimer_assign_alwon(void)
        bool quirk_unreliable_oscillator = false;
 
        /* Quirk unreliable 32 KiHz oscillator with incomplete dts */
-       if (of_machine_is_compatible("ti,omap3-beagle-ab4") ||
-           of_machine_is_compatible("timll,omap3-devkit8000")) {
+       if (of_machine_is_compatible("ti,omap3-beagle-ab4")) {
                quirk_unreliable_oscillator = true;
                counter_32k = -ENODEV;
        }
index b406b3f..d76bab3 100644 (file)
@@ -2112,7 +2112,7 @@ static void __exit scmi_driver_exit(void)
 }
 module_exit(scmi_driver_exit);
 
-MODULE_ALIAS("platform: arm-scmi");
+MODULE_ALIAS("platform:arm-scmi");
 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
 MODULE_DESCRIPTION("ARM SCMI protocol driver");
 MODULE_LICENSE("GPL v2");
index 380e4e2..9c46084 100644 (file)
@@ -25,7 +25,7 @@ typedef void __noreturn (*jump_kernel_func)(unsigned int, unsigned long);
 
 static u32 hartid;
 
-static u32 get_boot_hartid_from_fdt(void)
+static int get_boot_hartid_from_fdt(void)
 {
        const void *fdt;
        int chosen_node, len;
@@ -33,23 +33,26 @@ static u32 get_boot_hartid_from_fdt(void)
 
        fdt = get_efi_config_table(DEVICE_TREE_GUID);
        if (!fdt)
-               return U32_MAX;
+               return -EINVAL;
 
        chosen_node = fdt_path_offset(fdt, "/chosen");
        if (chosen_node < 0)
-               return U32_MAX;
+               return -EINVAL;
 
        prop = fdt_getprop((void *)fdt, chosen_node, "boot-hartid", &len);
        if (!prop || len != sizeof(u32))
-               return U32_MAX;
+               return -EINVAL;
 
-       return fdt32_to_cpu(*prop);
+       hartid = fdt32_to_cpu(*prop);
+       return 0;
 }
 
 efi_status_t check_platform_features(void)
 {
-       hartid = get_boot_hartid_from_fdt();
-       if (hartid == U32_MAX) {
+       int ret;
+
+       ret = get_boot_hartid_from_fdt();
+       if (ret) {
                efi_err("/chosen/boot-hartid missing or invalid!\n");
                return EFI_UNSUPPORTED;
        }
index abdc8a6..cae590b 100644 (file)
@@ -742,6 +742,7 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
 {
        const struct efivar_operations *ops;
        efi_status_t status;
+       unsigned long varsize;
 
        if (!__efivars)
                return -EINVAL;
@@ -764,15 +765,17 @@ int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes,
                return efivar_entry_set_nonblocking(name, vendor, attributes,
                                                    size, data);
 
+       varsize = size + ucs2_strsize(name, 1024);
        if (!block) {
                if (down_trylock(&efivars_lock))
                        return -EBUSY;
+               status = check_var_size_nonblocking(attributes, varsize);
        } else {
                if (down_interruptible(&efivars_lock))
                        return -EINTR;
+               status = check_var_size(attributes, varsize);
        }
 
-       status = check_var_size(attributes, size + ucs2_strsize(name, 1024));
        if (status != EFI_SUCCESS) {
                up(&efivars_lock);
                return -ENOSPC;
index 153fe79..8e5d879 100644 (file)
@@ -547,7 +547,7 @@ struct gpio_sim_bank {
         *
         * So we need to store the pointer to the parent struct here. We can
         * dereference it anywhere we need with no checks and no locking as
-        * it's guaranteed to survive the childred and protected by configfs
+        * it's guaranteed to survive the children and protected by configfs
         * locks.
         *
         * Same for other structures.
@@ -1322,7 +1322,7 @@ static void gpio_sim_hog_config_item_release(struct config_item *item)
        kfree(hog);
 }
 
-struct configfs_item_operations gpio_sim_hog_config_item_ops = {
+static struct configfs_item_operations gpio_sim_hog_config_item_ops = {
        .release        = gpio_sim_hog_config_item_release,
 };
 
index 8d298be..031fe10 100644 (file)
@@ -1075,6 +1075,7 @@ static const struct tegra_gpio_soc tegra241_main_soc = {
        .ports = tegra241_main_ports,
        .name = "tegra241-gpio",
        .instance = 0,
+       .num_irqs_per_bank = 8,
 };
 
 #define TEGRA241_AON_GPIO_PORT(_name, _bank, _port, _pins)     \
@@ -1095,6 +1096,7 @@ static const struct tegra_gpio_soc tegra241_aon_soc = {
        .ports = tegra241_aon_ports,
        .name = "tegra241-gpio-aon",
        .instance = 1,
+       .num_irqs_per_bank = 8,
 };
 
 static const struct of_device_id tegra186_gpio_of_match[] = {
index d885032..d918d2d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Digital I/O driver for Technologic Systems I2C FPGA Core
  *
- * Copyright (C) 2015 Technologic Systems
+ * Copyright (C) 2015, 2018 Technologic Systems
  * Copyright (C) 2016 Savoir-Faire Linux
  *
  * This program is free software; you can redistribute it and/or
@@ -55,19 +55,33 @@ static int ts4900_gpio_direction_input(struct gpio_chip *chip,
 {
        struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
 
-       /*
-        * This will clear the output enable bit, the other bits are
-        * dontcare when this is cleared
+       /* Only clear the OE bit here, requires a RMW. Prevents potential issue
+        * with OE and data getting to the physical pin at different times.
         */
-       return regmap_write(priv->regmap, offset, 0);
+       return regmap_update_bits(priv->regmap, offset, TS4900_GPIO_OE, 0);
 }
 
 static int ts4900_gpio_direction_output(struct gpio_chip *chip,
                                        unsigned int offset, int value)
 {
        struct ts4900_gpio_priv *priv = gpiochip_get_data(chip);
+       unsigned int reg;
        int ret;
 
+       /* If changing from an input to an output, we need to first set the
+        * proper data bit to what is requested and then set OE bit. This
+        * prevents a glitch that can occur on the IO line
+        */
+       regmap_read(priv->regmap, offset, &reg);
+       if (!(reg & TS4900_GPIO_OE)) {
+               if (value)
+                       reg = TS4900_GPIO_OUT;
+               else
+                       reg &= ~TS4900_GPIO_OUT;
+
+               regmap_write(priv->regmap, offset, reg);
+       }
+
        if (value)
                ret = regmap_write(priv->regmap, offset, TS4900_GPIO_OE |
                                                         TS4900_GPIO_OUT);
index c0f6a25..a5495ad 100644 (file)
@@ -307,7 +307,8 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
        if (IS_ERR(desc))
                return desc;
 
-       ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout);
+       /* ACPI uses hundredths of milliseconds units */
+       ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout * 10);
        if (ret)
                dev_warn(chip->parent,
                         "Failed to set debounce-timeout for pin 0x%04X, err %d\n",
@@ -1035,7 +1036,8 @@ int acpi_dev_gpio_irq_get_by(struct acpi_device *adev, const char *name, int ind
                        if (ret < 0)
                                return ret;
 
-                       ret = gpio_set_debounce_timeout(desc, info.debounce);
+                       /* ACPI uses hundredths of milliseconds units */
+                       ret = gpio_set_debounce_timeout(desc, info.debounce * 10);
                        if (ret)
                                return ret;
 
index a3d1427..defb7c4 100644 (file)
@@ -1701,11 +1701,6 @@ static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gc)
  */
 int gpiochip_generic_request(struct gpio_chip *gc, unsigned int offset)
 {
-#ifdef CONFIG_PINCTRL
-       if (list_empty(&gc->gpiodev->pin_ranges))
-               return 0;
-#endif
-
        return pinctrl_gpio_request(gc->gpiodev->base + offset);
 }
 EXPORT_SYMBOL_GPL(gpiochip_generic_request);
@@ -1717,11 +1712,6 @@ EXPORT_SYMBOL_GPL(gpiochip_generic_request);
  */
 void gpiochip_generic_free(struct gpio_chip *gc, unsigned int offset)
 {
-#ifdef CONFIG_PINCTRL
-       if (list_empty(&gc->gpiodev->pin_ranges))
-               return;
-#endif
-
        pinctrl_gpio_free(gc->gpiodev->base + offset);
 }
 EXPORT_SYMBOL_GPL(gpiochip_generic_free);
@@ -2227,6 +2217,16 @@ static int gpio_set_bias(struct gpio_desc *desc)
        return gpio_set_config_with_argument_optional(desc, bias, arg);
 }
 
+/**
+ * gpio_set_debounce_timeout() - Set debounce timeout
+ * @desc:      GPIO descriptor to set the debounce timeout
+ * @debounce:  Debounce timeout in microseconds
+ *
+ * The function calls the certain GPIO driver to set debounce timeout
+ * in the hardware.
+ *
+ * Returns 0 on success, or negative error code otherwise.
+ */
 int gpio_set_debounce_timeout(struct gpio_desc *desc, unsigned int debounce)
 {
        return gpio_set_config_with_argument_optional(desc,
index d62190b..418341a 100644 (file)
@@ -777,7 +777,8 @@ bool amdgpu_vm_ready(struct amdgpu_vm *vm)
        amdgpu_vm_eviction_lock(vm);
        ret = !vm->evicting;
        amdgpu_vm_eviction_unlock(vm);
-       return ret;
+
+       return ret && list_empty(&vm->evicted);
 }
 
 /**
index 58a2428..6e3f1d6 100644 (file)
@@ -6,6 +6,7 @@ config DRM_HDLCD
        depends on DRM && OF && (ARM || ARM64 || COMPILE_TEST)
        depends on COMMON_CLK
        select DRM_KMS_HELPER
+       select DRM_GEM_CMA_HELPER
        help
          Choose this option if you have an ARM High Definition Colour LCD
          controller.
index dab8f76..68d8415 100644 (file)
@@ -1802,6 +1802,7 @@ static inline void ti_sn_gpio_unregister(void) {}
 
 static void ti_sn65dsi86_runtime_disable(void *data)
 {
+       pm_runtime_dont_use_autosuspend(data);
        pm_runtime_disable(data);
 }
 
@@ -1861,11 +1862,11 @@ static int ti_sn65dsi86_probe(struct i2c_client *client,
                                     "failed to get reference clock\n");
 
        pm_runtime_enable(dev);
+       pm_runtime_set_autosuspend_delay(pdata->dev, 500);
+       pm_runtime_use_autosuspend(pdata->dev);
        ret = devm_add_action_or_reset(dev, ti_sn65dsi86_runtime_disable, dev);
        if (ret)
                return ret;
-       pm_runtime_set_autosuspend_delay(pdata->dev, 500);
-       pm_runtime_use_autosuspend(pdata->dev);
 
        ti_sn65dsi86_debugfs_init(pdata);
 
index a50c82b..76a8c70 100644 (file)
@@ -2330,6 +2330,9 @@ EXPORT_SYMBOL(drm_connector_atomic_hdr_metadata_equal);
 void drm_connector_set_vrr_capable_property(
                struct drm_connector *connector, bool capable)
 {
+       if (!connector->vrr_capable_property)
+               return;
+
        drm_object_property_set_value(&connector->base,
                                      connector->vrr_capable_property,
                                      capable);
index 12571ac..c04264f 100644 (file)
@@ -678,7 +678,6 @@ static int decon_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct decon_context *ctx;
        struct device_node *i80_if_timings;
-       struct resource *res;
        int ret;
 
        if (!dev->of_node)
@@ -728,16 +727,11 @@ static int decon_probe(struct platform_device *pdev)
                goto err_iounmap;
        }
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          ctx->i80_if ? "lcd_sys" : "vsync");
-       if (!res) {
-               dev_err(dev, "irq request failed.\n");
-               ret = -ENXIO;
+       ret =  platform_get_irq_byname(pdev, ctx->i80_if ? "lcd_sys" : "vsync");
+       if (ret < 0)
                goto err_iounmap;
-       }
 
-       ret = devm_request_irq(dev, res->start, decon_irq_handler,
-                                                       0, "drm_decon", ctx);
+       ret = devm_request_irq(dev, ret, decon_irq_handler, 0, "drm_decon", ctx);
        if (ret) {
                dev_err(dev, "irq request failed.\n");
                goto err_iounmap;
index 32a3657..d13f5e3 100644 (file)
@@ -1334,8 +1334,10 @@ static int exynos_dsi_register_te_irq(struct exynos_dsi *dsi,
        int ret;
        int te_gpio_irq;
 
-       dsi->te_gpio = devm_gpiod_get_optional(dsi->dev, "te", GPIOD_IN);
-       if (IS_ERR(dsi->te_gpio)) {
+       dsi->te_gpio = gpiod_get_optional(panel, "te", GPIOD_IN);
+       if (!dsi->te_gpio) {
+               return 0;
+       } else if (IS_ERR(dsi->te_gpio)) {
                dev_err(dsi->dev, "gpio request failed with %ld\n",
                                PTR_ERR(dsi->te_gpio));
                return PTR_ERR(dsi->te_gpio);
index 023f54e..0ee32e4 100644 (file)
@@ -1267,7 +1267,6 @@ static int fimc_probe(struct platform_device *pdev)
        struct exynos_drm_ipp_formats *formats;
        struct device *dev = &pdev->dev;
        struct fimc_context *ctx;
-       struct resource *res;
        int ret;
        int i, j, num_limits, num_formats;
 
@@ -1330,14 +1329,12 @@ static int fimc_probe(struct platform_device *pdev)
                return PTR_ERR(ctx->regs);
 
        /* resource irq */
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(dev, "failed to request irq resource.\n");
-               return -ENOENT;
-       }
+       ret = platform_get_irq(pdev, 0);
+       if (ret < 0)
+               return ret;
 
-       ret = devm_request_irq(dev, res->start, fimc_irq_handler,
-               0, dev_name(dev), ctx);
+       ret = devm_request_irq(dev, ret, fimc_irq_handler,
+                              0, dev_name(dev), ctx);
        if (ret < 0) {
                dev_err(dev, "failed to request irq.\n");
                return ret;
index c735e53..7d5a483 100644 (file)
@@ -1133,7 +1133,6 @@ static int fimd_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct fimd_context *ctx;
        struct device_node *i80_if_timings;
-       struct resource *res;
        int ret;
 
        if (!dev->of_node)
@@ -1206,15 +1205,11 @@ static int fimd_probe(struct platform_device *pdev)
        if (IS_ERR(ctx->regs))
                return PTR_ERR(ctx->regs);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
-                                          ctx->i80_if ? "lcd_sys" : "vsync");
-       if (!res) {
-               dev_err(dev, "irq request failed.\n");
-               return -ENXIO;
-       }
+       ret = platform_get_irq_byname(pdev, ctx->i80_if ? "lcd_sys" : "vsync");
+       if (ret < 0)
+               return ret;
 
-       ret = devm_request_irq(dev, res->start, fimd_irq_handler,
-                                                       0, "drm_fimd", ctx);
+       ret = devm_request_irq(dev, ret, fimd_irq_handler, 0, "drm_fimd", ctx);
        if (ret) {
                dev_err(dev, "irq request failed.\n");
                return ret;
index 166a802..964dceb 100644 (file)
@@ -1220,7 +1220,6 @@ static int gsc_probe(struct platform_device *pdev)
        struct gsc_driverdata *driver_data;
        struct exynos_drm_ipp_formats *formats;
        struct gsc_context *ctx;
-       struct resource *res;
        int num_formats, ret, i, j;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
@@ -1275,13 +1274,10 @@ static int gsc_probe(struct platform_device *pdev)
                return PTR_ERR(ctx->regs);
 
        /* resource irq */
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(dev, "failed to request irq resource.\n");
-               return -ENOENT;
-       }
+       ctx->irq = platform_get_irq(pdev, 0);
+       if (ctx->irq < 0)
+               return ctx->irq;
 
-       ctx->irq = res->start;
        ret = devm_request_irq(dev, ctx->irq, gsc_irq_handler, 0,
                               dev_name(dev), ctx);
        if (ret < 0) {
index 41c54f1..e5204be 100644 (file)
@@ -809,19 +809,17 @@ static int mixer_resources_init(struct mixer_context *mixer_ctx)
                return -ENXIO;
        }
 
-       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
-       if (res == NULL) {
-               dev_err(dev, "get interrupt resource failed.\n");
-               return -ENXIO;
-       }
+       ret = platform_get_irq(mixer_ctx->pdev, 0);
+       if (ret < 0)
+               return ret;
+       mixer_ctx->irq = ret;
 
-       ret = devm_request_irq(dev, res->start, mixer_irq_handler,
-                                               0, "drm_mixer", mixer_ctx);
+       ret = devm_request_irq(dev, mixer_ctx->irq, mixer_irq_handler,
+                              0, "drm_mixer", mixer_ctx);
        if (ret) {
                dev_err(dev, "request interrupt failed.\n");
                return ret;
        }
-       mixer_ctx->irq = res->start;
 
        return 0;
 }
index 13b27b8..ba21ace 100644 (file)
@@ -110,7 +110,7 @@ static int guc_action_slpc_unset_param(struct intel_guc *guc, u8 id)
 {
        u32 request[] = {
                GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST,
-               SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 2),
+               SLPC_EVENT(SLPC_EVENT_PARAMETER_UNSET, 1),
                id,
        };
 
index da8f82c..fc8a68f 100644 (file)
@@ -108,6 +108,7 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
                /* Comet Lake V PCH is based on KBP, which is SPT compatible */
                return PCH_SPT;
        case INTEL_PCH_ICP_DEVICE_ID_TYPE:
+       case INTEL_PCH_ICP2_DEVICE_ID_TYPE:
                drm_dbg_kms(&dev_priv->drm, "Found Ice Lake PCH\n");
                drm_WARN_ON(&dev_priv->drm, !IS_ICELAKE(dev_priv));
                return PCH_ICP;
@@ -123,7 +124,6 @@ intel_pch_type(const struct drm_i915_private *dev_priv, unsigned short id)
                            !IS_GEN9_BC(dev_priv));
                return PCH_TGP;
        case INTEL_PCH_JSP_DEVICE_ID_TYPE:
-       case INTEL_PCH_JSP2_DEVICE_ID_TYPE:
                drm_dbg_kms(&dev_priv->drm, "Found Jasper Lake PCH\n");
                drm_WARN_ON(&dev_priv->drm, !IS_JSL_EHL(dev_priv));
                return PCH_JSP;
index 6bff775..4ba0f19 100644 (file)
@@ -50,11 +50,11 @@ enum intel_pch {
 #define INTEL_PCH_CMP2_DEVICE_ID_TYPE          0x0680
 #define INTEL_PCH_CMP_V_DEVICE_ID_TYPE         0xA380
 #define INTEL_PCH_ICP_DEVICE_ID_TYPE           0x3480
+#define INTEL_PCH_ICP2_DEVICE_ID_TYPE          0x3880
 #define INTEL_PCH_MCC_DEVICE_ID_TYPE           0x4B00
 #define INTEL_PCH_TGP_DEVICE_ID_TYPE           0xA080
 #define INTEL_PCH_TGP2_DEVICE_ID_TYPE          0x4380
 #define INTEL_PCH_JSP_DEVICE_ID_TYPE           0x4D80
-#define INTEL_PCH_JSP2_DEVICE_ID_TYPE          0x3880
 #define INTEL_PCH_ADP_DEVICE_ID_TYPE           0x7A80
 #define INTEL_PCH_ADP2_DEVICE_ID_TYPE          0x5180
 #define INTEL_PCH_ADP3_DEVICE_ID_TYPE          0x7A00
index 26c31d7..81e7e40 100644 (file)
@@ -860,7 +860,9 @@ static const char *keys[KEY_MAX + 1] = {
        [KEY_F22] = "F22",                      [KEY_F23] = "F23",
        [KEY_F24] = "F24",                      [KEY_PLAYCD] = "PlayCD",
        [KEY_PAUSECD] = "PauseCD",              [KEY_PROG3] = "Prog3",
-       [KEY_PROG4] = "Prog4",                  [KEY_SUSPEND] = "Suspend",
+       [KEY_PROG4] = "Prog4",
+       [KEY_ALL_APPLICATIONS] = "AllApplications",
+       [KEY_SUSPEND] = "Suspend",
        [KEY_CLOSE] = "Close",                  [KEY_PLAY] = "Play",
        [KEY_FASTFORWARD] = "FastForward",      [KEY_BASSBOOST] = "BassBoost",
        [KEY_PRINT] = "Print",                  [KEY_HP] = "HP",
@@ -969,6 +971,7 @@ static const char *keys[KEY_MAX + 1] = {
        [KEY_ASSISTANT] = "Assistant",
        [KEY_KBD_LAYOUT_NEXT] = "KbdLayoutNext",
        [KEY_EMOJI_PICKER] = "EmojiPicker",
+       [KEY_DICTATE] = "Dictate",
        [KEY_BRIGHTNESS_MIN] = "BrightnessMin",
        [KEY_BRIGHTNESS_MAX] = "BrightnessMax",
        [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
index 9b42b0c..2876cb6 100644 (file)
@@ -228,7 +228,6 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
        struct elo_priv *priv;
        int ret;
-       struct usb_device *udev;
 
        if (!hid_is_usb(hdev))
                return -EINVAL;
@@ -238,8 +237,7 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
                return -ENOMEM;
 
        INIT_DELAYED_WORK(&priv->work, elo_work);
-       udev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
-       priv->usbdev = usb_get_dev(udev);
+       priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent));
 
        hid_set_drvdata(hdev, priv);
 
@@ -262,7 +260,6 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
        return 0;
 err_free:
-       usb_put_dev(udev);
        kfree(priv);
        return ret;
 }
@@ -271,8 +268,6 @@ static void elo_remove(struct hid_device *hdev)
 {
        struct elo_priv *priv = hid_get_drvdata(hdev);
 
-       usb_put_dev(priv->usbdev);
-
        hid_hw_stop(hdev);
        cancel_delayed_work_sync(&priv->work);
        kfree(priv);
index 112901d..56ec273 100644 (file)
@@ -992,6 +992,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x0cd: map_key_clear(KEY_PLAYPAUSE);       break;
                case 0x0cf: map_key_clear(KEY_VOICECOMMAND);    break;
 
+               case 0x0d8: map_key_clear(KEY_DICTATE);         break;
                case 0x0d9: map_key_clear(KEY_EMOJI_PICKER);    break;
 
                case 0x0e0: map_abs_clear(ABS_VOLUME);          break;
@@ -1083,6 +1084,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
                case 0x29d: map_key_clear(KEY_KBD_LAYOUT_NEXT); break;
 
+               case 0x2a2: map_key_clear(KEY_ALL_APPLICATIONS);        break;
+
                case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV);             break;
                case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT);             break;
                case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP);                break;
index 7106b92..c358778 100644 (file)
@@ -1068,6 +1068,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
                workitem.reports_supported |= STD_KEYBOARD;
                break;
        case 0x0f:
+       case 0x11:
                device_type = "eQUAD Lightspeed 1.2";
                logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
                workitem.reports_supported |= STD_KEYBOARD;
index b6a9a0f..2204de8 100644 (file)
@@ -2128,6 +2128,10 @@ static int nintendo_hid_probe(struct hid_device *hdev,
        spin_lock_init(&ctlr->lock);
        ctlr->rumble_queue = alloc_workqueue("hid-nintendo-rumble_wq",
                                             WQ_FREEZABLE | WQ_MEM_RECLAIM, 0);
+       if (!ctlr->rumble_queue) {
+               ret = -ENOMEM;
+               goto err;
+       }
        INIT_WORK(&ctlr->rumble_worker, joycon_rumble_worker);
 
        ret = hid_parse(hdev);
index 03b935f..c3e6d69 100644 (file)
@@ -64,7 +64,9 @@ struct tm_wheel_info {
  */
 static const struct tm_wheel_info tm_wheels_infos[] = {
        {0x0306, 0x0006, "Thrustmaster T150RS"},
+       {0x0200, 0x0005, "Thrustmaster T300RS (Missing Attachment)"},
        {0x0206, 0x0005, "Thrustmaster T300RS"},
+       {0x0209, 0x0005, "Thrustmaster T300RS (Open Wheel Attachment)"},
        {0x0204, 0x0005, "Thrustmaster T300 Ferrari Alcantara Edition"},
        {0x0002, 0x0002, "Thrustmaster T500RS"}
        //{0x0407, 0x0001, "Thrustmaster TMX"}
@@ -158,6 +160,12 @@ static void thrustmaster_interrupts(struct hid_device *hdev)
                return;
        }
 
+       if (usbif->cur_altsetting->desc.bNumEndpoints < 2) {
+               kfree(send_buf);
+               hid_err(hdev, "Wrong number of endpoints?\n");
+               return;
+       }
+
        ep = &usbif->cur_altsetting->endpoint[1];
        b_ep = ep->desc.bEndpointAddress;
 
index efa6140..42ceb20 100644 (file)
@@ -144,7 +144,7 @@ out:
 static int vivaldi_input_configured(struct hid_device *hdev,
                                    struct hid_input *hidinput)
 {
-       return sysfs_create_group(&hdev->dev.kobj, &input_attribute_group);
+       return devm_device_add_group(&hdev->dev, &input_attribute_group);
 }
 
 static const struct hid_device_id vivaldi_table[] = {
index 0c607da..9417ee0 100644 (file)
@@ -556,7 +556,7 @@ config KEYBOARD_PMIC8XXX
 
 config KEYBOARD_SAMSUNG
        tristate "Samsung keypad support"
-       depends on HAVE_CLK
+       depends on HAS_IOMEM && HAVE_CLK
        select INPUT_MATRIXKMAP
        help
          Say Y here if you want to use the keypad on your Samsung mobile
index 47af62c..e1758d5 100644 (file)
@@ -186,55 +186,21 @@ static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count,
        return 0;
 }
 
-static int elan_enable_power(struct elan_tp_data *data)
+static int elan_set_power(struct elan_tp_data *data, bool on)
 {
        int repeat = ETP_RETRY_COUNT;
        int error;
 
-       error = regulator_enable(data->vcc);
-       if (error) {
-               dev_err(&data->client->dev,
-                       "failed to enable regulator: %d\n", error);
-               return error;
-       }
-
        do {
-               error = data->ops->power_control(data->client, true);
+               error = data->ops->power_control(data->client, on);
                if (error >= 0)
                        return 0;
 
                msleep(30);
        } while (--repeat > 0);
 
-       dev_err(&data->client->dev, "failed to enable power: %d\n", error);
-       return error;
-}
-
-static int elan_disable_power(struct elan_tp_data *data)
-{
-       int repeat = ETP_RETRY_COUNT;
-       int error;
-
-       do {
-               error = data->ops->power_control(data->client, false);
-               if (!error) {
-                       error = regulator_disable(data->vcc);
-                       if (error) {
-                               dev_err(&data->client->dev,
-                                       "failed to disable regulator: %d\n",
-                                       error);
-                               /* Attempt to power the chip back up */
-                               data->ops->power_control(data->client, true);
-                               break;
-                       }
-
-                       return 0;
-               }
-
-               msleep(30);
-       } while (--repeat > 0);
-
-       dev_err(&data->client->dev, "failed to disable power: %d\n", error);
+       dev_err(&data->client->dev, "failed to set power %s: %d\n",
+               on ? "on" : "off", error);
        return error;
 }
 
@@ -1399,9 +1365,19 @@ static int __maybe_unused elan_suspend(struct device *dev)
                /* Enable wake from IRQ */
                data->irq_wake = (enable_irq_wake(client->irq) == 0);
        } else {
-               ret = elan_disable_power(data);
+               ret = elan_set_power(data, false);
+               if (ret)
+                       goto err;
+
+               ret = regulator_disable(data->vcc);
+               if (ret) {
+                       dev_err(dev, "error %d disabling regulator\n", ret);
+                       /* Attempt to power the chip back up */
+                       elan_set_power(data, true);
+               }
        }
 
+err:
        mutex_unlock(&data->sysfs_mutex);
        return ret;
 }
@@ -1412,12 +1388,18 @@ static int __maybe_unused elan_resume(struct device *dev)
        struct elan_tp_data *data = i2c_get_clientdata(client);
        int error;
 
-       if (device_may_wakeup(dev) && data->irq_wake) {
+       if (!device_may_wakeup(dev)) {
+               error = regulator_enable(data->vcc);
+               if (error) {
+                       dev_err(dev, "error %d enabling regulator\n", error);
+                       goto err;
+               }
+       } else if (data->irq_wake) {
                disable_irq_wake(client->irq);
                data->irq_wake = false;
        }
 
-       error = elan_enable_power(data);
+       error = elan_set_power(data, true);
        if (error) {
                dev_err(dev, "power up when resuming failed: %d\n", error);
                goto err;
index a3bfc7a..752e8ba 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/platform_data/x86/soc.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/of.h>
@@ -805,21 +806,6 @@ static int goodix_reset(struct goodix_ts_data *ts)
 }
 
 #ifdef ACPI_GPIO_SUPPORT
-#include <asm/cpu_device_id.h>
-#include <asm/intel-family.h>
-
-static const struct x86_cpu_id baytrail_cpu_ids[] = {
-       { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT, X86_FEATURE_ANY, },
-       {}
-};
-
-static inline bool is_byt(void)
-{
-       const struct x86_cpu_id *id = x86_match_cpu(baytrail_cpu_ids);
-
-       return !!id;
-}
-
 static const struct acpi_gpio_params first_gpio = { 0, 0, false };
 static const struct acpi_gpio_params second_gpio = { 1, 0, false };
 
@@ -878,7 +864,7 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
        const struct acpi_gpio_mapping *gpio_mapping = NULL;
        struct device *dev = &ts->client->dev;
        LIST_HEAD(resources);
-       int ret;
+       int irq, ret;
 
        ts->gpio_count = 0;
        ts->gpio_int_idx = -1;
@@ -891,6 +877,20 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
 
        acpi_dev_free_resource_list(&resources);
 
+       /*
+        * CHT devices should have a GpioInt + a regular GPIO ACPI resource.
+        * Some CHT devices have a bug (where the also is bogus Interrupt
+        * resource copied from a previous BYT based generation). i2c-core-acpi
+        * will use the non-working Interrupt resource, fix this up.
+        */
+       if (soc_intel_is_cht() && ts->gpio_count == 2 && ts->gpio_int_idx != -1) {
+               irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
+               if (irq > 0 && irq != ts->client->irq) {
+                       dev_warn(dev, "Overriding IRQ %d -> %d\n", ts->client->irq, irq);
+                       ts->client->irq = irq;
+               }
+       }
+
        if (ts->gpio_count == 2 && ts->gpio_int_idx == 0) {
                ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
                gpio_mapping = acpi_goodix_int_first_gpios;
@@ -903,7 +903,7 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
                dev_info(dev, "Using ACPI INTI and INTO methods for IRQ pin access\n");
                ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_METHOD;
                gpio_mapping = acpi_goodix_reset_only_gpios;
-       } else if (is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
+       } else if (soc_intel_is_byt() && ts->gpio_count == 2 && ts->gpio_int_idx == -1) {
                dev_info(dev, "No ACPI GpioInt resource, assuming that the GPIO order is reset, int\n");
                ts->irq_pin_access_method = IRQ_PIN_ACCESS_ACPI_GPIO;
                gpio_mapping = acpi_goodix_int_last_gpios;
index 416815a..bb95edf 100644 (file)
@@ -14,6 +14,7 @@
 extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
 extern void amd_iommu_apply_erratum_63(u16 devid);
+extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
 extern void amd_iommu_reset_cmd_buffer(struct amd_iommu *iommu);
 extern int amd_iommu_init_devices(void);
 extern void amd_iommu_uninit_devices(void);
index ffc89c4..47108ed 100644 (file)
 #define PASID_MASK             0x0000ffff
 
 /* MMIO status bits */
+#define MMIO_STATUS_EVT_OVERFLOW_INT_MASK      (1 << 0)
 #define MMIO_STATUS_EVT_INT_MASK       (1 << 1)
 #define MMIO_STATUS_COM_WAIT_INT_MASK  (1 << 2)
 #define MMIO_STATUS_PPR_INT_MASK       (1 << 6)
index b10fb52..7bfe37e 100644 (file)
@@ -657,6 +657,16 @@ static int __init alloc_command_buffer(struct amd_iommu *iommu)
        return iommu->cmd_buf ? 0 : -ENOMEM;
 }
 
+/*
+ * This function restarts event logging in case the IOMMU experienced
+ * an event log buffer overflow.
+ */
+void amd_iommu_restart_event_logging(struct amd_iommu *iommu)
+{
+       iommu_feature_disable(iommu, CONTROL_EVT_LOG_EN);
+       iommu_feature_enable(iommu, CONTROL_EVT_LOG_EN);
+}
+
 /*
  * This function resets the command buffer if the IOMMU stopped fetching
  * commands from it.
index b1bf412..6608d17 100644 (file)
@@ -492,18 +492,18 @@ static void v1_free_pgtable(struct io_pgtable *iop)
 
        dom = container_of(pgtable, struct protection_domain, iop);
 
-       /* Update data structure */
-       amd_iommu_domain_clr_pt_root(dom);
-
-       /* Make changes visible to IOMMUs */
-       amd_iommu_domain_update(dom);
-
        /* Page-table is not visible to IOMMU anymore, so free it */
        BUG_ON(pgtable->mode < PAGE_MODE_NONE ||
               pgtable->mode > PAGE_MODE_6_LEVEL);
 
        free_sub_pt(pgtable->root, pgtable->mode, &freelist);
 
+       /* Update data structure */
+       amd_iommu_domain_clr_pt_root(dom);
+
+       /* Make changes visible to IOMMUs */
+       amd_iommu_domain_update(dom);
+
        put_pages_list(&freelist);
 }
 
index 461f184..a18b549 100644 (file)
@@ -764,7 +764,8 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
 #endif /* !CONFIG_IRQ_REMAP */
 
 #define AMD_IOMMU_INT_MASK     \
-       (MMIO_STATUS_EVT_INT_MASK | \
+       (MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
+        MMIO_STATUS_EVT_INT_MASK | \
         MMIO_STATUS_PPR_INT_MASK | \
         MMIO_STATUS_GALOG_INT_MASK)
 
@@ -774,7 +775,7 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
        u32 status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
 
        while (status & AMD_IOMMU_INT_MASK) {
-               /* Enable EVT and PPR and GA interrupts again */
+               /* Enable interrupt sources again */
                writel(AMD_IOMMU_INT_MASK,
                        iommu->mmio_base + MMIO_STATUS_OFFSET);
 
@@ -795,6 +796,11 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
                }
 #endif
 
+               if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {
+                       pr_info_ratelimited("IOMMU event log overflow\n");
+                       amd_iommu_restart_event_logging(iommu);
+               }
+
                /*
                 * Hardware bug: ERBT1312
                 * When re-enabling interrupt (by writing 1
index 92fea3f..5b196cf 100644 (file)
@@ -2738,7 +2738,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu,
        spin_unlock_irqrestore(&device_domain_lock, flags);
 
        /* PASID table is mandatory for a PCI device in scalable mode. */
-       if (dev && dev_is_pci(dev) && sm_supported(iommu)) {
+       if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
                ret = intel_pasid_alloc_table(dev);
                if (ret) {
                        dev_err(dev, "PASID table allocation failed\n");
index e900e3c..2561ce8 100644 (file)
@@ -808,8 +808,10 @@ static struct tegra_smmu *tegra_smmu_find(struct device_node *np)
                return NULL;
 
        mc = platform_get_drvdata(pdev);
-       if (!mc)
+       if (!mc) {
+               put_device(&pdev->dev);
                return NULL;
+       }
 
        return mc->smmu;
 }
index d986ab4..820e5dc 100644 (file)
@@ -42,8 +42,7 @@ config MTD_NAND_OMAP2
        tristate "OMAP2, OMAP3, OMAP4 and Keystone NAND controller"
        depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
        depends on HAS_IOMEM
-       select MEMORY
-       select OMAP_GPMC
+       depends on OMAP_GPMC
        help
          Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4
          and Keystone platforms.
index 6382e19..c580acb 100644 (file)
@@ -138,6 +138,9 @@ static int com20020pci_probe(struct pci_dev *pdev,
                return -ENOMEM;
 
        ci = (struct com20020_pci_card_info *)id->driver_data;
+       if (!ci)
+               return -EINVAL;
+
        priv->ci = ci;
        mm = &ci->misc_map;
 
index b7dc1c3..acd7472 100644 (file)
@@ -1715,15 +1715,15 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
 
        netif_napi_add(ndev, &priv->napi, rcar_canfd_rx_poll,
                       RCANFD_NAPI_WEIGHT);
+       spin_lock_init(&priv->tx_lock);
+       devm_can_led_init(ndev);
+       gpriv->ch[priv->channel] = priv;
        err = register_candev(ndev);
        if (err) {
                dev_err(&pdev->dev,
                        "register_candev() failed, error %d\n", err);
                goto fail_candev;
        }
-       spin_lock_init(&priv->tx_lock);
-       devm_can_led_init(ndev);
-       gpriv->ch[priv->channel] = priv;
        dev_info(&pdev->dev, "device registered (channel %u)\n", priv->channel);
        return 0;
 
index 2ed2370..2d73ebb 100644 (file)
@@ -1787,7 +1787,7 @@ static int es58x_open(struct net_device *netdev)
        struct es58x_device *es58x_dev = es58x_priv(netdev)->es58x_dev;
        int ret;
 
-       if (atomic_inc_return(&es58x_dev->opened_channel_cnt) == 1) {
+       if (!es58x_dev->opened_channel_cnt) {
                ret = es58x_alloc_rx_urbs(es58x_dev);
                if (ret)
                        return ret;
@@ -1805,12 +1805,13 @@ static int es58x_open(struct net_device *netdev)
        if (ret)
                goto free_urbs;
 
+       es58x_dev->opened_channel_cnt++;
        netif_start_queue(netdev);
 
        return ret;
 
  free_urbs:
-       if (atomic_dec_and_test(&es58x_dev->opened_channel_cnt))
+       if (!es58x_dev->opened_channel_cnt)
                es58x_free_urbs(es58x_dev);
        netdev_err(netdev, "%s: Could not open the network device: %pe\n",
                   __func__, ERR_PTR(ret));
@@ -1845,7 +1846,8 @@ static int es58x_stop(struct net_device *netdev)
 
        es58x_flush_pending_tx_msg(netdev);
 
-       if (atomic_dec_and_test(&es58x_dev->opened_channel_cnt))
+       es58x_dev->opened_channel_cnt--;
+       if (!es58x_dev->opened_channel_cnt)
                es58x_free_urbs(es58x_dev);
 
        return 0;
@@ -2215,7 +2217,6 @@ static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf,
        init_usb_anchor(&es58x_dev->tx_urbs_idle);
        init_usb_anchor(&es58x_dev->tx_urbs_busy);
        atomic_set(&es58x_dev->tx_urbs_idle_cnt, 0);
-       atomic_set(&es58x_dev->opened_channel_cnt, 0);
        usb_set_intfdata(intf, es58x_dev);
 
        es58x_dev->rx_pipe = usb_rcvbulkpipe(es58x_dev->udev,
index 826a158..e5033cb 100644 (file)
@@ -373,8 +373,6 @@ struct es58x_operators {
  *     queue wake/stop logic should prevent this URB from getting
  *     empty. Please refer to es58x_get_tx_urb() for more details.
  * @tx_urbs_idle_cnt: number of urbs in @tx_urbs_idle.
- * @opened_channel_cnt: number of channels opened (c.f. es58x_open()
- *     and es58x_stop()).
  * @ktime_req_ns: kernel timestamp when es58x_set_realtime_diff_ns()
  *     was called.
  * @realtime_diff_ns: difference in nanoseconds between the clocks of
@@ -384,6 +382,10 @@ struct es58x_operators {
  *     in RX branches.
  * @rx_max_packet_size: Maximum length of bulk-in URB.
  * @num_can_ch: Number of CAN channel (i.e. number of elements of @netdev).
+ * @opened_channel_cnt: number of channels opened. Free of race
+ *     conditions because its two users (net_device_ops:ndo_open()
+ *     and net_device_ops:ndo_close()) guarantee that the network
+ *     stack big kernel lock (a.k.a. rtnl_mutex) is being hold.
  * @rx_cmd_buf_len: Length of @rx_cmd_buf.
  * @rx_cmd_buf: The device might split the URB commands in an
  *     arbitrary amount of pieces. This buffer is used to concatenate
@@ -406,7 +408,6 @@ struct es58x_device {
        struct usb_anchor tx_urbs_busy;
        struct usb_anchor tx_urbs_idle;
        atomic_t tx_urbs_idle_cnt;
-       atomic_t opened_channel_cnt;
 
        u64 ktime_req_ns;
        s64 realtime_diff_ns;
@@ -415,6 +416,7 @@ struct es58x_device {
 
        u16 rx_max_packet_size;
        u8 num_can_ch;
+       u8 opened_channel_cnt;
 
        u16 rx_cmd_buf_len;
        union es58x_urb_cmd rx_cmd_buf;
index b487e3f..d35749f 100644 (file)
@@ -191,8 +191,8 @@ struct gs_can {
 struct gs_usb {
        struct gs_can *canch[GS_MAX_INTF];
        struct usb_anchor rx_submitted;
-       atomic_t active_channels;
        struct usb_device *udev;
+       u8 active_channels;
 };
 
 /* 'allocate' a tx context.
@@ -589,7 +589,7 @@ static int gs_can_open(struct net_device *netdev)
        if (rc)
                return rc;
 
-       if (atomic_add_return(1, &parent->active_channels) == 1) {
+       if (!parent->active_channels) {
                for (i = 0; i < GS_MAX_RX_URBS; i++) {
                        struct urb *urb;
                        u8 *buf;
@@ -690,6 +690,7 @@ static int gs_can_open(struct net_device *netdev)
 
        dev->can.state = CAN_STATE_ERROR_ACTIVE;
 
+       parent->active_channels++;
        if (!(dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY))
                netif_start_queue(netdev);
 
@@ -705,7 +706,8 @@ static int gs_can_close(struct net_device *netdev)
        netif_stop_queue(netdev);
 
        /* Stop polling */
-       if (atomic_dec_and_test(&parent->active_channels))
+       parent->active_channels--;
+       if (!parent->active_channels)
                usb_kill_anchored_urbs(&parent->rx_submitted);
 
        /* Stop sending URBs */
@@ -984,8 +986,6 @@ static int gs_usb_probe(struct usb_interface *intf,
 
        init_usb_anchor(&dev->rx_submitted);
 
-       atomic_set(&dev->active_channels, 0);
-
        usb_set_intfdata(intf, dev);
        dev->udev = interface_to_usbdev(intf);
 
index e20aafe..b97ed9b 100644 (file)
@@ -8216,7 +8216,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
                rc = dma_set_coherent_mask(&pdev->dev, persist_dma_mask);
                if (rc) {
                        dev_err(&pdev->dev,
-                               "pci_set_consistent_dma_mask failed, aborting\n");
+                               "dma_set_coherent_mask failed, aborting\n");
                        goto err_out_unmap;
                }
        } else if ((rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) != 0) {
index da41eee..a06003b 100644 (file)
@@ -3613,6 +3613,8 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
            MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
        adapter->params.pci.vpd_cap_addr =
            pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+       if (!adapter->params.pci.vpd_cap_addr)
+               return -ENODEV;
        ret = get_vpd_params(adapter, &adapter->params.vpd);
        if (ret < 0)
                return ret;
index dee05a3..b423e94 100644 (file)
@@ -2212,6 +2212,19 @@ static const char *reset_reason_to_string(enum ibmvnic_reset_reason reason)
        return "UNKNOWN";
 }
 
+/*
+ * Initialize the init_done completion and return code values. We
+ * can get a transport event just after registering the CRQ and the
+ * tasklet will use this to communicate the transport event. To ensure
+ * we don't miss the notification/error, initialize these _before_
+ * regisering the CRQ.
+ */
+static inline void reinit_init_done(struct ibmvnic_adapter *adapter)
+{
+       reinit_completion(&adapter->init_done);
+       adapter->init_done_rc = 0;
+}
+
 /*
  * do_reset returns zero if we are able to keep processing reset events, or
  * non-zero if we hit a fatal error and must halt.
@@ -2318,6 +2331,8 @@ static int do_reset(struct ibmvnic_adapter *adapter,
                 */
                adapter->state = VNIC_PROBED;
 
+               reinit_init_done(adapter);
+
                if (adapter->reset_reason == VNIC_RESET_CHANGE_PARAM) {
                        rc = init_crq_queue(adapter);
                } else if (adapter->reset_reason == VNIC_RESET_MOBILITY) {
@@ -2461,7 +2476,8 @@ static int do_hard_reset(struct ibmvnic_adapter *adapter,
         */
        adapter->state = VNIC_PROBED;
 
-       reinit_completion(&adapter->init_done);
+       reinit_init_done(adapter);
+
        rc = init_crq_queue(adapter);
        if (rc) {
                netdev_err(adapter->netdev,
@@ -2602,23 +2618,82 @@ out:
 static void __ibmvnic_reset(struct work_struct *work)
 {
        struct ibmvnic_adapter *adapter;
-       bool saved_state = false;
+       unsigned int timeout = 5000;
        struct ibmvnic_rwi *tmprwi;
+       bool saved_state = false;
        struct ibmvnic_rwi *rwi;
        unsigned long flags;
-       u32 reset_state;
+       struct device *dev;
+       bool need_reset;
        int num_fails = 0;
+       u32 reset_state;
        int rc = 0;
 
        adapter = container_of(work, struct ibmvnic_adapter, ibmvnic_reset);
+               dev = &adapter->vdev->dev;
 
-       if (test_and_set_bit_lock(0, &adapter->resetting)) {
+       /* Wait for ibmvnic_probe() to complete. If probe is taking too long
+        * or if another reset is in progress, defer work for now. If probe
+        * eventually fails it will flush and terminate our work.
+        *
+        * Three possibilities here:
+        * 1. Adpater being removed  - just return
+        * 2. Timed out on probe or another reset in progress - delay the work
+        * 3. Completed probe - perform any resets in queue
+        */
+       if (adapter->state == VNIC_PROBING &&
+           !wait_for_completion_timeout(&adapter->probe_done, timeout)) {
+               dev_err(dev, "Reset thread timed out on probe");
                queue_delayed_work(system_long_wq,
                                   &adapter->ibmvnic_delayed_reset,
                                   IBMVNIC_RESET_DELAY);
                return;
        }
 
+       /* adapter is done with probe (i.e state is never VNIC_PROBING now) */
+       if (adapter->state == VNIC_REMOVING)
+               return;
+
+       /* ->rwi_list is stable now (no one else is removing entries) */
+
+       /* ibmvnic_probe() may have purged the reset queue after we were
+        * scheduled to process a reset so there maybe no resets to process.
+        * Before setting the ->resetting bit though, we have to make sure
+        * that there is infact a reset to process. Otherwise we may race
+        * with ibmvnic_open() and end up leaving the vnic down:
+        *
+        *      __ibmvnic_reset()           ibmvnic_open()
+        *      -----------------           --------------
+        *
+        *  set ->resetting bit
+        *                              find ->resetting bit is set
+        *                              set ->state to IBMVNIC_OPEN (i.e
+        *                              assume reset will open device)
+        *                              return
+        *  find reset queue empty
+        *  return
+        *
+        *      Neither performed vnic login/open and vnic stays down
+        *
+        * If we hold the lock and conditionally set the bit, either we
+        * or ibmvnic_open() will complete the open.
+        */
+       need_reset = false;
+       spin_lock(&adapter->rwi_lock);
+       if (!list_empty(&adapter->rwi_list)) {
+               if (test_and_set_bit_lock(0, &adapter->resetting)) {
+                       queue_delayed_work(system_long_wq,
+                                          &adapter->ibmvnic_delayed_reset,
+                                          IBMVNIC_RESET_DELAY);
+               } else {
+                       need_reset = true;
+               }
+       }
+       spin_unlock(&adapter->rwi_lock);
+
+       if (!need_reset)
+               return;
+
        rwi = get_next_rwi(adapter);
        while (rwi) {
                spin_lock_irqsave(&adapter->state_lock, flags);
@@ -2735,12 +2810,23 @@ static void __ibmvnic_delayed_reset(struct work_struct *work)
        __ibmvnic_reset(&adapter->ibmvnic_reset);
 }
 
+static void flush_reset_queue(struct ibmvnic_adapter *adapter)
+{
+       struct list_head *entry, *tmp_entry;
+
+       if (!list_empty(&adapter->rwi_list)) {
+               list_for_each_safe(entry, tmp_entry, &adapter->rwi_list) {
+                       list_del(entry);
+                       kfree(list_entry(entry, struct ibmvnic_rwi, list));
+               }
+       }
+}
+
 static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
                         enum ibmvnic_reset_reason reason)
 {
-       struct list_head *entry, *tmp_entry;
-       struct ibmvnic_rwi *rwi, *tmp;
        struct net_device *netdev = adapter->netdev;
+       struct ibmvnic_rwi *rwi, *tmp;
        unsigned long flags;
        int ret;
 
@@ -2759,13 +2845,6 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
                goto err;
        }
 
-       if (adapter->state == VNIC_PROBING) {
-               netdev_warn(netdev, "Adapter reset during probe\n");
-               adapter->init_done_rc = -EAGAIN;
-               ret = EAGAIN;
-               goto err;
-       }
-
        list_for_each_entry(tmp, &adapter->rwi_list, list) {
                if (tmp->reset_reason == reason) {
                        netdev_dbg(netdev, "Skipping matching reset, reason=%s\n",
@@ -2783,10 +2862,9 @@ static int ibmvnic_reset(struct ibmvnic_adapter *adapter,
        /* if we just received a transport event,
         * flush reset queue and process this reset
         */
-       if (adapter->force_reset_recovery && !list_empty(&adapter->rwi_list)) {
-               list_for_each_safe(entry, tmp_entry, &adapter->rwi_list)
-                       list_del(entry);
-       }
+       if (adapter->force_reset_recovery)
+               flush_reset_queue(adapter);
+
        rwi->reset_reason = reason;
        list_add_tail(&rwi->list, &adapter->rwi_list);
        netdev_dbg(adapter->netdev, "Scheduling reset (reason %s)\n",
@@ -5321,9 +5399,9 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                        }
 
                        if (!completion_done(&adapter->init_done)) {
-                               complete(&adapter->init_done);
                                if (!adapter->init_done_rc)
                                        adapter->init_done_rc = -EAGAIN;
+                               complete(&adapter->init_done);
                        }
 
                        break;
@@ -5346,6 +5424,13 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                        adapter->fw_done_rc = -EIO;
                        complete(&adapter->fw_done);
                }
+
+               /* if we got here during crq-init, retry crq-init */
+               if (!completion_done(&adapter->init_done)) {
+                       adapter->init_done_rc = -EAGAIN;
+                       complete(&adapter->init_done);
+               }
+
                if (!completion_done(&adapter->stats_done))
                        complete(&adapter->stats_done);
                if (test_bit(0, &adapter->resetting))
@@ -5662,10 +5747,6 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
 
        adapter->from_passive_init = false;
 
-       if (reset)
-               reinit_completion(&adapter->init_done);
-
-       adapter->init_done_rc = 0;
        rc = ibmvnic_send_crq_init(adapter);
        if (rc) {
                dev_err(dev, "Send crq init failed with error %d\n", rc);
@@ -5679,12 +5760,14 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
 
        if (adapter->init_done_rc) {
                release_crq_queue(adapter);
+               dev_err(dev, "CRQ-init failed, %d\n", adapter->init_done_rc);
                return adapter->init_done_rc;
        }
 
        if (adapter->from_passive_init) {
                adapter->state = VNIC_OPEN;
                adapter->from_passive_init = false;
+               dev_err(dev, "CRQ-init failed, passive-init\n");
                return -EINVAL;
        }
 
@@ -5724,6 +5807,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        struct ibmvnic_adapter *adapter;
        struct net_device *netdev;
        unsigned char *mac_addr_p;
+       unsigned long flags;
        bool init_success;
        int rc;
 
@@ -5768,6 +5852,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
        spin_lock_init(&adapter->rwi_lock);
        spin_lock_init(&adapter->state_lock);
        mutex_init(&adapter->fw_lock);
+       init_completion(&adapter->probe_done);
        init_completion(&adapter->init_done);
        init_completion(&adapter->fw_done);
        init_completion(&adapter->reset_done);
@@ -5778,6 +5863,33 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        init_success = false;
        do {
+               reinit_init_done(adapter);
+
+               /* clear any failovers we got in the previous pass
+                * since we are reinitializing the CRQ
+                */
+               adapter->failover_pending = false;
+
+               /* If we had already initialized CRQ, we may have one or
+                * more resets queued already. Discard those and release
+                * the CRQ before initializing the CRQ again.
+                */
+               release_crq_queue(adapter);
+
+               /* Since we are still in PROBING state, __ibmvnic_reset()
+                * will not access the ->rwi_list and since we released CRQ,
+                * we won't get _new_ transport events. But there maybe an
+                * ongoing ibmvnic_reset() call. So serialize access to
+                * rwi_list. If we win the race, ibvmnic_reset() could add
+                * a reset after we purged but thats ok - we just may end
+                * up with an extra reset (i.e similar to having two or more
+                * resets in the queue at once).
+                * CHECK.
+                */
+               spin_lock_irqsave(&adapter->rwi_lock, flags);
+               flush_reset_queue(adapter);
+               spin_unlock_irqrestore(&adapter->rwi_lock, flags);
+
                rc = init_crq_queue(adapter);
                if (rc) {
                        dev_err(&dev->dev, "Couldn't initialize crq. rc=%d\n",
@@ -5809,12 +5921,6 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
                goto ibmvnic_dev_file_err;
 
        netif_carrier_off(netdev);
-       rc = register_netdev(netdev);
-       if (rc) {
-               dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
-               goto ibmvnic_register_fail;
-       }
-       dev_info(&dev->dev, "ibmvnic registered\n");
 
        if (init_success) {
                adapter->state = VNIC_PROBED;
@@ -5827,6 +5933,16 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
 
        adapter->wait_for_reset = false;
        adapter->last_reset_time = jiffies;
+
+       rc = register_netdev(netdev);
+       if (rc) {
+               dev_err(&dev->dev, "failed to register netdev rc=%d\n", rc);
+               goto ibmvnic_register_fail;
+       }
+       dev_info(&dev->dev, "ibmvnic registered\n");
+
+       complete(&adapter->probe_done);
+
        return 0;
 
 ibmvnic_register_fail:
@@ -5841,6 +5957,17 @@ ibmvnic_stats_fail:
 ibmvnic_init_fail:
        release_sub_crqs(adapter, 1);
        release_crq_queue(adapter);
+
+       /* cleanup worker thread after releasing CRQ so we don't get
+        * transport events (i.e new work items for the worker thread).
+        */
+       adapter->state = VNIC_REMOVING;
+       complete(&adapter->probe_done);
+       flush_work(&adapter->ibmvnic_reset);
+       flush_delayed_work(&adapter->ibmvnic_delayed_reset);
+
+       flush_reset_queue(adapter);
+
        mutex_destroy(&adapter->fw_lock);
        free_netdev(netdev);
 
index 4a7a56f..fa2d607 100644 (file)
@@ -930,6 +930,7 @@ struct ibmvnic_adapter {
 
        struct ibmvnic_tx_pool *tx_pool;
        struct ibmvnic_tx_pool *tso_pool;
+       struct completion probe_done;
        struct completion init_done;
        int init_done_rc;
 
index bcf680e..13382df 100644 (file)
@@ -630,6 +630,7 @@ struct e1000_phy_info {
        bool disable_polarity_correction;
        bool is_mdix;
        bool polarity_correction;
+       bool reset_disable;
        bool speed_downgraded;
        bool autoneg_wait_to_complete;
 };
index c908c84..d60e201 100644 (file)
@@ -2050,6 +2050,10 @@ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
        bool blocked = false;
        int i = 0;
 
+       /* Check the PHY (LCD) reset flag */
+       if (hw->phy.reset_disable)
+               return true;
+
        while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) &&
               (i++ < 30))
                usleep_range(10000, 11000);
@@ -4136,9 +4140,9 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
                return ret_val;
 
        if (!(data & valid_csum_mask)) {
-               e_dbg("NVM Checksum Invalid\n");
+               e_dbg("NVM Checksum valid bit not set\n");
 
-               if (hw->mac.type < e1000_pch_cnp) {
+               if (hw->mac.type < e1000_pch_tgp) {
                        data |= valid_csum_mask;
                        ret_val = e1000_write_nvm(hw, word, 1, &data);
                        if (ret_val)
index 2504b11..638a3dd 100644 (file)
 #define I217_CGFREG_ENABLE_MTA_RESET   0x0002
 #define I217_MEMPWR                    PHY_REG(772, 26)
 #define I217_MEMPWR_DISABLE_SMB_RELEASE        0x0010
+#define I217_MEMPWR_MOEM               0x1000
 
 /* Receive Address Initial CRC Calculation */
 #define E1000_PCH_RAICC(_n)    (0x05F50 + ((_n) * 4))
index a42aeb5..c5bdef3 100644 (file)
@@ -6987,8 +6987,21 @@ static __maybe_unused int e1000e_pm_suspend(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
+       struct e1000_hw *hw = &adapter->hw;
+       u16 phy_data;
        int rc;
 
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
+               /* Mask OEM Bits / Gig Disable / Restart AN (772_26[12] = 1) */
+               e1e_rphy(hw, I217_MEMPWR, &phy_data);
+               phy_data |= I217_MEMPWR_MOEM;
+               e1e_wphy(hw, I217_MEMPWR, phy_data);
+
+               /* Disable LCD reset */
+               hw->phy.reset_disable = true;
+       }
+
        e1000e_flush_lpic(pdev);
 
        e1000e_pm_freeze(dev);
@@ -7010,6 +7023,8 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev));
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct pci_dev *pdev = to_pci_dev(dev);
+       struct e1000_hw *hw = &adapter->hw;
+       u16 phy_data;
        int rc;
 
        /* Introduce S0ix implementation */
@@ -7020,6 +7035,17 @@ static __maybe_unused int e1000e_pm_resume(struct device *dev)
        if (rc)
                return rc;
 
+       if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID &&
+           hw->mac.type >= e1000_pch_adp) {
+               /* Unmask OEM Bits / Gig Disable / Restart AN 772_26[12] = 0 */
+               e1e_rphy(hw, I217_MEMPWR, &phy_data);
+               phy_data &= ~I217_MEMPWR_MOEM;
+               e1e_wphy(hw, I217_MEMPWR, phy_data);
+
+               /* Enable LCD reset */
+               hw->phy.reset_disable = false;
+       }
+
        return e1000e_pm_thaw(dev);
 }
 
index 59806d1..8942394 100644 (file)
@@ -201,6 +201,10 @@ enum iavf_state_t {
        __IAVF_RUNNING,         /* opened, working */
 };
 
+enum iavf_critical_section_t {
+       __IAVF_IN_REMOVE_TASK,  /* device being removed */
+};
+
 #define IAVF_CLOUD_FIELD_OMAC          0x01
 #define IAVF_CLOUD_FIELD_IMAC          0x02
 #define IAVF_CLOUD_FIELD_IVLAN 0x04
@@ -246,7 +250,6 @@ struct iavf_adapter {
        struct list_head mac_filter_list;
        struct mutex crit_lock;
        struct mutex client_lock;
-       struct mutex remove_lock;
        /* Lock to protect accesses to MAC and VLAN lists */
        spinlock_t mac_vlan_list_lock;
        char misc_vector_name[IFNAMSIZ + 9];
@@ -284,6 +287,7 @@ struct iavf_adapter {
 #define IAVF_FLAG_LEGACY_RX                    BIT(15)
 #define IAVF_FLAG_REINIT_ITR_NEEDED            BIT(16)
 #define IAVF_FLAG_QUEUES_DISABLED              BIT(17)
+#define IAVF_FLAG_SETUP_NETDEV_FEATURES                BIT(18)
 /* duplicates for common code */
 #define IAVF_FLAG_DCB_ENABLED                  0
        /* flags for admin queue service task */
index 8125b91..dcf2426 100644 (file)
@@ -302,8 +302,9 @@ static irqreturn_t iavf_msix_aq(int irq, void *data)
        rd32(hw, IAVF_VFINT_ICR01);
        rd32(hw, IAVF_VFINT_ICR0_ENA1);
 
-       /* schedule work on the private workqueue */
-       queue_work(iavf_wq, &adapter->adminq_task);
+       if (adapter->state != __IAVF_REMOVE)
+               /* schedule work on the private workqueue */
+               queue_work(iavf_wq, &adapter->adminq_task);
 
        return IRQ_HANDLED;
 }
@@ -1136,8 +1137,7 @@ void iavf_down(struct iavf_adapter *adapter)
                rss->state = IAVF_ADV_RSS_DEL_REQUEST;
        spin_unlock_bh(&adapter->adv_rss_lock);
 
-       if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) &&
-           adapter->state != __IAVF_RESETTING) {
+       if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)) {
                /* cancel any current operation */
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
                /* Schedule operations to close down the HW. Don't wait
@@ -2374,17 +2374,22 @@ static void iavf_watchdog_task(struct work_struct *work)
        struct iavf_hw *hw = &adapter->hw;
        u32 reg_val;
 
-       if (!mutex_trylock(&adapter->crit_lock))
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state == __IAVF_REMOVE)
+                       return;
+
                goto restart_watchdog;
+       }
 
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                iavf_change_state(adapter, __IAVF_COMM_FAILED);
 
-       if (adapter->flags & IAVF_FLAG_RESET_NEEDED &&
-           adapter->state != __IAVF_RESETTING) {
-               iavf_change_state(adapter, __IAVF_RESETTING);
+       if (adapter->flags & IAVF_FLAG_RESET_NEEDED) {
                adapter->aq_required = 0;
                adapter->current_op = VIRTCHNL_OP_UNKNOWN;
+               mutex_unlock(&adapter->crit_lock);
+               queue_work(iavf_wq, &adapter->reset_task);
+               return;
        }
 
        switch (adapter->state) {
@@ -2419,6 +2424,15 @@ static void iavf_watchdog_task(struct work_struct *work)
                                   msecs_to_jiffies(1));
                return;
        case __IAVF_INIT_FAILED:
+               if (test_bit(__IAVF_IN_REMOVE_TASK,
+                            &adapter->crit_section)) {
+                       /* Do not update the state and do not reschedule
+                        * watchdog task, iavf_remove should handle this state
+                        * as it can loop forever
+                        */
+                       mutex_unlock(&adapter->crit_lock);
+                       return;
+               }
                if (++adapter->aq_wait_count > IAVF_AQ_MAX_ERR) {
                        dev_err(&adapter->pdev->dev,
                                "Failed to communicate with PF; waiting before retry\n");
@@ -2435,6 +2449,17 @@ static void iavf_watchdog_task(struct work_struct *work)
                queue_delayed_work(iavf_wq, &adapter->watchdog_task, HZ);
                return;
        case __IAVF_COMM_FAILED:
+               if (test_bit(__IAVF_IN_REMOVE_TASK,
+                            &adapter->crit_section)) {
+                       /* Set state to __IAVF_INIT_FAILED and perform remove
+                        * steps. Remove IAVF_FLAG_PF_COMMS_FAILED so the task
+                        * doesn't bring the state back to __IAVF_COMM_FAILED.
+                        */
+                       iavf_change_state(adapter, __IAVF_INIT_FAILED);
+                       adapter->flags &= ~IAVF_FLAG_PF_COMMS_FAILED;
+                       mutex_unlock(&adapter->crit_lock);
+                       return;
+               }
                reg_val = rd32(hw, IAVF_VFGEN_RSTAT) &
                          IAVF_VFGEN_RSTAT_VFR_STATE_MASK;
                if (reg_val == VIRTCHNL_VFR_VFACTIVE ||
@@ -2507,7 +2532,8 @@ static void iavf_watchdog_task(struct work_struct *work)
        schedule_delayed_work(&adapter->client_task, msecs_to_jiffies(5));
        mutex_unlock(&adapter->crit_lock);
 restart_watchdog:
-       queue_work(iavf_wq, &adapter->adminq_task);
+       if (adapter->state >= __IAVF_DOWN)
+               queue_work(iavf_wq, &adapter->adminq_task);
        if (adapter->aq_required)
                queue_delayed_work(iavf_wq, &adapter->watchdog_task,
                                   msecs_to_jiffies(20));
@@ -2601,13 +2627,13 @@ static void iavf_reset_task(struct work_struct *work)
        /* When device is being removed it doesn't make sense to run the reset
         * task, just return in such a case.
         */
-       if (mutex_is_locked(&adapter->remove_lock))
-               return;
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state != __IAVF_REMOVE)
+                       queue_work(iavf_wq, &adapter->reset_task);
 
-       if (iavf_lock_timeout(&adapter->crit_lock, 200)) {
-               schedule_work(&adapter->reset_task);
                return;
        }
+
        while (!mutex_trylock(&adapter->client_lock))
                usleep_range(500, 1000);
        if (CLIENT_ENABLED(adapter)) {
@@ -2662,6 +2688,7 @@ static void iavf_reset_task(struct work_struct *work)
                        reg_val);
                iavf_disable_vf(adapter);
                mutex_unlock(&adapter->client_lock);
+               mutex_unlock(&adapter->crit_lock);
                return; /* Do not attempt to reinit. It's dead, Jim. */
        }
 
@@ -2670,8 +2697,7 @@ continue_reset:
         * ndo_open() returning, so we can't assume it means all our open
         * tasks have finished, since we're not holding the rtnl_lock here.
         */
-       running = ((adapter->state == __IAVF_RUNNING) ||
-                  (adapter->state == __IAVF_RESETTING));
+       running = adapter->state == __IAVF_RUNNING;
 
        if (running) {
                netdev->flags &= ~IFF_UP;
@@ -2826,13 +2852,19 @@ static void iavf_adminq_task(struct work_struct *work)
        if (adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)
                goto out;
 
+       if (!mutex_trylock(&adapter->crit_lock)) {
+               if (adapter->state == __IAVF_REMOVE)
+                       return;
+
+               queue_work(iavf_wq, &adapter->adminq_task);
+               goto out;
+       }
+
        event.buf_len = IAVF_MAX_AQ_BUF_SIZE;
        event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
        if (!event.msg_buf)
                goto out;
 
-       if (iavf_lock_timeout(&adapter->crit_lock, 200))
-               goto freedom;
        do {
                ret = iavf_clean_arq_element(hw, &event, &pending);
                v_op = (enum virtchnl_ops)le32_to_cpu(event.desc.cookie_high);
@@ -2848,6 +2880,24 @@ static void iavf_adminq_task(struct work_struct *work)
        } while (pending);
        mutex_unlock(&adapter->crit_lock);
 
+       if ((adapter->flags & IAVF_FLAG_SETUP_NETDEV_FEATURES)) {
+               if (adapter->netdev_registered ||
+                   !test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section)) {
+                       struct net_device *netdev = adapter->netdev;
+
+                       rtnl_lock();
+                       netdev_update_features(netdev);
+                       rtnl_unlock();
+                       /* Request VLAN offload settings */
+                       if (VLAN_V2_ALLOWED(adapter))
+                               iavf_set_vlan_offload_features
+                                       (adapter, 0, netdev->features);
+
+                       iavf_set_queue_vlan_tag_loc(adapter);
+               }
+
+               adapter->flags &= ~IAVF_FLAG_SETUP_NETDEV_FEATURES;
+       }
        if ((adapter->flags &
             (IAVF_FLAG_RESET_PENDING | IAVF_FLAG_RESET_NEEDED)) ||
            adapter->state == __IAVF_RESETTING)
@@ -3800,11 +3850,12 @@ static int iavf_close(struct net_device *netdev)
        struct iavf_adapter *adapter = netdev_priv(netdev);
        int status;
 
-       if (adapter->state <= __IAVF_DOWN_PENDING)
-               return 0;
+       mutex_lock(&adapter->crit_lock);
 
-       while (!mutex_trylock(&adapter->crit_lock))
-               usleep_range(500, 1000);
+       if (adapter->state <= __IAVF_DOWN_PENDING) {
+               mutex_unlock(&adapter->crit_lock);
+               return 0;
+       }
 
        set_bit(__IAVF_VSI_DOWN, adapter->vsi.state);
        if (CLIENT_ENABLED(adapter))
@@ -3853,8 +3904,11 @@ static int iavf_change_mtu(struct net_device *netdev, int new_mtu)
                iavf_notify_client_l2_params(&adapter->vsi);
                adapter->flags |= IAVF_FLAG_SERVICE_CLIENT_REQUESTED;
        }
-       adapter->flags |= IAVF_FLAG_RESET_NEEDED;
-       queue_work(iavf_wq, &adapter->reset_task);
+
+       if (netif_running(netdev)) {
+               adapter->flags |= IAVF_FLAG_RESET_NEEDED;
+               queue_work(iavf_wq, &adapter->reset_task);
+       }
 
        return 0;
 }
@@ -4431,7 +4485,6 @@ static int iavf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
         */
        mutex_init(&adapter->crit_lock);
        mutex_init(&adapter->client_lock);
-       mutex_init(&adapter->remove_lock);
        mutex_init(&hw->aq.asq_mutex);
        mutex_init(&hw->aq.arq_mutex);
 
@@ -4547,7 +4600,6 @@ static int __maybe_unused iavf_resume(struct device *dev_d)
 static void iavf_remove(struct pci_dev *pdev)
 {
        struct iavf_adapter *adapter = iavf_pdev_to_adapter(pdev);
-       enum iavf_state_t prev_state = adapter->last_state;
        struct net_device *netdev = adapter->netdev;
        struct iavf_fdir_fltr *fdir, *fdirtmp;
        struct iavf_vlan_filter *vlf, *vlftmp;
@@ -4556,14 +4608,30 @@ static void iavf_remove(struct pci_dev *pdev)
        struct iavf_cloud_filter *cf, *cftmp;
        struct iavf_hw *hw = &adapter->hw;
        int err;
-       /* Indicate we are in remove and not to run reset_task */
-       mutex_lock(&adapter->remove_lock);
-       cancel_work_sync(&adapter->reset_task);
+
+       set_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section);
+       /* Wait until port initialization is complete.
+        * There are flows where register/unregister netdev may race.
+        */
+       while (1) {
+               mutex_lock(&adapter->crit_lock);
+               if (adapter->state == __IAVF_RUNNING ||
+                   adapter->state == __IAVF_DOWN ||
+                   adapter->state == __IAVF_INIT_FAILED) {
+                       mutex_unlock(&adapter->crit_lock);
+                       break;
+               }
+
+               mutex_unlock(&adapter->crit_lock);
+               usleep_range(500, 1000);
+       }
        cancel_delayed_work_sync(&adapter->watchdog_task);
-       cancel_delayed_work_sync(&adapter->client_task);
+
        if (adapter->netdev_registered) {
-               unregister_netdev(netdev);
+               rtnl_lock();
+               unregister_netdevice(netdev);
                adapter->netdev_registered = false;
+               rtnl_unlock();
        }
        if (CLIENT_ALLOWED(adapter)) {
                err = iavf_lan_del_device(adapter);
@@ -4572,6 +4640,10 @@ static void iavf_remove(struct pci_dev *pdev)
                                 err);
        }
 
+       mutex_lock(&adapter->crit_lock);
+       dev_info(&adapter->pdev->dev, "Remove device\n");
+       iavf_change_state(adapter, __IAVF_REMOVE);
+
        iavf_request_reset(adapter);
        msleep(50);
        /* If the FW isn't responding, kick it once, but only once. */
@@ -4579,37 +4651,24 @@ static void iavf_remove(struct pci_dev *pdev)
                iavf_request_reset(adapter);
                msleep(50);
        }
-       if (iavf_lock_timeout(&adapter->crit_lock, 5000))
-               dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n", __FUNCTION__);
 
-       dev_info(&adapter->pdev->dev, "Removing device\n");
+       iavf_misc_irq_disable(adapter);
        /* Shut down all the garbage mashers on the detention level */
-       iavf_change_state(adapter, __IAVF_REMOVE);
+       cancel_work_sync(&adapter->reset_task);
+       cancel_delayed_work_sync(&adapter->watchdog_task);
+       cancel_work_sync(&adapter->adminq_task);
+       cancel_delayed_work_sync(&adapter->client_task);
+
        adapter->aq_required = 0;
        adapter->flags &= ~IAVF_FLAG_REINIT_ITR_NEEDED;
 
        iavf_free_all_tx_resources(adapter);
        iavf_free_all_rx_resources(adapter);
-       iavf_misc_irq_disable(adapter);
        iavf_free_misc_irq(adapter);
 
-       /* In case we enter iavf_remove from erroneous state, free traffic irqs
-        * here, so as to not cause a kernel crash, when calling
-        * iavf_reset_interrupt_capability.
-        */
-       if ((adapter->last_state == __IAVF_RESETTING &&
-            prev_state != __IAVF_DOWN) ||
-           (adapter->last_state == __IAVF_RUNNING &&
-            !(netdev->flags & IFF_UP)))
-               iavf_free_traffic_irqs(adapter);
-
        iavf_reset_interrupt_capability(adapter);
        iavf_free_q_vectors(adapter);
 
-       cancel_delayed_work_sync(&adapter->watchdog_task);
-
-       cancel_work_sync(&adapter->adminq_task);
-
        iavf_free_rss(adapter);
 
        if (hw->aq.asq.count)
@@ -4621,8 +4680,6 @@ static void iavf_remove(struct pci_dev *pdev)
        mutex_destroy(&adapter->client_lock);
        mutex_unlock(&adapter->crit_lock);
        mutex_destroy(&adapter->crit_lock);
-       mutex_unlock(&adapter->remove_lock);
-       mutex_destroy(&adapter->remove_lock);
 
        iounmap(hw->hw_addr);
        pci_release_regions(pdev);
index 5ee1d11..88844d6 100644 (file)
@@ -2146,29 +2146,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,
                                     sizeof(adapter->vlan_v2_caps)));
 
                iavf_process_config(adapter);
-
-               /* unlock crit_lock before acquiring rtnl_lock as other
-                * processes holding rtnl_lock could be waiting for the same
-                * crit_lock
-                */
-               mutex_unlock(&adapter->crit_lock);
-               /* VLAN capabilities can change during VFR, so make sure to
-                * update the netdev features with the new capabilities
-                */
-               rtnl_lock();
-               netdev_update_features(netdev);
-               rtnl_unlock();
-               if (iavf_lock_timeout(&adapter->crit_lock, 10000))
-                       dev_warn(&adapter->pdev->dev, "failed to acquire crit_lock in %s\n",
-                                __FUNCTION__);
-
-               /* Request VLAN offload settings */
-               if (VLAN_V2_ALLOWED(adapter))
-                       iavf_set_vlan_offload_features(adapter, 0,
-                                                      netdev->features);
-
-               iavf_set_queue_vlan_tag_loc(adapter);
-
+               adapter->flags |= IAVF_FLAG_SETUP_NETDEV_FEATURES;
                }
                break;
        case VIRTCHNL_OP_ENABLE_QUEUES:
index 5cad31c..40dbf4b 100644 (file)
@@ -746,8 +746,6 @@ s32 igc_write_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 data)
                if (ret_val)
                        return ret_val;
                ret_val = igc_write_phy_reg_mdic(hw, offset, data);
-               if (ret_val)
-                       return ret_val;
                hw->phy.ops.release(hw);
        } else {
                ret_val = igc_write_xmdio_reg(hw, (u16)offset, dev_addr,
@@ -779,8 +777,6 @@ s32 igc_read_phy_reg_gpy(struct igc_hw *hw, u32 offset, u16 *data)
                if (ret_val)
                        return ret_val;
                ret_val = igc_read_phy_reg_mdic(hw, offset, data);
-               if (ret_val)
-                       return ret_val;
                hw->phy.ops.release(hw);
        } else {
                ret_val = igc_read_xmdio_reg(hw, (u16)offset, dev_addr,
index b3fd8e5..6a5e9cf 100644 (file)
@@ -390,12 +390,14 @@ static bool ixgbe_xmit_zc(struct ixgbe_ring *xdp_ring, unsigned int budget)
        u32 cmd_type;
 
        while (budget-- > 0) {
-               if (unlikely(!ixgbe_desc_unused(xdp_ring)) ||
-                   !netif_carrier_ok(xdp_ring->netdev)) {
+               if (unlikely(!ixgbe_desc_unused(xdp_ring))) {
                        work_done = false;
                        break;
                }
 
+               if (!netif_carrier_ok(xdp_ring->netdev))
+                       break;
+
                if (!xsk_tx_peek_desc(pool, &desc))
                        break;
 
index a1acc9b..d40e18c 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/phylink.h>
 #include <linux/hrtimer.h>
 
+#include "sparx5_main_regs.h"
+
 /* Target chip type */
 enum spx5_target_chiptype {
        SPX5_TARGET_CT_7546    = 0x7546,  /* SparX-5-64  Enterprise */
index 4ce490a..8e56ffa 100644 (file)
@@ -58,16 +58,6 @@ int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
        struct sparx5 *sparx5 = port->sparx5;
        int ret;
 
-       /* Make the port a member of the VLAN */
-       set_bit(port->portno, sparx5->vlan_mask[vid]);
-       ret = sparx5_vlant_set_mask(sparx5, vid);
-       if (ret)
-               return ret;
-
-       /* Default ingress vlan classification */
-       if (pvid)
-               port->pvid = vid;
-
        /* Untagged egress vlan classification */
        if (untagged && port->vid != vid) {
                if (port->vid) {
@@ -79,6 +69,16 @@ int sparx5_vlan_vid_add(struct sparx5_port *port, u16 vid, bool pvid,
                port->vid = vid;
        }
 
+       /* Make the port a member of the VLAN */
+       set_bit(port->portno, sparx5->vlan_mask[vid]);
+       ret = sparx5_vlant_set_mask(sparx5, vid);
+       if (ret)
+               return ret;
+
+       /* Default ingress vlan classification */
+       if (pvid)
+               port->pvid = vid;
+
        sparx5_vlan_port_apply(sparx5, port);
 
        return 0;
index 32161a5..2881f5b 100644 (file)
@@ -2285,18 +2285,18 @@ static int __init sxgbe_cmdline_opt(char *str)
        char *opt;
 
        if (!str || !*str)
-               return -EINVAL;
+               return 1;
        while ((opt = strsep(&str, ",")) != NULL) {
                if (!strncmp(opt, "eee_timer:", 10)) {
                        if (kstrtoint(opt + 10, 0, &eee_timer))
                                goto err;
                }
        }
-       return 0;
+       return 1;
 
 err:
        pr_err("%s: ERROR broken module parameter conversion\n", __func__);
-       return -EINVAL;
+       return 1;
 }
 
 __setup("sxgbeeth=", sxgbe_cmdline_opt);
index be6bfd6..50baf62 100644 (file)
@@ -163,9 +163,9 @@ static void efx_mcdi_send_request(struct efx_nic *efx, unsigned cmd,
        /* Serialise with efx_mcdi_ev_cpl() and efx_mcdi_ev_death() */
        spin_lock_bh(&mcdi->iface_lock);
        ++mcdi->seqno;
+       seqno = mcdi->seqno & SEQ_MASK;
        spin_unlock_bh(&mcdi->iface_lock);
 
-       seqno = mcdi->seqno & SEQ_MASK;
        xflags = 0;
        if (mcdi->mode == MCDI_MODE_EVENTS)
                xflags |= MCDI_HEADER_XFLAGS_EVREQ;
index bde76ea..422e322 100644 (file)
@@ -2262,6 +2262,23 @@ static void stmmac_stop_tx_dma(struct stmmac_priv *priv, u32 chan)
        stmmac_stop_tx(priv, priv->ioaddr, chan);
 }
 
+static void stmmac_enable_all_dma_irq(struct stmmac_priv *priv)
+{
+       u32 rx_channels_count = priv->plat->rx_queues_to_use;
+       u32 tx_channels_count = priv->plat->tx_queues_to_use;
+       u32 dma_csr_ch = max(rx_channels_count, tx_channels_count);
+       u32 chan;
+
+       for (chan = 0; chan < dma_csr_ch; chan++) {
+               struct stmmac_channel *ch = &priv->channel[chan];
+               unsigned long flags;
+
+               spin_lock_irqsave(&ch->lock, flags);
+               stmmac_enable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+               spin_unlock_irqrestore(&ch->lock, flags);
+       }
+}
+
 /**
  * stmmac_start_all_dma - start all RX and TX DMA channels
  * @priv: driver private structure
@@ -2904,8 +2921,10 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
                stmmac_axi(priv, priv->ioaddr, priv->plat->axi);
 
        /* DMA CSR Channel configuration */
-       for (chan = 0; chan < dma_csr_ch; chan++)
+       for (chan = 0; chan < dma_csr_ch; chan++) {
                stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
+               stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+       }
 
        /* DMA RX Channel Configuration */
        for (chan = 0; chan < rx_channels_count; chan++) {
@@ -3761,6 +3780,7 @@ static int stmmac_open(struct net_device *dev)
 
        stmmac_enable_all_queues(priv);
        netif_tx_start_all_queues(priv->dev);
+       stmmac_enable_all_dma_irq(priv);
 
        return 0;
 
@@ -6510,8 +6530,10 @@ int stmmac_xdp_open(struct net_device *dev)
        }
 
        /* DMA CSR Channel configuration */
-       for (chan = 0; chan < dma_csr_ch; chan++)
+       for (chan = 0; chan < dma_csr_ch; chan++) {
                stmmac_init_chan(priv, priv->ioaddr, priv->plat->dma_cfg, chan);
+               stmmac_disable_dma_irq(priv, priv->ioaddr, chan, 1, 1);
+       }
 
        /* Adjust Split header */
        sph_en = (priv->hw->rx_csum > 0) && priv->sph;
@@ -6572,6 +6594,7 @@ int stmmac_xdp_open(struct net_device *dev)
        stmmac_enable_all_queues(priv);
        netif_carrier_on(dev);
        netif_tx_start_all_queues(dev);
+       stmmac_enable_all_dma_irq(priv);
 
        return 0;
 
@@ -7451,6 +7474,7 @@ int stmmac_resume(struct device *dev)
        stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw);
 
        stmmac_enable_all_queues(priv);
+       stmmac_enable_all_dma_irq(priv);
 
        mutex_unlock(&priv->lock);
        rtnl_unlock();
@@ -7467,7 +7491,7 @@ static int __init stmmac_cmdline_opt(char *str)
        char *opt;
 
        if (!str || !*str)
-               return -EINVAL;
+               return 1;
        while ((opt = strsep(&str, ",")) != NULL) {
                if (!strncmp(opt, "debug:", 6)) {
                        if (kstrtoint(opt + 6, 0, &debug))
@@ -7498,11 +7522,11 @@ static int __init stmmac_cmdline_opt(char *str)
                                goto err;
                }
        }
-       return 0;
+       return 1;
 
 err:
        pr_err("%s: ERROR broken module parameter conversion", __func__);
-       return -EINVAL;
+       return 1;
 }
 
 __setup("stmmaceth=", stmmac_cmdline_opt);
index d037682..6782c2c 100644 (file)
@@ -2,7 +2,9 @@ config QCOM_IPA
        tristate "Qualcomm IPA support"
        depends on NET && QCOM_SMEM
        depends on ARCH_QCOM || COMPILE_TEST
+       depends on INTERCONNECT
        depends on QCOM_RPROC_COMMON || (QCOM_RPROC_COMMON=n && COMPILE_TEST)
+       depends on QCOM_AOSS_QMP || QCOM_AOSS_QMP=n
        select QCOM_MDT_LOADER if ARCH_QCOM
        select QCOM_SCM
        select QCOM_QMI_HELPERS
index 1364b00..208e73a 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_IPW2200) += ipw2x00/
 obj-$(CONFIG_IWLEGACY) += iwlegacy/
 
 obj-$(CONFIG_IWLWIFI)  += iwlwifi/
+obj-$(CONFIG_IWLMEI)   += iwlwifi/
index dd58c8f..04addf9 100644 (file)
@@ -553,8 +553,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_capa[] = {
                        .has_he = true,
                        .he_cap_elem = {
                                .mac_cap_info[0] =
-                                       IEEE80211_HE_MAC_CAP0_HTC_HE |
-                                       IEEE80211_HE_MAC_CAP0_TWT_REQ,
+                                       IEEE80211_HE_MAC_CAP0_HTC_HE,
                                .mac_cap_info[1] =
                                        IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US |
                                        IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8,
index 63432c2..445c94a 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
 #include <linux/vmalloc.h>
+#include <linux/err.h>
 #include <linux/ieee80211.h>
 #include <linux/netdevice.h>
 
@@ -1857,7 +1858,6 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw,
 void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
 {
        struct dentry *bcast_dir __maybe_unused;
-       char buf[100];
 
        spin_lock_init(&mvm->drv_stats_lock);
 
@@ -1939,6 +1939,11 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm)
         * Create a symlink with mac80211. It will be removed when mac80211
         * exists (before the opmode exists which removes the target.)
         */
-       snprintf(buf, 100, "../../%pd2", mvm->debugfs_dir->d_parent);
-       debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir, buf);
+       if (!IS_ERR(mvm->debugfs_dir)) {
+               char buf[100];
+
+               snprintf(buf, 100, "../../%pd2", mvm->debugfs_dir->d_parent);
+               debugfs_create_symlink("iwlwifi", mvm->hw->wiphy->debugfsdir,
+                                      buf);
+       }
 }
index 4ac599f..709a3df 100644 (file)
@@ -226,7 +226,6 @@ static const u8 he_if_types_ext_capa_sta[] = {
         [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
         [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT,
         [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
-        [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT,
 };
 
 static const struct wiphy_iftype_ext_capab he_iftypes_ext_capa[] = {
index 7845036..080a158 100644 (file)
@@ -71,12 +71,13 @@ static int iwl_mvm_vendor_host_get_ownership(struct wiphy *wiphy,
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+       int ret;
 
        mutex_lock(&mvm->mutex);
-       iwl_mvm_mei_get_ownership(mvm);
+       ret = iwl_mvm_mei_get_ownership(mvm);
        mutex_unlock(&mvm->mutex);
 
-       return 0;
+       return ret;
 }
 
 static const struct wiphy_vendor_command iwl_mvm_vendor_commands[] = {
index 8b18246..daa4e61 100644 (file)
@@ -424,14 +424,12 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue)
                        queue->tx_link[id] = TX_LINK_NONE;
                        skb = queue->tx_skbs[id];
                        queue->tx_skbs[id] = NULL;
-                       if (unlikely(gnttab_query_foreign_access(
-                               queue->grant_tx_ref[id]) != 0)) {
+                       if (unlikely(!gnttab_end_foreign_access_ref(
+                               queue->grant_tx_ref[id], GNTMAP_readonly))) {
                                dev_alert(dev,
                                          "Grant still in use by backend domain\n");
                                goto err;
                        }
-                       gnttab_end_foreign_access_ref(
-                               queue->grant_tx_ref[id], GNTMAP_readonly);
                        gnttab_release_grant_reference(
                                &queue->gref_tx_head, queue->grant_tx_ref[id]);
                        queue->grant_tx_ref[id] = GRANT_INVALID_REF;
@@ -842,6 +840,28 @@ static int xennet_close(struct net_device *dev)
        return 0;
 }
 
+static void xennet_destroy_queues(struct netfront_info *info)
+{
+       unsigned int i;
+
+       for (i = 0; i < info->netdev->real_num_tx_queues; i++) {
+               struct netfront_queue *queue = &info->queues[i];
+
+               if (netif_running(info->netdev))
+                       napi_disable(&queue->napi);
+               netif_napi_del(&queue->napi);
+       }
+
+       kfree(info->queues);
+       info->queues = NULL;
+}
+
+static void xennet_uninit(struct net_device *dev)
+{
+       struct netfront_info *np = netdev_priv(dev);
+       xennet_destroy_queues(np);
+}
+
 static void xennet_set_rx_rsp_cons(struct netfront_queue *queue, RING_IDX val)
 {
        unsigned long flags;
@@ -968,7 +988,6 @@ static int xennet_get_responses(struct netfront_queue *queue,
        struct device *dev = &queue->info->netdev->dev;
        struct bpf_prog *xdp_prog;
        struct xdp_buff xdp;
-       unsigned long ret;
        int slots = 1;
        int err = 0;
        u32 verdict;
@@ -1010,8 +1029,13 @@ static int xennet_get_responses(struct netfront_queue *queue,
                        goto next;
                }
 
-               ret = gnttab_end_foreign_access_ref(ref, 0);
-               BUG_ON(!ret);
+               if (!gnttab_end_foreign_access_ref(ref, 0)) {
+                       dev_alert(dev,
+                                 "Grant still in use by backend domain\n");
+                       queue->info->broken = true;
+                       dev_alert(dev, "Disabled for further use\n");
+                       return -EINVAL;
+               }
 
                gnttab_release_grant_reference(&queue->gref_rx_head, ref);
 
@@ -1232,6 +1256,10 @@ static int xennet_poll(struct napi_struct *napi, int budget)
                                           &need_xdp_flush);
 
                if (unlikely(err)) {
+                       if (queue->info->broken) {
+                               spin_unlock(&queue->rx_lock);
+                               return 0;
+                       }
 err:
                        while ((skb = __skb_dequeue(&tmpq)))
                                __skb_queue_tail(&errq, skb);
@@ -1611,6 +1639,7 @@ static int xennet_xdp(struct net_device *dev, struct netdev_bpf *xdp)
 }
 
 static const struct net_device_ops xennet_netdev_ops = {
+       .ndo_uninit          = xennet_uninit,
        .ndo_open            = xennet_open,
        .ndo_stop            = xennet_close,
        .ndo_start_xmit      = xennet_start_xmit,
@@ -1895,7 +1924,7 @@ static int setup_netfront(struct xenbus_device *dev,
                        struct netfront_queue *queue, unsigned int feature_split_evtchn)
 {
        struct xen_netif_tx_sring *txs;
-       struct xen_netif_rx_sring *rxs;
+       struct xen_netif_rx_sring *rxs = NULL;
        grant_ref_t gref;
        int err;
 
@@ -1915,21 +1944,21 @@ static int setup_netfront(struct xenbus_device *dev,
 
        err = xenbus_grant_ring(dev, txs, 1, &gref);
        if (err < 0)
-               goto grant_tx_ring_fail;
+               goto fail;
        queue->tx_ring_ref = gref;
 
        rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH);
        if (!rxs) {
                err = -ENOMEM;
                xenbus_dev_fatal(dev, err, "allocating rx ring page");
-               goto alloc_rx_ring_fail;
+               goto fail;
        }
        SHARED_RING_INIT(rxs);
        FRONT_RING_INIT(&queue->rx, rxs, XEN_PAGE_SIZE);
 
        err = xenbus_grant_ring(dev, rxs, 1, &gref);
        if (err < 0)
-               goto grant_rx_ring_fail;
+               goto fail;
        queue->rx_ring_ref = gref;
 
        if (feature_split_evtchn)
@@ -1942,22 +1971,28 @@ static int setup_netfront(struct xenbus_device *dev,
                err = setup_netfront_single(queue);
 
        if (err)
-               goto alloc_evtchn_fail;
+               goto fail;
 
        return 0;
 
        /* If we fail to setup netfront, it is safe to just revoke access to
         * granted pages because backend is not accessing it at this point.
         */
-alloc_evtchn_fail:
-       gnttab_end_foreign_access_ref(queue->rx_ring_ref, 0);
-grant_rx_ring_fail:
-       free_page((unsigned long)rxs);
-alloc_rx_ring_fail:
-       gnttab_end_foreign_access_ref(queue->tx_ring_ref, 0);
-grant_tx_ring_fail:
-       free_page((unsigned long)txs);
-fail:
+ fail:
+       if (queue->rx_ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(queue->rx_ring_ref, 0,
+                                         (unsigned long)rxs);
+               queue->rx_ring_ref = GRANT_INVALID_REF;
+       } else {
+               free_page((unsigned long)rxs);
+       }
+       if (queue->tx_ring_ref != GRANT_INVALID_REF) {
+               gnttab_end_foreign_access(queue->tx_ring_ref, 0,
+                                         (unsigned long)txs);
+               queue->tx_ring_ref = GRANT_INVALID_REF;
+       } else {
+               free_page((unsigned long)txs);
+       }
        return err;
 }
 
@@ -2103,22 +2138,6 @@ error:
        return err;
 }
 
-static void xennet_destroy_queues(struct netfront_info *info)
-{
-       unsigned int i;
-
-       for (i = 0; i < info->netdev->real_num_tx_queues; i++) {
-               struct netfront_queue *queue = &info->queues[i];
-
-               if (netif_running(info->netdev))
-                       napi_disable(&queue->napi);
-               netif_napi_del(&queue->napi);
-       }
-
-       kfree(info->queues);
-       info->queues = NULL;
-}
-
 
 
 static int xennet_create_page_pool(struct netfront_queue *queue)
index fede051..4081fc5 100644 (file)
@@ -168,6 +168,18 @@ static enum ntb_topo gen4_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd)
        return NTB_TOPO_NONE;
 }
 
+static enum ntb_topo spr_ppd_topo(struct intel_ntb_dev *ndev, u32 ppd)
+{
+       switch (ppd & SPR_PPD_TOPO_MASK) {
+       case SPR_PPD_TOPO_B2B_USD:
+               return NTB_TOPO_B2B_USD;
+       case SPR_PPD_TOPO_B2B_DSD:
+               return NTB_TOPO_B2B_DSD;
+       }
+
+       return NTB_TOPO_NONE;
+}
+
 int gen4_init_dev(struct intel_ntb_dev *ndev)
 {
        struct pci_dev *pdev = ndev->ntb.pdev;
@@ -183,7 +195,10 @@ int gen4_init_dev(struct intel_ntb_dev *ndev)
        }
 
        ppd1 = ioread32(ndev->self_mmio + GEN4_PPD1_OFFSET);
-       ndev->ntb.topo = gen4_ppd_topo(ndev, ppd1);
+       if (pdev_is_ICX(pdev))
+               ndev->ntb.topo = gen4_ppd_topo(ndev, ppd1);
+       else if (pdev_is_SPR(pdev))
+               ndev->ntb.topo = spr_ppd_topo(ndev, ppd1);
        dev_dbg(&pdev->dev, "ppd %#x topo %s\n", ppd1,
                ntb_topo_string(ndev->ntb.topo));
        if (ndev->ntb.topo == NTB_TOPO_NONE)
index 3fcd3fd..f91323e 100644 (file)
 #define GEN4_PPD_CLEAR_TRN             0x0001
 #define GEN4_PPD_LINKTRN               0x0008
 #define GEN4_PPD_CONN_MASK             0x0300
+#define SPR_PPD_CONN_MASK              0x0700
 #define GEN4_PPD_CONN_B2B              0x0200
 #define GEN4_PPD_DEV_MASK              0x1000
 #define GEN4_PPD_DEV_DSD               0x1000
 #define GEN4_PPD_DEV_USD               0x0000
+#define SPR_PPD_DEV_MASK               0x4000
+#define SPR_PPD_DEV_DSD                0x4000
+#define SPR_PPD_DEV_USD                0x0000
 #define GEN4_LINK_CTRL_LINK_DISABLE    0x0010
 
 #define GEN4_SLOTSTS                   0xb05a
 #define GEN4_PPD_TOPO_B2B_USD  (GEN4_PPD_CONN_B2B | GEN4_PPD_DEV_USD)
 #define GEN4_PPD_TOPO_B2B_DSD  (GEN4_PPD_CONN_B2B | GEN4_PPD_DEV_DSD)
 
+#define SPR_PPD_TOPO_MASK      (SPR_PPD_CONN_MASK | SPR_PPD_DEV_MASK)
+#define SPR_PPD_TOPO_B2B_USD   (GEN4_PPD_CONN_B2B | SPR_PPD_DEV_USD)
+#define SPR_PPD_TOPO_B2B_DSD   (GEN4_PPD_CONN_B2B | SPR_PPD_DEV_DSD)
+
 #define GEN4_DB_COUNT                  32
 #define GEN4_DB_LINK                   32
 #define GEN4_DB_LINK_BIT               BIT_ULL(GEN4_DB_LINK)
@@ -112,4 +120,12 @@ static inline int pdev_is_ICX(struct pci_dev *pdev)
        return 0;
 }
 
+static inline int pdev_is_SPR(struct pci_dev *pdev)
+{
+       if (pdev_is_gen4(pdev) &&
+           pdev->revision > PCI_DEVICE_REVISION_ICX_MAX)
+               return 1;
+       return 0;
+}
+
 #endif
index dd683cb..6295e55 100644 (file)
@@ -33,7 +33,6 @@ int ntb_msi_init(struct ntb_dev *ntb,
 {
        phys_addr_t mw_phys_addr;
        resource_size_t mw_size;
-       size_t struct_size;
        int peer_widx;
        int peers;
        int ret;
@@ -43,9 +42,8 @@ int ntb_msi_init(struct ntb_dev *ntb,
        if (peers <= 0)
                return -EINVAL;
 
-       struct_size = sizeof(*ntb->msi) + sizeof(*ntb->msi->peer_mws) * peers;
-
-       ntb->msi = devm_kzalloc(&ntb->dev, struct_size, GFP_KERNEL);
+       ntb->msi = devm_kzalloc(&ntb->dev, struct_size(ntb->msi, peer_mws, peers),
+                               GFP_KERNEL);
        if (!ntb->msi)
                return -ENOMEM;
 
index 80d6750..1f40137 100644 (file)
 #include "../core.h"
 #include "pinctrl-sunxi.h"
 
+/*
+ * These lock classes tell lockdep that GPIO IRQs are in a different
+ * category than their parents, so it won't report false recursion.
+ */
+static struct lock_class_key sunxi_pinctrl_irq_lock_class;
+static struct lock_class_key sunxi_pinctrl_irq_request_class;
+
 static struct irq_chip sunxi_pinctrl_edge_irq_chip;
 static struct irq_chip sunxi_pinctrl_level_irq_chip;
 
@@ -837,7 +844,8 @@ static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
 {
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
 
-       return sunxi_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, true);
+       return sunxi_pmx_gpio_set_direction(pctl->pctl_dev, NULL,
+                                           chip->base + offset, true);
 }
 
 static int sunxi_pinctrl_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -890,7 +898,8 @@ static int sunxi_pinctrl_gpio_direction_output(struct gpio_chip *chip,
        struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
 
        sunxi_pinctrl_gpio_set(chip, offset, value);
-       return sunxi_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, false);
+       return sunxi_pmx_gpio_set_direction(pctl->pctl_dev, NULL,
+                                           chip->base + offset, false);
 }
 
 static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc,
@@ -1555,6 +1564,8 @@ int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
        for (i = 0; i < (pctl->desc->irq_banks * IRQ_PER_BANK); i++) {
                int irqno = irq_create_mapping(pctl->domain, i);
 
+               irq_set_lockdep_class(irqno, &sunxi_pinctrl_irq_lock_class,
+                                     &sunxi_pinctrl_irq_request_class);
                irq_set_chip_and_handler(irqno, &sunxi_pinctrl_edge_irq_chip,
                                         handle_edge_irq);
                irq_set_chip_data(irqno, pctl);
index 0f1b5a7..17ad5f0 100644 (file)
@@ -607,7 +607,7 @@ ptp_ocp_settime(struct ptp_clock_info *ptp_info, const struct timespec64 *ts)
 }
 
 static void
-__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
+__ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u32 adj_val)
 {
        u32 select, ctrl;
 
@@ -615,7 +615,7 @@ __ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
        iowrite32(OCP_SELECT_CLK_REG, &bp->reg->select);
 
        iowrite32(adj_val, &bp->reg->offset_ns);
-       iowrite32(adj_val & 0x7f, &bp->reg->offset_window_ns);
+       iowrite32(NSEC_PER_SEC, &bp->reg->offset_window_ns);
 
        ctrl = OCP_CTRL_ADJUST_OFFSET | OCP_CTRL_ENABLE;
        iowrite32(ctrl, &bp->reg->ctrl);
@@ -624,6 +624,22 @@ __ptp_ocp_adjtime_locked(struct ptp_ocp *bp, u64 adj_val)
        iowrite32(select >> 16, &bp->reg->select);
 }
 
+static void
+ptp_ocp_adjtime_coarse(struct ptp_ocp *bp, u64 delta_ns)
+{
+       struct timespec64 ts;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&bp->lock, flags);
+       err = __ptp_ocp_gettime_locked(bp, &ts, NULL);
+       if (likely(!err)) {
+               timespec64_add_ns(&ts, delta_ns);
+               __ptp_ocp_settime_locked(bp, &ts);
+       }
+       spin_unlock_irqrestore(&bp->lock, flags);
+}
+
 static int
 ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
 {
@@ -631,6 +647,11 @@ ptp_ocp_adjtime(struct ptp_clock_info *ptp_info, s64 delta_ns)
        unsigned long flags;
        u32 adj_ns, sign;
 
+       if (delta_ns > NSEC_PER_SEC || -delta_ns > NSEC_PER_SEC) {
+               ptp_ocp_adjtime_coarse(bp, delta_ns);
+               return 0;
+       }
+
        sign = delta_ns < 0 ? BIT(31) : 0;
        adj_ns = sign ? -delta_ns : delta_ns;
 
index 12c10a5..7f42160 100644 (file)
@@ -233,12 +233,11 @@ static void scsifront_gnttab_done(struct vscsifrnt_info *info,
                return;
 
        for (i = 0; i < shadow->nr_grants; i++) {
-               if (unlikely(gnttab_query_foreign_access(shadow->gref[i]))) {
+               if (unlikely(!gnttab_try_end_foreign_access(shadow->gref[i]))) {
                        shost_printk(KERN_ALERT, info->host, KBUILD_MODNAME
                                     "grant still in use by backend\n");
                        BUG();
                }
-               gnttab_end_foreign_access(shadow->gref[i], 0, 0UL);
        }
 
        kfree(shadow->sg);
index 072473a..5ed2fc1 100644 (file)
@@ -28,7 +28,6 @@ struct fsl_soc_die_attr {
 static struct guts *guts;
 static struct soc_device_attribute soc_dev_attr;
 static struct soc_device *soc_dev;
-static struct device_node *root;
 
 
 /* SoC die attribute definition for QorIQ platform */
@@ -138,7 +137,7 @@ static u32 fsl_guts_get_svr(void)
 
 static int fsl_guts_probe(struct platform_device *pdev)
 {
-       struct device_node *np = pdev->dev.of_node;
+       struct device_node *root, *np = pdev->dev.of_node;
        struct device *dev = &pdev->dev;
        const struct fsl_soc_die_attr *soc_die;
        const char *machine;
@@ -159,8 +158,14 @@ static int fsl_guts_probe(struct platform_device *pdev)
        root = of_find_node_by_path("/");
        if (of_property_read_string(root, "model", &machine))
                of_property_read_string_index(root, "compatible", 0, &machine);
-       if (machine)
-               soc_dev_attr.machine = machine;
+       if (machine) {
+               soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL);
+               if (!soc_dev_attr.machine) {
+                       of_node_put(root);
+                       return -ENOMEM;
+               }
+       }
+       of_node_put(root);
 
        svr = fsl_guts_get_svr();
        soc_die = fsl_soc_die_match(svr, fsl_soc_die);
@@ -195,7 +200,6 @@ static int fsl_guts_probe(struct platform_device *pdev)
 static int fsl_guts_remove(struct platform_device *dev)
 {
        soc_device_unregister(soc_dev);
-       of_node_put(root);
        return 0;
 }
 
index 4d38c80..b3c226e 100644 (file)
@@ -147,7 +147,7 @@ EXPORT_SYMBOL(qe_issue_cmd);
  * memory mapped space.
  * The BRG clock is the QE clock divided by 2.
  * It was set up long ago during the initial boot phase and is
- * is given to us.
+ * given to us.
  * Baud rate clocks are zero-based in the driver code (as that maps
  * to port numbers). Documentation uses 1-based numbering.
  */
@@ -421,7 +421,7 @@ static void qe_upload_microcode(const void *base,
 
        for (i = 0; i < be32_to_cpu(ucode->count); i++)
                iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata);
-       
+
        /* Set I-RAM Ready Register */
        iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready);
 }
index e277c82..a5e2d0e 100644 (file)
@@ -35,6 +35,8 @@ int par_io_init(struct device_node *np)
        if (ret)
                return ret;
        par_io = ioremap(res.start, resource_size(&res));
+       if (!par_io)
+               return -ENOMEM;
 
        if (!of_property_read_u32(np, "num-ports", &num_ports))
                num_par_io_ports = num_ports;
index 3e59d47..3cb1230 100644 (file)
@@ -382,7 +382,8 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd)
        return 0;
 
 out_clk_disable:
-       clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
+       if (!domain->keep_clocks)
+               clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
 
        return ret;
 }
index 4599b12..d96082d 100644 (file)
@@ -1019,10 +1019,10 @@ int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
        int i, ret;
 
        if (vmalloced_buf || kmap_buf) {
-               desc_len = min_t(int, max_seg_size, PAGE_SIZE);
+               desc_len = min_t(unsigned int, max_seg_size, PAGE_SIZE);
                sgs = DIV_ROUND_UP(len + offset_in_page(buf), desc_len);
        } else if (virt_addr_valid(buf)) {
-               desc_len = min_t(int, max_seg_size, ctlr->max_dma_len);
+               desc_len = min_t(unsigned int, max_seg_size, ctlr->max_dma_len);
                sgs = DIV_ROUND_UP(len, desc_len);
        } else {
                return -EINVAL;
index f2bf6c6..f744ab1 100644 (file)
@@ -869,8 +869,10 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
        optee_supp_init(&optee->supp);
        ffa_dev_set_drvdata(ffa_dev, optee);
        ctx = teedev_open(optee->teedev);
-       if (IS_ERR(ctx))
+       if (IS_ERR(ctx)) {
+               rc = PTR_ERR(ctx);
                goto err_rhashtable_free;
+       }
        optee->ctx = ctx;
        rc = optee_notif_init(optee, OPTEE_DEFAULT_MAX_NOTIF_VALUE);
        if (rc)
index 1a55339..c517d31 100644 (file)
@@ -1417,8 +1417,10 @@ static int optee_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, optee);
        ctx = teedev_open(optee->teedev);
-       if (IS_ERR(ctx))
+       if (IS_ERR(ctx)) {
+               rc = PTR_ERR(ctx);
                goto err_supp_uninit;
+       }
        optee->ctx = ctx;
        rc = optee_notif_init(optee, max_notif_value);
        if (rc)
index a16dd4d..73e68cc 100644 (file)
@@ -419,11 +419,12 @@ static int thermal_genl_cmd_tz_get_trip(struct param *p)
        for (i = 0; i < tz->trips; i++) {
 
                enum thermal_trip_type type;
-               int temp, hyst;
+               int temp, hyst = 0;
 
                tz->ops->get_trip_type(tz, i, &type);
                tz->ops->get_trip_temp(tz, i, &temp);
-               tz->ops->get_trip_hyst(tz, i, &hyst);
+               if (tz->ops->get_trip_hyst)
+                       tz->ops->get_trip_hyst(tz, i, &hyst);
 
                if (nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_ID, i) ||
                    nla_put_u32(msg, THERMAL_GENL_ATTR_TZ_TRIP_TYPE, type) ||
index be09fd9..19b8c7e 100644 (file)
@@ -716,8 +716,9 @@ static int xenhcd_map_urb_for_request(struct xenhcd_info *info, struct urb *urb,
        return 0;
 }
 
-static void xenhcd_gnttab_done(struct usb_shadow *shadow)
+static void xenhcd_gnttab_done(struct xenhcd_info *info, unsigned int id)
 {
+       struct usb_shadow *shadow = info->shadow + id;
        int nr_segs = 0;
        int i;
 
@@ -726,8 +727,10 @@ static void xenhcd_gnttab_done(struct usb_shadow *shadow)
        if (xenusb_pipeisoc(shadow->req.pipe))
                nr_segs += shadow->req.u.isoc.nr_frame_desc_segs;
 
-       for (i = 0; i < nr_segs; i++)
-               gnttab_end_foreign_access(shadow->req.seg[i].gref, 0, 0UL);
+       for (i = 0; i < nr_segs; i++) {
+               if (!gnttab_try_end_foreign_access(shadow->req.seg[i].gref))
+                       xenhcd_set_error(info, "backend didn't release grant");
+       }
 
        shadow->req.nr_buffer_segs = 0;
        shadow->req.u.isoc.nr_frame_desc_segs = 0;
@@ -841,7 +844,9 @@ static void xenhcd_cancel_all_enqueued_urbs(struct xenhcd_info *info)
        list_for_each_entry_safe(urbp, tmp, &info->in_progress_list, list) {
                req_id = urbp->req_id;
                if (!urbp->unlinked) {
-                       xenhcd_gnttab_done(&info->shadow[req_id]);
+                       xenhcd_gnttab_done(info, req_id);
+                       if (info->error)
+                               return;
                        if (urbp->urb->status == -EINPROGRESS)
                                /* not dequeued */
                                xenhcd_giveback_urb(info, urbp->urb,
@@ -942,8 +947,7 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
        rp = info->urb_ring.sring->rsp_prod;
        if (RING_RESPONSE_PROD_OVERFLOW(&info->urb_ring, rp)) {
                xenhcd_set_error(info, "Illegal index on urb-ring");
-               spin_unlock_irqrestore(&info->lock, flags);
-               return 0;
+               goto err;
        }
        rmb(); /* ensure we see queued responses up to "rp" */
 
@@ -952,11 +956,13 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
                id = res.id;
                if (id >= XENUSB_URB_RING_SIZE) {
                        xenhcd_set_error(info, "Illegal data on urb-ring");
-                       continue;
+                       goto err;
                }
 
                if (likely(xenusb_pipesubmit(info->shadow[id].req.pipe))) {
-                       xenhcd_gnttab_done(&info->shadow[id]);
+                       xenhcd_gnttab_done(info, id);
+                       if (info->error)
+                               goto err;
                        urb = info->shadow[id].urb;
                        if (likely(urb)) {
                                urb->actual_length = res.actual_length;
@@ -978,6 +984,10 @@ static int xenhcd_urb_request_done(struct xenhcd_info *info)
        spin_unlock_irqrestore(&info->lock, flags);
 
        return more_to_do;
+
+ err:
+       spin_unlock_irqrestore(&info->lock, flags);
+       return 0;
 }
 
 static int xenhcd_conn_notify(struct xenhcd_info *info)
index f648f1c..d0f9107 100644 (file)
@@ -1563,11 +1563,27 @@ static virtio_net_ctrl_ack handle_ctrl_mq(struct mlx5_vdpa_dev *mvdev, u8 cmd)
 
        switch (cmd) {
        case VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET:
+               /* This mq feature check aligns with pre-existing userspace
+                * implementation.
+                *
+                * Without it, an untrusted driver could fake a multiqueue config
+                * request down to a non-mq device that may cause kernel to
+                * panic due to uninitialized resources for extra vqs. Even with
+                * a well behaving guest driver, it is not expected to allow
+                * changing the number of vqs on a non-mq device.
+                */
+               if (!MLX5_FEATURE(mvdev, VIRTIO_NET_F_MQ))
+                       break;
+
                read = vringh_iov_pull_iotlb(&cvq->vring, &cvq->riov, (void *)&mq, sizeof(mq));
                if (read != sizeof(mq))
                        break;
 
                newqps = mlx5vdpa16_to_cpu(mvdev, mq.virtqueue_pairs);
+               if (newqps < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN ||
+                   newqps > mlx5_vdpa_max_qps(mvdev->max_vqs))
+                       break;
+
                if (ndev->cur_num_vqs == 2 * newqps) {
                        status = VIRTIO_NET_OK;
                        break;
@@ -1897,11 +1913,25 @@ static u64 mlx5_vdpa_get_device_features(struct vdpa_device *vdev)
        return ndev->mvdev.mlx_features;
 }
 
-static int verify_min_features(struct mlx5_vdpa_dev *mvdev, u64 features)
+static int verify_driver_features(struct mlx5_vdpa_dev *mvdev, u64 features)
 {
+       /* Minimum features to expect */
        if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)))
                return -EOPNOTSUPP;
 
+       /* Double check features combination sent down by the driver.
+        * Fail invalid features due to absence of the depended feature.
+        *
+        * Per VIRTIO v1.1 specification, section 5.1.3.1 Feature bit
+        * requirements: "VIRTIO_NET_F_MQ Requires VIRTIO_NET_F_CTRL_VQ".
+        * By failing the invalid features sent down by untrusted drivers,
+        * we're assured the assumption made upon is_index_valid() and
+        * is_ctrl_vq_idx() will not be compromised.
+        */
+       if ((features & (BIT_ULL(VIRTIO_NET_F_MQ) | BIT_ULL(VIRTIO_NET_F_CTRL_VQ))) ==
+            BIT_ULL(VIRTIO_NET_F_MQ))
+               return -EINVAL;
+
        return 0;
 }
 
@@ -1977,7 +2007,7 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features)
 
        print_features(mvdev, features, true);
 
-       err = verify_min_features(mvdev, features);
+       err = verify_driver_features(mvdev, features);
        if (err)
                return err;
 
index 9846c9d..1ea5254 100644 (file)
@@ -393,7 +393,7 @@ static void vdpa_get_config_unlocked(struct vdpa_device *vdev,
         * If it does happen we assume a legacy guest.
         */
        if (!vdev->features_valid)
-               vdpa_set_features(vdev, 0, true);
+               vdpa_set_features_unlocked(vdev, 0);
        ops->get_config(vdev, offset, buf, len);
 }
 
index 2b1143f..0a4d93e 100644 (file)
@@ -294,7 +294,7 @@ vduse_domain_alloc_iova(struct iova_domain *iovad,
 
        iova_pfn = alloc_iova_fast(iovad, iova_len, limit >> shift, true);
 
-       return iova_pfn << shift;
+       return (dma_addr_t)iova_pfn << shift;
 }
 
 static void vduse_domain_free_iova(struct iova_domain *iovad,
index a57e381..cce101e 100644 (file)
@@ -533,8 +533,8 @@ static void vp_vdpa_remove(struct pci_dev *pdev)
 {
        struct vp_vdpa *vp_vdpa = pci_get_drvdata(pdev);
 
-       vdpa_unregister_device(&vp_vdpa->vdpa);
        vp_modern_remove(&vp_vdpa->mdev);
+       vdpa_unregister_device(&vp_vdpa->vdpa);
 }
 
 static struct pci_driver vp_vdpa_driver = {
index 670d56c..40b0983 100644 (file)
@@ -57,6 +57,17 @@ int vhost_iotlb_add_range_ctx(struct vhost_iotlb *iotlb,
        if (last < start)
                return -EFAULT;
 
+       /* If the range being mapped is [0, ULONG_MAX], split it into two entries
+        * otherwise its size would overflow u64.
+        */
+       if (start == 0 && last == ULONG_MAX) {
+               u64 mid = last / 2;
+
+               vhost_iotlb_add_range_ctx(iotlb, start, mid, addr, perm, opaque);
+               addr += mid + 1;
+               start = mid + 1;
+       }
+
        if (iotlb->limit &&
            iotlb->nmaps == iotlb->limit &&
            iotlb->flags & VHOST_IOTLB_FLAG_RETIRE) {
index 8515398..ec5249e 100644 (file)
@@ -286,7 +286,7 @@ static long vhost_vdpa_set_features(struct vhost_vdpa *v, u64 __user *featurep)
        if (copy_from_user(&features, featurep, sizeof(features)))
                return -EFAULT;
 
-       if (vdpa_set_features(vdpa, features, false))
+       if (vdpa_set_features(vdpa, features))
                return -EINVAL;
 
        return 0;
index 59edb5a..082380c 100644 (file)
@@ -1170,6 +1170,11 @@ ssize_t vhost_chr_write_iter(struct vhost_dev *dev,
                goto done;
        }
 
+       if (msg.size == 0) {
+               ret = -EINVAL;
+               goto done;
+       }
+
        if (dev->msg_handler)
                ret = dev->msg_handler(dev, &msg);
        else
@@ -1981,7 +1986,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
        return 0;
 }
 
-static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
+static int vhost_update_avail_event(struct vhost_virtqueue *vq)
 {
        if (vhost_put_avail_event(vq))
                return -EFAULT;
@@ -2527,7 +2532,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
                        return false;
                }
        } else {
-               r = vhost_update_avail_event(vq, vq->avail_idx);
+               r = vhost_update_avail_event(vq);
                if (r) {
                        vq_err(vq, "Failed to update avail event index at %p: %d\n",
                               vhost_avail_event(vq), r);
index 34f80b7..492fc26 100644 (file)
@@ -105,7 +105,6 @@ config VIRTIO_BALLOON
 
 config VIRTIO_MEM
        tristate "Virtio mem driver"
-       default m
        depends on X86_64
        depends on VIRTIO
        depends on MEMORY_HOTPLUG
index 00ac9db..22f15f4 100644 (file)
@@ -166,14 +166,13 @@ void virtio_add_status(struct virtio_device *dev, unsigned int status)
 }
 EXPORT_SYMBOL_GPL(virtio_add_status);
 
-int virtio_finalize_features(struct virtio_device *dev)
+/* Do some validation, then set FEATURES_OK */
+static int virtio_features_ok(struct virtio_device *dev)
 {
-       int ret = dev->config->finalize_features(dev);
        unsigned status;
+       int ret;
 
        might_sleep();
-       if (ret)
-               return ret;
 
        ret = arch_has_restricted_virtio_memory_access();
        if (ret) {
@@ -202,8 +201,23 @@ int virtio_finalize_features(struct virtio_device *dev)
        }
        return 0;
 }
-EXPORT_SYMBOL_GPL(virtio_finalize_features);
 
+/**
+ * virtio_reset_device - quiesce device for removal
+ * @dev: the device to reset
+ *
+ * Prevents device from sending interrupts and accessing memory.
+ *
+ * Generally used for cleanup during driver / device removal.
+ *
+ * Once this has been invoked, caller must ensure that
+ * virtqueue_notify / virtqueue_kick are not in progress.
+ *
+ * Note: this guarantees that vq callbacks are not in progress, however caller
+ * is responsible for preventing access from other contexts, such as a system
+ * call/workqueue/bh.  Invoking virtio_break_device then flushing any such
+ * contexts is one way to handle that.
+ * */
 void virtio_reset_device(struct virtio_device *dev)
 {
        dev->config->reset(dev);
@@ -245,17 +259,6 @@ static int virtio_dev_probe(struct device *_d)
                driver_features_legacy = driver_features;
        }
 
-       /*
-        * Some devices detect legacy solely via F_VERSION_1. Write
-        * F_VERSION_1 to force LE config space accesses before FEATURES_OK for
-        * these when needed.
-        */
-       if (drv->validate && !virtio_legacy_is_little_endian()
-                         && device_features & BIT_ULL(VIRTIO_F_VERSION_1)) {
-               dev->features = BIT_ULL(VIRTIO_F_VERSION_1);
-               dev->config->finalize_features(dev);
-       }
-
        if (device_features & (1ULL << VIRTIO_F_VERSION_1))
                dev->features = driver_features & device_features;
        else
@@ -266,13 +269,26 @@ static int virtio_dev_probe(struct device *_d)
                if (device_features & (1ULL << i))
                        __virtio_set_bit(dev, i);
 
+       err = dev->config->finalize_features(dev);
+       if (err)
+               goto err;
+
        if (drv->validate) {
+               u64 features = dev->features;
+
                err = drv->validate(dev);
                if (err)
                        goto err;
+
+               /* Did validation change any features? Then write them again. */
+               if (features != dev->features) {
+                       err = dev->config->finalize_features(dev);
+                       if (err)
+                               goto err;
+               }
        }
 
-       err = virtio_finalize_features(dev);
+       err = virtio_features_ok(dev);
        if (err)
                goto err;
 
@@ -496,7 +512,11 @@ int virtio_device_restore(struct virtio_device *dev)
        /* We have a driver! */
        virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);
 
-       ret = virtio_finalize_features(dev);
+       ret = dev->config->finalize_features(dev);
+       if (ret)
+               goto err;
+
+       ret = virtio_features_ok(dev);
        if (ret)
                goto err;
 
index 7767a7f..7650455 100644 (file)
@@ -317,7 +317,7 @@ static int virtio_vdpa_finalize_features(struct virtio_device *vdev)
        /* Give virtio_ring a chance to accept features. */
        vring_transport_features(vdev);
 
-       return vdpa_set_features(vdpa, vdev->features, false);
+       return vdpa_set_features(vdpa, vdev->features);
 }
 
 static const char *virtio_vdpa_bus_name(struct virtio_device *vdev)
index 3fa40c7..edb0acd 100644 (file)
@@ -169,20 +169,14 @@ undo:
                __del_gref(gref);
        }
 
-       /* It's possible for the target domain to map the just-allocated grant
-        * references by blindly guessing their IDs; if this is done, then
-        * __del_gref will leave them in the queue_gref list. They need to be
-        * added to the global list so that we can free them when they are no
-        * longer referenced.
-        */
-       if (unlikely(!list_empty(&queue_gref)))
-               list_splice_tail(&queue_gref, &gref_list);
        mutex_unlock(&gref_mutex);
        return rc;
 }
 
 static void __del_gref(struct gntalloc_gref *gref)
 {
+       unsigned long addr;
+
        if (gref->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
                uint8_t *tmp = kmap(gref->page);
                tmp[gref->notify.pgoff] = 0;
@@ -196,21 +190,16 @@ static void __del_gref(struct gntalloc_gref *gref)
        gref->notify.flags = 0;
 
        if (gref->gref_id) {
-               if (gnttab_query_foreign_access(gref->gref_id))
-                       return;
-
-               if (!gnttab_end_foreign_access_ref(gref->gref_id, 0))
-                       return;
-
-               gnttab_free_grant_reference(gref->gref_id);
+               if (gref->page) {
+                       addr = (unsigned long)page_to_virt(gref->page);
+                       gnttab_end_foreign_access(gref->gref_id, 0, addr);
+               } else
+                       gnttab_free_grant_reference(gref->gref_id);
        }
 
        gref_size--;
        list_del(&gref->next_gref);
 
-       if (gref->page)
-               __free_page(gref->page);
-
        kfree(gref);
 }
 
index 3729bea..5c83d41 100644 (file)
@@ -134,12 +134,9 @@ struct gnttab_ops {
         */
        unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
        /*
-        * Query the status of a grant entry. Ref parameter is reference of
-        * queried grant entry, return value is the status of queried entry.
-        * Detailed status(writing/reading) can be gotten from the return value
-        * by bit operations.
+        * Read the frame number related to a given grant reference.
         */
-       int (*query_foreign_access)(grant_ref_t ref);
+       unsigned long (*read_frame)(grant_ref_t ref);
 };
 
 struct unmap_refs_callback_data {
@@ -284,22 +281,6 @@ int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
 }
 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
 
-static int gnttab_query_foreign_access_v1(grant_ref_t ref)
-{
-       return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
-}
-
-static int gnttab_query_foreign_access_v2(grant_ref_t ref)
-{
-       return grstatus[ref] & (GTF_reading|GTF_writing);
-}
-
-int gnttab_query_foreign_access(grant_ref_t ref)
-{
-       return gnttab_interface->query_foreign_access(ref);
-}
-EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
-
 static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
 {
        u16 flags, nflags;
@@ -353,6 +334,16 @@ int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
 }
 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
 
+static unsigned long gnttab_read_frame_v1(grant_ref_t ref)
+{
+       return gnttab_shared.v1[ref].frame;
+}
+
+static unsigned long gnttab_read_frame_v2(grant_ref_t ref)
+{
+       return gnttab_shared.v2[ref].full_page.frame;
+}
+
 struct deferred_entry {
        struct list_head list;
        grant_ref_t ref;
@@ -382,12 +373,9 @@ static void gnttab_handle_deferred(struct timer_list *unused)
                spin_unlock_irqrestore(&gnttab_list_lock, flags);
                if (_gnttab_end_foreign_access_ref(entry->ref, entry->ro)) {
                        put_free_entry(entry->ref);
-                       if (entry->page) {
-                               pr_debug("freeing g.e. %#x (pfn %#lx)\n",
-                                        entry->ref, page_to_pfn(entry->page));
-                               put_page(entry->page);
-                       } else
-                               pr_info("freeing g.e. %#x\n", entry->ref);
+                       pr_debug("freeing g.e. %#x (pfn %#lx)\n",
+                                entry->ref, page_to_pfn(entry->page));
+                       put_page(entry->page);
                        kfree(entry);
                        entry = NULL;
                } else {
@@ -412,9 +400,18 @@ static void gnttab_handle_deferred(struct timer_list *unused)
 static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
                                struct page *page)
 {
-       struct deferred_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+       struct deferred_entry *entry;
+       gfp_t gfp = (in_atomic() || irqs_disabled()) ? GFP_ATOMIC : GFP_KERNEL;
        const char *what = KERN_WARNING "leaking";
 
+       entry = kmalloc(sizeof(*entry), gfp);
+       if (!page) {
+               unsigned long gfn = gnttab_interface->read_frame(ref);
+
+               page = pfn_to_page(gfn_to_pfn(gfn));
+               get_page(page);
+       }
+
        if (entry) {
                unsigned long flags;
 
@@ -435,11 +432,21 @@ static void gnttab_add_deferred(grant_ref_t ref, bool readonly,
               what, ref, page ? page_to_pfn(page) : -1);
 }
 
+int gnttab_try_end_foreign_access(grant_ref_t ref)
+{
+       int ret = _gnttab_end_foreign_access_ref(ref, 0);
+
+       if (ret)
+               put_free_entry(ref);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(gnttab_try_end_foreign_access);
+
 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
                               unsigned long page)
 {
-       if (gnttab_end_foreign_access_ref(ref, readonly)) {
-               put_free_entry(ref);
+       if (gnttab_try_end_foreign_access(ref)) {
                if (page != 0)
                        put_page(virt_to_page(page));
        } else
@@ -1417,7 +1424,7 @@ static const struct gnttab_ops gnttab_v1_ops = {
        .update_entry                   = gnttab_update_entry_v1,
        .end_foreign_access_ref         = gnttab_end_foreign_access_ref_v1,
        .end_foreign_transfer_ref       = gnttab_end_foreign_transfer_ref_v1,
-       .query_foreign_access           = gnttab_query_foreign_access_v1,
+       .read_frame                     = gnttab_read_frame_v1,
 };
 
 static const struct gnttab_ops gnttab_v2_ops = {
@@ -1429,7 +1436,7 @@ static const struct gnttab_ops gnttab_v2_ops = {
        .update_entry                   = gnttab_update_entry_v2,
        .end_foreign_access_ref         = gnttab_end_foreign_access_ref_v2,
        .end_foreign_transfer_ref       = gnttab_end_foreign_transfer_ref_v2,
-       .query_foreign_access           = gnttab_query_foreign_access_v2,
+       .read_frame                     = gnttab_read_frame_v2,
 };
 
 static bool gnttab_need_v2(void)
index 3c9ae15..0ca351f 100644 (file)
@@ -337,8 +337,8 @@ static void free_active_ring(struct sock_mapping *map)
        if (!map->active.ring)
                return;
 
-       free_pages((unsigned long)map->active.data.in,
-                       map->active.ring->ring_order);
+       free_pages_exact(map->active.data.in,
+                        PAGE_SIZE << map->active.ring->ring_order);
        free_page((unsigned long)map->active.ring);
 }
 
@@ -352,8 +352,8 @@ static int alloc_active_ring(struct sock_mapping *map)
                goto out;
 
        map->active.ring->ring_order = PVCALLS_RING_ORDER;
-       bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
-                                       PVCALLS_RING_ORDER);
+       bytes = alloc_pages_exact(PAGE_SIZE << PVCALLS_RING_ORDER,
+                                 GFP_KERNEL | __GFP_ZERO);
        if (!bytes)
                goto out;
 
index e8bed1c..df68906 100644 (file)
@@ -379,7 +379,14 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
                      unsigned int nr_pages, grant_ref_t *grefs)
 {
        int err;
-       int i, j;
+       unsigned int i;
+       grant_ref_t gref_head;
+
+       err = gnttab_alloc_grant_references(nr_pages, &gref_head);
+       if (err) {
+               xenbus_dev_fatal(dev, err, "granting access to ring page");
+               return err;
+       }
 
        for (i = 0; i < nr_pages; i++) {
                unsigned long gfn;
@@ -389,23 +396,14 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr,
                else
                        gfn = virt_to_gfn(vaddr);
 
-               err = gnttab_grant_foreign_access(dev->otherend_id, gfn, 0);
-               if (err < 0) {
-                       xenbus_dev_fatal(dev, err,
-                                        "granting access to ring page");
-                       goto fail;
-               }
-               grefs[i] = err;
+               grefs[i] = gnttab_claim_grant_reference(&gref_head);
+               gnttab_grant_foreign_access_ref(grefs[i], dev->otherend_id,
+                                               gfn, 0);
 
                vaddr = vaddr + XEN_PAGE_SIZE;
        }
 
        return 0;
-
-fail:
-       for (j = 0; j < i; j++)
-               gnttab_end_foreign_access_ref(grefs[j], 0);
-       return err;
 }
 EXPORT_SYMBOL_GPL(xenbus_grant_ring);
 
index 9e11e6f..d61543f 100644 (file)
@@ -1135,14 +1135,25 @@ out_free_interp:
                         * is then page aligned.
                         */
                        load_bias = ELF_PAGESTART(load_bias - vaddr);
-               }
 
-               /*
-                * Calculate the entire size of the ELF mapping (total_size).
-                * (Note that load_addr_set is set to true later once the
-                * initial mapping is performed.)
-                */
-               if (!load_addr_set) {
+                       /*
+                        * Calculate the entire size of the ELF mapping
+                        * (total_size), used for the initial mapping,
+                        * due to load_addr_set which is set to true later
+                        * once the initial mapping is performed.
+                        *
+                        * Note that this is only sensible when the LOAD
+                        * segments are contiguous (or overlapping). If
+                        * used for LOADs that are far apart, this would
+                        * cause the holes between LOADs to be mapped,
+                        * running the risk of having the mapping fail,
+                        * as it would be larger than the ELF file itself.
+                        *
+                        * As a result, only ET_DYN does this, since
+                        * some ET_EXEC (e.g. ia64) may have large virtual
+                        * memory holes between LOADs.
+                        *
+                        */
                        total_size = total_mapping_size(elf_phdata,
                                                        elf_ex->e_phnum);
                        if (!total_size) {
index 947f047..ebb2d10 100644 (file)
@@ -602,6 +602,9 @@ enum {
        /* Indicate that we want the transaction kthread to commit right now. */
        BTRFS_FS_COMMIT_TRANS,
 
+       /* Indicate we have half completed snapshot deletions pending. */
+       BTRFS_FS_UNFINISHED_DROPS,
+
 #if BITS_PER_LONG == 32
        /* Indicate if we have error/warn message printed on 32bit systems */
        BTRFS_FS_32BIT_ERROR,
@@ -1106,8 +1109,15 @@ enum {
        BTRFS_ROOT_QGROUP_FLUSHING,
        /* We started the orphan cleanup for this root. */
        BTRFS_ROOT_ORPHAN_CLEANUP,
+       /* This root has a drop operation that was started previously. */
+       BTRFS_ROOT_UNFINISHED_DROP,
 };
 
+static inline void btrfs_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
+{
+       clear_and_wake_up_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
+}
+
 /*
  * Record swapped tree blocks of a subvolume tree for delayed subtree trace
  * code. For detail check comment in fs/btrfs/qgroup.c.
index 87a5add..48590a3 100644 (file)
@@ -3813,6 +3813,10 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
 
        set_bit(BTRFS_FS_OPEN, &fs_info->flags);
 
+       /* Kick the cleaner thread so it'll start deleting snapshots. */
+       if (test_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags))
+               wake_up_process(fs_info->cleaner_kthread);
+
 clear_oneshot:
        btrfs_clear_oneshot_options(fs_info);
        return 0;
@@ -4538,6 +4542,12 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
         */
        kthread_park(fs_info->cleaner_kthread);
 
+       /*
+        * If we had UNFINISHED_DROPS we could still be processing them, so
+        * clear that bit and wake up relocation so it can stop.
+        */
+       btrfs_wake_unfinished_drop(fs_info);
+
        /* wait for the qgroup rescan worker to stop */
        btrfs_qgroup_wait_for_completion(fs_info, false);
 
index d89273c..96427b1 100644 (file)
@@ -5622,6 +5622,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
        int ret;
        int level;
        bool root_dropped = false;
+       bool unfinished_drop = false;
 
        btrfs_debug(fs_info, "Drop subvolume %llu", root->root_key.objectid);
 
@@ -5664,6 +5665,8 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
         * already dropped.
         */
        set_bit(BTRFS_ROOT_DELETING, &root->state);
+       unfinished_drop = test_bit(BTRFS_ROOT_UNFINISHED_DROP, &root->state);
+
        if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) {
                level = btrfs_header_level(root->node);
                path->nodes[level] = btrfs_lock_root_node(root);
@@ -5838,6 +5841,13 @@ out_free:
        kfree(wc);
        btrfs_free_path(path);
 out:
+       /*
+        * We were an unfinished drop root, check to see if there are any
+        * pending, and if not clear and wake up any waiters.
+        */
+       if (!err && unfinished_drop)
+               btrfs_maybe_wake_unfinished_drop(fs_info);
+
        /*
         * So if we need to stop dropping the snapshot for whatever reason we
         * need to make sure to add it back to the dead root list so that we
index 409bad3..4c91060 100644 (file)
@@ -6841,14 +6841,24 @@ static void assert_eb_page_uptodate(const struct extent_buffer *eb,
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
 
+       /*
+        * If we are using the commit root we could potentially clear a page
+        * Uptodate while we're using the extent buffer that we've previously
+        * looked up.  We don't want to complain in this case, as the page was
+        * valid before, we just didn't write it out.  Instead we want to catch
+        * the case where we didn't actually read the block properly, which
+        * would have !PageUptodate && !PageError, as we clear PageError before
+        * reading.
+        */
        if (fs_info->sectorsize < PAGE_SIZE) {
-               bool uptodate;
+               bool uptodate, error;
 
                uptodate = btrfs_subpage_test_uptodate(fs_info, page,
                                                       eb->start, eb->len);
-               WARN_ON(!uptodate);
+               error = btrfs_subpage_test_error(fs_info, page, eb->start, eb->len);
+               WARN_ON(!uptodate && !error);
        } else {
-               WARN_ON(!PageUptodate(page));
+               WARN_ON(!PageUptodate(page) && !PageError(page));
        }
 }
 
index 76e530f..5bbea5e 100644 (file)
@@ -7600,6 +7600,34 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        }
 
        len = min(len, em->len - (start - em->start));
+
+       /*
+        * If we have a NOWAIT request and the range contains multiple extents
+        * (or a mix of extents and holes), then we return -EAGAIN to make the
+        * caller fallback to a context where it can do a blocking (without
+        * NOWAIT) request. This way we avoid doing partial IO and returning
+        * success to the caller, which is not optimal for writes and for reads
+        * it can result in unexpected behaviour for an application.
+        *
+        * When doing a read, because we use IOMAP_DIO_PARTIAL when calling
+        * iomap_dio_rw(), we can end up returning less data then what the caller
+        * asked for, resulting in an unexpected, and incorrect, short read.
+        * That is, the caller asked to read N bytes and we return less than that,
+        * which is wrong unless we are crossing EOF. This happens if we get a
+        * page fault error when trying to fault in pages for the buffer that is
+        * associated to the struct iov_iter passed to iomap_dio_rw(), and we
+        * have previously submitted bios for other extents in the range, in
+        * which case iomap_dio_rw() may return us EIOCBQUEUED if not all of
+        * those bios have completed by the time we get the page fault error,
+        * which we return back to our caller - we should only return EIOCBQUEUED
+        * after we have submitted bios for all the extents in the range.
+        */
+       if ((flags & IOMAP_NOWAIT) && len < length) {
+               free_extent_map(em);
+               ret = -EAGAIN;
+               goto unlock_err;
+       }
+
        if (write) {
                ret = btrfs_get_blocks_direct_write(&em, inode, dio_data,
                                                    start, len);
index f12dc68..30d42ea 100644 (file)
@@ -1196,6 +1196,14 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
        if (!fs_info->quota_root)
                goto out;
 
+       /*
+        * Unlock the qgroup_ioctl_lock mutex before waiting for the rescan worker to
+        * complete. Otherwise we can deadlock because btrfs_remove_qgroup() needs
+        * to lock that mutex while holding a transaction handle and the rescan
+        * worker needs to commit a transaction.
+        */
+       mutex_unlock(&fs_info->qgroup_ioctl_lock);
+
        /*
         * Request qgroup rescan worker to complete and wait for it. This wait
         * must be done before transaction start for quota disable since it may
@@ -1203,7 +1211,6 @@ int btrfs_quota_disable(struct btrfs_fs_info *fs_info)
         */
        clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags);
        btrfs_qgroup_wait_for_completion(fs_info, false);
-       mutex_unlock(&fs_info->qgroup_ioctl_lock);
 
        /*
         * 1 For the root item
index f546519..9d80548 100644 (file)
@@ -3960,6 +3960,19 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
        int rw = 0;
        int err = 0;
 
+       /*
+        * This only gets set if we had a half-deleted snapshot on mount.  We
+        * cannot allow relocation to start while we're still trying to clean up
+        * these pending deletions.
+        */
+       ret = wait_on_bit(&fs_info->flags, BTRFS_FS_UNFINISHED_DROPS, TASK_INTERRUPTIBLE);
+       if (ret)
+               return ret;
+
+       /* We may have been woken up by close_ctree, so bail if we're closing. */
+       if (btrfs_fs_closing(fs_info))
+               return -EINTR;
+
        bg = btrfs_lookup_block_group(fs_info, group_start);
        if (!bg)
                return -ENOENT;
index 3d68d2d..ca7426e 100644 (file)
@@ -278,6 +278,21 @@ int btrfs_find_orphan_roots(struct btrfs_fs_info *fs_info)
 
                WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state));
                if (btrfs_root_refs(&root->root_item) == 0) {
+                       struct btrfs_key drop_key;
+
+                       btrfs_disk_key_to_cpu(&drop_key, &root->root_item.drop_progress);
+                       /*
+                        * If we have a non-zero drop_progress then we know we
+                        * made it partly through deleting this snapshot, and
+                        * thus we need to make sure we block any balance from
+                        * happening until this snapshot is completely dropped.
+                        */
+                       if (drop_key.objectid != 0 || drop_key.type != 0 ||
+                           drop_key.offset != 0) {
+                               set_bit(BTRFS_FS_UNFINISHED_DROPS, &fs_info->flags);
+                               set_bit(BTRFS_ROOT_UNFINISHED_DROP, &root->state);
+                       }
+
                        set_bit(BTRFS_ROOT_DEAD_TREE, &root->state);
                        btrfs_add_dead_root(root);
                }
index 29bd8c7..ef7ae20 100644 (file)
@@ -736,7 +736,7 @@ void btrfs_page_unlock_writer(struct btrfs_fs_info *fs_info, struct page *page,
         * Since we own the page lock, no one else could touch subpage::writers
         * and we are safe to do several atomic operations without spinlock.
         */
-       if (atomic_read(&subpage->writers))
+       if (atomic_read(&subpage->writers) == 0)
                /* No writers, locked by plain lock_page() */
                return unlock_page(page);
 
index c3cfdfd..1f1c25d 100644 (file)
@@ -854,7 +854,37 @@ btrfs_attach_transaction_barrier(struct btrfs_root *root)
 static noinline void wait_for_commit(struct btrfs_transaction *commit,
                                     const enum btrfs_trans_state min_state)
 {
-       wait_event(commit->commit_wait, commit->state >= min_state);
+       struct btrfs_fs_info *fs_info = commit->fs_info;
+       u64 transid = commit->transid;
+       bool put = false;
+
+       while (1) {
+               wait_event(commit->commit_wait, commit->state >= min_state);
+               if (put)
+                       btrfs_put_transaction(commit);
+
+               if (min_state < TRANS_STATE_COMPLETED)
+                       break;
+
+               /*
+                * A transaction isn't really completed until all of the
+                * previous transactions are completed, but with fsync we can
+                * end up with SUPER_COMMITTED transactions before a COMPLETED
+                * transaction. Wait for those.
+                */
+
+               spin_lock(&fs_info->trans_lock);
+               commit = list_first_entry_or_null(&fs_info->trans_list,
+                                                 struct btrfs_transaction,
+                                                 list);
+               if (!commit || commit->transid > transid) {
+                       spin_unlock(&fs_info->trans_lock);
+                       break;
+               }
+               refcount_inc(&commit->use_count);
+               put = true;
+               spin_unlock(&fs_info->trans_lock);
+       }
 }
 
 int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid)
@@ -1319,6 +1349,32 @@ again:
        return 0;
 }
 
+/*
+ * If we had a pending drop we need to see if there are any others left in our
+ * dead roots list, and if not clear our bit and wake any waiters.
+ */
+void btrfs_maybe_wake_unfinished_drop(struct btrfs_fs_info *fs_info)
+{
+       /*
+        * We put the drop in progress roots at the front of the list, so if the
+        * first entry doesn't have UNFINISHED_DROP set we can wake everybody
+        * up.
+        */
+       spin_lock(&fs_info->trans_lock);
+       if (!list_empty(&fs_info->dead_roots)) {
+               struct btrfs_root *root = list_first_entry(&fs_info->dead_roots,
+                                                          struct btrfs_root,
+                                                          root_list);
+               if (test_bit(BTRFS_ROOT_UNFINISHED_DROP, &root->state)) {
+                       spin_unlock(&fs_info->trans_lock);
+                       return;
+               }
+       }
+       spin_unlock(&fs_info->trans_lock);
+
+       btrfs_wake_unfinished_drop(fs_info);
+}
+
 /*
  * dead roots are old snapshots that need to be deleted.  This allocates
  * a dirty root struct and adds it into the list of dead roots that need to
@@ -1331,7 +1387,12 @@ void btrfs_add_dead_root(struct btrfs_root *root)
        spin_lock(&fs_info->trans_lock);
        if (list_empty(&root->root_list)) {
                btrfs_grab_root(root);
-               list_add_tail(&root->root_list, &fs_info->dead_roots);
+
+               /* We want to process the partially complete drops first. */
+               if (test_bit(BTRFS_ROOT_UNFINISHED_DROP, &root->state))
+                       list_add(&root->root_list, &fs_info->dead_roots);
+               else
+                       list_add_tail(&root->root_list, &fs_info->dead_roots);
        }
        spin_unlock(&fs_info->trans_lock);
 }
index 9402d8d..ba8a982 100644 (file)
@@ -216,6 +216,7 @@ int btrfs_wait_for_commit(struct btrfs_fs_info *fs_info, u64 transid);
 
 void btrfs_add_dead_root(struct btrfs_root *root);
 int btrfs_defrag_root(struct btrfs_root *root);
+void btrfs_maybe_wake_unfinished_drop(struct btrfs_fs_info *fs_info);
 int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root);
 int btrfs_commit_transaction(struct btrfs_trans_handle *trans);
 void btrfs_commit_transaction_async(struct btrfs_trans_handle *trans);
index 9fd145f..aae5697 100644 (file)
@@ -1682,6 +1682,7 @@ static int check_leaf(struct extent_buffer *leaf, bool check_item_data)
         */
        for (slot = 0; slot < nritems; slot++) {
                u32 item_end_expected;
+               u64 item_data_end;
                int ret;
 
                btrfs_item_key_to_cpu(leaf, &key, slot);
@@ -1696,6 +1697,8 @@ static int check_leaf(struct extent_buffer *leaf, bool check_item_data)
                        return -EUCLEAN;
                }
 
+               item_data_end = (u64)btrfs_item_offset(leaf, slot) +
+                               btrfs_item_size(leaf, slot);
                /*
                 * Make sure the offset and ends are right, remember that the
                 * item data starts at the end of the leaf and grows towards the
@@ -1706,11 +1709,10 @@ static int check_leaf(struct extent_buffer *leaf, bool check_item_data)
                else
                        item_end_expected = btrfs_item_offset(leaf,
                                                                 slot - 1);
-               if (unlikely(btrfs_item_data_end(leaf, slot) != item_end_expected)) {
+               if (unlikely(item_data_end != item_end_expected)) {
                        generic_err(leaf, slot,
-                               "unexpected item end, have %u expect %u",
-                               btrfs_item_data_end(leaf, slot),
-                               item_end_expected);
+                               "unexpected item end, have %llu expect %u",
+                               item_data_end, item_end_expected);
                        return -EUCLEAN;
                }
 
@@ -1719,12 +1721,10 @@ static int check_leaf(struct extent_buffer *leaf, bool check_item_data)
                 * just in case all the items are consistent to each other, but
                 * all point outside of the leaf.
                 */
-               if (unlikely(btrfs_item_data_end(leaf, slot) >
-                            BTRFS_LEAF_DATA_SIZE(fs_info))) {
+               if (unlikely(item_data_end > BTRFS_LEAF_DATA_SIZE(fs_info))) {
                        generic_err(leaf, slot,
-                       "slot end outside of leaf, have %u expect range [0, %u]",
-                               btrfs_item_data_end(leaf, slot),
-                               BTRFS_LEAF_DATA_SIZE(fs_info));
+                       "slot end outside of leaf, have %llu expect range [0, %u]",
+                               item_data_end, BTRFS_LEAF_DATA_SIZE(fs_info));
                        return -EUCLEAN;
                }
 
index 3ee014c..6bc8834 100644 (file)
@@ -1362,6 +1362,15 @@ again:
                                                 inode, name, namelen);
                        kfree(name);
                        iput(dir);
+                       /*
+                        * Whenever we need to check if a name exists or not, we
+                        * check the subvolume tree. So after an unlink we must
+                        * run delayed items, so that future checks for a name
+                        * during log replay see that the name does not exists
+                        * anymore.
+                        */
+                       if (!ret)
+                               ret = btrfs_run_delayed_items(trans);
                        if (ret)
                                goto out;
                        goto again;
@@ -1614,6 +1623,15 @@ static noinline int add_inode_ref(struct btrfs_trans_handle *trans,
                                 */
                                if (!ret && inode->i_nlink == 0)
                                        inc_nlink(inode);
+                               /*
+                                * Whenever we need to check if a name exists or
+                                * not, we check the subvolume tree. So after an
+                                * unlink we must run delayed items, so that future
+                                * checks for a name during log replay see that the
+                                * name does not exists anymore.
+                                */
+                               if (!ret)
+                                       ret = btrfs_run_delayed_items(trans);
                        }
                        if (ret < 0)
                                goto out;
@@ -4635,7 +4653,7 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
 
 /*
  * Log all prealloc extents beyond the inode's i_size to make sure we do not
- * lose them after doing a fast fsync and replaying the log. We scan the
+ * lose them after doing a full/fast fsync and replaying the log. We scan the
  * subvolume's root instead of iterating the inode's extent map tree because
  * otherwise we can log incorrect extent items based on extent map conversion.
  * That can happen due to the fact that extent maps are merged when they
@@ -5414,6 +5432,7 @@ static int copy_inode_items_to_log(struct btrfs_trans_handle *trans,
                                   struct btrfs_log_ctx *ctx,
                                   bool *need_log_inode_item)
 {
+       const u64 i_size = i_size_read(&inode->vfs_inode);
        struct btrfs_root *root = inode->root;
        int ins_start_slot = 0;
        int ins_nr = 0;
@@ -5434,13 +5453,21 @@ again:
                if (min_key->type > max_key->type)
                        break;
 
-               if (min_key->type == BTRFS_INODE_ITEM_KEY)
+               if (min_key->type == BTRFS_INODE_ITEM_KEY) {
                        *need_log_inode_item = false;
-
-               if ((min_key->type == BTRFS_INODE_REF_KEY ||
-                    min_key->type == BTRFS_INODE_EXTREF_KEY) &&
-                   inode->generation == trans->transid &&
-                   !recursive_logging) {
+               } else if (min_key->type == BTRFS_EXTENT_DATA_KEY &&
+                          min_key->offset >= i_size) {
+                       /*
+                        * Extents at and beyond eof are logged with
+                        * btrfs_log_prealloc_extents().
+                        * Only regular files have BTRFS_EXTENT_DATA_KEY keys,
+                        * and no keys greater than that, so bail out.
+                        */
+                       break;
+               } else if ((min_key->type == BTRFS_INODE_REF_KEY ||
+                           min_key->type == BTRFS_INODE_EXTREF_KEY) &&
+                          inode->generation == trans->transid &&
+                          !recursive_logging) {
                        u64 other_ino = 0;
                        u64 other_parent = 0;
 
@@ -5471,10 +5498,8 @@ again:
                                btrfs_release_path(path);
                                goto next_key;
                        }
-               }
-
-               /* Skip xattrs, we log them later with btrfs_log_all_xattrs() */
-               if (min_key->type == BTRFS_XATTR_ITEM_KEY) {
+               } else if (min_key->type == BTRFS_XATTR_ITEM_KEY) {
+                       /* Skip xattrs, logged later with btrfs_log_all_xattrs() */
                        if (ins_nr == 0)
                                goto next_slot;
                        ret = copy_items(trans, inode, dst_path, path,
@@ -5527,9 +5552,21 @@ next_key:
                        break;
                }
        }
-       if (ins_nr)
+       if (ins_nr) {
                ret = copy_items(trans, inode, dst_path, path, ins_start_slot,
                                 ins_nr, inode_only, logged_isize);
+               if (ret)
+                       return ret;
+       }
+
+       if (inode_only == LOG_INODE_ALL && S_ISREG(inode->vfs_inode.i_mode)) {
+               /*
+                * Release the path because otherwise we might attempt to double
+                * lock the same leaf with btrfs_log_prealloc_extents() below.
+                */
+               btrfs_release_path(path);
+               ret = btrfs_log_prealloc_extents(trans, inode, dst_path);
+       }
 
        return ret;
 }
index 51c968c..ae93cee 100644 (file)
@@ -254,7 +254,7 @@ static bool cachefiles_shorten_object(struct cachefiles_object *object,
                ret = cachefiles_inject_write_error();
                if (ret == 0)
                        ret = vfs_fallocate(file, FALLOC_FL_ZERO_RANGE,
-                                           new_size, dio_size);
+                                           new_size, dio_size - new_size);
                if (ret < 0) {
                        trace_cachefiles_io_error(object, file_inode(file), ret,
                                                  cachefiles_trace_fallocate_error);
index b8272fb..5aa2cf2 100644 (file)
@@ -325,7 +325,7 @@ struct erofs_inode {
                        unsigned char  z_algorithmtype[2];
                        unsigned char  z_logical_clusterbits;
                        unsigned long  z_tailextent_headlcn;
-                       unsigned int   z_idataoff;
+                       erofs_off_t    z_idataoff;
                        unsigned short z_idata_size;
                };
 #endif /* CONFIG_EROFS_FS_ZIP */
index cd54a52..592730f 100644 (file)
@@ -941,7 +941,17 @@ static int fuse_copy_page(struct fuse_copy_state *cs, struct page **pagep,
 
        while (count) {
                if (cs->write && cs->pipebufs && page) {
-                       return fuse_ref_page(cs, page, offset, count);
+                       /*
+                        * Can't control lifetime of pipe buffers, so always
+                        * copy user pages.
+                        */
+                       if (cs->req->args->user_pages) {
+                               err = fuse_copy_fill(cs);
+                               if (err)
+                                       return err;
+                       } else {
+                               return fuse_ref_page(cs, page, offset, count);
+                       }
                } else if (!cs->len) {
                        if (cs->move_pages && page &&
                            offset == 0 && count == PAGE_SIZE) {
index 8290944..0fc150c 100644 (file)
@@ -1413,6 +1413,7 @@ static int fuse_get_user_pages(struct fuse_args_pages *ap, struct iov_iter *ii,
                        (PAGE_SIZE - ret) & (PAGE_SIZE - 1);
        }
 
+       ap->args.user_pages = true;
        if (write)
                ap->args.in_pages = true;
        else
index e8e59fb..eac4984 100644 (file)
@@ -256,6 +256,7 @@ struct fuse_args {
        bool nocreds:1;
        bool in_pages:1;
        bool out_pages:1;
+       bool user_pages:1;
        bool out_argvar:1;
        bool page_zeroing:1;
        bool page_replace:1;
index ee846ce..9ee36aa 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/exportfs.h>
 #include <linux/posix_acl.h>
 #include <linux/pid_namespace.h>
+#include <uapi/linux/magic.h>
 
 MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>");
 MODULE_DESCRIPTION("Filesystem in Userspace");
@@ -50,8 +51,6 @@ MODULE_PARM_DESC(max_user_congthresh,
  "Global limit for the maximum congestion threshold an "
  "unprivileged user can set");
 
-#define FUSE_SUPER_MAGIC 0x65735546
-
 #define FUSE_DEFAULT_BLKSIZE 512
 
 /** Maximum number of outstanding background requests */
index fbc09da..df58966 100644 (file)
@@ -394,9 +394,12 @@ static int fuse_priv_ioctl(struct inode *inode, struct fuse_file *ff,
        args.out_args[1].value = ptr;
 
        err = fuse_simple_request(fm, &args);
-       if (!err && outarg.flags & FUSE_IOCTL_RETRY)
-               err = -EIO;
-
+       if (!err) {
+               if (outarg.result < 0)
+                       err = outarg.result;
+               else if (outarg.flags & FUSE_IOCTL_RETRY)
+                       err = -EIO;
+       }
        return err;
 }
 
index 6e97ed7..f46060e 100644 (file)
@@ -309,7 +309,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
 
        name = arch_vma_name(vma);
        if (!name) {
-               const char *anon_name;
+               struct anon_vma_name *anon_name;
 
                if (!mm) {
                        name = "[vdso]";
@@ -327,10 +327,10 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma)
                        goto done;
                }
 
-               anon_name = vma_anon_name(vma);
+               anon_name = anon_vma_name(vma);
                if (anon_name) {
                        seq_pad(m, ' ');
-                       seq_printf(m, "[anon:%s]", anon_name);
+                       seq_printf(m, "[anon:%s]", anon_name->name);
                }
        }
 
@@ -1597,7 +1597,8 @@ static const struct mm_walk_ops pagemap_ops = {
  * Bits 5-54  swap offset if swapped
  * Bit  55    pte is soft-dirty (see Documentation/admin-guide/mm/soft-dirty.rst)
  * Bit  56    page exclusively mapped
- * Bits 57-60 zero
+ * Bit  57    pte is uffd-wp write-protected
+ * Bits 58-60 zero
  * Bit  61    page is file-page or shared-anon
  * Bit  62    page swapped
  * Bit  63    page present
index e26b101..8e03b3d 100644 (file)
@@ -878,7 +878,7 @@ static int userfaultfd_release(struct inode *inode, struct file *file)
                                 new_flags, vma->anon_vma,
                                 vma->vm_file, vma->vm_pgoff,
                                 vma_policy(vma),
-                                NULL_VM_UFFD_CTX, vma_anon_name(vma));
+                                NULL_VM_UFFD_CTX, anon_vma_name(vma));
                if (prev)
                        vma = prev;
                else
@@ -1438,7 +1438,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                                 vma->anon_vma, vma->vm_file, vma->vm_pgoff,
                                 vma_policy(vma),
                                 ((struct vm_userfaultfd_ctx){ ctx }),
-                                vma_anon_name(vma));
+                                anon_vma_name(vma));
                if (prev) {
                        vma = prev;
                        goto next;
@@ -1615,7 +1615,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
                prev = vma_merge(mm, prev, start, vma_end, new_flags,
                                 vma->anon_vma, vma->vm_file, vma->vm_pgoff,
                                 vma_policy(vma),
-                                NULL_VM_UFFD_CTX, vma_anon_name(vma));
+                                NULL_VM_UFFD_CTX, anon_vma_name(vma));
                if (prev) {
                        vma = prev;
                        goto next;
index 63ccb52..220c8c6 100644 (file)
                           ARM_SMCCC_SMC_32,                            \
                           0, 0x7fff)
 
+#define ARM_SMCCC_ARCH_WORKAROUND_3                                    \
+       ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
+                          ARM_SMCCC_SMC_32,                            \
+                          0, 0x3fff)
+
 #define ARM_SMCCC_VENDOR_HYP_CALL_UID_FUNC_ID                          \
        ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,                         \
                           ARM_SMCCC_SMC_32,                            \
index d0ad379..3121d1f 100644 (file)
@@ -1792,6 +1792,11 @@ struct bpf_core_ctx {
 int bpf_core_apply(struct bpf_core_ctx *ctx, const struct bpf_core_relo *relo,
                   int relo_idx, void *insn);
 
+static inline bool unprivileged_ebpf_enabled(void)
+{
+       return !sysctl_unprivileged_bpf_disabled;
+}
+
 #else /* !CONFIG_BPF_SYSCALL */
 static inline struct bpf_prog *bpf_prog_get(u32 ufd)
 {
@@ -2011,6 +2016,12 @@ bpf_jit_find_kfunc_model(const struct bpf_prog *prog,
 {
        return NULL;
 }
+
+static inline bool unprivileged_ebpf_enabled(void)
+{
+       return false;
+}
+
 #endif /* CONFIG_BPF_SYSCALL */
 
 void __bpf_free_used_btfs(struct bpf_prog_aux *aux,
index 6150d11..dca2b13 100644 (file)
  */
 #define DMA_ATTR_PRIVILEGED            (1UL << 9)
 
-/*
- * This is a hint to the DMA-mapping subsystem that the device is expected
- * to overwrite the entire mapped size, thus the caller does not require any
- * of the previous buffer contents to be preserved. This allows
- * bounce-buffering implementations to optimise DMA_FROM_DEVICE transfers.
- */
-#define DMA_ATTR_OVERWRITE             (1UL << 10)
-
 /*
  * A dma_addr_t can hold any valid DMA or bus address for the platform.  It can
  * be given to a device to use as a DMA source or target.  It is specific to a
index 213cc56..5744a3f 100644 (file)
@@ -2626,7 +2626,7 @@ static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start,
 extern struct vm_area_struct *vma_merge(struct mm_struct *,
        struct vm_area_struct *prev, unsigned long addr, unsigned long end,
        unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t,
-       struct mempolicy *, struct vm_userfaultfd_ctx, const char *);
+       struct mempolicy *, struct vm_userfaultfd_ctx, struct anon_vma_name *);
 extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *);
 extern int __split_vma(struct mm_struct *, struct vm_area_struct *,
        unsigned long addr, int new_below);
@@ -3372,11 +3372,12 @@ static inline int seal_check_future_write(int seals, struct vm_area_struct *vma)
 
 #ifdef CONFIG_ANON_VMA_NAME
 int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
-                         unsigned long len_in, const char *name);
+                         unsigned long len_in,
+                         struct anon_vma_name *anon_name);
 #else
 static inline int
 madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
-                     unsigned long len_in, const char *name) {
+                     unsigned long len_in, struct anon_vma_name *anon_name) {
        return 0;
 }
 #endif
index b725839..cf90b1f 100644 (file)
@@ -140,50 +140,91 @@ static __always_inline void del_page_from_lru_list(struct page *page,
 
 #ifdef CONFIG_ANON_VMA_NAME
 /*
- * mmap_lock should be read-locked when calling vma_anon_name() and while using
- * the returned pointer.
+ * mmap_lock should be read-locked when calling anon_vma_name(). Caller should
+ * either keep holding the lock while using the returned pointer or it should
+ * raise anon_vma_name refcount before releasing the lock.
  */
-extern const char *vma_anon_name(struct vm_area_struct *vma);
+extern struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma);
+extern struct anon_vma_name *anon_vma_name_alloc(const char *name);
+extern void anon_vma_name_free(struct kref *kref);
 
-/*
- * mmap_lock should be read-locked for orig_vma->vm_mm.
- * mmap_lock should be write-locked for new_vma->vm_mm or new_vma should be
- * isolated.
- */
-extern void dup_vma_anon_name(struct vm_area_struct *orig_vma,
-                             struct vm_area_struct *new_vma);
+/* mmap_lock should be read-locked */
+static inline void anon_vma_name_get(struct anon_vma_name *anon_name)
+{
+       if (anon_name)
+               kref_get(&anon_name->kref);
+}
 
-/*
- * mmap_lock should be write-locked or vma should have been isolated under
- * write-locked mmap_lock protection.
- */
-extern void free_vma_anon_name(struct vm_area_struct *vma);
+static inline void anon_vma_name_put(struct anon_vma_name *anon_name)
+{
+       if (anon_name)
+               kref_put(&anon_name->kref, anon_vma_name_free);
+}
 
-/* mmap_lock should be read-locked */
-static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
-                                        const char *name)
+static inline
+struct anon_vma_name *anon_vma_name_reuse(struct anon_vma_name *anon_name)
+{
+       /* Prevent anon_name refcount saturation early on */
+       if (kref_read(&anon_name->kref) < REFCOUNT_MAX) {
+               anon_vma_name_get(anon_name);
+               return anon_name;
+
+       }
+       return anon_vma_name_alloc(anon_name->name);
+}
+
+static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
+                                    struct vm_area_struct *new_vma)
+{
+       struct anon_vma_name *anon_name = anon_vma_name(orig_vma);
+
+       if (anon_name)
+               new_vma->anon_name = anon_vma_name_reuse(anon_name);
+}
+
+static inline void free_anon_vma_name(struct vm_area_struct *vma)
 {
-       const char *vma_name = vma_anon_name(vma);
+       /*
+        * Not using anon_vma_name because it generates a warning if mmap_lock
+        * is not held, which might be the case here.
+        */
+       if (!vma->vm_file)
+               anon_vma_name_put(vma->anon_name);
+}
 
-       /* either both NULL, or pointers to same string */
-       if (vma_name == name)
+static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
+                                   struct anon_vma_name *anon_name2)
+{
+       if (anon_name1 == anon_name2)
                return true;
 
-       return name && vma_name && !strcmp(name, vma_name);
+       return anon_name1 && anon_name2 &&
+               !strcmp(anon_name1->name, anon_name2->name);
 }
+
 #else /* CONFIG_ANON_VMA_NAME */
-static inline const char *vma_anon_name(struct vm_area_struct *vma)
+static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
 {
        return NULL;
 }
-static inline void dup_vma_anon_name(struct vm_area_struct *orig_vma,
-                             struct vm_area_struct *new_vma) {}
-static inline void free_vma_anon_name(struct vm_area_struct *vma) {}
-static inline bool is_same_vma_anon_name(struct vm_area_struct *vma,
-                                        const char *name)
+
+static inline struct anon_vma_name *anon_vma_name_alloc(const char *name)
+{
+       return NULL;
+}
+
+static inline void anon_vma_name_get(struct anon_vma_name *anon_name) {}
+static inline void anon_vma_name_put(struct anon_vma_name *anon_name) {}
+static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
+                                    struct vm_area_struct *new_vma) {}
+static inline void free_anon_vma_name(struct vm_area_struct *vma) {}
+
+static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
+                                   struct anon_vma_name *anon_name2)
 {
        return true;
 }
+
 #endif  /* CONFIG_ANON_VMA_NAME */
 
 static inline void init_tlb_flush_pending(struct mm_struct *mm)
index 5140e5f..0f54987 100644 (file)
@@ -416,7 +416,10 @@ struct vm_area_struct {
                        struct rb_node rb;
                        unsigned long rb_subtree_last;
                } shared;
-               /* Serialized by mmap_sem. */
+               /*
+                * Serialized by mmap_sem. Never use directly because it is
+                * valid only when vm_file is NULL. Use anon_vma_name instead.
+                */
                struct anon_vma_name *anon_name;
        };
 
index b4dd96e..e6487a6 100644 (file)
@@ -101,7 +101,11 @@ static inline struct sk_buff *nf_hook_egress(struct sk_buff *skb, int *rc,
        nf_hook_state_init(&state, NF_NETDEV_EGRESS,
                           NFPROTO_NETDEV, dev, NULL, NULL,
                           dev_net(dev), NULL);
+
+       /* nf assumes rcu_read_lock, not just read_lock_bh */
+       rcu_read_lock();
        ret = nf_hook_slow(skb, &state, e, 0);
+       rcu_read_unlock();
 
        if (ret == 1) {
                return skb;
index c35f396..373003a 100644 (file)
@@ -308,6 +308,11 @@ static inline bool rfkill_blocked(struct rfkill *rfkill)
        return false;
 }
 
+static inline bool rfkill_soft_blocked(struct rfkill *rfkill)
+{
+       return false;
+}
+
 static inline enum rfkill_type rfkill_find_type(const char *name)
 {
        return RFKILL_TYPE_ALL;
index 2de442e..721089b 100644 (file)
@@ -401,18 +401,24 @@ static inline int vdpa_reset(struct vdpa_device *vdev)
        return ret;
 }
 
-static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features, bool locked)
+static inline int vdpa_set_features_unlocked(struct vdpa_device *vdev, u64 features)
 {
        const struct vdpa_config_ops *ops = vdev->config;
        int ret;
 
-       if (!locked)
-               mutex_lock(&vdev->cf_mutex);
-
        vdev->features_valid = true;
        ret = ops->set_driver_features(vdev, features);
-       if (!locked)
-               mutex_unlock(&vdev->cf_mutex);
+
+       return ret;
+}
+
+static inline int vdpa_set_features(struct vdpa_device *vdev, u64 features)
+{
+       int ret;
+
+       mutex_lock(&vdev->cf_mutex);
+       ret = vdpa_set_features_unlocked(vdev, features);
+       mutex_unlock(&vdev->cf_mutex);
 
        return ret;
 }
index 72292a6..5464f39 100644 (file)
@@ -133,7 +133,6 @@ bool is_virtio_device(struct device *dev);
 void virtio_break_device(struct virtio_device *dev);
 
 void virtio_config_changed(struct virtio_device *dev);
-int virtio_finalize_features(struct virtio_device *dev);
 #ifdef CONFIG_PM_SLEEP
 int virtio_device_freeze(struct virtio_device *dev);
 int virtio_device_restore(struct virtio_device *dev);
index 4d107ad..dafdc7f 100644 (file)
@@ -64,8 +64,9 @@ struct virtio_shm_region {
  *     Returns the first 64 feature bits (all we currently need).
  * @finalize_features: confirm what device features we'll be using.
  *     vdev: the virtio_device
- *     This gives the final feature bits for the device: it can change
+ *     This sends the driver feature bits to the device: it can change
  *     the dev->feature bits if it wants.
+ * Note: despite the name this can be called any number of times.
  *     Returns 0 on success or error status
  * @bus_name: return the bus name associated with the device (optional)
  *     vdev: the virtio_device
index 4b3d0b1..a647e5f 100644 (file)
@@ -506,8 +506,7 @@ static inline struct sk_buff *bt_skb_sendmmsg(struct sock *sk,
 
                tmp = bt_skb_sendmsg(sk, msg, len, mtu, headroom, tailroom);
                if (IS_ERR(tmp)) {
-                       kfree_skb(skb);
-                       return tmp;
+                       return skb;
                }
 
                len -= tmp->len;
index 586f69d..e336e9c 100644 (file)
@@ -1489,6 +1489,14 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 /* Extended advertising support */
 #define ext_adv_capable(dev) (((dev)->le_features[1] & HCI_LE_EXT_ADV))
 
+/* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E page 1789:
+ *
+ * C24: Mandatory if the LE Controller supports Connection State and either
+ * LE Feature (LL Privacy) or LE Feature (Extended Advertising) is supported
+ */
+#define use_enhanced_conn_complete(dev) (ll_privacy_capable(dev) || \
+                                        ext_adv_capable(dev))
+
 /* ----- HCI protocols ----- */
 #define HCI_PROTO_DEFER             0x01
 
index 53cb8de..47ffb36 100644 (file)
@@ -475,9 +475,9 @@ int igmp6_late_init(void);
 void igmp6_cleanup(void);
 void igmp6_late_cleanup(void);
 
-int igmp6_event_query(struct sk_buff *skb);
+void igmp6_event_query(struct sk_buff *skb);
 
-int igmp6_event_report(struct sk_buff *skb);
+void igmp6_event_report(struct sk_buff *skb);
 
 
 #ifdef CONFIG_SYSCTL
index a3647fa..bd59e95 100644 (file)
@@ -96,6 +96,7 @@ enum flow_offload_xmit_type {
        FLOW_OFFLOAD_XMIT_NEIGH,
        FLOW_OFFLOAD_XMIT_XFRM,
        FLOW_OFFLOAD_XMIT_DIRECT,
+       FLOW_OFFLOAD_XMIT_TC,
 };
 
 #define NF_FLOW_TABLE_ENCAP_MAX                2
@@ -127,7 +128,7 @@ struct flow_offload_tuple {
        struct { }                      __hash;
 
        u8                              dir:2,
-                                       xmit_type:2,
+                                       xmit_type:3,
                                        encap_num:2,
                                        in_vlan_ingress:2;
        u16                             mtu;
@@ -142,6 +143,9 @@ struct flow_offload_tuple {
                        u8              h_source[ETH_ALEN];
                        u8              h_dest[ETH_ALEN];
                } out;
+               struct {
+                       u32             iifidx;
+               } tc;
        };
 };
 
index 9eed51e..980daa6 100644 (file)
@@ -37,7 +37,7 @@ void nf_register_queue_handler(const struct nf_queue_handler *qh);
 void nf_unregister_queue_handler(void);
 void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict);
 
-void nf_queue_entry_get_refs(struct nf_queue_entry *entry);
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry);
 void nf_queue_entry_free(struct nf_queue_entry *entry);
 
 static inline void init_hashrandom(u32 *jhash_initval)
index fdb41e8..76aa6f1 100644 (file)
@@ -1568,7 +1568,6 @@ void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
 void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
 u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
 int xfrm_init_replay(struct xfrm_state *x);
-u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu);
 u32 xfrm_state_mtu(struct xfrm_state *x, int mtu);
 int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload);
 int xfrm_init_state(struct xfrm_state *x);
@@ -1681,14 +1680,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
               const struct xfrm_migrate *m, int num_bundles,
               const struct xfrm_kmaddress *k,
               const struct xfrm_encap_tmpl *encap);
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net);
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
+                                               u32 if_id);
 struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
                                      struct xfrm_migrate *m,
                                      struct xfrm_encap_tmpl *encap);
 int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_bundles,
                 struct xfrm_kmaddress *k, struct net *net,
-                struct xfrm_encap_tmpl *encap);
+                struct xfrm_encap_tmpl *encap, u32 if_id);
 #endif
 
 int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
index 90ae8d1..bae490c 100644 (file)
@@ -7,7 +7,8 @@
 #ifndef __FSL_DPAA2_FD_H
 #define __FSL_DPAA2_FD_H
 
-#include <linux/kernel.h>
+#include <linux/byteorder/generic.h>
+#include <linux/types.h>
 
 /**
  * DOC: DPAA2 FD - Frame Descriptor APIs for DPAA2
index 7614fee..edd601f 100644 (file)
@@ -13,7 +13,8 @@
 #define _ASM_POWERPC_IMMAP_QE_H
 #ifdef __KERNEL__
 
-#include <linux/kernel.h>
+#include <linux/types.h>
+
 #include <asm/io.h>
 
 #define QE_IMMAP_SIZE  (1024 * 1024)   /* 1MB from 1MB+IMMR */
index b6febe2..43ea830 100644 (file)
@@ -10,8 +10,8 @@
 #ifndef _QE_TDM_H_
 #define _QE_TDM_H_
 
-#include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/types.h>
 
 #include <soc/fsl/qe/immap_qe.h>
 #include <soc/fsl/qe/qe.h>
@@ -19,6 +19,8 @@
 #include <soc/fsl/qe/ucc.h>
 #include <soc/fsl/qe/ucc_fast.h>
 
+struct device_node;
+
 /* SI RAM entries */
 #define SIR_LAST       0x0001
 #define SIR_BYTE       0x0002
index 9696a5b..ad60b87 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef __UCC_FAST_H__
 #define __UCC_FAST_H__
 
-#include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <soc/fsl/qe/immap_qe.h>
 #include <soc/fsl/qe/qe.h>
index 11a216e..7548ce8 100644 (file)
@@ -11,7 +11,7 @@
 #ifndef __UCC_SLOW_H__
 #define __UCC_SLOW_H__
 
-#include <linux/kernel.h>
+#include <linux/types.h>
 
 #include <soc/fsl/qe/immap_qe.h>
 #include <soc/fsl/qe/qe.h>
index 225ec87..7989d94 100644 (file)
 #define KEY_PAUSECD            201
 #define KEY_PROG3              202
 #define KEY_PROG4              203
-#define KEY_DASHBOARD          204     /* AL Dashboard */
+#define KEY_ALL_APPLICATIONS   204     /* AC Desktop Show All Applications */
+#define KEY_DASHBOARD          KEY_ALL_APPLICATIONS
 #define KEY_SUSPEND            205
 #define KEY_CLOSE              206     /* AC Close */
 #define KEY_PLAY               207
 #define KEY_ASSISTANT          0x247   /* AL Context-aware desktop assistant */
 #define KEY_KBD_LAYOUT_NEXT    0x248   /* AC Next Keyboard Layout Select */
 #define KEY_EMOJI_PICKER       0x249   /* Show/hide emoji picker (HUTRR101) */
+#define KEY_DICTATE            0x24a   /* Start or Stop Voice Dictation Session (HUTRR99) */
 
 #define KEY_BRIGHTNESS_MIN             0x250   /* Set Brightness to Minimum */
 #define KEY_BRIGHTNESS_MAX             0x251   /* Set Brightness to Maximum */
index 0425cd7..f724129 100644 (file)
@@ -36,6 +36,7 @@
 #define EFIVARFS_MAGIC         0xde5e81e4
 #define HOSTFS_SUPER_MAGIC     0x00c0ffee
 #define OVERLAYFS_SUPER_MAGIC  0x794c7630
+#define FUSE_SUPER_MAGIC       0x65735546
 
 #define MINIX_SUPER_MAGIC      0x137F          /* minix v1 fs, 14 char names */
 #define MINIX_SUPER_MAGIC2     0x138F          /* minix v1 fs, 30 char names */
index 4e29d78..65e13a0 100644 (file)
@@ -511,6 +511,12 @@ struct xfrm_user_offload {
        int                             ifindex;
        __u8                            flags;
 };
+/* This flag was exposed without any kernel code that supporting it.
+ * Unfortunately, strongswan has the code that uses sets this flag,
+ * which makes impossible to reuse this bit.
+ *
+ * So leave it here to make sure that it won't be reused by mistake.
+ */
 #define XFRM_OFFLOAD_IPV6      1
 #define XFRM_OFFLOAD_INBOUND   2
 
index cb854df..c9fea93 100644 (file)
@@ -104,17 +104,32 @@ int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly);
  * access has been ended, free the given page too.  Access will be ended
  * immediately iff the grant entry is not in use, otherwise it will happen
  * some time later.  page may be 0, in which case no freeing will occur.
+ * Note that the granted page might still be accessed (read or write) by the
+ * other side after gnttab_end_foreign_access() returns, so even if page was
+ * specified as 0 it is not allowed to just reuse the page for other
+ * purposes immediately. gnttab_end_foreign_access() will take an additional
+ * reference to the granted page in this case, which is dropped only after
+ * the grant is no longer in use.
+ * This requires that multi page allocations for areas subject to
+ * gnttab_end_foreign_access() are done via alloc_pages_exact() (and freeing
+ * via free_pages_exact()) in order to avoid high order pages.
  */
 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
                               unsigned long page);
 
+/*
+ * End access through the given grant reference, iff the grant entry is
+ * no longer in use.  In case of success ending foreign access, the
+ * grant reference is deallocated.
+ * Return 1 if the grant entry was freed, 0 if it is still in use.
+ */
+int gnttab_try_end_foreign_access(grant_ref_t ref);
+
 int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn);
 
 unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref);
 unsigned long gnttab_end_foreign_transfer(grant_ref_t ref);
 
-int gnttab_query_foreign_access(grant_ref_t ref);
-
 /*
  * operations on reserved batches of grant references
  */
index e9ffb0c..07df6d9 100644 (file)
@@ -16,7 +16,7 @@ CONFIG_SYMBOLIC_ERRNAME=y
 #
 # Compile-time checks and compiler options
 #
-CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
 CONFIG_DEBUG_SECTION_MISMATCH=y
 CONFIG_FRAME_WARN=2048
 CONFIG_SECTION_MISMATCH_WARN_ONLY=y
index bfc56cb..6db1c47 100644 (file)
@@ -627,10 +627,14 @@ phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
        for (i = 0; i < nr_slots(alloc_size + offset); i++)
                mem->slots[index + i].orig_addr = slot_addr(orig_addr, i);
        tlb_addr = slot_addr(mem->start, index) + offset;
-       if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
-           (!(attrs & DMA_ATTR_OVERWRITE) || dir == DMA_TO_DEVICE ||
-           dir == DMA_BIDIRECTIONAL))
-               swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE);
+       /*
+        * When dir == DMA_FROM_DEVICE we could omit the copy from the orig
+        * to the tlb buffer, if we knew for sure the device will
+        * overwirte the entire current content. But we don't. Thus
+        * unconditional bounce may prevent leaking swiotlb content (i.e.
+        * kernel memory) to user-space.
+        */
+       swiotlb_bounce(dev, tlb_addr, mapping_size, DMA_TO_DEVICE);
        return tlb_addr;
 }
 
@@ -697,10 +701,13 @@ void swiotlb_tbl_unmap_single(struct device *dev, phys_addr_t tlb_addr,
 void swiotlb_sync_single_for_device(struct device *dev, phys_addr_t tlb_addr,
                size_t size, enum dma_data_direction dir)
 {
-       if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
-               swiotlb_bounce(dev, tlb_addr, size, DMA_TO_DEVICE);
-       else
-               BUG_ON(dir != DMA_FROM_DEVICE);
+       /*
+        * Unconditional bounce is necessary to avoid corruption on
+        * sync_*_for_cpu or dma_ummap_* when the device didn't overwrite
+        * the whole lengt of the bounce buffer.
+        */
+       swiotlb_bounce(dev, tlb_addr, size, DMA_TO_DEVICE);
+       BUG_ON(!valid_dma_direction(dir));
 }
 
 void swiotlb_sync_single_for_cpu(struct device *dev, phys_addr_t tlb_addr,
index a024bf6..f1e8900 100644 (file)
@@ -366,14 +366,14 @@ struct vm_area_struct *vm_area_dup(struct vm_area_struct *orig)
                *new = data_race(*orig);
                INIT_LIST_HEAD(&new->anon_vma_chain);
                new->vm_next = new->vm_prev = NULL;
-               dup_vma_anon_name(orig, new);
+               dup_anon_vma_name(orig, new);
        }
        return new;
 }
 
 void vm_area_free(struct vm_area_struct *vma)
 {
-       free_vma_anon_name(vma);
+       free_anon_vma_name(vma);
        kmem_cache_free(vm_area_cachep, vma);
 }
 
index 97dc9e5..5b0e172 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/export.h>
 #include <linux/mm.h>
+#include <linux/mm_inline.h>
 #include <linux/utsname.h>
 #include <linux/mman.h>
 #include <linux/reboot.h>
@@ -2286,15 +2287,16 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
 {
        struct mm_struct *mm = current->mm;
        const char __user *uname;
-       char *name, *pch;
+       struct anon_vma_name *anon_name = NULL;
        int error;
 
        switch (opt) {
        case PR_SET_VMA_ANON_NAME:
                uname = (const char __user *)arg;
                if (uname) {
-                       name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
+                       char *name, *pch;
 
+                       name = strndup_user(uname, ANON_VMA_NAME_MAX_LEN);
                        if (IS_ERR(name))
                                return PTR_ERR(name);
 
@@ -2304,15 +2306,18 @@ static int prctl_set_vma(unsigned long opt, unsigned long addr,
                                        return -EINVAL;
                                }
                        }
-               } else {
-                       /* Reset the name */
-                       name = NULL;
+                       /* anon_vma has its own copy */
+                       anon_name = anon_vma_name_alloc(name);
+                       kfree(name);
+                       if (!anon_name)
+                               return -ENOMEM;
+
                }
 
                mmap_write_lock(mm);
-               error = madvise_set_anon_name(mm, addr, size, name);
+               error = madvise_set_anon_name(mm, addr, size, anon_name);
                mmap_write_unlock(mm);
-               kfree(name);
+               anon_vma_name_put(anon_name);
                break;
        default:
                error = -EINVAL;
index 5ae443b..730ab56 100644 (file)
@@ -180,6 +180,10 @@ static int bpf_stats_handler(struct ctl_table *table, int write,
        return ret;
 }
 
+void __weak unpriv_ebpf_notify(int new_state)
+{
+}
+
 static int bpf_unpriv_handler(struct ctl_table *table, int write,
                              void *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -197,6 +201,9 @@ static int bpf_unpriv_handler(struct ctl_table *table, int write,
                        return -EPERM;
                *(int *)table->data = unpriv_enable;
        }
+
+       unpriv_ebpf_notify(unpriv_enable);
+
        return ret;
 }
 #endif /* CONFIG_BPF_SYSCALL && CONFIG_SYSCTL */
index af68a67..21dea90 100644 (file)
@@ -310,10 +310,20 @@ record_it:
        local_irq_restore(flags);
 }
 
-static void blk_trace_free(struct blk_trace *bt)
+static void blk_trace_free(struct request_queue *q, struct blk_trace *bt)
 {
        relay_close(bt->rchan);
-       debugfs_remove(bt->dir);
+
+       /*
+        * If 'bt->dir' is not set, then both 'dropped' and 'msg' are created
+        * under 'q->debugfs_dir', thus lookup and remove them.
+        */
+       if (!bt->dir) {
+               debugfs_remove(debugfs_lookup("dropped", q->debugfs_dir));
+               debugfs_remove(debugfs_lookup("msg", q->debugfs_dir));
+       } else {
+               debugfs_remove(bt->dir);
+       }
        free_percpu(bt->sequence);
        free_percpu(bt->msg_data);
        kfree(bt);
@@ -335,10 +345,10 @@ static void put_probe_ref(void)
        mutex_unlock(&blk_probe_mutex);
 }
 
-static void blk_trace_cleanup(struct blk_trace *bt)
+static void blk_trace_cleanup(struct request_queue *q, struct blk_trace *bt)
 {
        synchronize_rcu();
-       blk_trace_free(bt);
+       blk_trace_free(q, bt);
        put_probe_ref();
 }
 
@@ -352,7 +362,7 @@ static int __blk_trace_remove(struct request_queue *q)
                return -EINVAL;
 
        if (bt->trace_state != Blktrace_running)
-               blk_trace_cleanup(bt);
+               blk_trace_cleanup(q, bt);
 
        return 0;
 }
@@ -572,7 +582,7 @@ static int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev,
        ret = 0;
 err:
        if (ret)
-               blk_trace_free(bt);
+               blk_trace_free(q, bt);
        return ret;
 }
 
@@ -1616,7 +1626,7 @@ static int blk_trace_remove_queue(struct request_queue *q)
 
        put_probe_ref();
        synchronize_rcu();
-       blk_trace_free(bt);
+       blk_trace_free(q, bt);
        return 0;
 }
 
@@ -1647,7 +1657,7 @@ static int blk_trace_setup_queue(struct request_queue *q,
        return 0;
 
 free_bt:
-       blk_trace_free(bt);
+       blk_trace_free(q, bt);
        return ret;
 }
 
index 3050892..eb44418 100644 (file)
@@ -235,7 +235,7 @@ static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata;
 static int __init set_trace_boot_options(char *str)
 {
        strlcpy(trace_boot_options_buf, str, MAX_TRACER_SIZE);
-       return 0;
+       return 1;
 }
 __setup("trace_options=", set_trace_boot_options);
 
@@ -246,7 +246,7 @@ static int __init set_trace_boot_clock(char *str)
 {
        strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE);
        trace_boot_clock = trace_boot_clock_buf;
-       return 0;
+       return 1;
 }
 __setup("trace_clock=", set_trace_boot_clock);
 
index ada87bf..dc7f733 100644 (file)
@@ -2289,9 +2289,9 @@ parse_field(struct hist_trigger_data *hist_data, struct trace_event_file *file,
                        /*
                         * For backward compatibility, if field_name
                         * was "cpu", then we treat this the same as
-                        * common_cpu.
+                        * common_cpu. This also works for "CPU".
                         */
-                       if (strcmp(field_name, "cpu") == 0) {
+                       if (field && field->filter_type == FILTER_CPU) {
                                *flags |= HIST_FIELD_FL_CPU;
                        } else {
                                hist_err(tr, HIST_ERR_FIELD_NOT_FOUND,
@@ -4832,7 +4832,7 @@ static int create_tracing_map_fields(struct hist_trigger_data *hist_data)
 
                        if (hist_field->flags & HIST_FIELD_FL_STACKTRACE)
                                cmp_fn = tracing_map_cmp_none;
-                       else if (!field)
+                       else if (!field || hist_field->flags & HIST_FIELD_FL_CPU)
                                cmp_fn = tracing_map_cmp_num(hist_field->size,
                                                             hist_field->is_signed);
                        else if (is_string_field(field))
index 508f14a..b62fd78 100644 (file)
@@ -32,7 +32,7 @@ static int __init set_kprobe_boot_events(char *str)
        strlcpy(kprobe_boot_events_buf, str, COMMAND_LINE_SIZE);
        disable_tracing_selftest("running kprobe events");
 
-       return 0;
+       return 1;
 }
 __setup("kprobe_event=", set_kprobe_boot_events);
 
index 6b2e3ca..5481ba4 100644 (file)
@@ -58,6 +58,18 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
        cred->user_ns = user_ns;
 }
 
+static unsigned long enforced_nproc_rlimit(void)
+{
+       unsigned long limit = RLIM_INFINITY;
+
+       /* Is RLIMIT_NPROC currently enforced? */
+       if (!uid_eq(current_uid(), GLOBAL_ROOT_UID) ||
+           (current_user_ns() != &init_user_ns))
+               limit = rlimit(RLIMIT_NPROC);
+
+       return limit;
+}
+
 /*
  * Create a new user namespace, deriving the creator from the user in the
  * passed credentials, and replacing that user with the new root user for the
@@ -122,7 +134,7 @@ int create_user_ns(struct cred *new)
        for (i = 0; i < MAX_PER_NAMESPACE_UCOUNTS; i++) {
                ns->ucount_max[i] = INT_MAX;
        }
-       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, rlimit(RLIMIT_NPROC));
+       set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_NPROC, enforced_nproc_rlimit());
        set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MSGQUEUE, rlimit(RLIMIT_MSGQUEUE));
        set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_SIGPENDING, rlimit(RLIMIT_SIGPENDING));
        set_rlimit_ucount_max(ns, UCOUNT_RLIMIT_MEMLOCK, rlimit(RLIMIT_MEMLOCK));
index c80fde8..9b5a692 100644 (file)
@@ -45,7 +45,6 @@ config BITREVERSE
 config HAVE_ARCH_BITREVERSE
        bool
        default n
-       depends on BITREVERSE
        help
          This option enables the use of hardware bit-reversal instructions on
          architectures which support such operations.
index a9d4d72..7bc1ba9 100644 (file)
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1729,11 +1729,11 @@ EXPORT_SYMBOL(fault_in_writeable);
  * @uaddr: start of address range
  * @size: length of address range
  *
- * Faults in an address range using get_user_pages, i.e., without triggering
- * hardware page faults.  This is primarily useful when we already know that
- * some or all of the pages in the address range aren't in memory.
+ * Faults in an address range for writing.  This is primarily useful when we
+ * already know that some or all of the pages in the address range aren't in
+ * memory.
  *
- * Other than fault_in_writeable(), this function is non-destructive.
+ * Unlike fault_in_writeable(), this function is non-destructive.
  *
  * Note that we don't pin or otherwise hold the pages referenced that we fault
  * in.  There's no guarantee that they'll stay in memory for any duration of
@@ -1744,46 +1744,27 @@ EXPORT_SYMBOL(fault_in_writeable);
  */
 size_t fault_in_safe_writeable(const char __user *uaddr, size_t size)
 {
-       unsigned long start = (unsigned long)untagged_addr(uaddr);
-       unsigned long end, nstart, nend;
+       unsigned long start = (unsigned long)uaddr, end;
        struct mm_struct *mm = current->mm;
-       struct vm_area_struct *vma = NULL;
-       int locked = 0;
+       bool unlocked = false;
 
-       nstart = start & PAGE_MASK;
+       if (unlikely(size == 0))
+               return 0;
        end = PAGE_ALIGN(start + size);
-       if (end < nstart)
+       if (end < start)
                end = 0;
-       for (; nstart != end; nstart = nend) {
-               unsigned long nr_pages;
-               long ret;
 
-               if (!locked) {
-                       locked = 1;
-                       mmap_read_lock(mm);
-                       vma = find_vma(mm, nstart);
-               } else if (nstart >= vma->vm_end)
-                       vma = vma->vm_next;
-               if (!vma || vma->vm_start >= end)
-                       break;
-               nend = end ? min(end, vma->vm_end) : vma->vm_end;
-               if (vma->vm_flags & (VM_IO | VM_PFNMAP))
-                       continue;
-               if (nstart < vma->vm_start)
-                       nstart = vma->vm_start;
-               nr_pages = (nend - nstart) / PAGE_SIZE;
-               ret = __get_user_pages_locked(mm, nstart, nr_pages,
-                                             NULL, NULL, &locked,
-                                             FOLL_TOUCH | FOLL_WRITE);
-               if (ret <= 0)
+       mmap_read_lock(mm);
+       do {
+               if (fixup_user_fault(mm, start, FAULT_FLAG_WRITE, &unlocked))
                        break;
-               nend = nstart + ret * PAGE_SIZE;
-       }
-       if (locked)
-               mmap_read_unlock(mm);
-       if (nstart == end)
-               return 0;
-       return size - min_t(size_t, nstart - start, size);
+               start = (start + PAGE_SIZE) & PAGE_MASK;
+       } while (start != end);
+       mmap_read_unlock(mm);
+
+       if (size > (unsigned long)uaddr - start)
+               return size - ((unsigned long)uaddr - start);
+       return 0;
 }
 EXPORT_SYMBOL(fault_in_safe_writeable);
 
index 5604064..38d0f51 100644 (file)
@@ -65,7 +65,7 @@ static int madvise_need_mmap_write(int behavior)
 }
 
 #ifdef CONFIG_ANON_VMA_NAME
-static struct anon_vma_name *anon_vma_name_alloc(const char *name)
+struct anon_vma_name *anon_vma_name_alloc(const char *name)
 {
        struct anon_vma_name *anon_name;
        size_t count;
@@ -81,78 +81,48 @@ static struct anon_vma_name *anon_vma_name_alloc(const char *name)
        return anon_name;
 }
 
-static void vma_anon_name_free(struct kref *kref)
+void anon_vma_name_free(struct kref *kref)
 {
        struct anon_vma_name *anon_name =
                        container_of(kref, struct anon_vma_name, kref);
        kfree(anon_name);
 }
 
-static inline bool has_vma_anon_name(struct vm_area_struct *vma)
+struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
 {
-       return !vma->vm_file && vma->anon_name;
-}
-
-const char *vma_anon_name(struct vm_area_struct *vma)
-{
-       if (!has_vma_anon_name(vma))
-               return NULL;
-
        mmap_assert_locked(vma->vm_mm);
 
-       return vma->anon_name->name;
-}
-
-void dup_vma_anon_name(struct vm_area_struct *orig_vma,
-                      struct vm_area_struct *new_vma)
-{
-       if (!has_vma_anon_name(orig_vma))
-               return;
-
-       kref_get(&orig_vma->anon_name->kref);
-       new_vma->anon_name = orig_vma->anon_name;
-}
-
-void free_vma_anon_name(struct vm_area_struct *vma)
-{
-       struct anon_vma_name *anon_name;
-
-       if (!has_vma_anon_name(vma))
-               return;
+       if (vma->vm_file)
+               return NULL;
 
-       anon_name = vma->anon_name;
-       vma->anon_name = NULL;
-       kref_put(&anon_name->kref, vma_anon_name_free);
+       return vma->anon_name;
 }
 
 /* mmap_lock should be write-locked */
-static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
+static int replace_anon_vma_name(struct vm_area_struct *vma,
+                                struct anon_vma_name *anon_name)
 {
-       const char *anon_name;
+       struct anon_vma_name *orig_name = anon_vma_name(vma);
 
-       if (!name) {
-               free_vma_anon_name(vma);
+       if (!anon_name) {
+               vma->anon_name = NULL;
+               anon_vma_name_put(orig_name);
                return 0;
        }
 
-       anon_name = vma_anon_name(vma);
-       if (anon_name) {
-               /* Same name, nothing to do here */
-               if (!strcmp(name, anon_name))
-                       return 0;
+       if (anon_vma_name_eq(orig_name, anon_name))
+               return 0;
 
-               free_vma_anon_name(vma);
-       }
-       vma->anon_name = anon_vma_name_alloc(name);
-       if (!vma->anon_name)
-               return -ENOMEM;
+       vma->anon_name = anon_vma_name_reuse(anon_name);
+       anon_vma_name_put(orig_name);
 
        return 0;
 }
 #else /* CONFIG_ANON_VMA_NAME */
-static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
+static int replace_anon_vma_name(struct vm_area_struct *vma,
+                                struct anon_vma_name *anon_name)
 {
-       if (name)
+       if (anon_name)
                return -EINVAL;
 
        return 0;
@@ -161,17 +131,19 @@ static int replace_vma_anon_name(struct vm_area_struct *vma, const char *name)
 /*
  * Update the vm_flags on region of a vma, splitting it or merging it as
  * necessary.  Must be called with mmap_sem held for writing;
+ * Caller should ensure anon_name stability by raising its refcount even when
+ * anon_name belongs to a valid vma because this function might free that vma.
  */
 static int madvise_update_vma(struct vm_area_struct *vma,
                              struct vm_area_struct **prev, unsigned long start,
                              unsigned long end, unsigned long new_flags,
-                             const char *name)
+                             struct anon_vma_name *anon_name)
 {
        struct mm_struct *mm = vma->vm_mm;
        int error;
        pgoff_t pgoff;
 
-       if (new_flags == vma->vm_flags && is_same_vma_anon_name(vma, name)) {
+       if (new_flags == vma->vm_flags && anon_vma_name_eq(anon_vma_name(vma), anon_name)) {
                *prev = vma;
                return 0;
        }
@@ -179,7 +151,7 @@ static int madvise_update_vma(struct vm_area_struct *vma,
        pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
        *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma,
                          vma->vm_file, pgoff, vma_policy(vma),
-                         vma->vm_userfaultfd_ctx, name);
+                         vma->vm_userfaultfd_ctx, anon_name);
        if (*prev) {
                vma = *prev;
                goto success;
@@ -209,7 +181,7 @@ success:
         */
        vma->vm_flags = new_flags;
        if (!vma->vm_file) {
-               error = replace_vma_anon_name(vma, name);
+               error = replace_anon_vma_name(vma, anon_name);
                if (error)
                        return error;
        }
@@ -975,6 +947,7 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
                                unsigned long behavior)
 {
        int error;
+       struct anon_vma_name *anon_name;
        unsigned long new_flags = vma->vm_flags;
 
        switch (behavior) {
@@ -1040,8 +1013,11 @@ static int madvise_vma_behavior(struct vm_area_struct *vma,
                break;
        }
 
+       anon_name = anon_vma_name(vma);
+       anon_vma_name_get(anon_name);
        error = madvise_update_vma(vma, prev, start, end, new_flags,
-                                  vma_anon_name(vma));
+                                  anon_name);
+       anon_vma_name_put(anon_name);
 
 out:
        /*
@@ -1225,7 +1201,7 @@ int madvise_walk_vmas(struct mm_struct *mm, unsigned long start,
 static int madvise_vma_anon_name(struct vm_area_struct *vma,
                                 struct vm_area_struct **prev,
                                 unsigned long start, unsigned long end,
-                                unsigned long name)
+                                unsigned long anon_name)
 {
        int error;
 
@@ -1234,7 +1210,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
                return -EBADF;
 
        error = madvise_update_vma(vma, prev, start, end, vma->vm_flags,
-                                  (const char *)name);
+                                  (struct anon_vma_name *)anon_name);
 
        /*
         * madvise() returns EAGAIN if kernel resources, such as
@@ -1246,7 +1222,7 @@ static int madvise_vma_anon_name(struct vm_area_struct *vma,
 }
 
 int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
-                         unsigned long len_in, const char *name)
+                         unsigned long len_in, struct anon_vma_name *anon_name)
 {
        unsigned long end;
        unsigned long len;
@@ -1266,7 +1242,7 @@ int madvise_set_anon_name(struct mm_struct *mm, unsigned long start,
        if (end == start)
                return 0;
 
-       return madvise_walk_vmas(mm, start, end, (unsigned long)name,
+       return madvise_walk_vmas(mm, start, end, (unsigned long)anon_name,
                                 madvise_vma_anon_name);
 }
 #endif /* CONFIG_ANON_VMA_NAME */
index 9f80f16..08f5f83 100644 (file)
 static void memfd_tag_pins(struct xa_state *xas)
 {
        struct page *page;
-       unsigned int tagged = 0;
+       int latency = 0;
+       int cache_count;
 
        lru_add_drain();
 
        xas_lock_irq(xas);
        xas_for_each(xas, page, ULONG_MAX) {
-               if (xa_is_value(page))
-                       continue;
-               page = find_subpage(page, xas->xa_index);
-               if (page_count(page) - page_mapcount(page) > 1)
+               cache_count = 1;
+               if (!xa_is_value(page) &&
+                   PageTransHuge(page) && !PageHuge(page))
+                       cache_count = HPAGE_PMD_NR;
+
+               if (!xa_is_value(page) &&
+                   page_count(page) - total_mapcount(page) != cache_count)
                        xas_set_mark(xas, MEMFD_TAG_PINNED);
+               if (cache_count != 1)
+                       xas_set(xas, page->index + cache_count);
 
-               if (++tagged % XA_CHECK_SCHED)
+               latency += cache_count;
+               if (latency < XA_CHECK_SCHED)
                        continue;
+               latency = 0;
 
                xas_pause(xas);
                xas_unlock_irq(xas);
@@ -73,7 +81,8 @@ static int memfd_wait_for_pins(struct address_space *mapping)
 
        error = 0;
        for (scan = 0; scan <= LAST_SCAN; scan++) {
-               unsigned int tagged = 0;
+               int latency = 0;
+               int cache_count;
 
                if (!xas_marked(&xas, MEMFD_TAG_PINNED))
                        break;
@@ -87,10 +96,14 @@ static int memfd_wait_for_pins(struct address_space *mapping)
                xas_lock_irq(&xas);
                xas_for_each_marked(&xas, page, ULONG_MAX, MEMFD_TAG_PINNED) {
                        bool clear = true;
-                       if (xa_is_value(page))
-                               continue;
-                       page = find_subpage(page, xas.xa_index);
-                       if (page_count(page) - page_mapcount(page) != 1) {
+
+                       cache_count = 1;
+                       if (!xa_is_value(page) &&
+                           PageTransHuge(page) && !PageHuge(page))
+                               cache_count = HPAGE_PMD_NR;
+
+                       if (!xa_is_value(page) && cache_count !=
+                           page_count(page) - total_mapcount(page)) {
                                /*
                                 * On the last scan, we clean up all those tags
                                 * we inserted; but make a note that we still
@@ -103,8 +116,11 @@ static int memfd_wait_for_pins(struct address_space *mapping)
                        }
                        if (clear)
                                xas_clear_mark(&xas, MEMFD_TAG_PINNED);
-                       if (++tagged % XA_CHECK_SCHED)
+
+                       latency += cache_count;
+                       if (latency < XA_CHECK_SCHED)
                                continue;
+                       latency = 0;
 
                        xas_pause(&xas);
                        xas_unlock_irq(&xas);
index 028e8dd..69284d3 100644 (file)
@@ -814,7 +814,7 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
                prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags,
                                 vma->anon_vma, vma->vm_file, pgoff,
                                 new_pol, vma->vm_userfaultfd_ctx,
-                                vma_anon_name(vma));
+                                anon_vma_name(vma));
                if (prev) {
                        vma = prev;
                        next = vma->vm_next;
index 8f584ed..25934e7 100644 (file)
@@ -512,7 +512,7 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev,
        pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
        *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma,
                          vma->vm_file, pgoff, vma_policy(vma),
-                         vma->vm_userfaultfd_ctx, vma_anon_name(vma));
+                         vma->vm_userfaultfd_ctx, anon_vma_name(vma));
        if (*prev) {
                vma = *prev;
                goto success;
index d445c1b..f61a154 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1031,7 +1031,7 @@ again:
 static inline int is_mergeable_vma(struct vm_area_struct *vma,
                                struct file *file, unsigned long vm_flags,
                                struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
-                               const char *anon_name)
+                               struct anon_vma_name *anon_name)
 {
        /*
         * VM_SOFTDIRTY should not prevent from VMA merging, if we
@@ -1049,7 +1049,7 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma,
                return 0;
        if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx))
                return 0;
-       if (!is_same_vma_anon_name(vma, anon_name))
+       if (!anon_vma_name_eq(anon_vma_name(vma), anon_name))
                return 0;
        return 1;
 }
@@ -1084,7 +1084,7 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags,
                     struct anon_vma *anon_vma, struct file *file,
                     pgoff_t vm_pgoff,
                     struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
-                    const char *anon_name)
+                    struct anon_vma_name *anon_name)
 {
        if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) &&
            is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
@@ -1106,7 +1106,7 @@ can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags,
                    struct anon_vma *anon_vma, struct file *file,
                    pgoff_t vm_pgoff,
                    struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
-                   const char *anon_name)
+                   struct anon_vma_name *anon_name)
 {
        if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx, anon_name) &&
            is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) {
@@ -1167,7 +1167,7 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm,
                        struct anon_vma *anon_vma, struct file *file,
                        pgoff_t pgoff, struct mempolicy *policy,
                        struct vm_userfaultfd_ctx vm_userfaultfd_ctx,
-                       const char *anon_name)
+                       struct anon_vma_name *anon_name)
 {
        pgoff_t pglen = (end - addr) >> PAGE_SHIFT;
        struct vm_area_struct *area, *next;
@@ -3256,7 +3256,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                return NULL;    /* should never get here */
        new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags,
                            vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
-                           vma->vm_userfaultfd_ctx, vma_anon_name(vma));
+                           vma->vm_userfaultfd_ctx, anon_vma_name(vma));
        if (new_vma) {
                /*
                 * Source vma may have been merged into new_vma
index 5ca3fbc..2887644 100644 (file)
@@ -464,7 +464,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev,
        pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
        *pprev = vma_merge(mm, *pprev, start, end, newflags,
                           vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma),
-                          vma->vm_userfaultfd_ctx, vma_anon_name(vma));
+                          vma->vm_userfaultfd_ctx, anon_vma_name(vma));
        if (*pprev) {
                vma = *pprev;
                VM_WARN_ON((vma->vm_flags ^ newflags) & ~VM_SOFTDIRTY);
index 7e43369..d310208 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -587,8 +587,10 @@ void *kvmalloc_node(size_t size, gfp_t flags, int node)
                return ret;
 
        /* Don't even allow crazy sizes */
-       if (WARN_ON_ONCE(size > INT_MAX))
+       if (unlikely(size > INT_MAX)) {
+               WARN_ON_ONCE(!(flags & __GFP_NOWARN));
                return NULL;
+       }
 
        return __vmalloc_node(size, 1, flags, node,
                        __builtin_return_address(0));
index eb9fb55..01f8067 100644 (file)
@@ -281,9 +281,9 @@ static void xen_9pfs_front_free(struct xen_9pfs_front_priv *priv)
                                ref = priv->rings[i].intf->ref[j];
                                gnttab_end_foreign_access(ref, 0, 0);
                        }
-                       free_pages((unsigned long)priv->rings[i].data.in,
-                                  priv->rings[i].intf->ring_order -
-                                  (PAGE_SHIFT - XEN_PAGE_SHIFT));
+                       free_pages_exact(priv->rings[i].data.in,
+                                  1UL << (priv->rings[i].intf->ring_order +
+                                          XEN_PAGE_SHIFT));
                }
                gnttab_end_foreign_access(priv->rings[i].ref, 0, 0);
                free_page((unsigned long)priv->rings[i].intf);
@@ -322,8 +322,8 @@ static int xen_9pfs_front_alloc_dataring(struct xenbus_device *dev,
        if (ret < 0)
                goto out;
        ring->ref = ret;
-       bytes = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
-                       order - (PAGE_SHIFT - XEN_PAGE_SHIFT));
+       bytes = alloc_pages_exact(1UL << (order + XEN_PAGE_SHIFT),
+                                 GFP_KERNEL | __GFP_ZERO);
        if (!bytes) {
                ret = -ENOMEM;
                goto out;
@@ -354,9 +354,7 @@ out:
        if (bytes) {
                for (i--; i >= 0; i--)
                        gnttab_end_foreign_access(ring->intf->ref[i], 0, 0);
-               free_pages((unsigned long)bytes,
-                          ring->intf->ring_order -
-                          (PAGE_SHIFT - XEN_PAGE_SHIFT));
+               free_pages_exact(bytes, 1UL << (order + XEN_PAGE_SHIFT));
        }
        gnttab_end_foreign_access(ring->ref, 0, 0);
        free_page((unsigned long)ring->intf);
index 8a2b78f..35fadb9 100644 (file)
@@ -149,22 +149,25 @@ static bool batadv_is_on_batman_iface(const struct net_device *net_dev)
        struct net *net = dev_net(net_dev);
        struct net_device *parent_dev;
        struct net *parent_net;
+       int iflink;
        bool ret;
 
        /* check if this is a batman-adv mesh interface */
        if (batadv_softif_is_valid(net_dev))
                return true;
 
-       /* no more parents..stop recursion */
-       if (dev_get_iflink(net_dev) == 0 ||
-           dev_get_iflink(net_dev) == net_dev->ifindex)
+       iflink = dev_get_iflink(net_dev);
+       if (iflink == 0)
                return false;
 
        parent_net = batadv_getlink_net(net_dev, net);
 
+       /* iflink to itself, most likely physical device */
+       if (net == parent_net && iflink == net_dev->ifindex)
+               return false;
+
        /* recurse over the parent device */
-       parent_dev = __dev_get_by_index((struct net *)parent_net,
-                                       dev_get_iflink(net_dev));
+       parent_dev = __dev_get_by_index((struct net *)parent_net, iflink);
        /* if we got a NULL parent_dev there is something broken.. */
        if (!parent_dev) {
                pr_err("Cannot find parent device\n");
@@ -214,14 +217,15 @@ static struct net_device *batadv_get_real_netdevice(struct net_device *netdev)
        struct net_device *real_netdev = NULL;
        struct net *real_net;
        struct net *net;
-       int ifindex;
+       int iflink;
 
        ASSERT_RTNL();
 
        if (!netdev)
                return NULL;
 
-       if (netdev->ifindex == dev_get_iflink(netdev)) {
+       iflink = dev_get_iflink(netdev);
+       if (iflink == 0) {
                dev_hold(netdev);
                return netdev;
        }
@@ -231,9 +235,16 @@ static struct net_device *batadv_get_real_netdevice(struct net_device *netdev)
                goto out;
 
        net = dev_net(hard_iface->soft_iface);
-       ifindex = dev_get_iflink(netdev);
        real_net = batadv_getlink_net(netdev, net);
-       real_netdev = dev_get_by_index(real_net, ifindex);
+
+       /* iflink to itself, most likely physical device */
+       if (net == real_net && netdev->ifindex == iflink) {
+               real_netdev = netdev;
+               dev_hold(real_netdev);
+               goto out;
+       }
+
+       real_netdev = dev_get_by_index(real_net, iflink);
 
 out:
        batadv_hardif_put(hard_iface);
index 2b7bd36..2882bc7 100644 (file)
@@ -2738,6 +2738,7 @@ void hci_release_dev(struct hci_dev *hdev)
        hci_dev_unlock(hdev);
 
        ida_simple_remove(&hci_index_ida, hdev->id);
+       kfree_skb(hdev->sent_cmd);
        kfree(hdev);
 }
 EXPORT_SYMBOL(hci_release_dev);
index 0feb68f..9ba2a1a 100644 (file)
@@ -1841,6 +1841,7 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
        struct bdaddr_list *b, *t;
        u8 num_entries = 0;
        bool pend_conn, pend_report;
+       u8 filter_policy;
        int err;
 
        /* Pause advertising if resolving list can be used as controllers are
@@ -1927,6 +1928,8 @@ static u8 hci_update_accept_list_sync(struct hci_dev *hdev)
                err = -EINVAL;
 
 done:
+       filter_policy = err ? 0x00 : 0x01;
+
        /* Enable address resolution when LL Privacy is enabled. */
        err = hci_le_set_addr_resolution_enable_sync(hdev, 0x01);
        if (err)
@@ -1937,7 +1940,7 @@ done:
                hci_resume_advertising_sync(hdev);
 
        /* Select filter policy to use accept list */
-       return err ? 0x00 : 0x01;
+       return filter_policy;
 }
 
 /* Returns true if an le connection is in the scanning state */
@@ -3262,10 +3265,10 @@ static int hci_le_set_event_mask_sync(struct hci_dev *hdev)
        if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT)
                events[0] |= 0x40;      /* LE Data Length Change */
 
-       /* If the controller supports LL Privacy feature, enable
-        * the corresponding event.
+       /* If the controller supports LL Privacy feature or LE Extended Adv,
+        * enable the corresponding event.
         */
-       if (hdev->le_features[0] & HCI_LE_LL_PRIVACY)
+       if (use_enhanced_conn_complete(hdev))
                events[1] |= 0x02;      /* LE Enhanced Connection Complete */
 
        /* If the controller supports Extended Scanner Filter
@@ -4106,9 +4109,9 @@ int hci_dev_close_sync(struct hci_dev *hdev)
        hci_inquiry_cache_flush(hdev);
        hci_pend_le_actions_clear(hdev);
        hci_conn_hash_flush(hdev);
-       hci_dev_unlock(hdev);
-
+       /* Prevent data races on hdev->smp_data or hdev->smp_bredr_data */
        smp_unregister(hdev);
+       hci_dev_unlock(hdev);
 
        hci_sock_dev_event(hdev, HCI_DEV_DOWN);
 
@@ -5185,7 +5188,7 @@ int hci_le_ext_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn,
        return __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_EXT_CREATE_CONN,
                                        plen, data,
                                        HCI_EV_LE_ENHANCED_CONN_COMPLETE,
-                                       HCI_CMD_TIMEOUT, NULL);
+                                       conn->conn_timeout, NULL);
 }
 
 int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
@@ -5270,9 +5273,18 @@ int hci_le_create_conn_sync(struct hci_dev *hdev, struct hci_conn *conn)
        cp.min_ce_len = cpu_to_le16(0x0000);
        cp.max_ce_len = cpu_to_le16(0x0000);
 
+       /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E page 2261:
+        *
+        * If this event is unmasked and the HCI_LE_Connection_Complete event
+        * is unmasked, only the HCI_LE_Enhanced_Connection_Complete event is
+        * sent when a new connection has been created.
+        */
        err = __hci_cmd_sync_status_sk(hdev, HCI_OP_LE_CREATE_CONN,
-                                      sizeof(cp), &cp, HCI_EV_LE_CONN_COMPLETE,
-                                      HCI_CMD_TIMEOUT, NULL);
+                                      sizeof(cp), &cp,
+                                      use_enhanced_conn_complete(hdev) ?
+                                      HCI_EV_LE_ENHANCED_CONN_COMPLETE :
+                                      HCI_EV_LE_CONN_COMPLETE,
+                                      conn->conn_timeout, NULL);
 
 done:
        /* Re-enable advertising after the connection attempt is finished. */
index 37087cf..533cf60 100644 (file)
@@ -1218,7 +1218,13 @@ static int new_settings(struct hci_dev *hdev, struct sock *skip)
 static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct mgmt_pending_cmd *cmd = data;
-       struct mgmt_mode *cp = cmd->param;
+       struct mgmt_mode *cp;
+
+       /* Make sure cmd still outstanding. */
+       if (cmd != pending_find(MGMT_OP_SET_POWERED, hdev))
+               return;
+
+       cp = cmd->param;
 
        bt_dev_dbg(hdev, "err %d", err);
 
@@ -1242,7 +1248,7 @@ static void mgmt_set_powered_complete(struct hci_dev *hdev, void *data, int err)
                                mgmt_status(err));
        }
 
-       mgmt_pending_free(cmd);
+       mgmt_pending_remove(cmd);
 }
 
 static int set_powered_sync(struct hci_dev *hdev, void *data)
@@ -1281,7 +1287,7 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_new(sk, MGMT_OP_SET_POWERED, hdev, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1290,6 +1296,9 @@ static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
        err = hci_cmd_sync_queue(hdev, set_powered_sync, cmd,
                                 mgmt_set_powered_complete);
 
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
 failed:
        hci_dev_unlock(hdev);
        return err;
@@ -1383,6 +1392,10 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
 
        bt_dev_dbg(hdev, "err %d", err);
 
+       /* Make sure cmd still outstanding. */
+       if (cmd != pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
+               return;
+
        hci_dev_lock(hdev);
 
        if (err) {
@@ -1402,7 +1415,7 @@ static void mgmt_set_discoverable_complete(struct hci_dev *hdev, void *data,
        new_settings(hdev, cmd->sk);
 
 done:
-       mgmt_pending_free(cmd);
+       mgmt_pending_remove(cmd);
        hci_dev_unlock(hdev);
 }
 
@@ -1511,7 +1524,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_new(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1538,6 +1551,9 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
        err = hci_cmd_sync_queue(hdev, set_discoverable_sync, cmd,
                                 mgmt_set_discoverable_complete);
 
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
 failed:
        hci_dev_unlock(hdev);
        return err;
@@ -1550,6 +1566,10 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
 
        bt_dev_dbg(hdev, "err %d", err);
 
+       /* Make sure cmd still outstanding. */
+       if (cmd != pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
+               return;
+
        hci_dev_lock(hdev);
 
        if (err) {
@@ -1562,7 +1582,9 @@ static void mgmt_set_connectable_complete(struct hci_dev *hdev, void *data,
        new_settings(hdev, cmd->sk);
 
 done:
-       mgmt_pending_free(cmd);
+       if (cmd)
+               mgmt_pending_remove(cmd);
+
        hci_dev_unlock(hdev);
 }
 
@@ -1634,7 +1656,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_new(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1654,6 +1676,9 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
        err = hci_cmd_sync_queue(hdev, set_connectable_sync, cmd,
                                 mgmt_set_connectable_complete);
 
+       if (err < 0)
+               mgmt_pending_remove(cmd);
+
 failed:
        hci_dev_unlock(hdev);
        return err;
@@ -1774,6 +1799,10 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
        u8 enable = cp->val;
        bool changed;
 
+       /* Make sure cmd still outstanding. */
+       if (cmd != pending_find(MGMT_OP_SET_SSP, hdev))
+               return;
+
        if (err) {
                u8 mgmt_err = mgmt_status(err);
 
@@ -3321,6 +3350,9 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err)
 
        bt_dev_dbg(hdev, "err %d", err);
 
+       if (cmd != pending_find(MGMT_OP_SET_LOCAL_NAME, hdev))
+               return;
+
        if (status) {
                mgmt_cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
                                status);
@@ -3493,6 +3525,9 @@ static void set_default_phy_complete(struct hci_dev *hdev, void *data, int err)
        struct sk_buff *skb = cmd->skb;
        u8 status = mgmt_status(err);
 
+       if (cmd != pending_find(MGMT_OP_SET_PHY_CONFIGURATION, hdev))
+               return;
+
        if (!status) {
                if (!skb)
                        status = MGMT_STATUS_FAILED;
@@ -3759,13 +3794,6 @@ static int set_wideband_speech(struct sock *sk, struct hci_dev *hdev,
 
        hci_dev_lock(hdev);
 
-       if (pending_find(MGMT_OP_SET_WIDEBAND_SPEECH, hdev)) {
-               err = mgmt_cmd_status(sk, hdev->id,
-                                     MGMT_OP_SET_WIDEBAND_SPEECH,
-                                     MGMT_STATUS_BUSY);
-               goto unlock;
-       }
-
        if (hdev_is_powered(hdev) &&
            !!cp->val != hci_dev_test_flag(hdev,
                                           HCI_WIDEBAND_SPEECH_ENABLED)) {
@@ -5036,12 +5064,6 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       if (pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
-               err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                     MGMT_STATUS_BUSY);
-               goto unlock;
-       }
-
        cmd = mgmt_pending_new(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
        if (!cmd)
                err = -ENOMEM;
@@ -5261,11 +5283,16 @@ static void start_discovery_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct mgmt_pending_cmd *cmd = data;
 
+       if (cmd != pending_find(MGMT_OP_START_DISCOVERY, hdev) &&
+           cmd != pending_find(MGMT_OP_START_LIMITED_DISCOVERY, hdev) &&
+           cmd != pending_find(MGMT_OP_START_SERVICE_DISCOVERY, hdev))
+               return;
+
        bt_dev_dbg(hdev, "err %d", err);
 
        mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
                          cmd->param, 1);
-       mgmt_pending_free(cmd);
+       mgmt_pending_remove(cmd);
 
        hci_discovery_set_state(hdev, err ? DISCOVERY_STOPPED:
                                DISCOVERY_FINDING);
@@ -5327,7 +5354,7 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
        else
                hdev->discovery.limited = false;
 
-       cmd = mgmt_pending_new(sk, op, hdev, data, len);
+       cmd = mgmt_pending_add(sk, op, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -5336,7 +5363,7 @@ static int start_discovery_internal(struct sock *sk, struct hci_dev *hdev,
        err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
                                 start_discovery_complete);
        if (err < 0) {
-               mgmt_pending_free(cmd);
+               mgmt_pending_remove(cmd);
                goto failed;
        }
 
@@ -5430,7 +5457,7 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
                goto failed;
        }
 
-       cmd = mgmt_pending_new(sk, MGMT_OP_START_SERVICE_DISCOVERY,
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_SERVICE_DISCOVERY,
                               hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
@@ -5463,7 +5490,7 @@ static int start_service_discovery(struct sock *sk, struct hci_dev *hdev,
        err = hci_cmd_sync_queue(hdev, start_discovery_sync, cmd,
                                 start_discovery_complete);
        if (err < 0) {
-               mgmt_pending_free(cmd);
+               mgmt_pending_remove(cmd);
                goto failed;
        }
 
@@ -5495,11 +5522,14 @@ static void stop_discovery_complete(struct hci_dev *hdev, void *data, int err)
 {
        struct mgmt_pending_cmd *cmd = data;
 
+       if (cmd != pending_find(MGMT_OP_STOP_DISCOVERY, hdev))
+               return;
+
        bt_dev_dbg(hdev, "err %d", err);
 
        mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(err),
                          cmd->param, 1);
-       mgmt_pending_free(cmd);
+       mgmt_pending_remove(cmd);
 
        if (!err)
                hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
@@ -5535,7 +5565,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
-       cmd = mgmt_pending_new(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
@@ -5544,7 +5574,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
        err = hci_cmd_sync_queue(hdev, stop_discovery_sync, cmd,
                                 stop_discovery_complete);
        if (err < 0) {
-               mgmt_pending_free(cmd);
+               mgmt_pending_remove(cmd);
                goto unlock;
        }
 
@@ -7474,6 +7504,9 @@ static void read_local_oob_ext_data_complete(struct hci_dev *hdev, void *data,
        u8 status = mgmt_status(err);
        u16 eir_len;
 
+       if (cmd != pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev))
+               return;
+
        if (!status) {
                if (!skb)
                        status = MGMT_STATUS_FAILED;
@@ -7969,11 +8002,7 @@ static bool requested_adv_flags_are_valid(struct hci_dev *hdev, u32 adv_flags)
 
 static bool adv_busy(struct hci_dev *hdev)
 {
-       return (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
-               pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
-               pending_find(MGMT_OP_SET_LE, hdev) ||
-               pending_find(MGMT_OP_ADD_EXT_ADV_PARAMS, hdev) ||
-               pending_find(MGMT_OP_ADD_EXT_ADV_DATA, hdev));
+       return pending_find(MGMT_OP_SET_LE, hdev);
 }
 
 static void add_adv_complete(struct hci_dev *hdev, struct sock *sk, u8 instance,
@@ -8563,9 +8592,7 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) ||
-           pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) ||
-           pending_find(MGMT_OP_SET_LE, hdev)) {
+       if (pending_find(MGMT_OP_SET_LE, hdev)) {
                err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING,
                                      MGMT_STATUS_BUSY);
                goto unlock;
index edee60b..37eef2c 100644 (file)
@@ -77,11 +77,12 @@ int mgmt_send_event_skb(unsigned short channel, struct sk_buff *skb, int flag,
 {
        struct hci_dev *hdev;
        struct mgmt_hdr *hdr;
-       int len = skb->len;
+       int len;
 
        if (!skb)
                return -EINVAL;
 
+       len = skb->len;
        hdev = bt_cb(skb)->mgmt.hdev;
 
        /* Time stamp */
index b8138c3..ea51e23 100644 (file)
@@ -3876,6 +3876,7 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
                list_skb = list_skb->next;
 
                err = 0;
+               delta_truesize += nskb->truesize;
                if (skb_shared(nskb)) {
                        tmp = skb_clone(nskb, GFP_ATOMIC);
                        if (tmp) {
@@ -3900,7 +3901,6 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
                tail = nskb;
 
                delta_len += nskb->len;
-               delta_truesize += nskb->truesize;
 
                skb_push(nskb, -skb_network_offset(nskb) + offset);
 
index 8eb671c..929a2b0 100644 (file)
@@ -1153,7 +1153,7 @@ static int sk_psock_verdict_recv(read_descriptor_t *desc, struct sk_buff *skb,
        struct sk_psock *psock;
        struct bpf_prog *prog;
        int ret = __SK_DROP;
-       int len = skb->len;
+       int len = orig_len;
 
        /* clone here so sk_eat_skb() in tcp_read_sock does not drop our data */
        skb = skb_clone(skb, GFP_ATOMIC);
index b441ab3..dc4fb69 100644 (file)
@@ -2073,8 +2073,52 @@ u8 dcb_ieee_getapp_default_prio_mask(const struct net_device *dev)
 }
 EXPORT_SYMBOL(dcb_ieee_getapp_default_prio_mask);
 
+static void dcbnl_flush_dev(struct net_device *dev)
+{
+       struct dcb_app_type *itr, *tmp;
+
+       spin_lock_bh(&dcb_lock);
+
+       list_for_each_entry_safe(itr, tmp, &dcb_app_list, list) {
+               if (itr->ifindex == dev->ifindex) {
+                       list_del(&itr->list);
+                       kfree(itr);
+               }
+       }
+
+       spin_unlock_bh(&dcb_lock);
+}
+
+static int dcbnl_netdevice_event(struct notifier_block *nb,
+                                unsigned long event, void *ptr)
+{
+       struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
+               if (!dev->dcbnl_ops)
+                       return NOTIFY_DONE;
+
+               dcbnl_flush_dev(dev);
+
+               return NOTIFY_OK;
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+static struct notifier_block dcbnl_nb __read_mostly = {
+       .notifier_call  = dcbnl_netdevice_event,
+};
+
 static int __init dcbnl_init(void)
 {
+       int err;
+
+       err = register_netdevice_notifier(&dcbnl_nb);
+       if (err)
+               return err;
+
        rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL, 0);
        rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL, 0);
 
index dcad310..b4e6775 100644 (file)
@@ -1261,7 +1261,7 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
        info.tag_ops = tag_ops;
        err = dsa_tree_notify(dst, DSA_NOTIFIER_TAG_PROTO, &info);
        if (err)
-               return err;
+               goto out_unwind_tagger;
 
        err = dsa_tree_bind_tag_proto(dst, tag_ops);
        if (err)
index 851f542..e1b1d08 100644 (file)
@@ -671,7 +671,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
                struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
                u32 padto;
 
-               padto = min(x->tfcpad, __xfrm_state_mtu(x, dst->child_mtu_cached));
+               padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
                if (skb->len < padto)
                        esp.tfclen = padto - skb->len;
        }
index 02cb275..28ff2a8 100644 (file)
@@ -1684,11 +1684,13 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
                                if (!copied)
                                        copied = used;
                                break;
-                       } else if (used <= len) {
-                               seq += used;
-                               copied += used;
-                               offset += used;
                        }
+                       if (WARN_ON_ONCE(used > len))
+                               used = len;
+                       seq += used;
+                       copied += used;
+                       offset += used;
+
                        /* If recv_actor drops the lock (e.g. TCP splice
                         * receive) the skb pointer might be invalid when
                         * getting here: tcp_collapse might have deleted it
index 6c8ab3e..f908e2f 100644 (file)
@@ -3732,6 +3732,7 @@ static int addrconf_ifdown(struct net_device *dev, bool unregister)
        struct inet6_dev *idev;
        struct inet6_ifaddr *ifa, *tmp;
        bool keep_addr = false;
+       bool was_ready;
        int state, i;
 
        ASSERT_RTNL();
@@ -3797,7 +3798,10 @@ restart:
 
        addrconf_del_rs_timer(idev);
 
-       /* Step 2: clear flags for stateless addrconf */
+       /* Step 2: clear flags for stateless addrconf, repeated down
+        *         detection
+        */
+       was_ready = idev->if_flags & IF_READY;
        if (!unregister)
                idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
 
@@ -3871,7 +3875,7 @@ restart:
        if (unregister) {
                ipv6_ac_destroy_dev(idev);
                ipv6_mc_destroy_dev(idev);
-       } else {
+       } else if (was_ready) {
                ipv6_mc_down(idev);
        }
 
index 8bb2c40..7591160 100644 (file)
@@ -707,7 +707,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
                struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
                u32 padto;
 
-               padto = min(x->tfcpad, __xfrm_state_mtu(x, dst->child_mtu_cached));
+               padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
                if (skb->len < padto)
                        esp.tfclen = padto - skb->len;
        }
index 304a295..4788f6b 100644 (file)
@@ -1408,8 +1408,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
                if (np->frag_size)
                        mtu = np->frag_size;
        }
-       if (mtu < IPV6_MIN_MTU)
-               return -EINVAL;
        cork->base.fragsize = mtu;
        cork->base.gso_size = ipc6->gso_size;
        cork->base.tx_flags = 0;
@@ -1471,8 +1469,6 @@ static int __ip6_append_data(struct sock *sk,
 
        fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
                        (opt ? opt->opt_nflen : 0);
-       maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
-                    sizeof(struct frag_hdr);
 
        headersize = sizeof(struct ipv6hdr) +
                     (opt ? opt->opt_flen + opt->opt_nflen : 0) +
@@ -1480,6 +1476,13 @@ static int __ip6_append_data(struct sock *sk,
                      sizeof(struct frag_hdr) : 0) +
                     rt->rt6i_nfheader_len;
 
+       if (mtu < fragheaderlen ||
+           ((mtu - fragheaderlen) & ~7) + fragheaderlen < sizeof(struct frag_hdr))
+               goto emsgsize;
+
+       maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -
+                    sizeof(struct frag_hdr);
+
        /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit
         * the first fragment
         */
index a8861db..909f937 100644 (file)
@@ -1371,27 +1371,23 @@ static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,
 }
 
 /* called with rcu_read_lock() */
-int igmp6_event_query(struct sk_buff *skb)
+void igmp6_event_query(struct sk_buff *skb)
 {
        struct inet6_dev *idev = __in6_dev_get(skb->dev);
 
-       if (!idev)
-               return -EINVAL;
-
-       if (idev->dead) {
-               kfree_skb(skb);
-               return -ENODEV;
-       }
+       if (!idev || idev->dead)
+               goto out;
 
        spin_lock_bh(&idev->mc_query_lock);
        if (skb_queue_len(&idev->mc_query_queue) < MLD_MAX_SKBS) {
                __skb_queue_tail(&idev->mc_query_queue, skb);
                if (!mod_delayed_work(mld_wq, &idev->mc_query_work, 0))
                        in6_dev_hold(idev);
+               skb = NULL;
        }
        spin_unlock_bh(&idev->mc_query_lock);
-
-       return 0;
+out:
+       kfree_skb(skb);
 }
 
 static void __mld_query_work(struct sk_buff *skb)
@@ -1542,27 +1538,23 @@ static void mld_query_work(struct work_struct *work)
 }
 
 /* called with rcu_read_lock() */
-int igmp6_event_report(struct sk_buff *skb)
+void igmp6_event_report(struct sk_buff *skb)
 {
        struct inet6_dev *idev = __in6_dev_get(skb->dev);
 
-       if (!idev)
-               return -EINVAL;
-
-       if (idev->dead) {
-               kfree_skb(skb);
-               return -ENODEV;
-       }
+       if (!idev || idev->dead)
+               goto out;
 
        spin_lock_bh(&idev->mc_report_lock);
        if (skb_queue_len(&idev->mc_report_queue) < MLD_MAX_SKBS) {
                __skb_queue_tail(&idev->mc_report_queue, skb);
                if (!mod_delayed_work(mld_wq, &idev->mc_report_work, 0))
                        in6_dev_hold(idev);
+               skb = NULL;
        }
        spin_unlock_bh(&idev->mc_report_lock);
-
-       return 0;
+out:
+       kfree_skb(skb);
 }
 
 static void __mld_report_work(struct sk_buff *skb)
index de24a7d..9bf52a0 100644 (file)
@@ -2623,7 +2623,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb,
        }
 
        return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i,
-                           kma ? &k : NULL, net, NULL);
+                           kma ? &k : NULL, net, NULL, 0);
 
  out:
        return err;
index 74a878f..1deb3d8 100644 (file)
@@ -9,7 +9,7 @@
  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
  * Copyright 2007-2010, Intel Corporation
  * Copyright(c) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018 - 2021 Intel Corporation
+ * Copyright (C) 2018 - 2022 Intel Corporation
  */
 
 #include <linux/ieee80211.h>
@@ -626,6 +626,14 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
                return -EINVAL;
        }
 
+       if (test_sta_flag(sta, WLAN_STA_MFP) &&
+           !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
+               ht_dbg(sdata,
+                      "MFP STA not authorized - deny BA session request %pM tid %d\n",
+                      sta->sta.addr, tid);
+               return -EINVAL;
+       }
+
        /*
         * 802.11n-2009 11.5.1.1: If the initiating STA is an HT STA, is a
         * member of an IBSS, and has no other existing Block Ack agreement
index 330ea62..e87bcca 100644 (file)
@@ -376,7 +376,7 @@ struct ieee80211_mgd_auth_data {
 
        u8 key[WLAN_KEY_LEN_WEP104];
        u8 key_len, key_idx;
-       bool done;
+       bool done, waiting;
        bool peer_confirmed;
        bool timeout_started;
 
index e5ccf17..744842c 100644 (file)
@@ -37,6 +37,7 @@
 #define IEEE80211_AUTH_TIMEOUT_SAE     (HZ * 2)
 #define IEEE80211_AUTH_MAX_TRIES       3
 #define IEEE80211_AUTH_WAIT_ASSOC      (HZ * 5)
+#define IEEE80211_AUTH_WAIT_SAE_RETRY  (HZ * 2)
 #define IEEE80211_ASSOC_TIMEOUT                (HZ / 5)
 #define IEEE80211_ASSOC_TIMEOUT_LONG   (HZ / 2)
 #define IEEE80211_ASSOC_TIMEOUT_SHORT  (HZ / 10)
@@ -3011,8 +3012,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                    (status_code == WLAN_STATUS_ANTI_CLOG_REQUIRED ||
                     (auth_transaction == 1 &&
                      (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT ||
-                      status_code == WLAN_STATUS_SAE_PK))))
+                      status_code == WLAN_STATUS_SAE_PK)))) {
+                       /* waiting for userspace now */
+                       ifmgd->auth_data->waiting = true;
+                       ifmgd->auth_data->timeout =
+                               jiffies + IEEE80211_AUTH_WAIT_SAE_RETRY;
+                       ifmgd->auth_data->timeout_started = true;
+                       run_again(sdata, ifmgd->auth_data->timeout);
                        goto notify_driver;
+               }
 
                sdata_info(sdata, "%pM denied authentication (status %d)\n",
                           mgmt->sa, status_code);
@@ -4603,10 +4611,10 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
 
        if (ifmgd->auth_data && ifmgd->auth_data->timeout_started &&
            time_after(jiffies, ifmgd->auth_data->timeout)) {
-               if (ifmgd->auth_data->done) {
+               if (ifmgd->auth_data->done || ifmgd->auth_data->waiting) {
                        /*
-                        * ok ... we waited for assoc but userspace didn't,
-                        * so let's just kill the auth data
+                        * ok ... we waited for assoc or continuation but
+                        * userspace didn't do it, so kill the auth data
                         */
                        ieee80211_destroy_auth_data(sdata, false);
                } else if (ieee80211_auth(sdata)) {
index 93680af..48d9553 100644 (file)
@@ -2607,7 +2607,8 @@ static void ieee80211_deliver_skb_to_local_stack(struct sk_buff *skb,
                 * address, so that the authenticator (e.g. hostapd) will see
                 * the frame, but bridge won't forward it anywhere else. Note
                 * that due to earlier filtering, the only other address can
-                * be the PAE group address.
+                * be the PAE group address, unless the hardware allowed them
+                * through in 802.3 offloaded mode.
                 */
                if (unlikely(skb->protocol == sdata->control_port_protocol &&
                             !ether_addr_equal(ehdr->h_dest, sdata->vif.addr)))
@@ -2922,13 +2923,13 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            ether_addr_equal(sdata->vif.addr, hdr->addr3))
                return RX_CONTINUE;
 
-       ac = ieee80211_select_queue_80211(sdata, skb, hdr);
+       ac = ieee802_1d_to_ac[skb->priority];
        q = sdata->vif.hw_queue[ac];
        if (ieee80211_queue_stopped(&local->hw, q)) {
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
                return RX_DROP_MONITOR;
        }
-       skb_set_queue_mapping(skb, q);
+       skb_set_queue_mapping(skb, ac);
 
        if (!--mesh_hdr->ttl) {
                if (!is_multicast_ether_addr(hdr->addr1))
@@ -4514,12 +4515,7 @@ static void ieee80211_rx_8023(struct ieee80211_rx_data *rx,
 
        /* deliver to local stack */
        skb->protocol = eth_type_trans(skb, fast_rx->dev);
-       memset(skb->cb, 0, sizeof(skb->cb));
-       if (rx->list)
-               list_add_tail(&skb->list, rx->list);
-       else
-               netif_receive_skb(skb);
-
+       ieee80211_deliver_skb_to_local_stack(skb, rx);
 }
 
 static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
index f60f01b..1c72f25 100644 (file)
@@ -466,9 +466,12 @@ static bool mptcp_pending_data_fin(struct sock *sk, u64 *seq)
 static void mptcp_set_datafin_timeout(const struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
+       u32 retransmits;
 
-       mptcp_sk(sk)->timer_ival = min(TCP_RTO_MAX,
-                                      TCP_RTO_MIN << icsk->icsk_retransmits);
+       retransmits = min_t(u32, icsk->icsk_retransmits,
+                           ilog2(TCP_RTO_MAX / TCP_RTO_MIN));
+
+       mptcp_sk(sk)->timer_ival = TCP_RTO_MIN << retransmits;
 }
 
 static void __mptcp_set_timeout(struct sock *sk, long tout)
@@ -3294,6 +3297,17 @@ static int mptcp_ioctl_outq(const struct mptcp_sock *msk, u64 v)
                return 0;
 
        delta = msk->write_seq - v;
+       if (__mptcp_check_fallback(msk) && msk->first) {
+               struct tcp_sock *tp = tcp_sk(msk->first);
+
+               /* the first subflow is disconnected after close - see
+                * __mptcp_close_ssk(). tcp_disconnect() moves the write_seq
+                * so ignore that status, too.
+                */
+               if (!((1 << msk->first->sk_state) &
+                     (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)))
+                       delta += READ_ONCE(tp->write_seq) - tp->snd_una;
+       }
        if (delta > INT_MAX)
                delta = INT_MAX;
 
index 354cb47..8a77a3f 100644 (file)
@@ -428,14 +428,15 @@ static int __nf_register_net_hook(struct net *net, int pf,
        p = nf_entry_dereference(*pp);
        new_hooks = nf_hook_entries_grow(p, reg);
 
-       if (!IS_ERR(new_hooks))
+       if (!IS_ERR(new_hooks)) {
+               hooks_validate(new_hooks);
                rcu_assign_pointer(*pp, new_hooks);
+       }
 
        mutex_unlock(&nf_hook_mutex);
        if (IS_ERR(new_hooks))
                return PTR_ERR(new_hooks);
 
-       hooks_validate(new_hooks);
 #ifdef CONFIG_NETFILTER_INGRESS
        if (nf_ingress_hook(reg, pf))
                net_inc_ingress_queue();
index b561e0a..fc4265a 100644 (file)
@@ -110,7 +110,11 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
                nf_flow_rule_lwt_match(match, tun_info);
        }
 
-       key->meta.ingress_ifindex = tuple->iifidx;
+       if (tuple->xmit_type == FLOW_OFFLOAD_XMIT_TC)
+               key->meta.ingress_ifindex = tuple->tc.iifidx;
+       else
+               key->meta.ingress_ifindex = tuple->iifidx;
+
        mask->meta.ingress_ifindex = 0xffffffff;
 
        if (tuple->encap_num > 0 && !(tuple->in_vlan_ingress & BIT(0)) &&
index 6d12afa..63d1516 100644 (file)
@@ -46,6 +46,15 @@ void nf_unregister_queue_handler(void)
 }
 EXPORT_SYMBOL(nf_unregister_queue_handler);
 
+static void nf_queue_sock_put(struct sock *sk)
+{
+#ifdef CONFIG_INET
+       sock_gen_put(sk);
+#else
+       sock_put(sk);
+#endif
+}
+
 static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
 {
        struct nf_hook_state *state = &entry->state;
@@ -54,7 +63,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)
        dev_put(state->in);
        dev_put(state->out);
        if (state->sk)
-               sock_put(state->sk);
+               nf_queue_sock_put(state->sk);
 
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        dev_put(entry->physin);
@@ -87,19 +96,21 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry)
 }
 
 /* Bump dev refs so they don't vanish while packet is out */
-void nf_queue_entry_get_refs(struct nf_queue_entry *entry)
+bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)
 {
        struct nf_hook_state *state = &entry->state;
 
+       if (state->sk && !refcount_inc_not_zero(&state->sk->sk_refcnt))
+               return false;
+
        dev_hold(state->in);
        dev_hold(state->out);
-       if (state->sk)
-               sock_hold(state->sk);
 
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
        dev_hold(entry->physin);
        dev_hold(entry->physout);
 #endif
+       return true;
 }
 EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs);
 
@@ -169,6 +180,18 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
                break;
        }
 
+       if (skb_sk_is_prefetched(skb)) {
+               struct sock *sk = skb->sk;
+
+               if (!sk_is_refcounted(sk)) {
+                       if (!refcount_inc_not_zero(&sk->sk_refcnt))
+                               return -ENOTCONN;
+
+                       /* drop refcount on skb_orphan */
+                       skb->destructor = sock_edemux;
+               }
+       }
+
        entry = kmalloc(sizeof(*entry) + route_key_size, GFP_ATOMIC);
        if (!entry)
                return -ENOMEM;
@@ -187,7 +210,10 @@ static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state,
 
        __nf_queue_entry_init_physdevs(entry);
 
-       nf_queue_entry_get_refs(entry);
+       if (!nf_queue_entry_get_refs(entry)) {
+               kfree(entry);
+               return -ENOTCONN;
+       }
 
        switch (entry->state.pf) {
        case AF_INET:
index 9cd1d7a..c86748b 100644 (file)
@@ -4502,7 +4502,7 @@ static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
        list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
                list_del_rcu(&catchall->list);
                nft_set_elem_destroy(set, catchall->elem, true);
-               kfree_rcu(catchall);
+               kfree_rcu(catchall, rcu);
        }
 }
 
@@ -5669,7 +5669,7 @@ static void nft_setelem_catchall_remove(const struct net *net,
        list_for_each_entry_safe(catchall, next, &set->catchall_list, list) {
                if (catchall->elem == elem->priv) {
                        list_del_rcu(&catchall->list);
-                       kfree_rcu(catchall);
+                       kfree_rcu(catchall, rcu);
                        break;
                }
        }
index ea2d9c2..64a6acb 100644 (file)
@@ -710,9 +710,15 @@ static struct nf_queue_entry *
 nf_queue_entry_dup(struct nf_queue_entry *e)
 {
        struct nf_queue_entry *entry = kmemdup(e, e->size, GFP_ATOMIC);
-       if (entry)
-               nf_queue_entry_get_refs(entry);
-       return entry;
+
+       if (!entry)
+               return NULL;
+
+       if (nf_queue_entry_get_refs(entry))
+               return entry;
+
+       kfree(entry);
+       return NULL;
 }
 
 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
index 33e70d6..ec19f62 100644 (file)
@@ -361,6 +361,13 @@ static void tcf_ct_flow_table_put(struct tcf_ct_params *params)
        }
 }
 
+static void tcf_ct_flow_tc_ifidx(struct flow_offload *entry,
+                                struct nf_conn_act_ct_ext *act_ct_ext, u8 dir)
+{
+       entry->tuplehash[dir].tuple.xmit_type = FLOW_OFFLOAD_XMIT_TC;
+       entry->tuplehash[dir].tuple.tc.iifidx = act_ct_ext->ifindex[dir];
+}
+
 static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
                                  struct nf_conn *ct,
                                  bool tcp)
@@ -385,10 +392,8 @@ static void tcf_ct_flow_table_add(struct tcf_ct_flow_table *ct_ft,
 
        act_ct_ext = nf_conn_act_ct_ext_find(ct);
        if (act_ct_ext) {
-               entry->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.iifidx =
-                       act_ct_ext->ifindex[IP_CT_DIR_ORIGINAL];
-               entry->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.iifidx =
-                       act_ct_ext->ifindex[IP_CT_DIR_REPLY];
+               tcf_ct_flow_tc_ifidx(entry, act_ct_ext, FLOW_OFFLOAD_DIR_ORIGINAL);
+               tcf_ct_flow_tc_ifidx(entry, act_ct_ext, FLOW_OFFLOAD_DIR_REPLY);
        }
 
        err = flow_offload_add(&ct_ft->nf_ft, entry);
index 306d9e8..284befa 100644 (file)
@@ -183,7 +183,7 @@ static int smc_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
        struct smc_sock *smc;
-       int rc = 0;
+       int old_state, rc = 0;
 
        if (!sk)
                goto out;
@@ -191,8 +191,10 @@ static int smc_release(struct socket *sock)
        sock_hold(sk); /* sock_put below */
        smc = smc_sk(sk);
 
+       old_state = sk->sk_state;
+
        /* cleanup for a dangling non-blocking connect */
-       if (smc->connect_nonblock && sk->sk_state == SMC_INIT)
+       if (smc->connect_nonblock && old_state == SMC_INIT)
                tcp_abort(smc->clcsock->sk, ECONNABORTED);
 
        if (cancel_work_sync(&smc->connect_work))
@@ -206,6 +208,10 @@ static int smc_release(struct socket *sock)
        else
                lock_sock(sk);
 
+       if (old_state == SMC_INIT && sk->sk_state == SMC_ACTIVE &&
+           !smc->use_fallback)
+               smc_close_active_abort(smc);
+
        rc = __smc_release(smc);
 
        /* detach socket */
@@ -3081,12 +3087,14 @@ static int __init smc_init(void)
        rc = tcp_register_ulp(&smc_ulp_ops);
        if (rc) {
                pr_err("%s: tcp_ulp_register fails with %d\n", __func__, rc);
-               goto out_sock;
+               goto out_ib;
        }
 
        static_branch_enable(&tcp_have_smc);
        return 0;
 
+out_ib:
+       smc_ib_unregister_client();
 out_sock:
        sock_unregister(PF_SMC);
 out_proto6:
index 29525d0..be7d704 100644 (file)
@@ -1161,8 +1161,8 @@ void smc_conn_free(struct smc_connection *conn)
                        cancel_work_sync(&conn->abort_work);
        }
        if (!list_empty(&lgr->list)) {
-               smc_lgr_unregister_conn(conn);
                smc_buf_unuse(conn, lgr); /* allow buffer reuse */
+               smc_lgr_unregister_conn(conn);
        }
 
        if (!lgr->conns_num)
@@ -1864,7 +1864,8 @@ int smc_conn_create(struct smc_sock *smc, struct smc_init_info *ini)
                    (ini->smcd_version == SMC_V2 ||
                     lgr->vlan_id == ini->vlan_id) &&
                    (role == SMC_CLNT || ini->is_smcd ||
-                    lgr->conns_num < SMC_RMBS_PER_LGR_MAX)) {
+                   (lgr->conns_num < SMC_RMBS_PER_LGR_MAX &&
+                     !bitmap_full(lgr->rtokens_used_mask, SMC_RMBS_PER_LGR_MAX)))) {
                        /* link group found */
                        ini->first_contact_local = 0;
                        conn->lgr = lgr;
index 1e9be50..527ae66 100644 (file)
@@ -33,7 +33,7 @@ $(obj)/shipped-certs.c: $(wildcard $(srctree)/$(src)/certs/*.hex)
          echo 'unsigned int shipped_regdb_certs_len = sizeof(shipped_regdb_certs);'; \
         ) > $@
 
-$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDI) \
+$(obj)/extra-certs.c: $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR) \
                      $(wildcard $(CONFIG_CFG80211_EXTRA_REGDB_KEYDIR)/*.x509)
        @$(kecho) "  GEN     $@"
        $(Q)(set -e; \
index 578bff9..c01fbcc 100644 (file)
@@ -13411,6 +13411,9 @@ static int handle_nan_filter(struct nlattr *attr_filter,
        i = 0;
        nla_for_each_nested(attr, attr_filter, rem) {
                filter[i].filter = nla_memdup(attr, GFP_KERNEL);
+               if (!filter[i].filter)
+                       goto err;
+
                filter[i].len = nla_len(attr);
                i++;
        }
@@ -13423,6 +13426,15 @@ static int handle_nan_filter(struct nlattr *attr_filter,
        }
 
        return 0;
+
+err:
+       i = 0;
+       nla_for_each_nested(attr, attr_filter, rem) {
+               kfree(filter[i].filter);
+               i++;
+       }
+       kfree(filter);
+       return -ENOMEM;
 }
 
 static int nl80211_nan_add_func(struct sk_buff *skb,
@@ -17816,7 +17828,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
        wdev->chandef = *chandef;
        wdev->preset_chandef = *chandef;
 
-       if (wdev->iftype == NL80211_IFTYPE_STATION &&
+       if ((wdev->iftype == NL80211_IFTYPE_STATION ||
+            wdev->iftype == NL80211_IFTYPE_P2P_CLIENT) &&
            !WARN_ON(!wdev->current_bss))
                cfg80211_update_assoc_bss_entry(wdev, chandef->chan);
 
index 3fa0664..39bce5d 100644 (file)
@@ -223,6 +223,9 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
        if (x->encap || x->tfcpad)
                return -EINVAL;
 
+       if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
+               return -EINVAL;
+
        dev = dev_get_by_index(net, xuo->ifindex);
        if (!dev) {
                if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
@@ -262,7 +265,8 @@ int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
        netdev_tracker_alloc(dev, &xso->dev_tracker, GFP_ATOMIC);
        xso->real_dev = dev;
        xso->num_exthdrs = 1;
-       xso->flags = xuo->flags;
+       /* Don't forward bit that is not implemented */
+       xso->flags = xuo->flags & ~XFRM_OFFLOAD_IPV6;
 
        err = dev->xfrmdev_ops->xdo_dev_state_add(x);
        if (err) {
index 57448fc..4e3c62d 100644 (file)
@@ -673,12 +673,12 @@ static int xfrmi_changelink(struct net_device *dev, struct nlattr *tb[],
        struct net *net = xi->net;
        struct xfrm_if_parms p = {};
 
+       xfrmi_netlink_parms(data, &p);
        if (!p.if_id) {
                NL_SET_ERR_MSG(extack, "if_id must be non zero");
                return -EINVAL;
        }
 
-       xfrmi_netlink_parms(data, &p);
        xi = xfrmi_locate(net, &p);
        if (!xi) {
                xi = netdev_priv(dev);
index 04d1ce9..8825261 100644 (file)
@@ -4256,7 +4256,7 @@ static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp,
 }
 
 static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel,
-                                                   u8 dir, u8 type, struct net *net)
+                                                   u8 dir, u8 type, struct net *net, u32 if_id)
 {
        struct xfrm_policy *pol, *ret = NULL;
        struct hlist_head *chain;
@@ -4265,7 +4265,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
        spin_lock_bh(&net->xfrm.xfrm_policy_lock);
        chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir);
        hlist_for_each_entry(pol, chain, bydst) {
-               if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+               if ((if_id == 0 || pol->if_id == if_id) &&
+                   xfrm_migrate_selector_match(sel, &pol->selector) &&
                    pol->type == type) {
                        ret = pol;
                        priority = ret->priority;
@@ -4277,7 +4278,8 @@ static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *
                if ((pol->priority >= priority) && ret)
                        break;
 
-               if (xfrm_migrate_selector_match(sel, &pol->selector) &&
+               if ((if_id == 0 || pol->if_id == if_id) &&
+                   xfrm_migrate_selector_match(sel, &pol->selector) &&
                    pol->type == type) {
                        ret = pol;
                        break;
@@ -4393,7 +4395,7 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate)
 int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
                 struct xfrm_migrate *m, int num_migrate,
                 struct xfrm_kmaddress *k, struct net *net,
-                struct xfrm_encap_tmpl *encap)
+                struct xfrm_encap_tmpl *encap, u32 if_id)
 {
        int i, err, nx_cur = 0, nx_new = 0;
        struct xfrm_policy *pol = NULL;
@@ -4412,14 +4414,14 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
        }
 
        /* Stage 1 - find policy */
-       if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) {
+       if ((pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id)) == NULL) {
                err = -ENOENT;
                goto out;
        }
 
        /* Stage 2 - find and update state(s) */
        for (i = 0, mp = m; i < num_migrate; i++, mp++) {
-               if ((x = xfrm_migrate_state_find(mp, net))) {
+               if ((x = xfrm_migrate_state_find(mp, net, if_id))) {
                        x_cur[nx_cur] = x;
                        nx_cur++;
                        xc = xfrm_state_migrate(x, mp, encap);
index ca6bee1..b749935 100644 (file)
@@ -1579,9 +1579,6 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig,
        memcpy(&x->mark, &orig->mark, sizeof(x->mark));
        memcpy(&x->props.smark, &orig->props.smark, sizeof(x->props.smark));
 
-       if (xfrm_init_state(x) < 0)
-               goto error;
-
        x->props.flags = orig->props.flags;
        x->props.extra_flags = orig->props.extra_flags;
 
@@ -1606,7 +1603,8 @@ out:
        return NULL;
 }
 
-struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net)
+struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net,
+                                               u32 if_id)
 {
        unsigned int h;
        struct xfrm_state *x = NULL;
@@ -1622,6 +1620,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                                continue;
                        if (m->reqid && x->props.reqid != m->reqid)
                                continue;
+                       if (if_id != 0 && x->if_id != if_id)
+                               continue;
                        if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
                                             m->old_family) ||
                            !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
@@ -1637,6 +1637,8 @@ struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *n
                        if (x->props.mode != m->mode ||
                            x->id.proto != m->proto)
                                continue;
+                       if (if_id != 0 && x->if_id != if_id)
+                               continue;
                        if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr,
                                             m->old_family) ||
                            !xfrm_addr_equal(&x->props.saddr, &m->old_saddr,
@@ -1663,6 +1665,11 @@ struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x,
        if (!xc)
                return NULL;
 
+       xc->props.family = m->new_family;
+
+       if (xfrm_init_state(xc) < 0)
+               goto error;
+
        memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr));
        memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr));
 
@@ -2572,7 +2579,7 @@ void xfrm_state_delete_tunnel(struct xfrm_state *x)
 }
 EXPORT_SYMBOL(xfrm_state_delete_tunnel);
 
-u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu)
+u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
 {
        const struct xfrm_type *type = READ_ONCE(x->type);
        struct crypto_aead *aead;
@@ -2603,17 +2610,7 @@ u32 __xfrm_state_mtu(struct xfrm_state *x, int mtu)
        return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
                 net_adj) & ~(blksize - 1)) + net_adj - 2;
 }
-EXPORT_SYMBOL_GPL(__xfrm_state_mtu);
-
-u32 xfrm_state_mtu(struct xfrm_state *x, int mtu)
-{
-       mtu = __xfrm_state_mtu(x, mtu);
-
-       if (x->props.family == AF_INET6 && mtu < IPV6_MIN_MTU)
-               return IPV6_MIN_MTU;
-
-       return mtu;
-}
+EXPORT_SYMBOL_GPL(xfrm_state_mtu);
 
 int __xfrm_init_state(struct xfrm_state *x, bool init_replay, bool offload)
 {
index 8cd6c81..a4fb596 100644 (file)
@@ -2608,6 +2608,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
        int n = 0;
        struct net *net = sock_net(skb->sk);
        struct xfrm_encap_tmpl  *encap = NULL;
+       u32 if_id = 0;
 
        if (attrs[XFRMA_MIGRATE] == NULL)
                return -EINVAL;
@@ -2632,7 +2633,10 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
                        return -ENOMEM;
        }
 
-       err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap);
+       if (attrs[XFRMA_IF_ID])
+               if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+
+       err = xfrm_migrate(&pi->sel, pi->dir, type, m, n, kmp, net, encap, if_id);
 
        kfree(encap);
 
index 4aaee18..4415fb3 100644 (file)
@@ -150,7 +150,6 @@ static const struct snd_kcontrol_new cs4265_snd_controls[] = {
        SOC_SINGLE("E to F Buffer Disable Switch", CS4265_SPDIF_CTL1,
                                6, 1, 0),
        SOC_ENUM("C Data Access", cam_mode_enum),
-       SOC_SINGLE("SPDIF Switch", CS4265_SPDIF_CTL2, 5, 1, 1),
        SOC_SINGLE("Validity Bit Control Switch", CS4265_SPDIF_CTL2,
                                3, 1, 0),
        SOC_ENUM("SPDIF Mono/Stereo", spdif_mono_stereo_enum),
@@ -186,7 +185,7 @@ static const struct snd_soc_dapm_widget cs4265_dapm_widgets[] = {
 
        SND_SOC_DAPM_SWITCH("Loopback", SND_SOC_NOPM, 0, 0,
                        &loopback_ctl),
-       SND_SOC_DAPM_SWITCH("SPDIF", SND_SOC_NOPM, 0, 0,
+       SND_SOC_DAPM_SWITCH("SPDIF", CS4265_SPDIF_CTL2, 5, 1,
                        &spdif_switch),
        SND_SOC_DAPM_SWITCH("DAC", CS4265_PWRCTL, 1, 1,
                        &dac_switch),
index 03ea959..a0ca58b 100644 (file)
@@ -319,7 +319,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
        if (ucontrol->value.integer.value[0] < 0)
                return -EINVAL;
        val = ucontrol->value.integer.value[0];
-       if (mc->platform_max && val > mc->platform_max)
+       if (mc->platform_max && ((int)val + min) > mc->platform_max)
                return -EINVAL;
        if (val > max - min)
                return -EINVAL;
@@ -332,7 +332,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
                if (ucontrol->value.integer.value[1] < 0)
                        return -EINVAL;
                val2 = ucontrol->value.integer.value[1];
-               if (mc->platform_max && val2 > mc->platform_max)
+               if (mc->platform_max && ((int)val2 + min) > mc->platform_max)
                        return -EINVAL;
                if (val2 > max - min)
                        return -EINVAL;
index 1c94eaf..4a3ff64 100644 (file)
@@ -1261,7 +1261,7 @@ static int had_pcm_mmap(struct snd_pcm_substream *substream,
 {
        vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
        return remap_pfn_range(vma, vma->vm_start,
-                       substream->dma_buffer.addr >> PAGE_SHIFT,
+                       substream->runtime->dma_addr >> PAGE_SHIFT,
                        vma->vm_end - vma->vm_start, vma->vm_page_prot);
 }
 
index 6db4e29..ab4e537 100644 (file)
 /* FREE!                                ( 7*32+10) */
 #define X86_FEATURE_PTI                        ( 7*32+11) /* Kernel Page Table Isolation enabled */
 #define X86_FEATURE_RETPOLINE          ( 7*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
-#define X86_FEATURE_RETPOLINE_AMD      ( 7*32+13) /* "" AMD Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   ( 7*32+13) /* "" Use LFENCEs for Spectre variant 2 */
 #define X86_FEATURE_INTEL_PPIN         ( 7*32+14) /* Intel Processor Inventory Number */
 #define X86_FEATURE_CDP_L2             ( 7*32+15) /* Code and Data Prioritization L2 */
 #define X86_FEATURE_MSR_SPEC_CTRL      ( 7*32+16) /* "" MSR SPEC_CTRL is implemented */
index bcb110e..dea33dc 100755 (executable)
@@ -50,8 +50,8 @@ for current_test in ${TESTS:-$ALL_TESTS}; do
                        else
                                log_test "'$current_test' [$profile] overflow $target"
                        fi
+                       RET_FIN=$(( RET_FIN || RET ))
                done
-               RET_FIN=$(( RET_FIN || RET ))
        done
 done
 current_test=""
index 3e3e06e..86e7878 100644 (file)
@@ -60,7 +60,8 @@ __tc_police_test()
 
        tc_police_rules_create $count $should_fail
 
-       offload_count=$(tc filter show dev $swp1 ingress | grep in_hw | wc -l)
+       offload_count=$(tc -j filter show dev $swp1 ingress |
+                       jq "[.[] | select(.options.in_hw == true)] | length")
        ((offload_count == count))
        check_err_fail $should_fail $? "tc police offload count"
 }
index 9ad38bd..b08d30b 100644 (file)
@@ -366,6 +366,7 @@ static struct kvm_vm *test_vm_create(void)
 {
        struct kvm_vm *vm;
        unsigned int i;
+       int ret;
        int nr_vcpus = test_args.nr_vcpus;
 
        vm = vm_create_default_with_vcpus(nr_vcpus, 0, 0, guest_code, NULL);
@@ -382,7 +383,11 @@ static struct kvm_vm *test_vm_create(void)
 
        ucall_init(vm, NULL);
        test_init_timer_irq(vm);
-       vgic_v3_setup(vm, nr_vcpus, 64, GICD_BASE_GPA, GICR_BASE_GPA);
+       ret = vgic_v3_setup(vm, nr_vcpus, 64, GICD_BASE_GPA, GICR_BASE_GPA);
+       if (ret < 0) {
+               print_skip("Failed to create vgic-v3");
+               exit(KSFT_SKIP);
+       }
 
        /* Make all the test's cmdline args visible to the guest */
        sync_global_to_guest(vm, test_args);
index e6c7d7f..7eca977 100644 (file)
@@ -761,6 +761,10 @@ static void test_vgic(uint32_t nr_irqs, bool level_sensitive, bool eoi_split)
 
        gic_fd = vgic_v3_setup(vm, 1, nr_irqs,
                        GICD_BASE_GPA, GICR_BASE_GPA);
+       if (gic_fd < 0) {
+               print_skip("Failed to create vgic-v3, skipping");
+               exit(KSFT_SKIP);
+       }
 
        vm_install_exception_handler(vm, VECTOR_IRQ_CURRENT,
                guest_irq_handlers[args.eoi_split][args.level_sensitive]);
index b3a0fca..f5cd0c5 100644 (file)
@@ -52,7 +52,9 @@ int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, uint32_t nr_irqs,
                        nr_vcpus, nr_vcpus_created);
 
        /* Distributor setup */
-       gic_fd = kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, false);
+       if (_kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3,
+                              false, &gic_fd) != 0)
+               return -1;
 
        kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
                        0, &nr_irqs, true);
index cb5809b..f0f4ab9 100755 (executable)
@@ -763,8 +763,8 @@ run_tests_disconnect()
        run_tests_lo "$ns1" "$ns1" dead:beef:1::1 1 "-I 3 -i $old_cin"
 
        # restore previous status
-       cout=$old_cout
-       cout_disconnect="$cout".disconnect
+       sin=$old_sin
+       sin_disconnect="$cout".disconnect
        cin=$old_cin
        cin_disconnect="$cin".disconnect
        connect_per_transfer=1
index e4f845d..7e81c9a 100644 (file)
@@ -9,6 +9,6 @@ TEST_PROGS := nft_trans_stress.sh nft_fib.sh nft_nat.sh bridge_brouter.sh \
        conntrack_vrf.sh nft_synproxy.sh
 
 LDLIBS = -lmnl
-TEST_GEN_FILES =  nf-queue
+TEST_GEN_FILES =  nf-queue connect_close
 
 include ../lib.mk
diff --git a/tools/testing/selftests/netfilter/connect_close.c b/tools/testing/selftests/netfilter/connect_close.c
new file mode 100644 (file)
index 0000000..1c3b0ad
--- /dev/null
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#define PORT 12345
+#define RUNTIME 10
+
+static struct {
+       unsigned int timeout;
+       unsigned int port;
+} opts = {
+       .timeout = RUNTIME,
+       .port = PORT,
+};
+
+static void handler(int sig)
+{
+       _exit(sig == SIGALRM ? 0 : 1);
+}
+
+static void set_timeout(void)
+{
+       struct sigaction action = {
+               .sa_handler = handler,
+       };
+
+       sigaction(SIGALRM, &action, NULL);
+
+       alarm(opts.timeout);
+}
+
+static void do_connect(const struct sockaddr_in *dst)
+{
+       int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+       if (s >= 0)
+               fcntl(s, F_SETFL, O_NONBLOCK);
+
+       connect(s, (struct sockaddr *)dst, sizeof(*dst));
+       close(s);
+}
+
+static void do_accept(const struct sockaddr_in *src)
+{
+       int c, one = 1, s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+       if (s < 0)
+               return;
+
+       setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
+       setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one));
+
+       bind(s, (struct sockaddr *)src, sizeof(*src));
+
+       listen(s, 16);
+
+       c = accept(s, NULL, NULL);
+       if (c >= 0)
+               close(c);
+
+       close(s);
+}
+
+static int accept_loop(void)
+{
+       struct sockaddr_in src = {
+               .sin_family = AF_INET,
+               .sin_port = htons(opts.port),
+       };
+
+       inet_pton(AF_INET, "127.0.0.1", &src.sin_addr);
+
+       set_timeout();
+
+       for (;;)
+               do_accept(&src);
+
+       return 1;
+}
+
+static int connect_loop(void)
+{
+       struct sockaddr_in dst = {
+               .sin_family = AF_INET,
+               .sin_port = htons(opts.port),
+       };
+
+       inet_pton(AF_INET, "127.0.0.1", &dst.sin_addr);
+
+       set_timeout();
+
+       for (;;)
+               do_connect(&dst);
+
+       return 1;
+}
+
+static void parse_opts(int argc, char **argv)
+{
+       int c;
+
+       while ((c = getopt(argc, argv, "t:p:")) != -1) {
+               switch (c) {
+               case 't':
+                       opts.timeout = atoi(optarg);
+                       break;
+               case 'p':
+                       opts.port = atoi(optarg);
+                       break;
+               }
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       pid_t p;
+
+       parse_opts(argc, argv);
+
+       p = fork();
+       if (p < 0)
+               return 111;
+
+       if (p > 0)
+               return accept_loop();
+
+       return connect_loop();
+}
index 7d27f1f..e127297 100755 (executable)
@@ -113,6 +113,7 @@ table inet $name {
        chain output {
                type filter hook output priority $prio; policy accept;
                tcp dport 12345 queue num 3
+               tcp sport 23456 queue num 3
                jump nfq
        }
        chain post {
@@ -296,6 +297,23 @@ test_tcp_localhost()
        wait 2>/dev/null
 }
 
+test_tcp_localhost_connectclose()
+{
+       tmpfile=$(mktemp) || exit 1
+
+       ip netns exec ${nsrouter} ./connect_close -p 23456 -t $timeout &
+
+       ip netns exec ${nsrouter} ./nf-queue -q 3 -t $timeout &
+       local nfqpid=$!
+
+       sleep 1
+       rm -f "$tmpfile"
+
+       wait $rpid
+       [ $? -eq 0 ] && echo "PASS: tcp via loopback with connect/close"
+       wait 2>/dev/null
+}
+
 test_tcp_localhost_requeue()
 {
 ip netns exec ${nsrouter} nft -f /dev/stdin <<EOF
@@ -424,6 +442,7 @@ test_queue 20
 
 test_tcp_forward
 test_tcp_localhost
+test_tcp_localhost_connectclose
 test_tcp_localhost_requeue
 test_icmp_vrf
 
index 2a7c336..1d68908 100644 (file)
@@ -3,9 +3,10 @@
  * hugepage-mremap:
  *
  * Example of remapping huge page memory in a user application using the
- * mremap system call.  Code assumes a hugetlbfs filesystem is mounted
- * at './huge'.  The amount of memory used by this test is decided by a command
- * line argument in MBs. If missing, the default amount is 10MB.
+ * mremap system call.  The path to a file in a hugetlbfs filesystem must
+ * be passed as the last argument to this test.  The amount of memory used
+ * by this test in MBs can optionally be passed as an argument.  If no memory
+ * amount is passed, the default amount is 10MB.
  *
  * To make sure the test triggers pmd sharing and goes through the 'unshare'
  * path in the mremap code use 1GB (1024) or more.
@@ -25,7 +26,6 @@
 #define DEFAULT_LENGTH_MB 10UL
 #define MB_TO_BYTES(x) (x * 1024 * 1024)
 
-#define FILE_NAME "huge/hugepagefile"
 #define PROTECTION (PROT_READ | PROT_WRITE | PROT_EXEC)
 #define FLAGS (MAP_SHARED | MAP_ANONYMOUS)
 
@@ -107,17 +107,26 @@ static void register_region_with_uffd(char *addr, size_t len)
 
 int main(int argc, char *argv[])
 {
+       size_t length;
+
+       if (argc != 2 && argc != 3) {
+               printf("Usage: %s [length_in_MB] <hugetlb_file>\n", argv[0]);
+               exit(1);
+       }
+
        /* Read memory length as the first arg if valid, otherwise fallback to
-        * the default length. Any additional args are ignored.
+        * the default length.
         */
-       size_t length = argc > 1 ? (size_t)atoi(argv[1]) : 0UL;
+       if (argc == 3)
+               length = argc > 2 ? (size_t)atoi(argv[1]) : 0UL;
 
        length = length > 0 ? length : DEFAULT_LENGTH_MB;
        length = MB_TO_BYTES(length);
 
        int ret = 0;
 
-       int fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755);
+       /* last arg is the hugetlb file name */
+       int fd = open(argv[argc-1], O_CREAT | O_RDWR, 0755);
 
        if (fd < 0) {
                perror("Open failed");
@@ -169,5 +178,8 @@ int main(int argc, char *argv[])
 
        munmap(addr, length);
 
+       close(fd);
+       unlink(argv[argc-1]);
+
        return ret;
 }
index 75d4017..71d2dc1 100755 (executable)
@@ -111,13 +111,14 @@ fi
 echo "-----------------------"
 echo "running hugepage-mremap"
 echo "-----------------------"
-./hugepage-mremap 256
+./hugepage-mremap $mnt/huge_mremap
 if [ $? -ne 0 ]; then
        echo "[FAIL]"
        exitcode=1
 else
        echo "[PASS]"
 fi
+rm -f $mnt/huge_mremap
 
 echo "NOTE: The above hugetlb tests provide minimal coverage.  Use"
 echo "      https://github.com/libhugetlbfs/libhugetlbfs.git for"
index 2f49c9a..3fc1d2e 100644 (file)
@@ -46,6 +46,7 @@
 #include <signal.h>
 #include <poll.h>
 #include <string.h>
+#include <linux/mman.h>
 #include <sys/mman.h>
 #include <sys/syscall.h>
 #include <sys/ioctl.h>
diff --git a/tools/virtio/linux/mm_types.h b/tools/virtio/linux/mm_types.h
new file mode 100644 (file)
index 0000000..356ba4d
--- /dev/null
@@ -0,0 +1,3 @@
+struct folio {
+       struct page page;
+};
index cb3f29c..23f142a 100644 (file)
@@ -130,6 +130,7 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
        memset(dev, 0, sizeof *dev);
        dev->vdev.features = features;
        INIT_LIST_HEAD(&dev->vdev.vqs);
+       spin_lock_init(&dev->vdev.vqs_list_lock);
        dev->buf_size = 1024;
        dev->buf = malloc(dev->buf_size);
        assert(dev->buf);