Merge tag 'perf_urgent_for_v5.19_rc7' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 17 Jul 2022 15:34:02 +0000 (08:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 17 Jul 2022 15:34:02 +0000 (08:34 -0700)
Pull perf fix from Borislav Petkov:

 - A single data race fix on the perf event cleanup path to avoid
   endless loops due to insufficient locking

* tag 'perf_urgent_for_v5.19_rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  perf/core: Fix data race between perf_event_set_output() and perf_mmap_close()

627 files changed:
.mailmap
CREDITS
Documentation/admin-guide/kernel-parameters.txt
Documentation/core-api/kernel-api.rst
Documentation/core-api/symbol-namespaces.rst
Documentation/devicetree/bindings/display/allwinner,sun4i-a10-display-engine.yaml
Documentation/devicetree/bindings/dma/allwinner,sun50i-a64-dma.yaml
Documentation/devicetree/bindings/net/wireless/qca,ath9k.yaml
Documentation/devicetree/bindings/net/wireless/qcom,ath11k.yaml
Documentation/devicetree/bindings/sound/qcom,lpass-cpu.yaml
Documentation/filesystems/netfs_library.rst
Documentation/filesystems/overlayfs.rst
Documentation/livepatch/module-elf-format.rst
Documentation/networking/ip-sysctl.rst
Documentation/process/maintainer-netdev.rst
Documentation/sound/soc/dai.rst
Documentation/translations/it_IT/core-api/symbol-namespaces.rst
Documentation/translations/zh_CN/core-api/kernel-api.rst
Documentation/translations/zh_CN/core-api/symbol-namespaces.rst
Documentation/virt/kvm/api.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/at91-sam9x60ek.dts
arch/arm/boot/dts/at91-sama5d2_icp.dts
arch/arm/boot/dts/imx6qdl-ts7970.dtsi
arch/arm/boot/dts/imx6ull-colibri.dtsi
arch/arm/boot/dts/imx7d-smegw01.dts
arch/arm/boot/dts/lan966x-kontron-kswitch-d10-mmt.dtsi
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/sama5d2.dtsi
arch/arm/boot/dts/stm32mp15-scmi.dtsi
arch/arm/boot/dts/stm32mp151.dtsi
arch/arm/boot/dts/stm32mp157a-dk1-scmi.dts
arch/arm/boot/dts/stm32mp157c-dk2-scmi.dts
arch/arm/boot/dts/stm32mp157c-ed1-scmi.dts
arch/arm/boot/dts/stm32mp157c-ev1-scmi.dts
arch/arm/boot/dts/sun8i-h2-plus-orangepi-zero.dts
arch/arm/configs/mxs_defconfig
arch/arm/include/asm/domain.h
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/ptrace.h
arch/arm/kernel/entry-common.S
arch/arm/mach-at91/pm.c
arch/arm/mach-meson/platsmp.c
arch/arm/mach-rockchip/pm.c
arch/arm/mm/Kconfig
arch/arm/mm/alignment.c
arch/arm/mm/mmu.c
arch/arm/mm/proc-v7-bugs.c
arch/arm/probes/decode.h
arch/arm/xen/p2m.c
arch/arm64/boot/dts/broadcom/bcm4908/bcm4906.dtsi
arch/arm64/boot/dts/broadcom/bcm4908/bcm4908.dtsi
arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi
arch/arm64/boot/dts/freescale/imx8mp-evk.dts
arch/arm64/boot/dts/freescale/imx8mp-icore-mx8mp-edimm2.2.dts
arch/arm64/boot/dts/freescale/imx8mp-phyboard-pollux-rdk.dts
arch/arm64/boot/dts/freescale/imx8mp-venice-gw74xx.dts
arch/arm64/boot/dts/freescale/imx8mp.dtsi
arch/arm64/boot/dts/qcom/msm8992-lg-bullhead.dtsi
arch/arm64/boot/dts/qcom/msm8992-xiaomi-libra.dts
arch/arm64/boot/dts/qcom/msm8994.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-homestar.dtsi
arch/arm64/boot/dts/qcom/sc7180-trogdor-lazor.dtsi
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sm8450.dtsi
arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi
arch/arm64/boot/dts/rockchip/rk3399.dtsi
arch/arm64/boot/dts/rockchip/rk3566-quartz64-a.dts
arch/arm64/boot/dts/rockchip/rk3566-quartz64-b.dts
arch/loongarch/Kconfig
arch/loongarch/include/asm/fpregdef.h
arch/loongarch/include/asm/page.h
arch/loongarch/include/asm/processor.h
arch/loongarch/kernel/asm-offsets.c
arch/loongarch/kernel/fpu.S
arch/loongarch/kernel/numa.c
arch/loongarch/vdso/Makefile
arch/openrisc/kernel/unwinder.c
arch/powerpc/platforms/powernv/rng.c
arch/riscv/Kconfig
arch/riscv/boot/dts/microchip/mpfs.dtsi
arch/riscv/errata/sifive/errata.c
arch/riscv/include/asm/pgtable-64.h
arch/riscv/include/asm/pgtable.h
arch/riscv/kvm/mmu.c
arch/riscv/kvm/vcpu.c
arch/s390/Makefile
arch/s390/include/asm/nospec-insn.h
arch/s390/lib/Makefile
arch/s390/lib/expoline/Makefile [new file with mode: 0644]
arch/s390/lib/expoline/expoline.S [moved from arch/s390/lib/expoline.S with 100% similarity]
arch/sh/include/asm/io.h
arch/um/include/asm/page.h
arch/um/include/shared/mem.h
arch/um/kernel/um_arch.c
arch/um/os-Linux/skas/process.c
arch/x86/Kconfig
arch/x86/Makefile
arch/x86/boot/compressed/ident_map_64.c
arch/x86/entry/Makefile
arch/x86/entry/calling.h
arch/x86/entry/entry.S [new file with mode: 0644]
arch/x86/entry/entry_32.S
arch/x86/entry/entry_64.S
arch/x86/entry/entry_64_compat.S
arch/x86/entry/vdso/Makefile
arch/x86/entry/vsyscall/vsyscall_emu_64.S
arch/x86/include/asm/alternative.h
arch/x86/include/asm/cpufeatures.h
arch/x86/include/asm/disabled-features.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/msr-index.h
arch/x86/include/asm/nospec-branch.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/static_call.h
arch/x86/include/asm/unwind_hints.h
arch/x86/include/uapi/asm/bootparam.h
arch/x86/kernel/acpi/cppc.c
arch/x86/kernel/alternative.c
arch/x86/kernel/asm-offsets.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/bugs.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/cpu.h
arch/x86/kernel/cpu/hygon.c
arch/x86/kernel/cpu/scattered.c
arch/x86/kernel/ftrace.c
arch/x86/kernel/head64.c
arch/x86/kernel/head_32.S
arch/x86/kernel/head_64.S
arch/x86/kernel/module.c
arch/x86/kernel/process.c
arch/x86/kernel/relocate_kernel_32.S
arch/x86/kernel/relocate_kernel_64.S
arch/x86/kernel/static_call.c
arch/x86/kernel/vmlinux.lds.S
arch/x86/kvm/emulate.c
arch/x86/kvm/svm/vmenter.S
arch/x86/kvm/vmx/capabilities.h
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/vmx/run_flags.h [new file with mode: 0644]
arch/x86/kvm/vmx/vmenter.S
arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.h
arch/x86/kvm/vmx/vmx_ops.h
arch/x86/kvm/x86.c
arch/x86/lib/memmove_64.S
arch/x86/lib/retpoline.S
arch/x86/mm/init.c
arch/x86/mm/mem_encrypt_boot.S
arch/x86/net/bpf_jit_comp.c
arch/x86/platform/efi/efi_thunk_64.S
arch/x86/xen/enlighten_pv.c
arch/x86/xen/setup.c
arch/x86/xen/xen-asm.S
arch/x86/xen/xen-head.S
arch/x86/xen/xen-ops.h
block/blk-merge.c
crypto/Kconfig
drivers/acpi/acpi_video.c
drivers/acpi/bus.c
drivers/acpi/cppc_acpi.c
drivers/amba/bus.c
drivers/base/core.c
drivers/base/cpu.c
drivers/base/power/runtime.c
drivers/block/xen-blkfront.c
drivers/char/random.c
drivers/cpufreq/mediatek-cpufreq.c
drivers/crypto/Kconfig
drivers/cxl/core/hdm.c
drivers/cxl/core/mbox.c
drivers/cxl/core/port.c
drivers/cxl/cxl.h
drivers/cxl/cxlmem.h
drivers/cxl/mem.c
drivers/cxl/pmem.c
drivers/devfreq/exynos-bus.c
drivers/dma-buf/dma-resv.c
drivers/dma/at_xdmac.c
drivers/dma/dmatest.c
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/idxd/device.c
drivers/dma/idxd/init.c
drivers/dma/imx-sdma.c
drivers/dma/lgm/lgm-dma.c
drivers/dma/pl330.c
drivers/dma/qcom/bam_dma.c
drivers/dma/ti/dma-crossbar.c
drivers/firmware/arm_scmi/bus.c
drivers/firmware/arm_scmi/clock.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/arm_scmi/optee.c
drivers/firmware/arm_scmi/protocols.h
drivers/firmware/efi/reboot.c
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-vf610.c
drivers/gpio/gpiolib-cdev.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vkms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h [deleted file]
drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
drivers/gpu/drm/amd/amdgpu/dce_v6_0.c
drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/display/Kconfig
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c
drivers/gpu/drm/bridge/fsl-ldb.c
drivers/gpu/drm/drm_aperture.c
drivers/gpu/drm/drm_panel_orientation_quirks.c
drivers/gpu/drm/i915/display/intel_dp_mst.c
drivers/gpu/drm/i915/gem/i915_gem_ttm.c
drivers/gpu/drm/i915/gem/i915_gem_wait.c
drivers/gpu/drm/i915/gt/intel_gt.c
drivers/gpu/drm/i915/gt/intel_reset.c
drivers/gpu/drm/i915/gt/selftest_lrc.c
drivers/gpu/drm/i915/gt/uc/intel_uc_fw.c
drivers/gpu/drm/i915/gvt/cmd_parser.c
drivers/gpu/drm/i915/i915_scatterlist.c
drivers/gpu/drm/i915/i915_scatterlist.h
drivers/gpu/drm/i915/i915_vma.c
drivers/gpu/drm/i915/intel_region_ttm.c
drivers/gpu/drm/i915/intel_region_ttm.h
drivers/gpu/drm/i915/selftests/i915_gem_gtt.c
drivers/gpu/drm/i915/selftests/intel_memory_region.c
drivers/gpu/drm/i915/selftests/mock_region.c
drivers/gpu/drm/panfrost/panfrost_drv.c
drivers/gpu/drm/panfrost/panfrost_mmu.c
drivers/gpu/drm/rockchip/rockchip_drm_drv.c
drivers/gpu/drm/solomon/ssd130x.c
drivers/i2c/busses/i2c-cadence.c
drivers/i2c/busses/i2c-piix4.c
drivers/idle/intel_idle.c
drivers/input/touchscreen/goodix.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/input/touchscreen/wm97xx-core.c
drivers/iommu/intel/dmar.c
drivers/iommu/intel/iommu.c
drivers/iommu/intel/pasid.c
drivers/iommu/intel/pasid.h
drivers/irqchip/Kconfig
drivers/irqchip/irq-apple-aic.c
drivers/irqchip/irq-gic-v3.c
drivers/irqchip/irq-or1k-pic.c
drivers/misc/cardreader/rtsx_usb.c
drivers/misc/eeprom/at25.c
drivers/net/Kconfig
drivers/net/can/grcan.c
drivers/net/can/m_can/m_can.c
drivers/net/can/rcar/rcar_canfd.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-core.c
drivers/net/can/spi/mcp251xfd/mcp251xfd-regmap.c
drivers/net/can/usb/gs_usb.c
drivers/net/can/usb/kvaser_usb/kvaser_usb.h
drivers/net/can/usb/kvaser_usb/kvaser_usb_core.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c
drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c
drivers/net/can/xilinx_can.c
drivers/net/ethernet/aquantia/atlantic/aq_pci_func.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt.h
drivers/net/ethernet/broadcom/bnxt/bnxt_devlink.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c
drivers/net/ethernet/chelsio/inline_crypto/chtls/chtls_cm.c
drivers/net/ethernet/faraday/ftgmac100.c
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_register.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/ice/ice_devids.h
drivers/net/ethernet/intel/ice/ice_devlink.c
drivers/net/ethernet/intel/ice/ice_fw_update.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/marvell/prestera/prestera_router.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_ct.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_rx.c
drivers/net/ethernet/mellanox/mlx5/core/en_accel/ktls_tx.c
drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
drivers/net/ethernet/mellanox/mlx5/core/esw/legacy.c
drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.c
drivers/net/ethernet/microchip/lan966x/lan966x_main.h
drivers/net/ethernet/mscc/ocelot_fdma.c
drivers/net/ethernet/netronome/nfp/flower/tunnel_conf.c
drivers/net/ethernet/netronome/nfp/nfdk/dp.c
drivers/net/ethernet/realtek/r8169_main.c
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/ef10_sriov.c
drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c
drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c
drivers/net/ethernet/sun/sunhme.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/usb/catc.c
drivers/net/usb/r8152.c
drivers/net/usb/usbnet.c
drivers/net/wireless/ath/ath11k/wmi.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/rtw8821c.c
drivers/net/xen-netback/rx.c
drivers/net/xen-netfront.c
drivers/nvme/host/core.c
drivers/nvme/host/pci.c
drivers/nvme/host/trace.h
drivers/pinctrl/aspeed/pinctrl-aspeed.c
drivers/pinctrl/freescale/pinctrl-imx93.c
drivers/pinctrl/stm32/pinctrl-stm32.c
drivers/pinctrl/sunxi/pinctrl-sun8i-a83t.c
drivers/pinctrl/sunxi/pinctrl-sunxi.c
drivers/platform/x86/amd-pmc.c
drivers/platform/x86/asus-nb-wmi.c
drivers/platform/x86/gigabyte-wmi.c
drivers/platform/x86/intel/atomisp2/led.c
drivers/platform/x86/intel/ifs/Kconfig
drivers/platform/x86/x86-android-tablets.c
drivers/power/reset/arm-versatile-reboot.c
drivers/power/supply/ab8500_fg.c
drivers/power/supply/power_supply_core.c
drivers/s390/crypto/ap_bus.c
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/pm8001/pm8001_hwi.c
drivers/scsi/pm8001/pm8001_init.c
drivers/scsi/pm8001/pm80xx_hwi.c
drivers/soc/atmel/soc.c
drivers/soc/ixp4xx/ixp4xx-npe.c
drivers/soc/qcom/smem.c
drivers/spi/spi-amd.c
drivers/spi/spi-aspeed-smc.c
drivers/spi/spi-cadence-quadspi.c
drivers/staging/wlan-ng/hfa384x_usb.c
drivers/target/target_core_file.c
drivers/target/target_core_iblock.c
drivers/target/target_core_sbc.c
drivers/tee/optee/optee_smc.h
drivers/tee/optee/smc_abi.c
drivers/tee/tee_core.c
drivers/tty/pty.c
drivers/tty/serial/8250/8250_core.c
drivers/tty/serial/8250/8250_dma.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_port.c
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/mvebu-uart.c
drivers/tty/serial/samsung_tty.c
drivers/tty/serial/serial_core.c
drivers/tty/serial/stm32-usart.c
drivers/tty/tty.h
drivers/tty/tty_buffer.c
drivers/tty/vt/vt.c
drivers/ufs/core/ufshcd.c
drivers/usb/dwc3/dwc3-am62.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/typec/class.c
drivers/vfio/vfio.c
drivers/video/fbdev/core/fbcon.c
drivers/video/fbdev/core/fbmem.c
drivers/xen/gntdev.c
fs/afs/file.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/send.c
fs/btrfs/tests/btrfs-tests.c
fs/btrfs/transaction.c
fs/btrfs/zoned.c
fs/cachefiles/ondemand.c
fs/ceph/addr.c
fs/cifs/connect.c
fs/cifs/sess.c
fs/cifs/smb2pdu.c
fs/exec.c
fs/fscache/cookie.c
fs/fscache/volume.c
fs/io_uring.c
fs/lockd/svcsubs.c
fs/netfs/buffered_read.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsd.h
fs/nilfs2/nilfs.h
fs/overlayfs/super.c
fs/remap_range.c
include/acpi/cppc_acpi.h
include/linux/acpi.h
include/linux/cgroup-defs.h
include/linux/cpu.h
include/linux/fbcon.h
include/linux/fscache.h
include/linux/highmem.h
include/linux/intel-iommu.h
include/linux/kexec.h
include/linux/kvm_host.h
include/linux/memregion.h
include/linux/netfs.h
include/linux/nvme.h
include/linux/objtool.h
include/linux/pm_runtime.h
include/linux/reset.h
include/linux/rtsx_usb.h
include/linux/sched/task.h
include/linux/serial_core.h
include/net/cfg80211.h
include/net/flow_offload.h
include/net/mac80211.h
include/net/netfilter/nf_tables.h
include/net/raw.h
include/net/sock.h
include/net/tls.h
include/sound/soc.h
include/trace/events/iocost.h
include/trace/events/sock.h
include/uapi/linux/bpf.h
include/uapi/linux/input.h
include/uapi/linux/io_uring.h
include/uapi/linux/kvm.h
include/uapi/linux/tty.h
include/video/of_display_timing.h
ipc/namespace.c
kernel/bpf/core.c
kernel/bpf/helpers.c
kernel/bpf/verifier.c
kernel/cgroup/cgroup.c
kernel/exit.c
kernel/kexec_file.c
kernel/module/internal.h
kernel/module/kallsyms.c
kernel/module/main.c
kernel/printk/printk.c
kernel/ptrace.c
kernel/signal.c
kernel/sysctl.c
kernel/time/posix-timers.c
kernel/trace/Kconfig
kernel/trace/trace.c
kernel/trace/trace_events_hist.c
lib/Kconfig.ubsan
lib/idr.c
mm/damon/vaddr.c
mm/memory.c
mm/rmap.c
mm/sparse-vmemmap.c
mm/userfaultfd.c
net/8021q/vlan_netlink.c
net/bluetooth/hci_core.c
net/bluetooth/hci_sync.c
net/can/bcm.c
net/core/dev.c
net/core/filter.c
net/ipv4/af_inet.c
net/ipv4/cipso_ipv4.c
net/ipv4/fib_semantics.c
net/ipv4/fib_trie.c
net/ipv4/icmp.c
net/ipv4/inet_timewait_sock.c
net/ipv4/inetpeer.c
net/ipv4/nexthop.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_output.c
net/ipv6/icmp.c
net/ipv6/route.c
net/ipv6/seg6_iptunnel.c
net/ipv6/seg6_local.c
net/mac80211/cfg.c
net/mac80211/iface.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mptcp/options.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.c
net/mptcp/protocol.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_standalone.c
net/netfilter/nf_log_syslog.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_set_pipapo.c
net/rose/rose_route.c
net/sched/act_police.c
net/tls/tls_device.c
net/tls/tls_main.c
net/tls/tls_sw.c
net/wireless/sme.c
net/xdp/xsk_buff_pool.c
samples/fprobe/fprobe_example.c
samples/kprobes/kprobe_example.c
samples/kprobes/kretprobe_example.c
scripts/Makefile.lib
scripts/Makefile.modinst
scripts/Makefile.vmlinux_o
scripts/clang-tools/gen_compile_commands.py
security/Kconfig
security/integrity/evm/evm_crypto.c
security/integrity/ima/ima_appraise.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_efi.c
security/integrity/ima/ima_template_lib.c
sound/pci/cs46xx/cs46xx.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_realtek.c
sound/soc/codecs/ak4613.c
sound/soc/codecs/arizona.c
sound/soc/codecs/cs35l41-lib.c
sound/soc/codecs/cs35l41.c
sound/soc/codecs/cs47l15.c
sound/soc/codecs/cs47l92.c
sound/soc/codecs/madera.c
sound/soc/codecs/max98373-sdw.c
sound/soc/codecs/max98396.c
sound/soc/codecs/rt1308-sdw.c
sound/soc/codecs/rt1316-sdw.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/rt5682-sdw.c
sound/soc/codecs/rt700-sdw.c
sound/soc/codecs/rt700.c
sound/soc/codecs/rt711-sdca-sdw.c
sound/soc/codecs/rt711-sdca.c
sound/soc/codecs/rt711-sdw.c
sound/soc/codecs/rt711.c
sound/soc/codecs/rt715-sdca-sdw.c
sound/soc/codecs/rt715-sdw.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sgtl5000.h
sound/soc/codecs/tas2764.c
sound/soc/codecs/tas2764.h
sound/soc/codecs/tlv320adcx140.c
sound/soc/codecs/wcd9335.c
sound/soc/codecs/wcd938x.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8998.c
sound/soc/codecs/wm_adsp.c
sound/soc/generic/audio-graph-card2.c
sound/soc/intel/avs/topology.c
sound/soc/intel/boards/bytcr_wm5102.c
sound/soc/intel/boards/sof_rt5682.c
sound/soc/intel/boards/sof_sdw.c
sound/soc/intel/skylake/skl-nhlt.c
sound/soc/qcom/qdsp6/q6apm-dai.c
sound/soc/qcom/qdsp6/q6apm.c
sound/soc/rockchip/rockchip_i2s.c
sound/soc/soc-dapm.c
sound/soc/soc-ops.c
sound/soc/sof/intel/hda-dsp.c
sound/soc/sof/intel/hda-loader.c
sound/soc/sof/intel/hda-pcm.c
sound/soc/sof/intel/hda-stream.c
sound/soc/sof/intel/hda.h
sound/soc/sof/ipc3-topology.c
sound/soc/sof/mediatek/mt8186/mt8186.c
sound/soc/sof/pm.c
sound/soc/sof/sof-priv.h
sound/soc/ti/omap-mcbsp-priv.h
sound/soc/ti/omap-mcbsp-st.c
sound/soc/ti/omap-mcbsp.c
sound/usb/quirks-table.h
sound/usb/quirks.c
tools/arch/x86/include/asm/msr-index.h
tools/include/linux/objtool.h
tools/include/uapi/linux/bpf.h
tools/objtool/arch/x86/decode.c
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/arch.h
tools/objtool/include/objtool/builtin.h
tools/objtool/include/objtool/check.h
tools/objtool/include/objtool/elf.h
tools/objtool/include/objtool/objtool.h
tools/objtool/objtool.c
tools/testing/selftests/bpf/progs/dynptr_fail.c
tools/testing/selftests/bpf/progs/dynptr_success.c
tools/testing/selftests/bpf/verifier/jmp32.c
tools/testing/selftests/bpf/verifier/jump.c
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/Makefile
tools/testing/selftests/net/fib_nexthop_nongw.sh [new file with mode: 0755]
tools/testing/selftests/net/forwarding/Makefile
tools/testing/selftests/net/forwarding/lib.sh
tools/testing/selftests/net/mptcp/Makefile
tools/testing/selftests/net/mptcp/pm_nl_ctl.c
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/net/udpgro.sh
tools/testing/selftests/net/udpgro_bench.sh
tools/testing/selftests/net/udpgro_frglist.sh
tools/testing/selftests/net/udpgro_fwd.sh
tools/testing/selftests/net/veth.sh
tools/testing/selftests/wireguard/qemu/Makefile
tools/testing/selftests/wireguard/qemu/arch/arm.config
tools/testing/selftests/wireguard/qemu/arch/armeb.config
tools/testing/selftests/wireguard/qemu/arch/i686.config
tools/testing/selftests/wireguard/qemu/arch/m68k.config
tools/testing/selftests/wireguard/qemu/arch/mips.config
tools/testing/selftests/wireguard/qemu/arch/mipsel.config
tools/testing/selftests/wireguard/qemu/arch/powerpc.config
tools/testing/selftests/wireguard/qemu/arch/x86_64.config
tools/testing/selftests/wireguard/qemu/init.c

index 2ed1cf8..13e4f50 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -64,6 +64,9 @@ Bart Van Assche <bvanassche@acm.org> <bart.vanassche@sandisk.com>
 Bart Van Assche <bvanassche@acm.org> <bart.vanassche@wdc.com>
 Ben Gardner <bgardner@wabtec.com>
 Ben M Cahill <ben.m.cahill@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <ben@bwidawsk.net>
+Ben Widawsky <bwidawsk@kernel.org> <ben.widawsky@intel.com>
+Ben Widawsky <bwidawsk@kernel.org> <benjamin.widawsky@intel.com>
 Björn Steinbrink <B.Steinbrink@gmx.de>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@gmail.com>
 Björn Töpel <bjorn@kernel.org> <bjorn.topel@intel.com>
diff --git a/CREDITS b/CREDITS
index 7e85a53..40d3c65 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -627,6 +627,10 @@ S: 48287 Sawleaf
 S: Fremont, California 94539
 S: USA
 
+N: Tomas Cech
+E: sleep_walker@suse.com
+D: arm/palm treo support
+
 N: Florent Chabaud
 E: florent.chabaud@polytechnique.org
 D: software suspend
index 2522b11..f2d26cb 100644 (file)
 
        retain_initrd   [RAM] Keep initrd memory after extraction
 
+       retbleed=       [X86] Control mitigation of RETBleed (Arbitrary
+                       Speculative Code Execution with Return Instructions)
+                       vulnerability.
+
+                       off          - no mitigation
+                       auto         - automatically select a migitation
+                       auto,nosmt   - automatically select a mitigation,
+                                      disabling SMT if necessary for
+                                      the full mitigation (only on Zen1
+                                      and older without STIBP).
+                       ibpb         - mitigate short speculation windows on
+                                      basic block boundaries too. Safe, highest
+                                      perf impact.
+                       unret        - force enable untrained return thunks,
+                                      only effective on AMD f15h-f17h
+                                      based systems.
+                       unret,nosmt  - like unret, will disable SMT when STIBP
+                                      is not available.
+
+                       Selecting 'auto' will choose a mitigation method at run
+                       time according to the CPU.
+
+                       Not specifying this option is equivalent to retbleed=auto.
+
        rfkill.default_state=
                0       "airplane mode".  All wifi, bluetooth, wimax, gps, fm,
                        etc. communication is blocked by default.
                        eibrs             - enhanced IBRS
                        eibrs,retpoline   - enhanced IBRS + Retpolines
                        eibrs,lfence      - enhanced IBRS + LFENCE
+                       ibrs              - use IBRS to protect kernel
 
                        Not specifying this option is equivalent to
                        spectre_v2=auto.
index d6b3f94..0793c40 100644 (file)
@@ -223,7 +223,7 @@ Module Loading
 Inter Module support
 --------------------
 
-Refer to the file kernel/module.c for more information.
+Refer to the files in kernel/module/ for more information.
 
 Hardware Interfaces
 ===================
index 5ad9e0a..12e4aec 100644 (file)
@@ -51,8 +51,8 @@ namespace ``USB_STORAGE``, use::
 The corresponding ksymtab entry struct ``kernel_symbol`` will have the member
 ``namespace`` set accordingly. A symbol that is exported without a namespace will
 refer to ``NULL``. There is no default namespace if none is defined. ``modpost``
-and kernel/module.c make use the namespace at build time or module load time,
-respectively.
+and kernel/module/main.c make use the namespace at build time or module load
+time, respectively.
 
 2.2 Using the DEFAULT_SYMBOL_NAMESPACE define
 =============================================
index c388ae5..c9c346e 100644 (file)
@@ -94,6 +94,7 @@ if:
           - allwinner,sun8i-a83t-display-engine
           - allwinner,sun8i-r40-display-engine
           - allwinner,sun9i-a80-display-engine
+          - allwinner,sun20i-d1-display-engine
           - allwinner,sun50i-a64-display-engine
 
 then:
index ff0a5c5..e712444 100644 (file)
@@ -67,7 +67,7 @@ if:
 then:
   properties:
     clocks:
-      maxItems: 2
+      minItems: 2
 
   required:
     - clock-names
index 8cd0adb..7029cb1 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Atheros ath9k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Toke Høiland-Jørgensen <toke@toke.dk>
 
 description: |
   This node provides properties for configuring the ath9k wireless device.
index 8c01fdb..a677b05 100644 (file)
@@ -9,7 +9,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Qualcomm Technologies ath11k wireless devices Generic Binding
 
 maintainers:
-  - Kalle Valo <kvalo@codeaurora.org>
+  - Kalle Valo <kvalo@kernel.org>
 
 description: |
   These are dt entries for Qualcomm Technologies, Inc. IEEE 802.11ax
index e9a5330..ef18a57 100644 (file)
@@ -25,12 +25,12 @@ properties:
       - qcom,sc7280-lpass-cpu
 
   reg:
-    minItems: 2
+    minItems: 1
     maxItems: 6
     description: LPAIF core registers
 
   reg-names:
-    minItems: 2
+    minItems: 1
     maxItems: 6
 
   clocks:
@@ -42,12 +42,12 @@ properties:
     maxItems: 10
 
   interrupts:
-    minItems: 2
+    minItems: 1
     maxItems: 4
     description: LPAIF DMA buffer interrupt
 
   interrupt-names:
-    minItems: 2
+    minItems: 1
     maxItems: 4
 
   qcom,adsp:
index 4d19b19..73a4176 100644 (file)
@@ -301,7 +301,7 @@ through which it can issue requests and negotiate::
                void (*issue_read)(struct netfs_io_subrequest *subreq);
                bool (*is_still_valid)(struct netfs_io_request *rreq);
                int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                        struct folio *folio, void **_fsdata);
+                                        struct folio **foliop, void **_fsdata);
                void (*done)(struct netfs_io_request *rreq);
        };
 
@@ -381,8 +381,10 @@ The operations are as follows:
    allocated/grabbed the folio to be modified to allow the filesystem to flush
    conflicting state before allowing it to be modified.
 
-   It should return 0 if everything is now fine, -EAGAIN if the folio should be
-   regrabbed and any other error code to abort the operation.
+   It may unlock and discard the folio it was given and set the caller's folio
+   pointer to NULL.  It should return 0 if everything is now fine (``*foliop``
+   left set) or the op should be retried (``*foliop`` cleared) and any other
+   error code to abort the operation.
 
  * ``done``
 
index 7da6c30..316cfd8 100644 (file)
@@ -466,6 +466,10 @@ overlay filesystem and the value of st_ino for filesystem objects may not be
 persistent and could change even while the overlay filesystem is mounted, as
 summarized in the `Inode properties`_ table above.
 
+4) "idmapped mounts"
+When the upper or lower layers are idmapped mounts overlayfs will be mounted
+without support for POSIX Access Control Lists (ACLs). This limitation will
+eventually be lifted.
 
 Changes to underlying filesystems
 ---------------------------------
index dbe9b40..7347638 100644 (file)
@@ -210,11 +210,11 @@ module->symtab.
 =====================================
 Normally, a stripped down copy of a module's symbol table (containing only
 "core" symbols) is made available through module->symtab (See layout_symtab()
-in kernel/module.c). For livepatch modules, the symbol table copied into memory
-on module load must be exactly the same as the symbol table produced when the
-patch module was compiled. This is because the relocations in each livepatch
-relocation section refer to their respective symbols with their symbol indices,
-and the original symbol indices (and thus the symtab ordering) must be
+in kernel/module/kallsyms.c). For livepatch modules, the symbol table copied
+into memory on module load must be exactly the same as the symbol table produced
+when the patch module was compiled. This is because the relocations in each
+livepatch relocation section refer to their respective symbols with their symbol
+indices, and the original symbol indices (and thus the symtab ordering) must be
 preserved in order for apply_relocate_add() to find the right symbol.
 
 For example, take this particular rela from a livepatch module:::
index 9f41961..b3a534e 100644 (file)
@@ -1085,7 +1085,7 @@ cipso_cache_enable - BOOLEAN
 cipso_cache_bucket_size - INTEGER
        The CIPSO label cache consists of a fixed size hash table with each
        hash bucket containing a number of cache entries.  This variable limits
-       the number of entries in each hash bucket; the larger the value the
+       the number of entries in each hash bucket; the larger the value is, the
        more CIPSO label mappings that can be cached.  When the number of
        entries in a given hash bucket reaches this limit adding new entries
        causes the oldest entry in the bucket to be removed to make room.
@@ -1179,7 +1179,7 @@ ip_autobind_reuse - BOOLEAN
        option should only be set by experts.
        Default: 0
 
-ip_dynaddr - BOOLEAN
+ip_dynaddr - INTEGER
        If set non-zero, enables support for dynamic addresses.
        If set to a non-zero value larger than 1, a kernel log
        message will be printed when dynamic address rewriting
index c456b52..d140070 100644 (file)
@@ -6,6 +6,15 @@
 netdev FAQ
 ==========
 
+tl;dr
+-----
+
+ - designate your patch to a tree - ``[PATCH net]`` or ``[PATCH net-next]``
+ - for fixes the ``Fixes:`` tag is required, regardless of the tree
+ - don't post large series (> 15 patches), break them up
+ - don't repost your patches within one 24h period
+ - reverse xmas tree
+
 What is netdev?
 ---------------
 It is a mailing list for all network-related Linux stuff.  This
@@ -136,6 +145,20 @@ it to the maintainer to figure out what is the most recent and current
 version that should be applied. If there is any doubt, the maintainer
 will reply and ask what should be done.
 
+How do I divide my work into patches?
+-------------------------------------
+
+Put yourself in the shoes of the reviewer. Each patch is read separately
+and therefore should constitute a comprehensible step towards your stated
+goal.
+
+Avoid sending series longer than 15 patches. Larger series takes longer
+to review as reviewers will defer looking at it until they find a large
+chunk of time. A small series can be reviewed in a short time, so Maintainers
+just do it. As a result, a sequence of smaller series gets merged quicker and
+with better review coverage. Re-posting large series also increases the mailing
+list traffic.
+
 I made changes to only a few patches in a patch series should I resend only those changed?
 ------------------------------------------------------------------------------------------
 No, please resend the entire patch series and make sure you do number your
@@ -183,6 +206,19 @@ it is requested that you make it look like this::
    * another line of text
    */
 
+What is "reverse xmas tree"?
+----------------------------
+
+Netdev has a convention for ordering local variables in functions.
+Order the variable declaration lines longest to shortest, e.g.::
+
+  struct scatterlist *sg;
+  struct sk_buff *skb;
+  int err, i;
+
+If there are dependencies between the variables preventing the ordering
+move the initialization out of line.
+
 I am working in existing code which uses non-standard formatting. Which formatting should I use?
 ------------------------------------------------------------------------------------------------
 Make your code follow the most recent guidelines, so that eventually all code
index 009b07e..bf84313 100644 (file)
@@ -10,7 +10,7 @@ AC97
 ====
 
 AC97 is a five wire interface commonly found on many PC sound cards. It is
-now also popular in many portable devices. This DAI has a reset line and time
+now also popular in many portable devices. This DAI has a RESET line and time
 multiplexes its data on its SDATA_OUT (playback) and SDATA_IN (capture) lines.
 The bit clock (BCLK) is always driven by the CODEC (usually 12.288MHz) and the
 frame (FRAME) (usually 48kHz) is always driven by the controller. Each AC97
index 42f5d04..0f68988 100644 (file)
@@ -50,9 +50,9 @@ Di conseguenza, nella tabella dei simboli del kernel ci sarà una voce
 rappresentata dalla struttura ``kernel_symbol`` che avrà il campo
 ``namespace`` (spazio dei nomi) impostato. Un simbolo esportato senza uno spazio
 dei nomi avrà questo campo impostato a ``NULL``. Non esiste uno spazio dei nomi
-di base. Il programma ``modpost`` e il codice in kernel/module.c usano lo spazio
-dei nomi, rispettivamente, durante la compilazione e durante il caricamento
-di un modulo.
+di base. Il programma ``modpost`` e il codice in kernel/module/main.c usano lo
+spazio dei nomi, rispettivamente, durante la compilazione e durante il
+caricamento di un modulo.
 
 2.2 Usare il simbolo di preprocessore DEFAULT_SYMBOL_NAMESPACE
 ==============================================================
index e45fe80..962d31d 100644 (file)
@@ -224,7 +224,7 @@ kernel/kmod.c
 模块接口支持
 ------------
 
-更多信息请参考文件kernel/module.c
+更多信息请参阅kernel/module/目录下的文件
 
 硬件接口
 ========
index 6abf7ed..bb16f06 100644 (file)
@@ -52,7 +52,7 @@
 
 相应的 ksymtab 条目结构体 ``kernel_symbol`` 将有相应的成员 ``命名空间`` 集。
 导出时未指明命名空间的符号将指向 ``NULL`` 。如果没有定义命名空间,则默认没有。
-``modpost`` 和kernel/module.c分别在构建时或模块加载时使用名称空间。
+``modpost`` 和kernel/module/main.c分别在构建时或模块加载时使用名称空间。
 
 2.2 使用DEFAULT_SYMBOL_NAMESPACE定义
 ====================================
index 11e00a4..6e090fb 100644 (file)
@@ -5657,6 +5657,7 @@ by a string of size ``name_size``.
        #define KVM_STATS_UNIT_BYTES            (0x1 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_SECONDS          (0x2 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_CYCLES           (0x3 << KVM_STATS_UNIT_SHIFT)
+       #define KVM_STATS_UNIT_BOOLEAN          (0x4 << KVM_STATS_UNIT_SHIFT)
        #define KVM_STATS_UNIT_MAX              KVM_STATS_UNIT_CYCLES
 
        #define KVM_STATS_BASE_SHIFT            8
@@ -5702,14 +5703,13 @@ Bits 0-3 of ``flags`` encode the type:
     by the ``hist_param`` field. The range of the Nth bucket (1 <= N < ``size``)
     is [``hist_param``*(N-1), ``hist_param``*N), while the range of the last
     bucket is [``hist_param``*(``size``-1), +INF). (+INF means positive infinity
-    value.) The bucket value indicates how many samples fell in the bucket's range.
+    value.)
   * ``KVM_STATS_TYPE_LOG_HIST``
     The statistic is reported as a logarithmic histogram. The number of
     buckets is specified by the ``size`` field. The range of the first bucket is
     [0, 1), while the range of the last bucket is [pow(2, ``size``-2), +INF).
     Otherwise, The Nth bucket (1 < N < ``size``) covers
-    [pow(2, N-2), pow(2, N-1)). The bucket value indicates how many samples fell
-    in the bucket's range.
+    [pow(2, N-2), pow(2, N-1)).
 
 Bits 4-7 of ``flags`` encode the unit:
 
@@ -5724,6 +5724,15 @@ Bits 4-7 of ``flags`` encode the unit:
     It indicates that the statistics data is used to measure time or latency.
   * ``KVM_STATS_UNIT_CYCLES``
     It indicates that the statistics data is used to measure CPU clock cycles.
+  * ``KVM_STATS_UNIT_BOOLEAN``
+    It indicates that the statistic will always be either 0 or 1.  Boolean
+    statistics of "peak" type will never go back from 1 to 0.  Boolean
+    statistics can be linear histograms (with two buckets) but not logarithmic
+    histograms.
+
+Note that, in the case of histograms, the unit applies to the bucket
+ranges, while the bucket value indicates how many samples fell in the
+bucket's range.
 
 Bits 8-11 of ``flags``, together with ``exponent``, encode the scale of the
 unit:
@@ -5746,7 +5755,7 @@ the corresponding statistics data.
 
 The ``bucket_size`` field is used as a parameter for histogram statistics data.
 It is only used by linear histogram statistics data, specifying the size of a
-bucket.
+bucket in the unit expressed by bits 4-11 of ``flags`` together with ``exponent``.
 
 The ``name`` field is the name string of the statistics data. The name string
 starts at the end of ``struct kvm_stats_desc``.  The maximum length including
index 66bffb2..651616e 100644 (file)
@@ -426,7 +426,6 @@ F:  drivers/acpi/*thermal*
 ACPI VIOT DRIVER
 M:     Jean-Philippe Brucker <jean-philippe@linaro.org>
 L:     linux-acpi@vger.kernel.org
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/acpi/viot.c
@@ -960,7 +959,6 @@ F:  drivers/video/fbdev/geode/
 AMD IOMMU (AMD-VI)
 M:     Joerg Roedel <joro@8bytes.org>
 R:     Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -1040,6 +1038,7 @@ F:        arch/arm64/boot/dts/amd/
 
 AMD XGBE DRIVER
 M:     Tom Lendacky <thomas.lendacky@amd.com>
+M:     "Shyam Sundar S K" <Shyam-sundar.S-k@amd.com>
 L:     netdev@vger.kernel.org
 S:     Supported
 F:     arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi
@@ -2499,10 +2498,8 @@ F:       drivers/power/reset/oxnas-restart.c
 N:     oxnas
 
 ARM/PALM TREO SUPPORT
-M:     Tomas Cech <sleep_walker@suse.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-S:     Maintained
-W:     http://hackndev.com
+S:     Orphan
 F:     arch/arm/mach-pxa/palmtreo.*
 
 ARM/PALMTX,PALMT5,PALMLD,PALMTE2,PALMTC SUPPORT
@@ -2540,6 +2537,7 @@ W:        http://www.armlinux.org.uk/
 ARM/QUALCOMM SUPPORT
 M:     Andy Gross <agross@kernel.org>
 M:     Bjorn Andersson <bjorn.andersson@linaro.org>
+R:     Konrad Dybcio <konrad.dybcio@somainline.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux.git
@@ -3617,16 +3615,18 @@ S:      Maintained
 F:     Documentation/devicetree/bindings/iio/accel/bosch,bma400.yaml
 F:     drivers/iio/accel/bma400*
 
-BPF (Safe dynamic programs and tools)
+BPF [GENERAL] (Safe Dynamic Programs and Tools)
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Andrii Nakryiko <andrii@kernel.org>
-R:     Martin KaFai Lau <kafai@fb.com>
-R:     Song Liu <songliubraving@fb.com>
+R:     Martin KaFai Lau <martin.lau@linux.dev>
+R:     Song Liu <song@kernel.org>
 R:     Yonghong Song <yhs@fb.com>
 R:     John Fastabend <john.fastabend@gmail.com>
 R:     KP Singh <kpsingh@kernel.org>
-L:     netdev@vger.kernel.org
+R:     Stanislav Fomichev <sdf@google.com>
+R:     Hao Luo <haoluo@google.com>
+R:     Jiri Olsa <jolsa@kernel.org>
 L:     bpf@vger.kernel.org
 S:     Supported
 W:     https://bpf.io/
@@ -3658,12 +3658,9 @@ F:       scripts/pahole-version.sh
 F:     tools/bpf/
 F:     tools/lib/bpf/
 F:     tools/testing/selftests/bpf/
-N:     bpf
-K:     bpf
 
 BPF JIT for ARM
 M:     Shubham Bansal <illusionist.neo@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/arm/net/
@@ -3672,7 +3669,6 @@ BPF JIT for ARM64
 M:     Daniel Borkmann <daniel@iogearbox.net>
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Zi Shen Lim <zlim.lnx@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/arm64/net/
@@ -3680,14 +3676,12 @@ F:      arch/arm64/net/
 BPF JIT for MIPS (32-BIT AND 64-BIT)
 M:     Johan Almbladh <johan.almbladh@anyfinetworks.com>
 M:     Paul Burton <paulburton@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/mips/net/
 
 BPF JIT for NFP NICs
 M:     Jakub Kicinski <kuba@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     drivers/net/ethernet/netronome/nfp/bpf/
@@ -3695,7 +3689,6 @@ F:        drivers/net/ethernet/netronome/nfp/bpf/
 BPF JIT for POWERPC (32-BIT AND 64-BIT)
 M:     Naveen N. Rao <naveen.n.rao@linux.ibm.com>
 M:     Michael Ellerman <mpe@ellerman.id.au>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/powerpc/net/
@@ -3703,7 +3696,6 @@ F:        arch/powerpc/net/
 BPF JIT for RISC-V (32-bit)
 M:     Luke Nelson <luke.r.nels@gmail.com>
 M:     Xi Wang <xi.wang@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3711,7 +3703,6 @@ X:        arch/riscv/net/bpf_jit_comp64.c
 
 BPF JIT for RISC-V (64-bit)
 M:     Björn Töpel <bjorn@kernel.org>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     arch/riscv/net/
@@ -3721,7 +3712,6 @@ BPF JIT for S390
 M:     Ilya Leoshkevich <iii@linux.ibm.com>
 M:     Heiko Carstens <hca@linux.ibm.com>
 M:     Vasily Gorbik <gor@linux.ibm.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/s390/net/
@@ -3729,14 +3719,12 @@ X:      arch/s390/net/pnet.c
 
 BPF JIT for SPARC (32-BIT AND 64-BIT)
 M:     David S. Miller <davem@davemloft.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/sparc/net/
 
 BPF JIT for X86 32-BIT
 M:     Wang YanQing <udknight@gmail.com>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Odd Fixes
 F:     arch/x86/net/bpf_jit_comp32.c
@@ -3744,13 +3732,60 @@ F:      arch/x86/net/bpf_jit_comp32.c
 BPF JIT for X86 64-BIT
 M:     Alexei Starovoitov <ast@kernel.org>
 M:     Daniel Borkmann <daniel@iogearbox.net>
-L:     netdev@vger.kernel.org
 L:     bpf@vger.kernel.org
 S:     Supported
 F:     arch/x86/net/
 X:     arch/x86/net/bpf_jit_comp32.c
 
-BPF LSM (Security Audit and Enforcement using BPF)
+BPF [CORE]
+M:     Alexei Starovoitov <ast@kernel.org>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/verifier.c
+F:     kernel/bpf/tnum.c
+F:     kernel/bpf/core.c
+F:     kernel/bpf/syscall.c
+F:     kernel/bpf/dispatcher.c
+F:     kernel/bpf/trampoline.c
+F:     include/linux/bpf*
+F:     include/linux/filter.h
+
+BPF [BTF]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/btf.c
+F:     include/linux/btf*
+
+BPF [TRACING]
+M:     Song Liu <song@kernel.org>
+R:     Jiri Olsa <jolsa@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/trace/bpf_trace.c
+F:     kernel/bpf/stackmap.c
+
+BPF [NETWORKING] (tc BPF, sock_addr)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+M:     Daniel Borkmann <daniel@iogearbox.net>
+R:     John Fastabend <john.fastabend@gmail.com>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     net/core/filter.c
+F:     net/sched/act_bpf.c
+F:     net/sched/cls_bpf.c
+
+BPF [NETWORKING] (struct_ops, reuseport)
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+L:     netdev@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/bpf_struct*
+
+BPF [SECURITY & LSM] (Security Audit and Enforcement using BPF)
 M:     KP Singh <kpsingh@kernel.org>
 R:     Florent Revest <revest@chromium.org>
 R:     Brendan Jackman <jackmanb@chromium.org>
@@ -3761,7 +3796,27 @@ F:       include/linux/bpf_lsm.h
 F:     kernel/bpf/bpf_lsm.c
 F:     security/bpf/
 
-BPF L7 FRAMEWORK
+BPF [STORAGE & CGROUPS]
+M:     Martin KaFai Lau <martin.lau@linux.dev>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/cgroup.c
+F:     kernel/bpf/*storage.c
+F:     kernel/bpf/bpf_lru*
+
+BPF [RINGBUF]
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/ringbuf.c
+
+BPF [ITERATOR]
+M:     Yonghong Song <yhs@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     kernel/bpf/*iter.c
+
+BPF [L7 FRAMEWORK] (sockmap)
 M:     John Fastabend <john.fastabend@gmail.com>
 M:     Jakub Sitnicki <jakub@cloudflare.com>
 L:     netdev@vger.kernel.org
@@ -3774,13 +3829,31 @@ F:      net/ipv4/tcp_bpf.c
 F:     net/ipv4/udp_bpf.c
 F:     net/unix/unix_bpf.c
 
-BPFTOOL
+BPF [LIBRARY] (libbpf)
+M:     Andrii Nakryiko <andrii@kernel.org>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/lib/bpf/
+
+BPF [TOOLING] (bpftool)
 M:     Quentin Monnet <quentin@isovalent.com>
 L:     bpf@vger.kernel.org
 S:     Maintained
 F:     kernel/bpf/disasm.*
 F:     tools/bpf/bpftool/
 
+BPF [SELFTESTS] (Test Runners & Infrastructure)
+M:     Andrii Nakryiko <andrii@kernel.org>
+R:     Mykola Lysenko <mykolal@fb.com>
+L:     bpf@vger.kernel.org
+S:     Maintained
+F:     tools/testing/selftests/bpf/
+
+BPF [MISC]
+L:     bpf@vger.kernel.org
+S:     Odd Fixes
+K:     (?:\b|_)bpf(?:\b|_)
+
 BROADCOM B44 10/100 ETHERNET DRIVER
 M:     Michael Chan <michael.chan@broadcom.com>
 L:     netdev@vger.kernel.org
@@ -5027,7 +5100,7 @@ COMPUTE EXPRESS LINK (CXL)
 M:     Alison Schofield <alison.schofield@intel.com>
 M:     Vishal Verma <vishal.l.verma@intel.com>
 M:     Ira Weiny <ira.weiny@intel.com>
-M:     Ben Widawsky <ben.widawsky@intel.com>
+M:     Ben Widawsky <bwidawsk@kernel.org>
 M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-cxl@vger.kernel.org
 S:     Maintained
@@ -5979,7 +6052,6 @@ DMA MAPPING HELPERS
 M:     Christoph Hellwig <hch@lst.de>
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
 R:     Robin Murphy <robin.murphy@arm.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -5992,7 +6064,6 @@ F:        kernel/dma/
 
 DMA MAPPING BENCHMARK
 M:     Xiang Chen <chenxiang66@hisilicon.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 F:     kernel/dma/map_benchmark.c
 F:     tools/testing/selftests/dma/
@@ -7577,7 +7648,6 @@ F:        drivers/gpu/drm/exynos/exynos_dp*
 
 EXYNOS SYSMMU (IOMMU) driver
 M:     Marek Szyprowski <m.szyprowski@samsung.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 F:     drivers/iommu/exynos-iommu.c
@@ -9836,7 +9906,10 @@ INTEL ASoC DRIVERS
 M:     Cezary Rojewski <cezary.rojewski@intel.com>
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <liam.r.girdwood@linux.intel.com>
-M:     Jie Yang <yang.jie@linux.intel.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
+M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
+M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/intel/
@@ -9999,7 +10072,6 @@ F:       drivers/hid/intel-ish-hid/
 INTEL IOMMU (VT-d)
 M:     David Woodhouse <dwmw2@infradead.org>
 M:     Lu Baolu <baolu.lu@linux.intel.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -10379,7 +10451,6 @@ F:      include/linux/iomap.h
 IOMMU DRIVERS
 M:     Joerg Roedel <joro@8bytes.org>
 M:     Will Deacon <will@kernel.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
@@ -12539,7 +12610,6 @@ F:      drivers/i2c/busses/i2c-mt65xx.c
 
 MEDIATEK IOMMU DRIVER
 M:     Yong Wu <yong.wu@mediatek.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
@@ -14292,7 +14362,8 @@ S:      Maintained
 F:     drivers/net/phy/nxp-c45-tja11xx.c
 
 NXP FSPI DRIVER
-M:     Ashish Kumar <ashish.kumar@nxp.com>
+M:     Han Xu <han.xu@nxp.com>
+M:     Haibo Chen <haibo.chen@nxp.com>
 R:     Yogesh Gaur <yogeshgaur.83@gmail.com>
 L:     linux-spi@vger.kernel.org
 S:     Maintained
@@ -15788,7 +15859,7 @@ F:      drivers/pinctrl/freescale/
 PIN CONTROLLER - INTEL
 M:     Mika Westerberg <mika.westerberg@linux.intel.com>
 M:     Andy Shevchenko <andy@kernel.org>
-S:     Maintained
+S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/pinctrl/intel.git
 F:     drivers/pinctrl/intel/
 
@@ -16310,7 +16381,7 @@ F:      drivers/crypto/qat/
 
 QCOM AUDIO (ASoC) DRIVERS
 M:     Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
-M:     Banajit Goswami <bgoswami@codeaurora.org>
+M:     Banajit Goswami <bgoswami@quicinc.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
 F:     sound/soc/codecs/lpass-va-macro.c
@@ -16591,7 +16662,6 @@ F:      drivers/i2c/busses/i2c-qcom-cci.c
 
 QUALCOMM IOMMU
 M:     Rob Clark <robdclark@gmail.com>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
@@ -17203,12 +17273,15 @@ N:    riscv
 K:     riscv
 
 RISC-V/MICROCHIP POLARFIRE SOC SUPPORT
-M:     Lewis Hanly <lewis.hanly@microchip.com>
 M:     Conor Dooley <conor.dooley@microchip.com>
+M:     Daire McNamara <daire.mcnamara@microchip.com>
 L:     linux-riscv@lists.infradead.org
 S:     Supported
 F:     arch/riscv/boot/dts/microchip/
+F:     drivers/char/hw_random/mpfs-rng.c
+F:     drivers/clk/microchip/clk-mpfs.c
 F:     drivers/mailbox/mailbox-mpfs.c
+F:     drivers/pci/controller/pcie-microchip-host.c
 F:     drivers/soc/microchip/
 F:     include/soc/microchip/mpfs.h
 
@@ -18105,6 +18178,7 @@ F:      drivers/misc/sgi-xp/
 
 SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Karsten Graul <kgraul@linux.ibm.com>
+M:     Wenjia Zhang <wenjia@linux.ibm.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
 W:     http://www.ibm.com/developerworks/linux/linux390/
@@ -18737,8 +18811,10 @@ F:     sound/soc/
 SOUND - SOUND OPEN FIRMWARE (SOF) DRIVERS
 M:     Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
 M:     Liam Girdwood <lgirdwood@gmail.com>
+M:     Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
+M:     Bard Liao <yung-chuan.liao@linux.intel.com>
 M:     Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
-M:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
+R:     Kai Vehmanen <kai.vehmanen@linux.intel.com>
 M:     Daniel Baluta <daniel.baluta@nxp.com>
 L:     sound-open-firmware@alsa-project.org (moderated for non-subscribers)
 S:     Supported
@@ -19217,7 +19293,6 @@ F:      arch/x86/boot/video*
 
 SWIOTLB SUBSYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 W:     http://git.infradead.org/users/hch/dma-mapping.git
@@ -21893,7 +21968,6 @@ XEN SWIOTLB SUBSYSTEM
 M:     Juergen Gross <jgross@suse.com>
 M:     Stefano Stabellini <sstabellini@kernel.org>
 L:     xen-devel@lists.xenproject.org (moderated for non-subscribers)
-L:     iommu@lists.linux-foundation.org
 L:     iommu@lists.linux.dev
 S:     Supported
 F:     arch/x86/xen/*swiotlb*
index 990d2ee..faa4880 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 5
 PATCHLEVEL = 19
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Superb Owl
 
 # *DOCUMENTATION*
index 7719ea3..81ccb06 100644 (file)
                status = "okay";
 
                eeprom@53 {
-                       compatible = "atmel,24c32";
+                       compatible = "atmel,24c02";
                        reg = <0x53>;
                        pagesize = <16>;
-                       size = <128>;
                        status = "okay";
                };
        };
index 806eb1d..164201a 100644 (file)
        status = "okay";
 
        eeprom@50 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x50>;
                pagesize = <16>;
                status = "okay";
        };
 
        eeprom@52 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x52>;
                pagesize = <16>;
                status = "disabled";
        };
 
        eeprom@53 {
-               compatible = "atmel,24c32";
+               compatible = "atmel,24c02";
                reg = <0x53>;
                pagesize = <16>;
                status = "disabled";
index fded07f..d6ba4b2 100644 (file)
                reg = <0x28>;
                #gpio-cells = <2>;
                gpio-controller;
-               ngpio = <32>;
+               ngpios = <62>;
        };
 
        sgtl5000: codec@a {
index 15621e0..2c3ae71 100644 (file)
        atmel_mxt_ts: touchscreen@4a {
                compatible = "atmel,maxtouch";
                pinctrl-names = "default";
-               pinctrl-0 = <&pinctrl_atmel_conn>;
+               pinctrl-0 = <&pinctrl_atmel_conn &pinctrl_atmel_snvs_conn>;
                reg = <0x4a>;
                interrupt-parent = <&gpio5>;
                interrupts = <4 IRQ_TYPE_EDGE_FALLING>;       /* SODIMM 107 / INT */
        pinctrl_atmel_conn: atmelconngrp {
                fsl,pins = <
                        MX6UL_PAD_JTAG_MOD__GPIO1_IO10          0xb0a0  /* SODIMM 106 */
-                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
                >;
        };
 
 };
 
 &iomuxc_snvs {
+       pinctrl_atmel_snvs_conn: atmelsnvsconngrp {
+               fsl,pins = <
+                       MX6ULL_PAD_SNVS_TAMPER4__GPIO5_IO04     0xb0a0  /* SODIMM 107 */
+               >;
+       };
+
        pinctrl_snvs_gpio1: snvsgpio1grp {
                fsl,pins = <
                        MX6ULL_PAD_SNVS_TAMPER6__GPIO5_IO06     0x110a0 /* SODIMM 93 */
index c6b3206..21b509c 100644 (file)
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
+       no-1-8-v;
        non-removable;
-       cap-sd-highspeed;
-       sd-uhs-ddr50;
-       mmc-ddr-1_8v;
        vmmc-supply = <&reg_wifi>;
        enable-sdio-wakeup;
        status = "okay";
index 4cab1b3..725dcf7 100644 (file)
 
        phy4: ethernet-phy@5 {
                reg = <5>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy5: ethernet-phy@6 {
                reg = <6>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy6: ethernet-phy@7 {
                reg = <7>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 
        phy7: ethernet-phy@8 {
                reg = <8>;
-               coma-mode-gpios = <&gpio 37 GPIO_ACTIVE_HIGH>;
+               coma-mode-gpios = <&gpio 37 GPIO_OPEN_DRAIN>;
        };
 };
 
index 814ad0b..c3b8a6d 100644 (file)
                        interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp1_uart2_default>;
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 113 IRQ_TYPE_NONE>;
                        clocks = <&gcc GCC_BLSP2_UART1_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&blsp2_uart1_default>;
+                       pinctrl-1 = <&blsp2_uart1_sleep>;
                        status = "disabled";
                };
 
                        interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_UART4_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&blsp2_uart4_default>;
                        status = "disabled";
                };
 
                        interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
                        clocks = <&gcc GCC_BLSP2_QUP6_I2C_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
                        clock-names = "core", "iface";
+                       pinctrl-names = "default", "sleep";
+                       pinctrl-0 = <&blsp2_i2c6_default>;
+                       pinctrl-1 = <&blsp2_i2c6_sleep>;
                        #address-cells = <1>;
                        #size-cells = <0>;
                };
                                };
                        };
 
-                       blsp1_uart2_active: blsp1-uart2-active {
+                       blsp1_uart2_default: blsp1-uart2-default {
                                rx {
                                        pins = "gpio5";
                                        function = "blsp_uart2";
                                };
                        };
 
-                       blsp2_uart1_active: blsp2-uart1-active {
+                       blsp2_uart1_default: blsp2-uart1-default {
                                tx-rts {
                                        pins = "gpio41", "gpio44";
                                        function = "blsp_uart7";
                                bias-pull-down;
                        };
 
-                       blsp2_uart4_active: blsp2-uart4-active {
+                       blsp2_uart4_default: blsp2-uart4-default {
                                tx-rts {
                                        pins = "gpio53", "gpio56";
                                        function = "blsp_uart10";
                                bias-pull-up;
                        };
 
-                       /* BLSP2_I2C6 info is missing - nobody uses it though? */
+                       blsp2_i2c6_default: blsp2-i2c6-default {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-disable;
+                       };
+
+                       blsp2_i2c6_sleep: blsp2-i2c6-sleep {
+                               pins = "gpio87", "gpio88";
+                               function = "blsp_i2c12";
+                               drive-strength = <2>;
+                               bias-pull-up;
+                       };
 
                        spi8_default: spi8_default {
                                mosi {
index 89c71d4..659a17f 100644 (file)
                                clocks = <&pmc PMC_TYPE_PERIPHERAL 55>, <&pmc PMC_TYPE_GCK 55>;
                                clock-names = "pclk", "gclk";
                                assigned-clocks = <&pmc PMC_TYPE_CORE PMC_I2S1_MUX>;
-                               assigned-parrents = <&pmc PMC_TYPE_GCK 55>;
+                               assigned-clock-parents = <&pmc PMC_TYPE_GCK 55>;
                                status = "disabled";
                        };
 
index e90cf3a..543f24c 100644 (file)
                                reg = <0x16>;
                                #reset-cells = <1>;
                        };
+
+                       scmi_voltd: protocol@17 {
+                               reg = <0x17>;
+
+                               scmi_reguls: regulators {
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       scmi_reg11: reg11@0 {
+                                               reg = <0>;
+                                               regulator-name = "reg11";
+                                               regulator-min-microvolt = <1100000>;
+                                               regulator-max-microvolt = <1100000>;
+                                       };
+
+                                       scmi_reg18: reg18@1 {
+                                               voltd-name = "reg18";
+                                               reg = <1>;
+                                               regulator-name = "reg18";
+                                               regulator-min-microvolt = <1800000>;
+                                               regulator-max-microvolt = <1800000>;
+                                       };
+
+                                       scmi_usb33: usb33@2 {
+                                               reg = <2>;
+                                               regulator-name = "usb33";
+                                               regulator-min-microvolt = <3300000>;
+                                               regulator-max-microvolt = <3300000>;
+                                       };
+                               };
+                       };
                };
        };
 
                };
        };
 };
+
+&reg11 {
+       status = "disabled";
+};
+
+&reg18 {
+       status = "disabled";
+};
+
+&usb33 {
+       status = "disabled";
+};
+
+&usbotg_hs {
+       usb33d-supply = <&scmi_usb33>;
+};
+
+&usbphyc {
+       vdda1v1-supply = <&scmi_reg11>;
+       vdda1v8-supply = <&scmi_reg18>;
+};
+
+/delete-node/ &clk_hse;
+/delete-node/ &clk_hsi;
+/delete-node/ &clk_lse;
+/delete-node/ &clk_lsi;
+/delete-node/ &clk_csi;
index 7fdc324..e04dda5 100644 (file)
                        compatible = "st,stm32-cec";
                        reg = <0x40016000 0x400>;
                        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
-                       clocks = <&rcc CEC_K>, <&clk_lse>;
+                       clocks = <&rcc CEC_K>, <&rcc CEC>;
                        clock-names = "cec", "hdmi-cec";
                        status = "disabled";
                };
                usbh_ohci: usb@5800c000 {
                        compatible = "generic-ohci";
                        reg = <0x5800c000 0x1000>;
-                       clocks = <&rcc USBH>, <&usbphyc>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
                        status = "disabled";
                usbh_ehci: usb@5800d000 {
                        compatible = "generic-ehci";
                        reg = <0x5800d000 0x1000>;
-                       clocks = <&rcc USBH>;
+                       clocks = <&usbphyc>, <&rcc USBH>;
                        resets = <&rcc USBH_R>;
                        interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
                        companion = <&usbh_ohci>;
index 36371d6..e539cc8 100644 (file)
        clocks = <&scmi_clk CK_SCMI_MPU>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
index 03226a5..97e4f94 100644 (file)
@@ -35,6 +35,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
index c1a7927..9cf0a44 100644 (file)
        resets = <&scmi_reset RST_SCMI_CRYP1>;
 };
 
+&dsi {
+       clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
+};
+
 &gpioz {
        clocks = <&scmi_clk CK_SCMI_GPIOZ>;
 };
index 7842384..3b9dd6f 100644 (file)
@@ -36,6 +36,7 @@
 };
 
 &dsi {
+       phy-dsi-supply = <&scmi_reg18>;
        clocks = <&rcc DSI_K>, <&scmi_clk CK_SCMI_HSE>, <&rcc DSI_PX>;
 };
 
index f19ed98..3706216 100644 (file)
        flash@0 {
                #address-cells = <1>;
                #size-cells = <1>;
-               compatible = "mxicy,mx25l1606e", "winbond,w25q128";
+               compatible = "mxicy,mx25l1606e", "jedec,spi-nor";
                reg = <0>;
                spi-max-frequency = <40000000>;
        };
index ca32446..f53086d 100644 (file)
@@ -93,6 +93,7 @@ CONFIG_REGULATOR_FIXED_VOLTAGE=y
 CONFIG_DRM=y
 CONFIG_DRM_PANEL_SEIKO_43WVF1G=y
 CONFIG_DRM_MXSFB=y
+CONFIG_FB=y
 CONFIG_FB_MODE_HELPERS=y
 CONFIG_LCD_CLASS_DEVICE=y
 CONFIG_BACKLIGHT_CLASS_DEVICE=y
index f1d0a78..41536fe 100644 (file)
@@ -112,19 +112,6 @@ static __always_inline void set_domain(unsigned int val)
 }
 #endif
 
-#ifdef CONFIG_CPU_USE_DOMAINS
-#define modify_domain(dom,type)                                        \
-       do {                                                    \
-               unsigned int domain = get_domain();             \
-               domain &= ~domain_mask(dom);                    \
-               domain = domain | domain_val(dom, type);        \
-               set_domain(domain);                             \
-       } while (0)
-
-#else
-static inline void modify_domain(unsigned dom, unsigned type)  { }
-#endif
-
 /*
  * Generate the T (user) versions of the LDR/STR and related
  * instructions (inline assembly)
index 9228255..2b8970d 100644 (file)
@@ -27,6 +27,7 @@ enum {
        MT_HIGH_VECTORS,
        MT_MEMORY_RWX,
        MT_MEMORY_RW,
+       MT_MEMORY_RO,
        MT_ROM,
        MT_MEMORY_RWX_NONCACHED,
        MT_MEMORY_RW_DTCM,
index 93051e2..1408a6a 100644 (file)
@@ -163,5 +163,31 @@ static inline unsigned long user_stack_pointer(struct pt_regs *regs)
                ((current_stack_pointer | (THREAD_SIZE - 1)) - 7) - 1;  \
 })
 
+
+/*
+ * Update ITSTATE after normal execution of an IT block instruction.
+ *
+ * The 8 IT state bits are split into two parts in CPSR:
+ *     ITSTATE<1:0> are in CPSR<26:25>
+ *     ITSTATE<7:2> are in CPSR<15:10>
+ */
+static inline unsigned long it_advance(unsigned long cpsr)
+{
+       if ((cpsr & 0x06000400) == 0) {
+               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
+               cpsr &= ~PSR_IT_MASK;
+       } else {
+               /* We need to shift left ITSTATE<4:0> */
+               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
+               unsigned long it = cpsr & mask;
+               it <<= 1;
+               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
+               it &= mask;
+               cpsr &= ~mask;
+               cpsr |= it;
+       }
+       return cpsr;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif
index 7aa3ded..6a447ac 100644 (file)
@@ -302,6 +302,7 @@ local_restart:
        b       ret_fast_syscall
 #endif
 ENDPROC(vector_swi)
+       .ltorg
 
        /*
         * This is the really slow path.  We're going to be doing
index b1a43d7..df6d673 100644 (file)
@@ -202,7 +202,7 @@ static const struct wakeup_source_info ws_info[] = {
 
 static const struct of_device_id sama5d2_ws_ids[] = {
        { .compatible = "atmel,sama5d2-gem",            .data = &ws_info[0] },
-       { .compatible = "atmel,at91rm9200-rtc",         .data = &ws_info[1] },
+       { .compatible = "atmel,sama5d2-rtc",            .data = &ws_info[1] },
        { .compatible = "atmel,sama5d3-udc",            .data = &ws_info[2] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
@@ -213,24 +213,24 @@ static const struct of_device_id sama5d2_ws_ids[] = {
 };
 
 static const struct of_device_id sam9x60_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sam9x60-rtc",        .data = &ws_info[1] },
        { .compatible = "atmel,at91rm9200-ohci",        .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sam9x60-rtt",        .data = &ws_info[4] },
        { .compatible = "cdns,sam9x60-macb",            .data = &ws_info[5] },
        { /* sentinel */ }
 };
 
 static const struct of_device_id sama7g5_ws_ids[] = {
-       { .compatible = "atmel,at91sam9x5-rtc",         .data = &ws_info[1] },
+       { .compatible = "microchip,sama7g5-rtc",        .data = &ws_info[1] },
        { .compatible = "microchip,sama7g5-ohci",       .data = &ws_info[2] },
        { .compatible = "usb-ohci",                     .data = &ws_info[2] },
        { .compatible = "atmel,at91sam9g45-ehci",       .data = &ws_info[2] },
        { .compatible = "usb-ehci",                     .data = &ws_info[2] },
        { .compatible = "microchip,sama7g5-sdhci",      .data = &ws_info[3] },
-       { .compatible = "atmel,at91sam9260-rtt",        .data = &ws_info[4] },
+       { .compatible = "microchip,sama7g5-rtt",        .data = &ws_info[4] },
        { /* sentinel */ }
 };
 
@@ -1079,7 +1079,7 @@ securam_fail:
        return ret;
 }
 
-static void at91_pm_secure_init(void)
+static void __init at91_pm_secure_init(void)
 {
        int suspend_mode;
        struct arm_smccc_res res;
index 4b8ad72..32ac60b 100644 (file)
@@ -71,6 +71,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        sram_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!sram_base) {
                pr_err("Couldn't map SRAM registers\n");
                return;
@@ -91,6 +92,7 @@ static void __init meson_smp_prepare_cpus(const char *scu_compatible,
        }
 
        scu_base = of_iomap(node, 0);
+       of_node_put(node);
        if (!scu_base) {
                pr_err("Couldn't map SCU registers\n");
                return;
index 87389d9..30d781d 100644 (file)
@@ -311,7 +311,7 @@ void __init rockchip_suspend_init(void)
                                             &match);
        if (!match) {
                pr_err("Failed to find PMU node\n");
-               return;
+               goto out_put;
        }
        pm_data = (struct rockchip_pm_data *) match->data;
 
@@ -320,9 +320,12 @@ void __init rockchip_suspend_init(void)
 
                if (ret) {
                        pr_err("%s: matches init error %d\n", __func__, ret);
-                       return;
+                       goto out_put;
                }
        }
 
        suspend_set_ops(pm_data->ops);
+
+out_put:
+       of_node_put(np);
 }
index a3a4589..fc439c2 100644 (file)
@@ -631,7 +631,11 @@ config CPU_USE_DOMAINS
        bool
        help
          This option enables or disables the use of domain switching
-         via the set_fs() function.
+         using the DACR (domain access control register) to protect memory
+         domains from each other. In Linux we use three domains: kernel, user
+         and IO. The domains are used to protect userspace from kernelspace
+         and to handle IO-space as a special type of memory by assigning
+         manager or client roles to running code (such as a process).
 
 config CPU_V7M_NUM_IRQ
        int "Number of external interrupts connected to the NVIC"
index 6f49955..f8dd0b3 100644 (file)
@@ -935,6 +935,9 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (type == TYPE_LDST)
                do_alignment_finish_ldst(addr, instr, regs, offset);
 
+       if (thumb_mode(regs))
+               regs->ARM_cpsr = it_advance(regs->ARM_cpsr);
+
        return 0;
 
  bad_or_fault:
index 5e2be37..cd17e32 100644 (file)
@@ -296,6 +296,13 @@ static struct mem_type mem_types[] __ro_after_init = {
                .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE,
                .domain    = DOMAIN_KERNEL,
        },
+       [MT_MEMORY_RO] = {
+               .prot_pte  = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+                            L_PTE_XN | L_PTE_RDONLY,
+               .prot_l1   = PMD_TYPE_TABLE,
+               .prot_sect = PMD_TYPE_SECT,
+               .domain    = DOMAIN_KERNEL,
+       },
        [MT_ROM] = {
                .prot_sect = PMD_TYPE_SECT,
                .domain    = DOMAIN_KERNEL,
@@ -489,6 +496,7 @@ static void __init build_mem_type_table(void)
 
                        /* Also setup NX memory mapping */
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_XN;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_XN;
                }
                if (cpu_arch >= CPU_ARCH_ARMv7 && (cr & CR_TRE)) {
                        /*
@@ -568,6 +576,7 @@ static void __init build_mem_type_table(void)
                mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
                mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+               mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
 #endif
 
                /*
@@ -587,6 +596,8 @@ static void __init build_mem_type_table(void)
                        mem_types[MT_MEMORY_RWX].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RW].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RW].prot_pte |= L_PTE_SHARED;
+                       mem_types[MT_MEMORY_RO].prot_sect |= PMD_SECT_S;
+                       mem_types[MT_MEMORY_RO].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_DMA_READY].prot_pte |= L_PTE_SHARED;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= PMD_SECT_S;
                        mem_types[MT_MEMORY_RWX_NONCACHED].prot_pte |= L_PTE_SHARED;
@@ -647,6 +658,8 @@ static void __init build_mem_type_table(void)
        mem_types[MT_MEMORY_RWX].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RW].prot_sect |= ecc_mask | cp->pmd;
        mem_types[MT_MEMORY_RW].prot_pte |= kern_pgprot;
+       mem_types[MT_MEMORY_RO].prot_sect |= ecc_mask | cp->pmd;
+       mem_types[MT_MEMORY_RO].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_DMA_READY].prot_pte |= kern_pgprot;
        mem_types[MT_MEMORY_RWX_NONCACHED].prot_sect |= ecc_mask;
        mem_types[MT_ROM].prot_sect |= cp->pmd;
@@ -1360,7 +1373,7 @@ static void __init devicemaps_init(const struct machine_desc *mdesc)
                map.pfn = __phys_to_pfn(__atags_pointer & SECTION_MASK);
                map.virtual = FDT_FIXED_BASE;
                map.length = FDT_FIXED_SIZE;
-               map.type = MT_ROM;
+               map.type = MT_MEMORY_RO;
                create_mapping(&map);
        }
 
index fb9f3eb..8bc7a2d 100644 (file)
@@ -108,8 +108,7 @@ static unsigned int spectre_v2_install_workaround(unsigned int method)
 #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());
+       pr_info_once("Spectre V2: workarounds disabled by configuration\n");
 
        return SPECTRE_VULNERABLE;
 }
@@ -209,10 +208,10 @@ static int spectre_bhb_install_workaround(int method)
                        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));
+               pr_info("CPU%u: Spectre BHB: enabling %s workaround for all CPUs\n",
+                       smp_processor_id(), spectre_bhb_method_name(method));
+       }
 
        return SPECTRE_MITIGATED;
 }
index 9731735..facc889 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/types.h>
 #include <linux/stddef.h>
 #include <asm/probes.h>
+#include <asm/ptrace.h>
 #include <asm/kprobes.h>
 
 void __init arm_probes_decode_init(void);
@@ -35,31 +36,6 @@ void __init find_str_pc_offset(void);
 #endif
 
 
-/*
- * Update ITSTATE after normal execution of an IT block instruction.
- *
- * The 8 IT state bits are split into two parts in CPSR:
- *     ITSTATE<1:0> are in CPSR<26:25>
- *     ITSTATE<7:2> are in CPSR<15:10>
- */
-static inline unsigned long it_advance(unsigned long cpsr)
-       {
-       if ((cpsr & 0x06000400) == 0) {
-               /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */
-               cpsr &= ~PSR_IT_MASK;
-       } else {
-               /* We need to shift left ITSTATE<4:0> */
-               const unsigned long mask = 0x06001c00;  /* Mask ITSTATE<4:0> */
-               unsigned long it = cpsr & mask;
-               it <<= 1;
-               it |= it >> (27 - 10);  /* Carry ITSTATE<2> to correct place */
-               it &= mask;
-               cpsr &= ~mask;
-               cpsr |= it;
-       }
-       return cpsr;
-}
-
 static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs)
 {
        long cpsr = regs->ARM_cpsr;
index 84a1cea..309648c 100644 (file)
@@ -63,11 +63,12 @@ out:
 
 unsigned long __pfn_to_mfn(unsigned long pfn)
 {
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
        struct xen_p2m_entry *entry;
        unsigned long irqflags;
 
        read_lock_irqsave(&p2m_lock, irqflags);
+       n = phys_to_mach.rb_node;
        while (n) {
                entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                if (entry->pfn <= pfn &&
@@ -152,10 +153,11 @@ bool __set_phys_to_machine_multi(unsigned long pfn,
        int rc;
        unsigned long irqflags;
        struct xen_p2m_entry *p2m_entry;
-       struct rb_node *n = phys_to_mach.rb_node;
+       struct rb_node *n;
 
        if (mfn == INVALID_P2M_ENTRY) {
                write_lock_irqsave(&p2m_lock, irqflags);
+               n = phys_to_mach.rb_node;
                while (n) {
                        p2m_entry = rb_entry(n, struct xen_p2m_entry, rbnode_phys);
                        if (p2m_entry->pfn <= pfn &&
index 66023d5..d084c33 100644 (file)
@@ -9,6 +9,14 @@
                /delete-node/ cpu@3;
        };
 
+       timer {
+               compatible = "arm,armv8-timer";
+               interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+                            <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+       };
+
        pmu {
                compatible = "arm,cortex-a53-pmu";
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
index a4be040..967d2cd 100644 (file)
@@ -29,6 +29,8 @@
                        device_type = "cpu";
                        compatible = "brcm,brahma-b53";
                        reg = <0x0>;
+                       enable-method = "spin-table";
+                       cpu-release-addr = <0x0 0xfff8>;
                        next-level-cache = <&l2>;
                };
 
index 92465f7..d5cdd77 100644 (file)
                        little-endian;
                };
 
-               efuse@1e80000 {
+               sfp: efuse@1e80000 {
                        compatible = "fsl,ls1028a-sfp";
                        reg = <0x0 0x1e80000 0x0 0x10000>;
+                       clocks = <&clockgen QORIQ_CLK_PLATFORM_PLL
+                                           QORIQ_CLK_PLL_DIV(4)>;
+                       clock-names = "sfp";
                        #address-cells = <1>;
                        #size-cells = <1>;
 
index 4c3ac42..9a4de73 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22                               0x10
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x3
-                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x3
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x19
+                       MX8MP_IOMUXC_SAI1_RXD2__ENET1_MDC               0x2
+                       MX8MP_IOMUXC_SAI1_RXD3__ENET1_MDIO              0x2
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02              0x10
                >;
        };
 
 
        pinctrl_gpio_led: gpioledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x19
+                       MX8MP_IOMUXC_NAND_READY_B__GPIO3_IO16   0x140
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c5: i2c5grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c3
-                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c3
+                       MX8MP_IOMUXC_SPDIF_RX__I2C5_SDA         0x400001c2
+                       MX8MP_IOMUXC_SPDIF_TX__I2C5_SCL         0x400001c2
                >;
        };
 
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x140
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x140
                >;
        };
 
        pinctrl_usb1_vbus: usb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__USB2_OTG_PWR   0x10
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
index 70a701a..dd703b6 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                            0x19
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0                       0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1                       0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2                       0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3                       0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL                 0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0                       0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1                       0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2                       0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3                       0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL                 0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07                            0x10
                >;
        };
 
        pinctrl_uart2: uart2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART2_TXD__UART2_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
 
        pinctrl_reg_usb1: regusb1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x19
+                       MX8MP_IOMUXC_GPIO1_IO14__GPIO1_IO14     0x10
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 };
index 984a6b9..6aa720b 100644 (file)
 &iomuxc {
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                     0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                   0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
                        MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20                      0x10
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2_gpio: i2c2gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e3
-                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e3
+                       MX8MP_IOMUXC_I2C2_SCL__GPIO5_IO16       0x1e2
+                       MX8MP_IOMUXC_I2C2_SDA__GPIO5_IO17       0x1e2
                >;
        };
 
        pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x41
+                       MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19    0x40
                >;
        };
 
        pinctrl_uart1: uart1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x49
-                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x49
+                       MX8MP_IOMUXC_UART1_RXD__UART1_DCE_RX    0x40
+                       MX8MP_IOMUXC_UART1_TXD__UART1_DCE_TX    0x40
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d0
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d0
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d0
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d4
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d4
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d4
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 
                        MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1    0x1d6
                        MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2    0x1d6
                        MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3    0x1d6
-                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc1
+                       MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
                >;
        };
 };
index 101d311..5212155 100644 (file)
 
        pinctrl_hog: hoggrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000041 /* DIO0 */
-                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000041 /* DIO1 */
-                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000041 /* M2SKT_OFF# */
-                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000159 /* PCIE1_WDIS# */
-                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000159 /* PCIE2_WDIS# */
-                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000159 /* PCIE3_WDIS# */
-                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000041 /* M2SKT_RST# */
-                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000159 /* M2SKT_WDIS# */
-                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000159 /* M2SKT_GDIS# */
+                       MX8MP_IOMUXC_GPIO1_IO09__GPIO1_IO09     0x40000040 /* DIO0 */
+                       MX8MP_IOMUXC_GPIO1_IO11__GPIO1_IO11     0x40000040 /* DIO1 */
+                       MX8MP_IOMUXC_NAND_DQS__GPIO3_IO14       0x40000040 /* M2SKT_OFF# */
+                       MX8MP_IOMUXC_SD2_DATA2__GPIO2_IO17      0x40000150 /* PCIE1_WDIS# */
+                       MX8MP_IOMUXC_SD2_DATA3__GPIO2_IO18      0x40000150 /* PCIE2_WDIS# */
+                       MX8MP_IOMUXC_SD2_CMD__GPIO2_IO14        0x40000150 /* PCIE3_WDIS# */
+                       MX8MP_IOMUXC_NAND_DATA00__GPIO3_IO06    0x40000040 /* M2SKT_RST# */
+                       MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18      0x40000150 /* M2SKT_WDIS# */
+                       MX8MP_IOMUXC_NAND_ALE__GPIO3_IO00       0x40000150 /* M2SKT_GDIS# */
                        MX8MP_IOMUXC_SAI3_TXD__GPIO5_IO01       0x40000104 /* UART_TERM */
                        MX8MP_IOMUXC_SAI3_TXFS__GPIO4_IO31      0x40000104 /* UART_RS485 */
                        MX8MP_IOMUXC_SAI3_TXC__GPIO5_IO00       0x40000104 /* UART_HALF */
 
        pinctrl_accel: accelgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x159
+                       MX8MP_IOMUXC_GPIO1_IO07__GPIO1_IO07     0x150
                >;
        };
 
        pinctrl_eqos: eqosgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x3
-                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x3
-                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x91
-                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x91
-                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x91
-                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x91
-                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x91
-                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x91
-                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x1f
-                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x1f
-                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x1f
-                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x1f
-                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x1f
-                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x1f
-                       MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30               0x141 /* RST# */
-                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x159 /* IRQ# */
+                       MX8MP_IOMUXC_ENET_MDC__ENET_QOS_MDC                             0x2
+                       MX8MP_IOMUXC_ENET_MDIO__ENET_QOS_MDIO                           0x2
+                       MX8MP_IOMUXC_ENET_RD0__ENET_QOS_RGMII_RD0               0x90
+                       MX8MP_IOMUXC_ENET_RD1__ENET_QOS_RGMII_RD1               0x90
+                       MX8MP_IOMUXC_ENET_RD2__ENET_QOS_RGMII_RD2               0x90
+                       MX8MP_IOMUXC_ENET_RD3__ENET_QOS_RGMII_RD3               0x90
+                       MX8MP_IOMUXC_ENET_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK       0x90
+                       MX8MP_IOMUXC_ENET_RX_CTL__ENET_QOS_RGMII_RX_CTL         0x90
+                       MX8MP_IOMUXC_ENET_TD0__ENET_QOS_RGMII_TD0               0x16
+                       MX8MP_IOMUXC_ENET_TD1__ENET_QOS_RGMII_TD1               0x16
+                       MX8MP_IOMUXC_ENET_TD2__ENET_QOS_RGMII_TD2               0x16
+                       MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3               0x16
+                       MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL         0x16
+                       MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK       0x16
+                       MX8MP_IOMUXC_SAI3_RXD__GPIO4_IO30               0x140 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXFS__GPIO4_IO28              0x150 /* IRQ# */
                >;
        };
 
        pinctrl_fec: fecgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x91
-                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x91
-                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x91
-                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x91
-                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x91
-                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x91
-                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x1f
-                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x1f
-                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x1f
-                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x141
-                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x141
+                       MX8MP_IOMUXC_SAI1_RXD4__ENET1_RGMII_RD0         0x90
+                       MX8MP_IOMUXC_SAI1_RXD5__ENET1_RGMII_RD1         0x90
+                       MX8MP_IOMUXC_SAI1_RXD6__ENET1_RGMII_RD2         0x90
+                       MX8MP_IOMUXC_SAI1_RXD7__ENET1_RGMII_RD3         0x90
+                       MX8MP_IOMUXC_SAI1_TXC__ENET1_RGMII_RXC          0x90
+                       MX8MP_IOMUXC_SAI1_TXFS__ENET1_RGMII_RX_CTL      0x90
+                       MX8MP_IOMUXC_SAI1_TXD0__ENET1_RGMII_TD0         0x16
+                       MX8MP_IOMUXC_SAI1_TXD1__ENET1_RGMII_TD1         0x16
+                       MX8MP_IOMUXC_SAI1_TXD2__ENET1_RGMII_TD2         0x16
+                       MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3         0x16
+                       MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL      0x16
+                       MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC         0x16
+                       MX8MP_IOMUXC_SAI1_RXFS__ENET1_1588_EVENT0_IN    0x140
+                       MX8MP_IOMUXC_SAI1_RXC__ENET1_1588_EVENT0_OUT    0x140
                >;
        };
 
 
        pinctrl_gsc: gscgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x159
+                       MX8MP_IOMUXC_SAI1_MCLK__GPIO4_IO20      0x150
                >;
        };
 
        pinctrl_i2c1: i2c1grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C1_SCL__I2C1_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C1_SDA__I2C1_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c2: i2c2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C2_SCL__I2C2_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C2_SDA__I2C2_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c3: i2c3grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C3_SCL__I2C3_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C3_SDA__I2C3_SDA         0x400001c2
                >;
        };
 
        pinctrl_i2c4: i2c4grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c3
-                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c3
+                       MX8MP_IOMUXC_I2C4_SCL__I2C4_SCL         0x400001c2
+                       MX8MP_IOMUXC_I2C4_SDA__I2C4_SDA         0x400001c2
                >;
        };
 
        pinctrl_ksz: kszgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x159 /* IRQ# */
-                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x141 /* RST# */
+                       MX8MP_IOMUXC_SAI3_RXC__GPIO4_IO29       0x150 /* IRQ# */
+                       MX8MP_IOMUXC_SAI3_MCLK__GPIO5_IO02      0x140 /* RST# */
                >;
        };
 
        pinctrl_gpio_leds: ledgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x19
-                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x19
+                       MX8MP_IOMUXC_SD2_DATA0__GPIO2_IO15      0x10
+                       MX8MP_IOMUXC_SD2_DATA1__GPIO2_IO16      0x10
                >;
        };
 
        pinctrl_pmic: pmicgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x141
+                       MX8MP_IOMUXC_NAND_DATA01__GPIO3_IO07    0x140
                >;
        };
 
        pinctrl_pps: ppsgrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x141
+                       MX8MP_IOMUXC_GPIO1_IO12__GPIO1_IO12     0x140
                >;
        };
 
 
        pinctrl_reg_usb2: regusb2grp {
                fsl,pins = <
-                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x141
+                       MX8MP_IOMUXC_GPIO1_IO06__GPIO1_IO06     0x140
                >;
        };
 
        pinctrl_reg_wifi: regwifigrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x119
+                       MX8MP_IOMUXC_NAND_DATA03__GPIO3_IO09    0x110
                >;
        };
 
 
        pinctrl_uart3_gpio: uart3gpiogrp {
                fsl,pins = <
-                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x119
+                       MX8MP_IOMUXC_NAND_DATA02__GPIO3_IO08    0x110
                >;
        };
 
index d9542df..410d0d5 100644 (file)
                                        pgc_ispdwp: power-domain@18 {
                                                #power-domain-cells = <0>;
                                                reg = <IMX8MP_POWER_DOMAIN_MEDIAMIX_ISPDWP>;
-                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_DIV>;
+                                               clocks = <&clk IMX8MP_CLK_MEDIA_ISP_ROOT>;
                                        };
                                };
                        };
index 3b0cc85..71e373b 100644 (file)
@@ -74,7 +74,7 @@
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index 7748b74..afa91ca 100644 (file)
                vdd_l17_29-supply = <&vph_pwr>;
                vdd_l20_21-supply = <&vph_pwr>;
                vdd_l25-supply = <&pm8994_s5>;
-               vdd_lvs1_2 = <&pm8994_s4>;
+               vdd_lvs1_2-supply = <&pm8994_s4>;
 
                /* S1, S2, S6 and S12 are managed by RPMPD */
 
index 0318d42..1ac2913 100644 (file)
                CPU6: cpu@102 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x102>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
                CPU7: cpu@103 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a57";
-                       reg = <0x0 0x101>;
+                       reg = <0x0 0x103>;
                        enable-method = "psci";
                        next-level-cache = <&L2_1>;
                };
index 9b3e3d1..d1e2df5 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2021 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
 
 / {
        /* BOARD-SPECIFIC TOP LEVEL NODES */
index fe2369c..88f6a7d 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2020 Google LLC.
  */
 
-#include "sc7180-trogdor.dtsi"
+/* This file must be included after sc7180-trogdor.dtsi */
 
 &ap_sar_sensor {
        semtech,cs0-ground;
index 0692ae0..038538c 100644 (file)
 
                        power-domains = <&dispcc MDSS_GDSC>;
 
-                       clocks = <&gcc GCC_DISP_AHB_CLK>,
+                       clocks = <&dispcc DISP_CC_MDSS_AHB_CLK>,
                                 <&dispcc DISP_CC_MDSS_MDP_CLK>;
                        clock-names = "iface", "core";
 
index 7d08fad..b87756b 100644 (file)
                        reg = <0x0 0x17100000 0x0 0x10000>,     /* GICD */
                              <0x0 0x17180000 0x0 0x200000>;    /* GICR * 8 */
                        interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       ranges;
+
+                       gic_its: msi-controller@17140000 {
+                               compatible = "arm,gic-v3-its";
+                               reg = <0x0 0x17140000 0x0 0x20000>;
+                               msi-controller;
+                               #msi-cells = <1>;
+                       };
                };
 
                timer@17420000 {
 
                        iommus = <&apps_smmu 0xe0 0x0>;
 
-                       interconnects = <&aggre1_noc MASTER_UFS_MEM &mc_virt SLAVE_EBI1>,
-                                       <&gem_noc MASTER_APPSS_PROC &config_noc SLAVE_UFS_MEM_CFG>;
+                       interconnects = <&aggre1_noc MASTER_UFS_MEM 0 &mc_virt SLAVE_EBI1 0>,
+                                       <&gem_noc MASTER_APPSS_PROC 0 &config_noc SLAVE_UFS_MEM_CFG 0>;
                        interconnect-names = "ufs-ddr", "cpu-ufs";
                        clock-names =
                                "core_clk",
index 913d845..1977103 100644 (file)
@@ -376,7 +376,8 @@ camera: &i2c7 {
                <&cru ACLK_VIO>,
                <&cru ACLK_GIC_PRE>,
                <&cru PCLK_DDR>,
-               <&cru ACLK_HDCP>;
+               <&cru ACLK_HDCP>,
+               <&cru ACLK_VDU>;
        assigned-clock-rates =
                <600000000>, <1600000000>,
                <1000000000>,
@@ -388,6 +389,7 @@ camera: &i2c7 {
                <400000000>,
                <200000000>,
                <200000000>,
+               <400000000>,
                <400000000>;
 };
 
index fbd0346..9d5b0e8 100644 (file)
                        <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>,
                        <&cru ACLK_VIO>, <&cru ACLK_HDCP>,
                        <&cru ACLK_GIC_PRE>,
-                       <&cru PCLK_DDR>;
+                       <&cru PCLK_DDR>,
+                       <&cru ACLK_VDU>;
                assigned-clock-rates =
                         <594000000>,  <800000000>,
                        <1000000000>,
                         <100000000>,   <50000000>,
                         <400000000>, <400000000>,
                         <200000000>,
-                        <200000000>;
+                        <200000000>,
+                        <400000000>;
        };
 
        grf: syscon@ff770000 {
index 1534e11..fa953b7 100644 (file)
 };
 
 &usb_host0_xhci {
+       dr_mode = "host";
        status = "okay";
 };
 
index 7bdcecc..02d5f5a 100644 (file)
        assigned-clocks = <&cru SCLK_GMAC1_RX_TX>, <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>;
        assigned-clock-parents = <&cru SCLK_GMAC1_RGMII_SPEED>, <&cru SCLK_GMAC1>, <&gmac1_clkin>;
        clock_in_out = "input";
-       phy-mode = "rgmii-id";
+       phy-mode = "rgmii";
        phy-supply = <&vcc_3v3>;
        pinctrl-names = "default";
        pinctrl-0 = <&gmac1m1_miim
index 1920d52..53a912b 100644 (file)
@@ -54,7 +54,6 @@ config LOONGARCH
        select GENERIC_CMOS_UPDATE
        select GENERIC_CPU_AUTOPROBE
        select GENERIC_ENTRY
-       select GENERIC_FIND_FIRST_BIT
        select GENERIC_GETTIMEOFDAY
        select GENERIC_IRQ_MULTI_HANDLER
        select GENERIC_IRQ_PROBE
@@ -77,7 +76,6 @@ config LOONGARCH
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE
        select HAVE_ASM_MODVERSIONS
        select HAVE_CONTEXT_TRACKING
-       select HAVE_COPY_THREAD_TLS
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_DMA_CONTIGUOUS
        select HAVE_EXIT_THREAD
@@ -86,8 +84,6 @@ config LOONGARCH
        select HAVE_IOREMAP_PROT
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
        select HAVE_IRQ_TIME_ACCOUNTING
-       select HAVE_MEMBLOCK
-       select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_MOD_ARCH_SPECIFIC
        select HAVE_NMI
        select HAVE_PERF_EVENTS
index adb16e4..b6be527 100644 (file)
@@ -48,6 +48,5 @@
 #define fcsr1  $r1
 #define fcsr2  $r2
 #define fcsr3  $r3
-#define vcsr16 $r16
 
 #endif /* _ASM_FPREGDEF_H */
index 3dba498..dc47fc7 100644 (file)
@@ -6,6 +6,7 @@
 #define _ASM_PAGE_H
 
 #include <linux/const.h>
+#include <asm/addrspace.h>
 
 /*
  * PAGE_SHIFT determines the page size
index 1d63c93..57ec45a 100644 (file)
@@ -80,7 +80,6 @@ BUILD_FPR_ACCESS(64)
 
 struct loongarch_fpu {
        unsigned int    fcsr;
-       unsigned int    vcsr;
        uint64_t        fcc;    /* 8x8 */
        union fpureg    fpr[NUM_FPU_REGS];
 };
@@ -161,7 +160,6 @@ struct thread_struct {
         */                                                     \
        .fpu                    = {                             \
                .fcsr           = 0,                            \
-               .vcsr           = 0,                            \
                .fcc            = 0,                            \
                .fpr            = {{{0,},},},                   \
        },                                                      \
index bfb65eb..20cd9e1 100644 (file)
@@ -166,7 +166,6 @@ void output_thread_fpu_defines(void)
 
        OFFSET(THREAD_FCSR, loongarch_fpu, fcsr);
        OFFSET(THREAD_FCC,  loongarch_fpu, fcc);
-       OFFSET(THREAD_VCSR, loongarch_fpu, vcsr);
        BLANK();
 }
 
index 75c6ce0..a631a71 100644 (file)
        movgr2fcsr      fcsr0, \tmp0
        .endm
 
-       .macro sc_save_vcsr base, tmp0
-       movfcsr2gr      \tmp0, vcsr16
-       EX      st.w \tmp0, \base, 0
-       .endm
-
-       .macro sc_restore_vcsr base, tmp0
-       EX      ld.w \tmp0, \base, 0
-       movgr2fcsr      vcsr16, \tmp0
-       .endm
-
 /*
  * Save a thread's fp context.
  */
index a76f547..a13f925 100644 (file)
@@ -429,7 +429,6 @@ int __init init_numa_memory(void)
        return 0;
 }
 
-EXPORT_SYMBOL(init_numa_memory);
 #endif
 
 void __init paging_init(void)
index 6b6e167..92e4040 100644 (file)
@@ -21,6 +21,7 @@ ccflags-vdso += $(filter --target=%,$(KBUILD_CFLAGS))
 endif
 
 cflags-vdso := $(ccflags-vdso) \
+       -isystem $(shell $(CC) -print-file-name=include) \
        $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
        -O2 -g -fno-strict-aliasing -fno-common -fno-builtin -G0 \
        -fno-stack-protector -fno-jump-tables -DDISABLE_BRANCH_PROFILING \
index 8ae15c2..c6ad6f8 100644 (file)
@@ -25,7 +25,7 @@ struct or1k_frameinfo {
 /*
  * Verify a frameinfo structure.  The return address should be a valid text
  * address.  The frame pointer may be null if its the last frame, otherwise
- * the frame pointer should point to a location in the stack after the the
+ * the frame pointer should point to a location in the stack after the
  * top of the next frame up.
  */
 static inline int or1k_frameinfo_valid(struct or1k_frameinfo *frameinfo)
index 463c78c..3805ad1 100644 (file)
@@ -176,12 +176,8 @@ static int __init pnv_get_random_long_early(unsigned long *v)
                    NULL) != pnv_get_random_long_early)
                return 0;
 
-       for_each_compatible_node(dn, NULL, "ibm,power-rng") {
-               if (rng_create(dn))
-                       continue;
-               /* Create devices for hwrng driver */
-               of_platform_device_create(dn, NULL, NULL);
-       }
+       for_each_compatible_node(dn, NULL, "ibm,power-rng")
+               rng_create(dn);
 
        if (!ppc_md.get_random_seed)
                return 0;
@@ -205,10 +201,18 @@ void __init pnv_rng_init(void)
 
 static int __init pnv_rng_late_init(void)
 {
+       struct device_node *dn;
        unsigned long v;
+
        /* In case it wasn't called during init for some other reason. */
        if (ppc_md.get_random_seed == pnv_get_random_long_early)
                pnv_get_random_long_early(&v);
+
+       if (ppc_md.get_random_seed == powernv_get_random_long) {
+               for_each_compatible_node(dn, NULL, "ibm,power-rng")
+                       of_platform_device_create(dn, NULL, NULL);
+       }
+
        return 0;
 }
 machine_subsys_initcall(powernv, pnv_rng_late_init);
index 32ffef9..fcbb81f 100644 (file)
@@ -38,7 +38,7 @@ config RISCV
        select ARCH_SUPPORTS_ATOMIC_RMW
        select ARCH_SUPPORTS_DEBUG_PAGEALLOC if MMU
        select ARCH_SUPPORTS_HUGETLBFS if MMU
-       select ARCH_SUPPORTS_PAGE_TABLE_CHECK
+       select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
        select ARCH_USE_MEMTEST
        select ARCH_USE_QUEUED_RWLOCKS
        select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT if MMU
index 3095d08..496d3b7 100644 (file)
@@ -50,6 +50,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu1_intc: interrupt-controller {
@@ -77,6 +78,7 @@
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu2_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
 
                        cpu3_intc: interrupt-controller {
                        riscv,isa = "rv64imafdc";
                        clocks = <&clkcfg CLK_CPU>;
                        tlb-split;
+                       next-level-cache = <&cctrllr>;
                        status = "okay";
                        cpu4_intc: interrupt-controller {
                                #interrupt-cells = <1>;
index 672f02b..1031038 100644 (file)
@@ -111,6 +111,7 @@ void __init_or_module sifive_errata_patch_func(struct alt_entry *begin,
                        cpu_apply_errata |= tmp;
                }
        }
-       if (cpu_apply_errata != cpu_req_errata)
+       if (stage != RISCV_ALTERNATIVES_MODULE &&
+           cpu_apply_errata != cpu_req_errata)
                warn_miss_errata(cpu_req_errata - cpu_apply_errata);
 }
index 5c2aba5..dc42375 100644 (file)
@@ -175,7 +175,7 @@ static inline pud_t pfn_pud(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pud_pfn(pud_t pud)
 {
-       return pud_val(pud) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pud_val(pud));
 }
 
 static inline pmd_t *pud_pgtable(pud_t pud)
@@ -278,13 +278,13 @@ static inline p4d_t pfn_p4d(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _p4d_pfn(p4d_t p4d)
 {
-       return p4d_val(p4d) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(p4d_val(p4d));
 }
 
 static inline pud_t *p4d_pgtable(p4d_t p4d)
 {
        if (pgtable_l4_enabled)
-               return (pud_t *)pfn_to_virt(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+               return (pud_t *)pfn_to_virt(__page_val_to_pfn(p4d_val(p4d)));
 
        return (pud_t *)pud_pgtable((pud_t) { p4d_val(p4d) });
 }
@@ -292,7 +292,7 @@ static inline pud_t *p4d_pgtable(p4d_t p4d)
 
 static inline struct page *p4d_page(p4d_t p4d)
 {
-       return pfn_to_page(p4d_val(p4d) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(p4d_val(p4d)));
 }
 
 #define pud_index(addr) (((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
@@ -347,7 +347,7 @@ static inline void pgd_clear(pgd_t *pgd)
 static inline p4d_t *pgd_pgtable(pgd_t pgd)
 {
        if (pgtable_l5_enabled)
-               return (p4d_t *)pfn_to_virt(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+               return (p4d_t *)pfn_to_virt(__page_val_to_pfn(pgd_val(pgd)));
 
        return (p4d_t *)p4d_pgtable((p4d_t) { pgd_val(pgd) });
 }
@@ -355,7 +355,7 @@ static inline p4d_t *pgd_pgtable(pgd_t pgd)
 
 static inline struct page *pgd_page(pgd_t pgd)
 {
-       return pfn_to_page(pgd_val(pgd) >> _PAGE_PFN_SHIFT);
+       return pfn_to_page(__page_val_to_pfn(pgd_val(pgd)));
 }
 #define pgd_page(pgd)  pgd_page(pgd)
 
index 1d1be9d..5dbd661 100644 (file)
@@ -261,7 +261,7 @@ static inline pgd_t pfn_pgd(unsigned long pfn, pgprot_t prot)
 
 static inline unsigned long _pgd_pfn(pgd_t pgd)
 {
-       return pgd_val(pgd) >> _PAGE_PFN_SHIFT;
+       return __page_val_to_pfn(pgd_val(pgd));
 }
 
 static inline struct page *pmd_page(pmd_t pmd)
@@ -590,14 +590,14 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd)
        return __pmd(pmd_val(pmd) & ~(_PAGE_PRESENT|_PAGE_PROT_NONE));
 }
 
-#define __pmd_to_phys(pmd)  (pmd_val(pmd) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pmd_to_phys(pmd)  (__page_val_to_pfn(pmd_val(pmd)) << PAGE_SHIFT)
 
 static inline unsigned long pmd_pfn(pmd_t pmd)
 {
        return ((__pmd_to_phys(pmd) & PMD_MASK) >> PAGE_SHIFT);
 }
 
-#define __pud_to_phys(pud)  (pud_val(pud) >> _PAGE_PFN_SHIFT << PAGE_SHIFT)
+#define __pud_to_phys(pud)  (__page_val_to_pfn(pud_val(pud)) << PAGE_SHIFT)
 
 static inline unsigned long pud_pfn(pud_t pud)
 {
index 1c00695..9826073 100644 (file)
@@ -54,7 +54,7 @@ static inline unsigned long gstage_pte_index(gpa_t addr, u32 level)
 
 static inline unsigned long gstage_pte_page_vaddr(pte_t pte)
 {
-       return (unsigned long)pfn_to_virt(pte_val(pte) >> _PAGE_PFN_SHIFT);
+       return (unsigned long)pfn_to_virt(__page_val_to_pfn(pte_val(pte)));
 }
 
 static int gstage_page_size_to_level(unsigned long page_size, u32 *out_level)
index 7f4ad5e..f3455dc 100644 (file)
@@ -781,9 +781,11 @@ static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu)
 
        if (kvm_request_pending(vcpu)) {
                if (kvm_check_request(KVM_REQ_SLEEP, vcpu)) {
+                       kvm_vcpu_srcu_read_unlock(vcpu);
                        rcuwait_wait_event(wait,
                                (!vcpu->arch.power_off) && (!vcpu->arch.pause),
                                TASK_INTERRUPTIBLE);
+                       kvm_vcpu_srcu_read_lock(vcpu);
 
                        if (vcpu->arch.power_off || vcpu->arch.pause) {
                                /*
index 495c68a..4cb5d17 100644 (file)
@@ -82,7 +82,7 @@ endif
 
 ifdef CONFIG_EXPOLINE
   ifdef CONFIG_EXPOLINE_EXTERN
-    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline.o
+    KBUILD_LDFLAGS_MODULE += arch/s390/lib/expoline/expoline.o
     CC_FLAGS_EXPOLINE := -mindirect-branch=thunk-extern
     CC_FLAGS_EXPOLINE += -mfunction-return=thunk-extern
   else
@@ -163,6 +163,12 @@ vdso_prepare: prepare0
        $(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h
        $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
                $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
+
+ifdef CONFIG_EXPOLINE_EXTERN
+modules_prepare: expoline_prepare
+expoline_prepare:
+       $(Q)$(MAKE) $(build)=arch/s390/lib/expoline arch/s390/lib/expoline/expoline.o
+endif
 endif
 
 # Don't use tabs in echo arguments
index d910d71..7e9e995 100644 (file)
@@ -2,8 +2,6 @@
 #ifndef _ASM_S390_NOSPEC_ASM_H
 #define _ASM_S390_NOSPEC_ASM_H
 
-#include <asm/alternative-asm.h>
-#include <asm/asm-offsets.h>
 #include <asm/dwarf.h>
 
 #ifdef __ASSEMBLY__
index 5d415b3..580d2e3 100644 (file)
@@ -7,7 +7,6 @@ lib-y += delay.o string.o uaccess.o find.o spinlock.o
 obj-y += mem.o xor.o
 lib-$(CONFIG_KPROBES) += probes.o
 lib-$(CONFIG_UPROBES) += probes.o
-obj-$(CONFIG_EXPOLINE_EXTERN) += expoline.o
 obj-$(CONFIG_S390_KPROBES_SANITY_TEST) += test_kprobes_s390.o
 test_kprobes_s390-objs += test_kprobes_asm.o test_kprobes.o
 
@@ -22,3 +21,5 @@ obj-$(CONFIG_S390_MODULES_SANITY_TEST) += test_modules.o
 obj-$(CONFIG_S390_MODULES_SANITY_TEST_HELPERS) += test_modules_helpers.o
 
 lib-$(CONFIG_FUNCTION_ERROR_INJECTION) += error-inject.o
+
+obj-$(CONFIG_EXPOLINE_EXTERN) += expoline/
diff --git a/arch/s390/lib/expoline/Makefile b/arch/s390/lib/expoline/Makefile
new file mode 100644 (file)
index 0000000..854631d
--- /dev/null
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += expoline.o
index cf9a3ec..fba90e6 100644 (file)
@@ -271,8 +271,12 @@ static inline void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
 #endif /* CONFIG_HAVE_IOREMAP_PROT */
 
 #else /* CONFIG_MMU */
-#define iounmap(addr)          do { } while (0)
-#define ioremap(offset, size)  ((void __iomem *)(unsigned long)(offset))
+static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
+{
+       return (void __iomem *)(unsigned long)offset;
+}
+
+static inline void iounmap(volatile void __iomem *addr) { }
 #endif /* CONFIG_MMU */
 
 #define ioremap_uc     ioremap
index 95af12e..cdbd965 100644 (file)
@@ -102,8 +102,8 @@ extern unsigned long uml_physmem;
  * casting is the right thing, but 32-bit UML can't have 64-bit virtual
  * addresses
  */
-#define __pa(virt) to_phys((void *) (unsigned long) (virt))
-#define __va(phys) to_virt((unsigned long) (phys))
+#define __pa(virt) uml_to_phys((void *) (unsigned long) (virt))
+#define __va(phys) uml_to_virt((unsigned long) (phys))
 
 #define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
 #define pfn_to_phys(pfn) PFN_PHYS(pfn)
index 4862c91..98aacd5 100644 (file)
@@ -9,12 +9,12 @@
 extern int phys_mapping(unsigned long phys, unsigned long long *offset_out);
 
 extern unsigned long uml_physmem;
-static inline unsigned long to_phys(void *virt)
+static inline unsigned long uml_to_phys(void *virt)
 {
        return(((unsigned long) virt) - uml_physmem);
 }
 
-static inline void *to_virt(unsigned long phys)
+static inline void *uml_to_virt(unsigned long phys)
 {
        return((void *) uml_physmem + phys);
 }
index 0760e24..9838967 100644 (file)
@@ -432,6 +432,10 @@ void apply_retpolines(s32 *start, s32 *end)
 {
 }
 
+void apply_returns(s32 *start, s32 *end)
+{
+}
+
 void apply_alternatives(struct alt_instr *start, struct alt_instr *end)
 {
 }
index 87d3129..c316c99 100644 (file)
@@ -251,7 +251,7 @@ static int userspace_tramp(void *stack)
        signal(SIGTERM, SIG_DFL);
        signal(SIGWINCH, SIG_IGN);
 
-       fd = phys_mapping(to_phys(__syscall_stub_start), &offset);
+       fd = phys_mapping(uml_to_phys(__syscall_stub_start), &offset);
        addr = mmap64((void *) STUB_CODE, UM_KERN_PAGE_SIZE,
                      PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
        if (addr == MAP_FAILED) {
@@ -261,7 +261,7 @@ static int userspace_tramp(void *stack)
        }
 
        if (stack != NULL) {
-               fd = phys_mapping(to_phys(stack), &offset);
+               fd = phys_mapping(uml_to_phys(stack), &offset);
                addr = mmap((void *) STUB_DATA,
                            UM_KERN_PAGE_SIZE, PROT_READ | PROT_WRITE,
                            MAP_FIXED | MAP_SHARED, fd, offset);
@@ -534,7 +534,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
        struct stub_data *data = (struct stub_data *) current_stack;
        struct stub_data *child_data = (struct stub_data *) new_stack;
        unsigned long long new_offset;
-       int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+       int new_fd = phys_mapping(uml_to_phys((void *)new_stack), &new_offset);
 
        /*
         * prepare offset and fd of child's stack as argument for parent's
index be0b95e..e58798f 100644 (file)
@@ -462,29 +462,6 @@ config GOLDFISH
        def_bool y
        depends on X86_GOLDFISH
 
-config RETPOLINE
-       bool "Avoid speculative indirect branches in kernel"
-       select OBJTOOL if HAVE_OBJTOOL
-       default y
-       help
-         Compile kernel with the retpoline compiler options to guard against
-         kernel-to-user data leaks by avoiding speculative indirect
-         branches. Requires a compiler with -mindirect-branch=thunk-extern
-         support for full protection. The kernel may run slower.
-
-config CC_HAS_SLS
-       def_bool $(cc-option,-mharden-sls=all)
-
-config SLS
-       bool "Mitigate Straight-Line-Speculation"
-       depends on CC_HAS_SLS && X86_64
-       select OBJTOOL if HAVE_OBJTOOL
-       default n
-       help
-         Compile the kernel with straight-line-speculation options to guard
-         against straight line speculation. The kernel image might be slightly
-         larger.
-
 config X86_CPU_RESCTRL
        bool "x86 CPU resource control support"
        depends on X86 && (CPU_SUP_INTEL || CPU_SUP_AMD)
@@ -2453,6 +2430,91 @@ source "kernel/livepatch/Kconfig"
 
 endmenu
 
+config CC_HAS_SLS
+       def_bool $(cc-option,-mharden-sls=all)
+
+config CC_HAS_RETURN_THUNK
+       def_bool $(cc-option,-mfunction-return=thunk-extern)
+
+menuconfig SPECULATION_MITIGATIONS
+       bool "Mitigations for speculative execution vulnerabilities"
+       default y
+       help
+         Say Y here to enable options which enable mitigations for
+         speculative execution hardware vulnerabilities.
+
+         If you say N, all mitigations will be disabled. You really
+         should know what you are doing to say so.
+
+if SPECULATION_MITIGATIONS
+
+config PAGE_TABLE_ISOLATION
+       bool "Remove the kernel mapping in user mode"
+       default y
+       depends on (X86_64 || X86_PAE)
+       help
+         This feature reduces the number of hardware side channels by
+         ensuring that the majority of kernel addresses are not mapped
+         into userspace.
+
+         See Documentation/x86/pti.rst for more details.
+
+config RETPOLINE
+       bool "Avoid speculative indirect branches in kernel"
+       select OBJTOOL if HAVE_OBJTOOL
+       default y
+       help
+         Compile kernel with the retpoline compiler options to guard against
+         kernel-to-user data leaks by avoiding speculative indirect
+         branches. Requires a compiler with -mindirect-branch=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config RETHUNK
+       bool "Enable return-thunks"
+       depends on RETPOLINE && CC_HAS_RETURN_THUNK
+       select OBJTOOL if HAVE_OBJTOOL
+       default y
+       help
+         Compile the kernel with the return-thunks compiler option to guard
+         against kernel-to-user data leaks by avoiding return speculation.
+         Requires a compiler with -mfunction-return=thunk-extern
+         support for full protection. The kernel may run slower.
+
+config CPU_UNRET_ENTRY
+       bool "Enable UNRET on kernel entry"
+       depends on CPU_SUP_AMD && RETHUNK
+       default y
+       help
+         Compile the kernel with support for the retbleed=unret mitigation.
+
+config CPU_IBPB_ENTRY
+       bool "Enable IBPB on kernel entry"
+       depends on CPU_SUP_AMD
+       default y
+       help
+         Compile the kernel with support for the retbleed=ibpb mitigation.
+
+config CPU_IBRS_ENTRY
+       bool "Enable IBRS on kernel entry"
+       depends on CPU_SUP_INTEL
+       default y
+       help
+         Compile the kernel with support for the spectre_v2=ibrs mitigation.
+         This mitigates both spectre_v2 and retbleed at great cost to
+         performance.
+
+config SLS
+       bool "Mitigate Straight-Line-Speculation"
+       depends on CC_HAS_SLS && X86_64
+       select OBJTOOL if HAVE_OBJTOOL
+       default n
+       help
+         Compile the kernel with straight-line-speculation options to guard
+         against straight line speculation. The kernel image might be slightly
+         larger.
+
+endif
+
 config ARCH_HAS_ADD_PAGES
        def_bool y
        depends on ARCH_ENABLE_MEMORY_HOTPLUG
index a74886a..1f40dad 100644 (file)
@@ -21,6 +21,12 @@ ifdef CONFIG_CC_IS_CLANG
 RETPOLINE_CFLAGS       := -mretpoline-external-thunk
 RETPOLINE_VDSO_CFLAGS  := -mretpoline
 endif
+
+ifdef CONFIG_RETHUNK
+RETHUNK_CFLAGS         := -mfunction-return=thunk-extern
+RETPOLINE_CFLAGS       += $(RETHUNK_CFLAGS)
+endif
+
 export RETPOLINE_CFLAGS
 export RETPOLINE_VDSO_CFLAGS
 
index 44c350d..d4a314c 100644 (file)
@@ -110,6 +110,7 @@ void kernel_add_identity_map(unsigned long start, unsigned long end)
 void initialize_identity_maps(void *rmode)
 {
        unsigned long cmdline;
+       struct setup_data *sd;
 
        /* Exclude the encryption mask from __PHYSICAL_MASK */
        physical_mask &= ~sme_me_mask;
@@ -163,6 +164,18 @@ void initialize_identity_maps(void *rmode)
        cmdline = get_cmd_line_ptr();
        kernel_add_identity_map(cmdline, cmdline + COMMAND_LINE_SIZE);
 
+       /*
+        * Also map the setup_data entries passed via boot_params in case they
+        * need to be accessed by uncompressed kernel via the identity mapping.
+        */
+       sd = (struct setup_data *)boot_params->hdr.setup_data;
+       while (sd) {
+               unsigned long sd_addr = (unsigned long)sd;
+
+               kernel_add_identity_map(sd_addr, sd_addr + sizeof(*sd) + sd->len);
+               sd = (struct setup_data *)sd->next;
+       }
+
        sev_prep_identity_maps(top_level_pgt);
 
        /* Load the new page-table. */
index 7fec5dc..eeadbd7 100644 (file)
@@ -11,7 +11,7 @@ CFLAGS_REMOVE_common.o                = $(CC_FLAGS_FTRACE)
 
 CFLAGS_common.o                        += -fno-stack-protector
 
-obj-y                          := entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
+obj-y                          := entry.o entry_$(BITS).o thunk_$(BITS).o syscall_$(BITS).o
 obj-y                          += common.o
 
 obj-y                          += vdso/
index 29b36e9..f690762 100644 (file)
@@ -7,6 +7,8 @@
 #include <asm/asm-offsets.h>
 #include <asm/processor-flags.h>
 #include <asm/ptrace-abi.h>
+#include <asm/msr.h>
+#include <asm/nospec-branch.h>
 
 /*
 
@@ -283,6 +285,66 @@ For 32-bit we have the following conventions - kernel is built with
 #endif
 
 /*
+ * IBRS kernel mitigation for Spectre_v2.
+ *
+ * Assumes full context is established (PUSH_REGS, CR3 and GS) and it clobbers
+ * the regs it uses (AX, CX, DX). Must be called before the first RET
+ * instruction (NOTE! UNTRAIN_RET includes a RET instruction)
+ *
+ * The optional argument is used to save/restore the current value,
+ * which is used on the paranoid paths.
+ *
+ * Assumes x86_spec_ctrl_{base,current} to have SPEC_CTRL_IBRS set.
+ */
+.macro IBRS_ENTER save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       rdmsr
+       shl     $32, %rdx
+       or      %rdx, %rax
+       mov     %rax, \save_reg
+       test    $SPEC_CTRL_IBRS, %eax
+       jz      .Ldo_wrmsr_\@
+       lfence
+       jmp     .Lend_\@
+.Ldo_wrmsr_\@:
+.endif
+
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
+/*
+ * Similar to IBRS_ENTER, requires KERNEL GS,CR3 and clobbers (AX, CX, DX)
+ * regs. Must be called after the last RET.
+ */
+.macro IBRS_EXIT save_reg
+#ifdef CONFIG_CPU_IBRS_ENTRY
+       ALTERNATIVE "jmp .Lend_\@", "", X86_FEATURE_KERNEL_IBRS
+       movl    $MSR_IA32_SPEC_CTRL, %ecx
+
+.ifnb \save_reg
+       mov     \save_reg, %rdx
+.else
+       movq    PER_CPU_VAR(x86_spec_ctrl_current), %rdx
+       andl    $(~SPEC_CTRL_IBRS), %edx
+.endif
+
+       movl    %edx, %eax
+       shr     $32, %rdx
+       wrmsr
+.Lend_\@:
+#endif
+.endm
+
+/*
  * Mitigate Spectre v1 for conditional swapgs code paths.
  *
  * FENCE_SWAPGS_USER_ENTRY is used in the user entry swapgs code path, to
diff --git a/arch/x86/entry/entry.S b/arch/x86/entry/entry.S
new file mode 100644 (file)
index 0000000..bfb7bcb
--- /dev/null
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common place for both 32- and 64-bit entry routines.
+ */
+
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/msr-index.h>
+
+.pushsection .noinstr.text, "ax"
+
+SYM_FUNC_START(entry_ibpb)
+       movl    $MSR_IA32_PRED_CMD, %ecx
+       movl    $PRED_CMD_IBPB, %eax
+       xorl    %edx, %edx
+       wrmsr
+       RET
+SYM_FUNC_END(entry_ibpb)
+/* For KVM */
+EXPORT_SYMBOL_GPL(entry_ibpb);
+
+.popsection
index 8874208..e309e71 100644 (file)
@@ -698,7 +698,6 @@ SYM_CODE_START(__switch_to_asm)
        movl    %ebx, PER_CPU_VAR(__stack_chk_guard)
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -707,7 +706,6 @@ SYM_CODE_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* Restore flags or the incoming task to restore AC state. */
        popfl
index 4300ba4..9953d96 100644 (file)
@@ -85,7 +85,7 @@
  */
 
 SYM_CODE_START(entry_SYSCALL_64)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
 
        swapgs
@@ -112,6 +112,11 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
        movq    %rsp, %rdi
        /* Sign extend the lower 32bit as syscall numbers are treated as int */
        movslq  %eax, %rsi
+
+       /* clobbers %rax, make sure it is after saving the syscall nr */
+       IBRS_ENTER
+       UNTRAIN_RET
+
        call    do_syscall_64           /* returns with IRQs disabled */
 
        /*
@@ -191,6 +196,7 @@ SYM_INNER_LABEL(entry_SYSCALL_64_after_hwframe, SYM_L_GLOBAL)
         * perf profiles. Nothing jumps here.
         */
 syscall_return_via_sysret:
+       IBRS_EXIT
        POP_REGS pop_rdi=0
 
        /*
@@ -249,7 +255,6 @@ SYM_FUNC_START(__switch_to_asm)
        movq    %rbx, PER_CPU_VAR(fixed_percpu_data) + stack_canary_offset
 #endif
 
-#ifdef CONFIG_RETPOLINE
        /*
         * When switching from a shallower to a deeper call stack
         * the RSB may either underflow or use entries populated
@@ -258,7 +263,6 @@ SYM_FUNC_START(__switch_to_asm)
         * speculative execution to prevent attack.
         */
        FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW
-#endif
 
        /* restore callee-saved registers */
        popq    %r15
@@ -322,13 +326,13 @@ SYM_CODE_END(ret_from_fork)
 #endif
 .endm
 
-/* Save all registers in pt_regs */
-SYM_CODE_START_LOCAL(push_and_clear_regs)
+SYM_CODE_START_LOCAL(xen_error_entry)
        UNWIND_HINT_FUNC
        PUSH_AND_CLEAR_REGS save_ret=1
        ENCODE_FRAME_POINTER 8
+       UNTRAIN_RET
        RET
-SYM_CODE_END(push_and_clear_regs)
+SYM_CODE_END(xen_error_entry)
 
 /**
  * idtentry_body - Macro to emit code calling the C function
@@ -337,9 +341,6 @@ SYM_CODE_END(push_and_clear_regs)
  */
 .macro idtentry_body cfunc has_error_code:req
 
-       call push_and_clear_regs
-       UNWIND_HINT_REGS
-
        /*
         * Call error_entry() and switch to the task stack if from userspace.
         *
@@ -349,7 +350,7 @@ SYM_CODE_END(push_and_clear_regs)
         * switch the CR3.  So it can skip invoking error_entry().
         */
        ALTERNATIVE "call error_entry; movq %rax, %rsp", \
-               "", X86_FEATURE_XENPV
+                   "call xen_error_entry", X86_FEATURE_XENPV
 
        ENCODE_FRAME_POINTER
        UNWIND_HINT_REGS
@@ -612,6 +613,7 @@ __irqentry_text_end:
 
 SYM_CODE_START_LOCAL(common_interrupt_return)
 SYM_INNER_LABEL(swapgs_restore_regs_and_return_to_usermode, SYM_L_GLOBAL)
+       IBRS_EXIT
 #ifdef CONFIG_DEBUG_ENTRY
        /* Assert that pt_regs indicates user mode. */
        testb   $3, CS(%rsp)
@@ -897,6 +899,9 @@ SYM_CODE_END(xen_failsafe_callback)
  *              1 -> no SWAPGS on exit
  *
  *     Y        GSBASE value at entry, must be restored in paranoid_exit
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_entry)
        UNWIND_HINT_FUNC
@@ -940,7 +945,7 @@ SYM_CODE_START_LOCAL(paranoid_entry)
         * is needed here.
         */
        SAVE_AND_SET_GSBASE scratch_reg=%rax save_reg=%rbx
-       RET
+       jmp .Lparanoid_gsbase_done
 
 .Lparanoid_entry_checkgs:
        /* EBX = 1 -> kernel GSBASE active, no restore required */
@@ -959,8 +964,16 @@ SYM_CODE_START_LOCAL(paranoid_entry)
        xorl    %ebx, %ebx
        swapgs
 .Lparanoid_kernel_gsbase:
-
        FENCE_SWAPGS_KERNEL_ENTRY
+.Lparanoid_gsbase_done:
+
+       /*
+        * Once we have CR3 and %GS setup save and set SPEC_CTRL. Just like
+        * CR3 above, keep the old value in a callee saved register.
+        */
+       IBRS_ENTER save_reg=%r15
+       UNTRAIN_RET
+
        RET
 SYM_CODE_END(paranoid_entry)
 
@@ -982,9 +995,19 @@ SYM_CODE_END(paranoid_entry)
  *              1 -> no SWAPGS on exit
  *
  *     Y        User space GSBASE, must be restored unconditionally
+ *
+ * R14 - old CR3
+ * R15 - old SPEC_CTRL
  */
 SYM_CODE_START_LOCAL(paranoid_exit)
        UNWIND_HINT_REGS
+
+       /*
+        * Must restore IBRS state before both CR3 and %GS since we need access
+        * to the per-CPU x86_spec_ctrl_shadow variable.
+        */
+       IBRS_EXIT save_reg=%r15
+
        /*
         * The order of operations is important. RESTORE_CR3 requires
         * kernel GSBASE.
@@ -1017,6 +1040,10 @@ SYM_CODE_END(paranoid_exit)
  */
 SYM_CODE_START_LOCAL(error_entry)
        UNWIND_HINT_FUNC
+
+       PUSH_AND_CLEAR_REGS save_ret=1
+       ENCODE_FRAME_POINTER 8
+
        testb   $3, CS+8(%rsp)
        jz      .Lerror_kernelspace
 
@@ -1028,9 +1055,12 @@ SYM_CODE_START_LOCAL(error_entry)
        FENCE_SWAPGS_USER_ENTRY
        /* We have user CR3.  Change to kernel CR3. */
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        leaq    8(%rsp), %rdi                   /* arg0 = pt_regs pointer */
 .Lerror_entry_from_usermode_after_swapgs:
+
        /* Put us onto the real thread stack. */
        call    sync_regs
        RET
@@ -1065,6 +1095,7 @@ SYM_CODE_START_LOCAL(error_entry)
 .Lerror_entry_done_lfence:
        FENCE_SWAPGS_KERNEL_ENTRY
        leaq    8(%rsp), %rax                   /* return pt_regs pointer */
+       ANNOTATE_UNRET_END
        RET
 
 .Lbstep_iret:
@@ -1080,6 +1111,8 @@ SYM_CODE_START_LOCAL(error_entry)
        swapgs
        FENCE_SWAPGS_USER_ENTRY
        SWITCH_TO_KERNEL_CR3 scratch_reg=%rax
+       IBRS_ENTER
+       UNTRAIN_RET
 
        /*
         * Pretend that the exception came from user mode: set up pt_regs
@@ -1185,6 +1218,9 @@ SYM_CODE_START(asm_exc_nmi)
        PUSH_AND_CLEAR_REGS rdx=(%rdx)
        ENCODE_FRAME_POINTER
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * At this point we no longer need to worry about stack damage
         * due to nesting -- we're on the normal thread stack and we're
@@ -1409,6 +1445,9 @@ end_repeat_nmi:
        movq    $-1, %rsi
        call    exc_nmi
 
+       /* Always restore stashed SPEC_CTRL value (see paranoid_entry) */
+       IBRS_EXIT save_reg=%r15
+
        /* Always restore stashed CR3 value (see paranoid_entry) */
        RESTORE_CR3 scratch_reg=%r15 save_reg=%r14
 
index d105274..682338e 100644 (file)
@@ -4,7 +4,6 @@
  *
  * Copyright 2000-2002 Andi Kleen, SuSE Labs.
  */
-#include "calling.h"
 #include <asm/asm-offsets.h>
 #include <asm/current.h>
 #include <asm/errno.h>
 #include <asm/irqflags.h>
 #include <asm/asm.h>
 #include <asm/smap.h>
+#include <asm/nospec-branch.h>
 #include <linux/linkage.h>
 #include <linux/err.h>
 
+#include "calling.h"
+
        .section .entry.text, "ax"
 
 /*
@@ -47,7 +49,7 @@
  * 0(%ebp) arg6
  */
 SYM_CODE_START(entry_SYSENTER_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -88,6 +90,9 @@ SYM_INNER_LABEL(entry_SYSENTER_compat_after_hwframe, SYM_L_GLOBAL)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        /*
         * SYSENTER doesn't filter flags, so we need to clear NT and AC
         * ourselves.  To save a few cycles, we can check whether
@@ -174,7 +179,7 @@ SYM_CODE_END(entry_SYSENTER_compat)
  * 0(%esp) arg6
  */
 SYM_CODE_START(entry_SYSCALL_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /* Interrupts are off on entry. */
        swapgs
@@ -203,6 +208,9 @@ SYM_INNER_LABEL(entry_SYSCALL_compat_after_hwframe, SYM_L_GLOBAL)
        PUSH_AND_CLEAR_REGS rcx=%rbp rax=$-ENOSYS
        UNWIND_HINT_REGS
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_fast_syscall_32
        /* XEN PV guests always use IRET path */
@@ -217,6 +225,8 @@ sysret32_from_system_call:
         */
        STACKLEAK_ERASE
 
+       IBRS_EXIT
+
        movq    RBX(%rsp), %rbx         /* pt_regs->rbx */
        movq    RBP(%rsp), %rbp         /* pt_regs->rbp */
        movq    EFLAGS(%rsp), %r11      /* pt_regs->flags (in r11) */
@@ -295,7 +305,7 @@ SYM_CODE_END(entry_SYSCALL_compat)
  * ebp  arg6
  */
 SYM_CODE_START(entry_INT80_compat)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * Interrupts are off on entry.
@@ -337,6 +347,9 @@ SYM_CODE_START(entry_INT80_compat)
 
        cld
 
+       IBRS_ENTER
+       UNTRAIN_RET
+
        movq    %rsp, %rdi
        call    do_int80_syscall_32
        jmp     swapgs_restore_regs_and_return_to_usermode
index c2a8b76..76cd790 100644 (file)
@@ -92,6 +92,7 @@ endif
 endif
 
 $(vobjs): KBUILD_CFLAGS := $(filter-out $(CC_FLAGS_LTO) $(RANDSTRUCT_CFLAGS) $(GCC_PLUGINS_CFLAGS) $(RETPOLINE_CFLAGS),$(KBUILD_CFLAGS)) $(CFL)
+$(vobjs): KBUILD_AFLAGS += -DBUILD_VDSO
 
 #
 # vDSO code runs in userspace and -pg doesn't help with profiling anyway.
index 15e3515..ef2dd18 100644 (file)
@@ -19,17 +19,20 @@ __vsyscall_page:
 
        mov $__NR_gettimeofday, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_time, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 1024, 0xcc
        mov $__NR_getcpu, %rax
        syscall
-       RET
+       ret
+       int3
 
        .balign 4096, 0xcc
 
index 9b10c8c..9542c58 100644 (file)
@@ -76,6 +76,7 @@ extern int alternatives_patched;
 extern void alternative_instructions(void);
 extern void apply_alternatives(struct alt_instr *start, struct alt_instr *end);
 extern void apply_retpolines(s32 *start, s32 *end);
+extern void apply_returns(s32 *start, s32 *end);
 extern void apply_ibt_endbr(s32 *start, s32 *end);
 
 struct module;
index 03acc82..00f5227 100644 (file)
 #define X86_FEATURE_PROC_FEEDBACK      ( 7*32+ 9) /* AMD ProcFeedbackInterface */
 #define X86_FEATURE_XCOMPACTED         ( 7*32+10) /* "" Use compacted XSTATE (XSAVES or XSAVEC) */
 #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_LFENCE   ( 7*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_KERNEL_IBRS                ( 7*32+12) /* "" Set/clear IBRS on kernel entry/exit */
+#define X86_FEATURE_RSB_VMEXIT         ( 7*32+13) /* "" Fill RSB on VM-Exit */
 #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 */
 #define X86_FEATURE_PER_THREAD_MBA     (11*32+ 7) /* "" Per-thread Memory Bandwidth Allocation */
 #define X86_FEATURE_SGX1               (11*32+ 8) /* "" Basic SGX */
 #define X86_FEATURE_SGX2               (11*32+ 9) /* "" SGX Enclave Dynamic Memory Management (EDMM) */
+#define X86_FEATURE_ENTRY_IBPB         (11*32+10) /* "" Issue an IBPB on kernel entry */
+#define X86_FEATURE_RRSBA_CTRL         (11*32+11) /* "" RET prediction control */
+#define X86_FEATURE_RETPOLINE          (11*32+12) /* "" Generic Retpoline mitigation for Spectre variant 2 */
+#define X86_FEATURE_RETPOLINE_LFENCE   (11*32+13) /* "" Use LFENCE for Spectre variant 2 */
+#define X86_FEATURE_RETHUNK            (11*32+14) /* "" Use REturn THUNK */
+#define X86_FEATURE_UNRET              (11*32+15) /* "" AMD BTB untrain return */
 
 /* Intel-defined CPU features, CPUID level 0x00000007:1 (EAX), word 12 */
 #define X86_FEATURE_AVX_VNNI           (12*32+ 4) /* AVX VNNI instructions */
 #define X86_FEATURE_VIRT_SSBD          (13*32+25) /* Virtualized Speculative Store Bypass Disable */
 #define X86_FEATURE_AMD_SSB_NO         (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */
 #define X86_FEATURE_CPPC               (13*32+27) /* Collaborative Processor Performance Control */
+#define X86_FEATURE_BTC_NO             (13*32+29) /* "" Not vulnerable to Branch Type Confusion */
 #define X86_FEATURE_BRS                        (13*32+31) /* Branch Sampling available */
 
 /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */
 #define X86_BUG_ITLB_MULTIHIT          X86_BUG(23) /* CPU may incur MCE during certain page attribute changes */
 #define X86_BUG_SRBDS                  X86_BUG(24) /* CPU may leak RNG bits if not mitigated */
 #define X86_BUG_MMIO_STALE_DATA                X86_BUG(25) /* CPU is affected by Processor MMIO Stale Data vulnerabilities */
+#define X86_BUG_RETBLEED               X86_BUG(26) /* CPU is affected by RETBleed */
 
 #endif /* _ASM_X86_CPUFEATURES_H */
index 36369e7..33d2cd0 100644 (file)
 # define DISABLE_PTI           (1 << (X86_FEATURE_PTI & 31))
 #endif
 
+#ifdef CONFIG_RETPOLINE
+# define DISABLE_RETPOLINE     0
+#else
+# define DISABLE_RETPOLINE     ((1 << (X86_FEATURE_RETPOLINE & 31)) | \
+                                (1 << (X86_FEATURE_RETPOLINE_LFENCE & 31)))
+#endif
+
+#ifdef CONFIG_RETHUNK
+# define DISABLE_RETHUNK       0
+#else
+# define DISABLE_RETHUNK       (1 << (X86_FEATURE_RETHUNK & 31))
+#endif
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+# define DISABLE_UNRET         0
+#else
+# define DISABLE_UNRET         (1 << (X86_FEATURE_UNRET & 31))
+#endif
+
 #ifdef CONFIG_INTEL_IOMMU_SVM
 # define DISABLE_ENQCMD                0
 #else
 #define DISABLED_MASK8 (DISABLE_TDX_GUEST)
 #define DISABLED_MASK9 (DISABLE_SGX)
 #define DISABLED_MASK10        0
-#define DISABLED_MASK11        0
+#define DISABLED_MASK11        (DISABLE_RETPOLINE|DISABLE_RETHUNK|DISABLE_UNRET)
 #define DISABLED_MASK12        0
 #define DISABLED_MASK13        0
 #define DISABLED_MASK14        0
index 85865f1..73ca200 100644 (file)
 #define __ALIGN_STR    __stringify(__ALIGN)
 #endif
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define RET    jmp __x86_return_thunk
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define RET    ret; int3
 #else
 #define RET    ret
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #else /* __ASSEMBLY__ */
 
+#if defined(CONFIG_RETHUNK) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
+#define ASM_RET        "jmp __x86_return_thunk\n\t"
+#else /* CONFIG_RETPOLINE */
 #ifdef CONFIG_SLS
 #define ASM_RET        "ret; int3\n\t"
 #else
 #define ASM_RET        "ret\n\t"
 #endif
+#endif /* CONFIG_RETPOLINE */
 
 #endif /* __ASSEMBLY__ */
 
index d27e058..cc615be 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
@@ -93,6 +95,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES     0x0000010a
 #define ARCH_CAP_RDCL_NO               BIT(0)  /* Not susceptible to Meltdown */
 #define ARCH_CAP_IBRS_ALL              BIT(1)  /* Enhanced IBRS support */
+#define ARCH_CAP_RSBA                  BIT(2)  /* RET may use alternative branch predictors */
 #define ARCH_CAP_SKIP_VMENTRY_L1DFLUSH BIT(3)  /* Skip L1D flush on vmentry */
 #define ARCH_CAP_SSB_NO                        BIT(4)  /*
                                                 * Not susceptible to Speculative Store Bypass
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
 /* Fam 17h MSRs */
 #define MSR_F17H_IRPERF                        0xc00000e9
 
+#define MSR_ZEN2_SPECTRAL_CHICKEN      0xc00110e3
+#define MSR_ZEN2_SPECTRAL_CHICKEN_BIT  BIT_ULL(1)
+
 /* Fam 16h MSRs */
 #define MSR_F16H_L2I_PERF_CTL          0xc0010230
 #define MSR_F16H_L2I_PERF_CTR          0xc0010231
index da251a5..10a3bfc 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/msr-index.h>
 #include <asm/unwind_hints.h>
+#include <asm/percpu.h>
 
 #define RETPOLINE_THUNK_SIZE   32
 
 .endm
 
 /*
+ * (ab)use RETPOLINE_SAFE on RET to annotate away 'bare' RET instructions
+ * vs RETBleed validation.
+ */
+#define ANNOTATE_UNRET_SAFE ANNOTATE_RETPOLINE_SAFE
+
+/*
+ * Abuse ANNOTATE_RETPOLINE_SAFE on a NOP to indicate UNRET_END, should
+ * eventually turn into it's own annotation.
+ */
+.macro ANNOTATE_UNRET_END
+#ifdef CONFIG_DEBUG_ENTRY
+       ANNOTATE_RETPOLINE_SAFE
+       nop
+#endif
+.endm
+
+/*
  * JMP_NOSPEC and CALL_NOSPEC macros can be used instead of a simple
  * indirect jmp/call which may be susceptible to the Spectre variant 2
  * attack.
   * monstrosity above, manually.
   */
 .macro FILL_RETURN_BUFFER reg:req nr:req ftr:req
-#ifdef CONFIG_RETPOLINE
        ALTERNATIVE "jmp .Lskip_rsb_\@", "", \ftr
        __FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)
 .Lskip_rsb_\@:
+.endm
+
+#ifdef CONFIG_CPU_UNRET_ENTRY
+#define CALL_ZEN_UNTRAIN_RET   "call zen_untrain_ret"
+#else
+#define CALL_ZEN_UNTRAIN_RET   ""
+#endif
+
+/*
+ * Mitigate RETBleed for AMD/Hygon Zen uarch. Requires KERNEL CR3 because the
+ * return thunk isn't mapped into the userspace tables (then again, AMD
+ * typically has NO_MELTDOWN).
+ *
+ * While zen_untrain_ret() doesn't clobber anything but requires stack,
+ * entry_ibpb() will clobber AX, CX, DX.
+ *
+ * As such, this must be placed after every *SWITCH_TO_KERNEL_CR3 at a point
+ * where we have a stack but before any RET instruction.
+ */
+.macro UNTRAIN_RET
+#if defined(CONFIG_CPU_UNRET_ENTRY) || defined(CONFIG_CPU_IBPB_ENTRY)
+       ANNOTATE_UNRET_END
+       ALTERNATIVE_2 "",                                               \
+                     CALL_ZEN_UNTRAIN_RET, X86_FEATURE_UNRET,          \
+                     "call entry_ibpb", X86_FEATURE_ENTRY_IBPB
 #endif
 .endm
 
        _ASM_PTR " 999b\n\t"                                    \
        ".popsection\n\t"
 
-#ifdef CONFIG_RETPOLINE
-
 typedef u8 retpoline_thunk_t[RETPOLINE_THUNK_SIZE];
+extern retpoline_thunk_t __x86_indirect_thunk_array[];
+
+extern void __x86_return_thunk(void);
+extern void zen_untrain_ret(void);
+extern void entry_ibpb(void);
+
+#ifdef CONFIG_RETPOLINE
 
 #define GEN(reg) \
        extern retpoline_thunk_t __x86_indirect_thunk_ ## reg;
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
 
-extern retpoline_thunk_t __x86_indirect_thunk_array[];
-
 #ifdef CONFIG_X86_64
 
 /*
@@ -193,6 +238,7 @@ enum spectre_v2_mitigation {
        SPECTRE_V2_EIBRS,
        SPECTRE_V2_EIBRS_RETPOLINE,
        SPECTRE_V2_EIBRS_LFENCE,
+       SPECTRE_V2_IBRS,
 };
 
 /* The indirect branch speculation control variants */
@@ -235,6 +281,9 @@ static inline void indirect_branch_prediction_barrier(void)
 
 /* The Intel SPEC CTRL MSR base value cache */
 extern u64 x86_spec_ctrl_base;
+DECLARE_PER_CPU(u64, x86_spec_ctrl_current);
+extern void write_spec_ctrl_current(u64 val, bool force);
+extern u64 spec_ctrl_current(void);
 
 /*
  * With retpoline, we must use IBRS to restrict branch prediction
@@ -244,18 +293,16 @@ extern u64 x86_spec_ctrl_base;
  */
 #define firmware_restrict_branch_speculation_start()                   \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base | SPEC_CTRL_IBRS;                  \
-                                                                       \
        preempt_disable();                                              \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current() | SPEC_CTRL_IBRS,     \
                              X86_FEATURE_USE_IBRS_FW);                 \
 } while (0)
 
 #define firmware_restrict_branch_speculation_end()                     \
 do {                                                                   \
-       u64 val = x86_spec_ctrl_base;                                   \
-                                                                       \
-       alternative_msr_write(MSR_IA32_SPEC_CTRL, val,                  \
+       alternative_msr_write(MSR_IA32_SPEC_CTRL,                       \
+                             spec_ctrl_current(),                      \
                              X86_FEATURE_USE_IBRS_FW);                 \
        preempt_enable();                                               \
 } while (0)
index f8b9ee9..f37cbff 100644 (file)
@@ -120,6 +120,9 @@ void *extend_brk(size_t size, size_t align);
        static char __brk_##name[size]
 
 extern void probe_roms(void);
+
+void clear_bss(void);
+
 #ifdef __i386__
 
 asmlinkage void __init i386_start_kernel(void);
index 2d8dacd..343b722 100644 (file)
  * relative displacement across sections.
  */
 
+/*
+ * The trampoline is 8 bytes and of the general form:
+ *
+ *   jmp.d32 \func
+ *   ud1 %esp, %ecx
+ *
+ * That trailing #UD provides both a speculation stop and serves as a unique
+ * 3 byte signature identifying static call trampolines. Also see tramp_ud[]
+ * and __static_call_fixup().
+ */
 #define __ARCH_DEFINE_STATIC_CALL_TRAMP(name, insns)                   \
        asm(".pushsection .static_call.text, \"ax\"             \n"     \
            ".align 4                                           \n"     \
@@ -28,7 +38,7 @@
            STATIC_CALL_TRAMP_STR(name) ":                      \n"     \
            ANNOTATE_NOENDBR                                            \
            insns "                                             \n"     \
-           ".byte 0x53, 0x43, 0x54                             \n"     \
+           ".byte 0x0f, 0xb9, 0xcc                             \n"     \
            ".type " STATIC_CALL_TRAMP_STR(name) ", @function   \n"     \
            ".size " STATIC_CALL_TRAMP_STR(name) ", . - " STATIC_CALL_TRAMP_STR(name) " \n" \
            ".popsection                                        \n")
 #define ARCH_DEFINE_STATIC_CALL_TRAMP(name, func)                      \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, ".byte 0xe9; .long " #func " - (. + 4)")
 
+#ifdef CONFIG_RETHUNK
+#define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
+       __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "jmp __x86_return_thunk")
+#else
 #define ARCH_DEFINE_STATIC_CALL_NULL_TRAMP(name)                       \
        __ARCH_DEFINE_STATIC_CALL_TRAMP(name, "ret; int3; nop; nop; nop")
+#endif
 
 #define ARCH_DEFINE_STATIC_CALL_RET0_TRAMP(name)                       \
        ARCH_DEFINE_STATIC_CALL_TRAMP(name, __static_call_return0)
@@ -48,4 +63,6 @@
            ".long " STATIC_CALL_KEY_STR(name) " - .            \n"     \
            ".popsection                                        \n")
 
+extern bool __static_call_fixup(void *tramp, u8 op, void *dest);
+
 #endif /* _ASM_STATIC_CALL_H */
index 8b33674..f66fbe6 100644 (file)
@@ -8,7 +8,11 @@
 #ifdef __ASSEMBLY__
 
 .macro UNWIND_HINT_EMPTY
-       UNWIND_HINT sp_reg=ORC_REG_UNDEFINED type=UNWIND_HINT_TYPE_CALL end=1
+       UNWIND_HINT type=UNWIND_HINT_TYPE_CALL end=1
+.endm
+
+.macro UNWIND_HINT_ENTRY
+       UNWIND_HINT type=UNWIND_HINT_TYPE_ENTRY end=1
 .endm
 
 .macro UNWIND_HINT_REGS base=%rsp offset=0 indirect=0 extra=1 partial=0
        UNWIND_HINT sp_reg=ORC_REG_SP sp_offset=8 type=UNWIND_HINT_TYPE_FUNC
 .endm
 
+.macro UNWIND_HINT_SAVE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_SAVE
+.endm
+
+.macro UNWIND_HINT_RESTORE
+       UNWIND_HINT type=UNWIND_HINT_TYPE_RESTORE
+.endm
+
 #else
 
 #define UNWIND_HINT_FUNC \
index bea5cdc..e02a8a8 100644 (file)
@@ -15,7 +15,7 @@
 #define SETUP_INDIRECT                 (1<<31)
 
 /* SETUP_INDIRECT | max(SETUP_*) */
-#define SETUP_TYPE_MAX                 (SETUP_INDIRECT | SETUP_JAILHOUSE)
+#define SETUP_TYPE_MAX                 (SETUP_INDIRECT | SETUP_CC_BLOB)
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK       0x07FF
index 8b8cbf2..8d8752b 100644 (file)
 
 /* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
 
+bool cpc_supported_by_cpu(void)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+       case X86_VENDOR_HYGON:
+               if (boot_cpu_data.x86 == 0x19 && ((boot_cpu_data.x86_model <= 0x0f) ||
+                   (boot_cpu_data.x86_model >= 0x20 && boot_cpu_data.x86_model <= 0x2f)))
+                       return true;
+               else if (boot_cpu_data.x86 == 0x17 &&
+                        boot_cpu_data.x86_model >= 0x70 && boot_cpu_data.x86_model <= 0x7f)
+                       return true;
+               return boot_cpu_has(X86_FEATURE_CPPC);
+       }
+       return false;
+}
+
 bool cpc_ffh_supported(void)
 {
        return true;
index e257f6c..d685853 100644 (file)
@@ -115,6 +115,7 @@ static void __init_or_module add_nops(void *insns, unsigned int len)
 }
 
 extern s32 __retpoline_sites[], __retpoline_sites_end[];
+extern s32 __return_sites[], __return_sites_end[];
 extern s32 __ibt_endbr_seal[], __ibt_endbr_seal_end[];
 extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
 extern s32 __smp_locks[], __smp_locks_end[];
@@ -507,9 +508,76 @@ void __init_or_module noinline apply_retpolines(s32 *start, s32 *end)
        }
 }
 
+#ifdef CONFIG_RETHUNK
+/*
+ * Rewrite the compiler generated return thunk tail-calls.
+ *
+ * For example, convert:
+ *
+ *   JMP __x86_return_thunk
+ *
+ * into:
+ *
+ *   RET
+ */
+static int patch_return(void *addr, struct insn *insn, u8 *bytes)
+{
+       int i = 0;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               return -1;
+
+       bytes[i++] = RET_INSN_OPCODE;
+
+       for (; i < insn->length;)
+               bytes[i++] = INT3_INSN_OPCODE;
+
+       return i;
+}
+
+void __init_or_module noinline apply_returns(s32 *start, s32 *end)
+{
+       s32 *s;
+
+       for (s = start; s < end; s++) {
+               void *dest = NULL, *addr = (void *)s + *s;
+               struct insn insn;
+               int len, ret;
+               u8 bytes[16];
+               u8 op;
+
+               ret = insn_decode_kernel(&insn, addr);
+               if (WARN_ON_ONCE(ret < 0))
+                       continue;
+
+               op = insn.opcode.bytes[0];
+               if (op == JMP32_INSN_OPCODE)
+                       dest = addr + insn.length + insn.immediate.value;
+
+               if (__static_call_fixup(addr, op, dest) ||
+                   WARN_ON_ONCE(dest != &__x86_return_thunk))
+                       continue;
+
+               DPRINTK("return thunk at: %pS (%px) len: %d to: %pS",
+                       addr, addr, insn.length,
+                       addr + insn.length + insn.immediate.value);
+
+               len = patch_return(addr, &insn, bytes);
+               if (len == insn.length) {
+                       DUMP_BYTES(((u8*)addr),  len, "%px: orig: ", addr);
+                       DUMP_BYTES(((u8*)bytes), len, "%px: repl: ", addr);
+                       text_poke_early(addr, bytes, len);
+               }
+       }
+}
+#else
+void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
+#endif /* CONFIG_RETHUNK */
+
 #else /* !CONFIG_RETPOLINE || !CONFIG_OBJTOOL */
 
 void __init_or_module noinline apply_retpolines(s32 *start, s32 *end) { }
+void __init_or_module noinline apply_returns(s32 *start, s32 *end) { }
 
 #endif /* CONFIG_RETPOLINE && CONFIG_OBJTOOL */
 
@@ -860,6 +928,7 @@ void __init alternative_instructions(void)
         * those can rewrite the retpoline thunks.
         */
        apply_retpolines(__retpoline_sites, __retpoline_sites_end);
+       apply_returns(__return_sites, __return_sites_end);
 
        /*
         * Then patch alternatives, such that those paravirt calls that are in
index 4373080..cb50589 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/suspend.h>
 #include <asm/tlbflush.h>
 #include <asm/tdx.h>
+#include "../kvm/vmx/vmx.h"
 
 #ifdef CONFIG_XEN
 #include <xen/interface/xen.h>
@@ -107,4 +108,9 @@ static void __used common(void)
        OFFSET(TSS_sp0, tss_struct, x86_tss.sp0);
        OFFSET(TSS_sp1, tss_struct, x86_tss.sp1);
        OFFSET(TSS_sp2, tss_struct, x86_tss.sp2);
+
+       if (IS_ENABLED(CONFIG_KVM_INTEL)) {
+               BLANK();
+               OFFSET(VMX_spec_ctrl, vcpu_vmx, spec_ctrl);
+       }
 }
index 0c0b097..35d5288 100644 (file)
@@ -862,6 +862,28 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
        clear_rdrand_cpuid_bit(c);
 }
 
+void init_spectral_chicken(struct cpuinfo_x86 *c)
+{
+#ifdef CONFIG_CPU_UNRET_ENTRY
+       u64 value;
+
+       /*
+        * On Zen2 we offer this chicken (bit) on the altar of Speculation.
+        *
+        * This suppresses speculation from the middle of a basic block, i.e. it
+        * suppresses non-branch predictions.
+        *
+        * We use STIBP as a heuristic to filter out Zen2 from the rest of F17H
+        */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && cpu_has(c, X86_FEATURE_AMD_STIBP)) {
+               if (!rdmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, &value)) {
+                       value |= MSR_ZEN2_SPECTRAL_CHICKEN_BIT;
+                       wrmsrl_safe(MSR_ZEN2_SPECTRAL_CHICKEN, value);
+               }
+       }
+#endif
+}
+
 static void init_amd_zn(struct cpuinfo_x86 *c)
 {
        set_cpu_cap(c, X86_FEATURE_ZEN);
@@ -870,12 +892,21 @@ static void init_amd_zn(struct cpuinfo_x86 *c)
        node_reclaim_distance = 32;
 #endif
 
-       /*
-        * Fix erratum 1076: CPB feature bit not being set in CPUID.
-        * Always set it, except when running under a hypervisor.
-        */
-       if (!cpu_has(c, X86_FEATURE_HYPERVISOR) && !cpu_has(c, X86_FEATURE_CPB))
-               set_cpu_cap(c, X86_FEATURE_CPB);
+       /* Fix up CPUID bits, but only if not virtualised. */
+       if (!cpu_has(c, X86_FEATURE_HYPERVISOR)) {
+
+               /* Erratum 1076: CPB feature bit not being set in CPUID. */
+               if (!cpu_has(c, X86_FEATURE_CPB))
+                       set_cpu_cap(c, X86_FEATURE_CPB);
+
+               /*
+                * Zen3 (Fam19 model < 0x10) parts are not susceptible to
+                * Branch Type Confusion, but predate the allocation of the
+                * BTC_NO bit.
+                */
+               if (c->x86 == 0x19 && !cpu_has(c, X86_FEATURE_BTC_NO))
+                       set_cpu_cap(c, X86_FEATURE_BTC_NO);
+       }
 }
 
 static void init_amd(struct cpuinfo_x86 *c)
@@ -907,7 +938,8 @@ static void init_amd(struct cpuinfo_x86 *c)
        case 0x12: init_amd_ln(c); break;
        case 0x15: init_amd_bd(c); break;
        case 0x16: init_amd_jg(c); break;
-       case 0x17: fallthrough;
+       case 0x17: init_spectral_chicken(c);
+                  fallthrough;
        case 0x19: init_amd_zn(c); break;
        }
 
index 74c62cc..aa34f90 100644 (file)
@@ -38,6 +38,8 @@
 
 static void __init spectre_v1_select_mitigation(void);
 static void __init spectre_v2_select_mitigation(void);
+static void __init retbleed_select_mitigation(void);
+static void __init spectre_v2_user_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
 static void __init mds_select_mitigation(void);
@@ -48,16 +50,40 @@ static void __init mmio_select_mitigation(void);
 static void __init srbds_select_mitigation(void);
 static void __init l1d_flush_select_mitigation(void);
 
-/* The base value of the SPEC_CTRL MSR that always has to be preserved. */
+/* The base value of the SPEC_CTRL MSR without task-specific bits set */
 u64 x86_spec_ctrl_base;
 EXPORT_SYMBOL_GPL(x86_spec_ctrl_base);
+
+/* The current value of the SPEC_CTRL MSR with task-specific bits set */
+DEFINE_PER_CPU(u64, x86_spec_ctrl_current);
+EXPORT_SYMBOL_GPL(x86_spec_ctrl_current);
+
 static DEFINE_MUTEX(spec_ctrl_mutex);
 
 /*
- * The vendor and possibly platform specific bits which can be modified in
- * x86_spec_ctrl_base.
+ * Keep track of the SPEC_CTRL MSR value for the current task, which may differ
+ * from x86_spec_ctrl_base due to STIBP/SSB in __speculation_ctrl_update().
  */
-static u64 __ro_after_init x86_spec_ctrl_mask = SPEC_CTRL_IBRS;
+void write_spec_ctrl_current(u64 val, bool force)
+{
+       if (this_cpu_read(x86_spec_ctrl_current) == val)
+               return;
+
+       this_cpu_write(x86_spec_ctrl_current, val);
+
+       /*
+        * When KERNEL_IBRS this MSR is written on return-to-user, unless
+        * forced the update can be delayed until that time.
+        */
+       if (force || !cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS))
+               wrmsrl(MSR_IA32_SPEC_CTRL, val);
+}
+
+u64 spec_ctrl_current(void)
+{
+       return this_cpu_read(x86_spec_ctrl_current);
+}
+EXPORT_SYMBOL_GPL(spec_ctrl_current);
 
 /*
  * AMD specific MSR info for Speculative Store Bypass control.
@@ -114,13 +140,21 @@ void __init check_bugs(void)
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
                rdmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
 
-       /* Allow STIBP in MSR_SPEC_CTRL if supported */
-       if (boot_cpu_has(X86_FEATURE_STIBP))
-               x86_spec_ctrl_mask |= SPEC_CTRL_STIBP;
-
        /* Select the proper CPU mitigations before patching alternatives: */
        spectre_v1_select_mitigation();
        spectre_v2_select_mitigation();
+       /*
+        * retbleed_select_mitigation() relies on the state set by
+        * spectre_v2_select_mitigation(); specifically it wants to know about
+        * spectre_v2=ibrs.
+        */
+       retbleed_select_mitigation();
+       /*
+        * spectre_v2_user_select_mitigation() relies on the state set by
+        * retbleed_select_mitigation(); specifically the STIBP selection is
+        * forced for UNRET.
+        */
+       spectre_v2_user_select_mitigation();
        ssb_select_mitigation();
        l1tf_select_mitigation();
        md_clear_select_mitigation();
@@ -161,31 +195,17 @@ void __init check_bugs(void)
 #endif
 }
 
+/*
+ * NOTE: This function is *only* called for SVM.  VMX spec_ctrl handling is
+ * done in vmenter.S.
+ */
 void
 x86_virt_spec_ctrl(u64 guest_spec_ctrl, u64 guest_virt_spec_ctrl, bool setguest)
 {
-       u64 msrval, guestval, hostval = x86_spec_ctrl_base;
+       u64 msrval, guestval = guest_spec_ctrl, hostval = spec_ctrl_current();
        struct thread_info *ti = current_thread_info();
 
-       /* Is MSR_SPEC_CTRL implemented ? */
        if (static_cpu_has(X86_FEATURE_MSR_SPEC_CTRL)) {
-               /*
-                * Restrict guest_spec_ctrl to supported values. Clear the
-                * modifiable bits in the host base value and or the
-                * modifiable bits from the guest value.
-                */
-               guestval = hostval & ~x86_spec_ctrl_mask;
-               guestval |= guest_spec_ctrl & x86_spec_ctrl_mask;
-
-               /* SSBD controlled in MSR_SPEC_CTRL */
-               if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-                   static_cpu_has(X86_FEATURE_AMD_SSBD))
-                       hostval |= ssbd_tif_to_spec_ctrl(ti->flags);
-
-               /* Conditional STIBP enabled? */
-               if (static_branch_unlikely(&switch_to_cond_stibp))
-                       hostval |= stibp_tif_to_spec_ctrl(ti->flags);
-
                if (hostval != guestval) {
                        msrval = setguest ? guestval : hostval;
                        wrmsrl(MSR_IA32_SPEC_CTRL, msrval);
@@ -752,12 +772,180 @@ static int __init nospectre_v1_cmdline(char *str)
 }
 early_param("nospectre_v1", nospectre_v1_cmdline);
 
-#undef pr_fmt
-#define pr_fmt(fmt)     "Spectre V2 : " fmt
-
 static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init =
        SPECTRE_V2_NONE;
 
+#undef pr_fmt
+#define pr_fmt(fmt)     "RETBleed: " fmt
+
+enum retbleed_mitigation {
+       RETBLEED_MITIGATION_NONE,
+       RETBLEED_MITIGATION_UNRET,
+       RETBLEED_MITIGATION_IBPB,
+       RETBLEED_MITIGATION_IBRS,
+       RETBLEED_MITIGATION_EIBRS,
+};
+
+enum retbleed_mitigation_cmd {
+       RETBLEED_CMD_OFF,
+       RETBLEED_CMD_AUTO,
+       RETBLEED_CMD_UNRET,
+       RETBLEED_CMD_IBPB,
+};
+
+static const char * const retbleed_strings[] = {
+       [RETBLEED_MITIGATION_NONE]      = "Vulnerable",
+       [RETBLEED_MITIGATION_UNRET]     = "Mitigation: untrained return thunk",
+       [RETBLEED_MITIGATION_IBPB]      = "Mitigation: IBPB",
+       [RETBLEED_MITIGATION_IBRS]      = "Mitigation: IBRS",
+       [RETBLEED_MITIGATION_EIBRS]     = "Mitigation: Enhanced IBRS",
+};
+
+static enum retbleed_mitigation retbleed_mitigation __ro_after_init =
+       RETBLEED_MITIGATION_NONE;
+static enum retbleed_mitigation_cmd retbleed_cmd __ro_after_init =
+       RETBLEED_CMD_AUTO;
+
+static int __ro_after_init retbleed_nosmt = false;
+
+static int __init retbleed_parse_cmdline(char *str)
+{
+       if (!str)
+               return -EINVAL;
+
+       while (str) {
+               char *next = strchr(str, ',');
+               if (next) {
+                       *next = 0;
+                       next++;
+               }
+
+               if (!strcmp(str, "off")) {
+                       retbleed_cmd = RETBLEED_CMD_OFF;
+               } else if (!strcmp(str, "auto")) {
+                       retbleed_cmd = RETBLEED_CMD_AUTO;
+               } else if (!strcmp(str, "unret")) {
+                       retbleed_cmd = RETBLEED_CMD_UNRET;
+               } else if (!strcmp(str, "ibpb")) {
+                       retbleed_cmd = RETBLEED_CMD_IBPB;
+               } else if (!strcmp(str, "nosmt")) {
+                       retbleed_nosmt = true;
+               } else {
+                       pr_err("Ignoring unknown retbleed option (%s).", str);
+               }
+
+               str = next;
+       }
+
+       return 0;
+}
+early_param("retbleed", retbleed_parse_cmdline);
+
+#define RETBLEED_UNTRAIN_MSG "WARNING: BTB untrained return thunk mitigation is only effective on AMD/Hygon!\n"
+#define RETBLEED_INTEL_MSG "WARNING: Spectre v2 mitigation leaves CPU vulnerable to RETBleed attacks, data leaks possible!\n"
+
+static void __init retbleed_select_mitigation(void)
+{
+       bool mitigate_smt = false;
+
+       if (!boot_cpu_has_bug(X86_BUG_RETBLEED) || cpu_mitigations_off())
+               return;
+
+       switch (retbleed_cmd) {
+       case RETBLEED_CMD_OFF:
+               return;
+
+       case RETBLEED_CMD_UNRET:
+               if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_UNRET_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+       case RETBLEED_CMD_IBPB:
+               if (!boot_cpu_has(X86_FEATURE_IBPB)) {
+                       pr_err("WARNING: CPU does not support IBPB.\n");
+                       goto do_cmd_auto;
+               } else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY)) {
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               } else {
+                       pr_err("WARNING: kernel not compiled with CPU_IBPB_ENTRY.\n");
+                       goto do_cmd_auto;
+               }
+               break;
+
+do_cmd_auto:
+       case RETBLEED_CMD_AUTO:
+       default:
+               if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||
+                   boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) {
+                       if (IS_ENABLED(CONFIG_CPU_UNRET_ENTRY))
+                               retbleed_mitigation = RETBLEED_MITIGATION_UNRET;
+                       else if (IS_ENABLED(CONFIG_CPU_IBPB_ENTRY) && boot_cpu_has(X86_FEATURE_IBPB))
+                               retbleed_mitigation = RETBLEED_MITIGATION_IBPB;
+               }
+
+               /*
+                * The Intel mitigation (IBRS or eIBRS) was already selected in
+                * spectre_v2_select_mitigation().  'retbleed_mitigation' will
+                * be set accordingly below.
+                */
+
+               break;
+       }
+
+       switch (retbleed_mitigation) {
+       case RETBLEED_MITIGATION_UNRET:
+               setup_force_cpu_cap(X86_FEATURE_RETHUNK);
+               setup_force_cpu_cap(X86_FEATURE_UNRET);
+
+               if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+                   boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                       pr_err(RETBLEED_UNTRAIN_MSG);
+
+               mitigate_smt = true;
+               break;
+
+       case RETBLEED_MITIGATION_IBPB:
+               setup_force_cpu_cap(X86_FEATURE_ENTRY_IBPB);
+               mitigate_smt = true;
+               break;
+
+       default:
+               break;
+       }
+
+       if (mitigate_smt && !boot_cpu_has(X86_FEATURE_STIBP) &&
+           (retbleed_nosmt || cpu_mitigations_auto_nosmt()))
+               cpu_smt_disable(false);
+
+       /*
+        * Let IBRS trump all on Intel without affecting the effects of the
+        * retbleed= cmdline option.
+        */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+               switch (spectre_v2_enabled) {
+               case SPECTRE_V2_IBRS:
+                       retbleed_mitigation = RETBLEED_MITIGATION_IBRS;
+                       break;
+               case SPECTRE_V2_EIBRS:
+               case SPECTRE_V2_EIBRS_RETPOLINE:
+               case SPECTRE_V2_EIBRS_LFENCE:
+                       retbleed_mitigation = RETBLEED_MITIGATION_EIBRS;
+                       break;
+               default:
+                       pr_err(RETBLEED_INTEL_MSG);
+               }
+       }
+
+       pr_info("%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
+#undef pr_fmt
+#define pr_fmt(fmt)     "Spectre V2 : " fmt
+
 static enum spectre_v2_user_mitigation spectre_v2_user_stibp __ro_after_init =
        SPECTRE_V2_USER_NONE;
 static enum spectre_v2_user_mitigation spectre_v2_user_ibpb __ro_after_init =
@@ -828,6 +1016,7 @@ enum spectre_v2_mitigation_cmd {
        SPECTRE_V2_CMD_EIBRS,
        SPECTRE_V2_CMD_EIBRS_RETPOLINE,
        SPECTRE_V2_CMD_EIBRS_LFENCE,
+       SPECTRE_V2_CMD_IBRS,
 };
 
 enum spectre_v2_user_cmd {
@@ -868,13 +1057,15 @@ static void __init spec_v2_user_print_cond(const char *reason, bool secure)
                pr_info("spectre_v2_user=%s forced on command line.\n", reason);
 }
 
+static __ro_after_init enum spectre_v2_mitigation_cmd spectre_v2_cmd;
+
 static enum spectre_v2_user_cmd __init
-spectre_v2_parse_user_cmdline(enum spectre_v2_mitigation_cmd v2_cmd)
+spectre_v2_parse_user_cmdline(void)
 {
        char arg[20];
        int ret, i;
 
-       switch (v2_cmd) {
+       switch (spectre_v2_cmd) {
        case SPECTRE_V2_CMD_NONE:
                return SPECTRE_V2_USER_CMD_NONE;
        case SPECTRE_V2_CMD_FORCE:
@@ -900,15 +1091,16 @@ 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)
+static inline bool spectre_v2_in_ibrs_mode(enum spectre_v2_mitigation mode)
 {
-       return (mode == SPECTRE_V2_EIBRS ||
-               mode == SPECTRE_V2_EIBRS_RETPOLINE ||
-               mode == SPECTRE_V2_EIBRS_LFENCE);
+       return mode == SPECTRE_V2_IBRS ||
+              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)
+spectre_v2_user_select_mitigation(void)
 {
        enum spectre_v2_user_mitigation mode = SPECTRE_V2_USER_NONE;
        bool smt_possible = IS_ENABLED(CONFIG_SMP);
@@ -921,7 +1113,7 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
                smt_possible = false;
 
-       cmd = spectre_v2_parse_user_cmdline(v2_cmd);
+       cmd = spectre_v2_parse_user_cmdline();
        switch (cmd) {
        case SPECTRE_V2_USER_CMD_NONE:
                goto set_mode;
@@ -969,12 +1161,12 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
        }
 
        /*
-        * If no STIBP, enhanced IBRS is enabled or SMT impossible, STIBP is not
-        * required.
+        * If no STIBP, IBRS or enhanced IBRS is enabled, or SMT impossible,
+        * STIBP is not required.
         */
        if (!boot_cpu_has(X86_FEATURE_STIBP) ||
            !smt_possible ||
-           spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+           spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return;
 
        /*
@@ -986,6 +1178,13 @@ spectre_v2_user_select_mitigation(enum spectre_v2_mitigation_cmd v2_cmd)
            boot_cpu_has(X86_FEATURE_AMD_STIBP_ALWAYS_ON))
                mode = SPECTRE_V2_USER_STRICT_PREFERRED;
 
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+               if (mode != SPECTRE_V2_USER_STRICT &&
+                   mode != SPECTRE_V2_USER_STRICT_PREFERRED)
+                       pr_info("Selecting STIBP always-on mode to complement retbleed mitigation\n");
+               mode = SPECTRE_V2_USER_STRICT_PREFERRED;
+       }
+
        spectre_v2_user_stibp = mode;
 
 set_mode:
@@ -999,6 +1198,7 @@ static const char * const spectre_v2_strings[] = {
        [SPECTRE_V2_EIBRS]                      = "Mitigation: Enhanced IBRS",
        [SPECTRE_V2_EIBRS_LFENCE]               = "Mitigation: Enhanced IBRS + LFENCE",
        [SPECTRE_V2_EIBRS_RETPOLINE]            = "Mitigation: Enhanced IBRS + Retpolines",
+       [SPECTRE_V2_IBRS]                       = "Mitigation: IBRS",
 };
 
 static const struct {
@@ -1016,6 +1216,7 @@ static const struct {
        { "eibrs,lfence",       SPECTRE_V2_CMD_EIBRS_LFENCE,      false },
        { "eibrs,retpoline",    SPECTRE_V2_CMD_EIBRS_RETPOLINE,   false },
        { "auto",               SPECTRE_V2_CMD_AUTO,              false },
+       { "ibrs",               SPECTRE_V2_CMD_IBRS,              false },
 };
 
 static void __init spec_v2_print_cond(const char *reason, bool secure)
@@ -1078,6 +1279,30 @@ static enum spectre_v2_mitigation_cmd __init spectre_v2_parse_cmdline(void)
                return SPECTRE_V2_CMD_AUTO;
        }
 
+       if (cmd == SPECTRE_V2_CMD_IBRS && !IS_ENABLED(CONFIG_CPU_IBRS_ENTRY)) {
+               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_IBRS && boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) {
+               pr_err("%s selected but not Intel CPU. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && !boot_cpu_has(X86_FEATURE_IBRS)) {
+               pr_err("%s selected but CPU doesn't have IBRS. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
+       if (cmd == SPECTRE_V2_CMD_IBRS && boot_cpu_has(X86_FEATURE_XENPV)) {
+               pr_err("%s selected but running as XenPV guest. Switching to AUTO select\n",
+                      mitigation_options[i].option);
+               return SPECTRE_V2_CMD_AUTO;
+       }
+
        spec_v2_print_cond(mitigation_options[i].option,
                           mitigation_options[i].secure);
        return cmd;
@@ -1093,6 +1318,22 @@ static enum spectre_v2_mitigation __init spectre_v2_select_retpoline(void)
        return SPECTRE_V2_RETPOLINE;
 }
 
+/* Disable in-kernel use of non-RSB RET predictors */
+static void __init spec_ctrl_disable_kernel_rrsba(void)
+{
+       u64 ia32_cap;
+
+       if (!boot_cpu_has(X86_FEATURE_RRSBA_CTRL))
+               return;
+
+       ia32_cap = x86_read_arch_cap_msr();
+
+       if (ia32_cap & ARCH_CAP_RRSBA) {
+               x86_spec_ctrl_base |= SPEC_CTRL_RRSBA_DIS_S;
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
+       }
+}
+
 static void __init spectre_v2_select_mitigation(void)
 {
        enum spectre_v2_mitigation_cmd cmd = spectre_v2_parse_cmdline();
@@ -1117,6 +1358,15 @@ static void __init spectre_v2_select_mitigation(void)
                        break;
                }
 
+               if (IS_ENABLED(CONFIG_CPU_IBRS_ENTRY) &&
+                   boot_cpu_has_bug(X86_BUG_RETBLEED) &&
+                   retbleed_cmd != RETBLEED_CMD_OFF &&
+                   boot_cpu_has(X86_FEATURE_IBRS) &&
+                   boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
+                       mode = SPECTRE_V2_IBRS;
+                       break;
+               }
+
                mode = spectre_v2_select_retpoline();
                break;
 
@@ -1133,6 +1383,10 @@ static void __init spectre_v2_select_mitigation(void)
                mode = spectre_v2_select_retpoline();
                break;
 
+       case SPECTRE_V2_CMD_IBRS:
+               mode = SPECTRE_V2_IBRS;
+               break;
+
        case SPECTRE_V2_CMD_EIBRS:
                mode = SPECTRE_V2_EIBRS;
                break;
@@ -1149,10 +1403,9 @@ static void __init spectre_v2_select_mitigation(void)
        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 */
+       if (spectre_v2_in_ibrs_mode(mode)) {
                x86_spec_ctrl_base |= SPEC_CTRL_IBRS;
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
        }
 
        switch (mode) {
@@ -1160,6 +1413,10 @@ static void __init spectre_v2_select_mitigation(void)
        case SPECTRE_V2_EIBRS:
                break;
 
+       case SPECTRE_V2_IBRS:
+               setup_force_cpu_cap(X86_FEATURE_KERNEL_IBRS);
+               break;
+
        case SPECTRE_V2_LFENCE:
        case SPECTRE_V2_EIBRS_LFENCE:
                setup_force_cpu_cap(X86_FEATURE_RETPOLINE_LFENCE);
@@ -1171,43 +1428,107 @@ static void __init spectre_v2_select_mitigation(void)
                break;
        }
 
+       /*
+        * Disable alternate RSB predictions in kernel when indirect CALLs and
+        * JMPs gets protection against BHI and Intramode-BTI, but RET
+        * prediction from a non-RSB predictor is still a risk.
+        */
+       if (mode == SPECTRE_V2_EIBRS_LFENCE ||
+           mode == SPECTRE_V2_EIBRS_RETPOLINE ||
+           mode == SPECTRE_V2_RETPOLINE)
+               spec_ctrl_disable_kernel_rrsba();
+
        spectre_v2_enabled = mode;
        pr_info("%s\n", spectre_v2_strings[mode]);
 
        /*
-        * If spectre v2 protection has been enabled, unconditionally fill
-        * RSB during a context switch; this protects against two independent
-        * issues:
+        * If Spectre v2 protection has been enabled, fill the RSB during a
+        * context switch.  In general there are two types of RSB attacks
+        * across context switches, for which the CALLs/RETs may be unbalanced.
         *
-        *      - RSB underflow (and switch to BTB) on Skylake+
-        *      - SpectreRSB variant of spectre v2 on X86_BUG_SPECTRE_V2 CPUs
+        * 1) RSB underflow
+        *
+        *    Some Intel parts have "bottomless RSB".  When the RSB is empty,
+        *    speculated return targets may come from the branch predictor,
+        *    which could have a user-poisoned BTB or BHB entry.
+        *
+        *    AMD has it even worse: *all* returns are speculated from the BTB,
+        *    regardless of the state of the RSB.
+        *
+        *    When IBRS or eIBRS is enabled, the "user -> kernel" attack
+        *    scenario is mitigated by the IBRS branch prediction isolation
+        *    properties, so the RSB buffer filling wouldn't be necessary to
+        *    protect against this type of attack.
+        *
+        *    The "user -> user" attack scenario is mitigated by RSB filling.
+        *
+        * 2) Poisoned RSB entry
+        *
+        *    If the 'next' in-kernel return stack is shorter than 'prev',
+        *    'next' could be tricked into speculating with a user-poisoned RSB
+        *    entry.
+        *
+        *    The "user -> kernel" attack scenario is mitigated by SMEP and
+        *    eIBRS.
+        *
+        *    The "user -> user" scenario, also known as SpectreBHB, requires
+        *    RSB clearing.
+        *
+        * So to mitigate all cases, unconditionally fill RSB on context
+        * switches.
+        *
+        * FIXME: Is this pointless for retbleed-affected AMD?
         */
        setup_force_cpu_cap(X86_FEATURE_RSB_CTXSW);
        pr_info("Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch\n");
 
        /*
-        * Retpoline means the kernel is safe because it has no indirect
-        * branches. Enhanced IBRS protects firmware too, so, enable restricted
-        * speculation around firmware calls only when Enhanced IBRS isn't
-        * supported.
+        * Similar to context switches, there are two types of RSB attacks
+        * after vmexit:
+        *
+        * 1) RSB underflow
+        *
+        * 2) Poisoned RSB entry
+        *
+        * When retpoline is enabled, both are mitigated by filling/clearing
+        * the RSB.
+        *
+        * When IBRS is enabled, while #1 would be mitigated by the IBRS branch
+        * prediction isolation protections, RSB still needs to be cleared
+        * because of #2.  Note that SMEP provides no protection here, unlike
+        * user-space-poisoned RSB entries.
+        *
+        * eIBRS, on the other hand, has RSB-poisoning protections, so it
+        * doesn't need RSB clearing after vmexit.
+        */
+       if (boot_cpu_has(X86_FEATURE_RETPOLINE) ||
+           boot_cpu_has(X86_FEATURE_KERNEL_IBRS))
+               setup_force_cpu_cap(X86_FEATURE_RSB_VMEXIT);
+
+       /*
+        * Retpoline protects the kernel, but doesn't protect firmware.  IBRS
+        * and Enhanced IBRS protect firmware too, so enable IBRS around
+        * firmware calls only when IBRS / Enhanced IBRS aren't otherwise
+        * enabled.
         *
         * Use "mode" to check Enhanced IBRS instead of boot_cpu_has(), because
         * the user might select retpoline on the kernel command line and if
         * the CPU supports Enhanced IBRS, kernel might un-intentionally not
         * enable IBRS around firmware calls.
         */
-       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_eibrs_mode(mode)) {
+       if (boot_cpu_has(X86_FEATURE_IBRS) && !spectre_v2_in_ibrs_mode(mode)) {
                setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW);
                pr_info("Enabling Restricted Speculation for firmware calls\n");
        }
 
        /* Set up IBPB and STIBP depending on the general spectre V2 command */
-       spectre_v2_user_select_mitigation(cmd);
+       spectre_v2_cmd = cmd;
 }
 
 static void update_stibp_msr(void * __unused)
 {
-       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+       u64 val = spec_ctrl_current() | (x86_spec_ctrl_base & SPEC_CTRL_STIBP);
+       write_spec_ctrl_current(val, true);
 }
 
 /* Update x86_spec_ctrl_base in case SMT state changed. */
@@ -1424,16 +1745,6 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
        }
 
        /*
-        * If SSBD is controlled by the SPEC_CTRL MSR, then set the proper
-        * bit in the mask to allow guests to use the mitigation even in the
-        * case where the host does not enable it.
-        */
-       if (static_cpu_has(X86_FEATURE_SPEC_CTRL_SSBD) ||
-           static_cpu_has(X86_FEATURE_AMD_SSBD)) {
-               x86_spec_ctrl_mask |= SPEC_CTRL_SSBD;
-       }
-
-       /*
         * We have three CPU feature flags that are in play here:
         *  - X86_BUG_SPEC_STORE_BYPASS - CPU is susceptible.
         *  - X86_FEATURE_SSBD - CPU is able to turn off speculative store bypass
@@ -1450,7 +1761,7 @@ static enum ssb_mitigation __init __ssb_select_mitigation(void)
                        x86_amd_ssb_disable();
                } else {
                        x86_spec_ctrl_base |= SPEC_CTRL_SSBD;
-                       wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+                       write_spec_ctrl_current(x86_spec_ctrl_base, true);
                }
        }
 
@@ -1701,7 +2012,7 @@ int arch_prctl_spec_ctrl_get(struct task_struct *task, unsigned long which)
 void x86_spec_ctrl_setup_ap(void)
 {
        if (boot_cpu_has(X86_FEATURE_MSR_SPEC_CTRL))
-               wrmsrl(MSR_IA32_SPEC_CTRL, x86_spec_ctrl_base);
+               write_spec_ctrl_current(x86_spec_ctrl_base, true);
 
        if (ssb_mode == SPEC_STORE_BYPASS_DISABLE)
                x86_amd_ssb_disable();
@@ -1938,7 +2249,7 @@ static ssize_t mmio_stale_data_show_state(char *buf)
 
 static char *stibp_state(void)
 {
-       if (spectre_v2_in_eibrs_mode(spectre_v2_enabled))
+       if (spectre_v2_in_ibrs_mode(spectre_v2_enabled))
                return "";
 
        switch (spectre_v2_user_stibp) {
@@ -1994,6 +2305,24 @@ static ssize_t srbds_show_state(char *buf)
        return sprintf(buf, "%s\n", srbds_strings[srbds_mitigation]);
 }
 
+static ssize_t retbleed_show_state(char *buf)
+{
+       if (retbleed_mitigation == RETBLEED_MITIGATION_UNRET) {
+           if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
+               boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
+                   return sprintf(buf, "Vulnerable: untrained return thunk on non-Zen uarch\n");
+
+           return sprintf(buf, "%s; SMT %s\n",
+                          retbleed_strings[retbleed_mitigation],
+                          !sched_smt_active() ? "disabled" :
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT ||
+                          spectre_v2_user_stibp == SPECTRE_V2_USER_STRICT_PREFERRED ?
+                          "enabled with STIBP protection" : "vulnerable");
+       }
+
+       return sprintf(buf, "%s\n", retbleed_strings[retbleed_mitigation]);
+}
+
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
                               char *buf, unsigned int bug)
 {
@@ -2039,6 +2368,9 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_MMIO_STALE_DATA:
                return mmio_stale_data_show_state(buf);
 
+       case X86_BUG_RETBLEED:
+               return retbleed_show_state(buf);
+
        default:
                break;
        }
@@ -2095,4 +2427,9 @@ ssize_t cpu_show_mmio_stale_data(struct device *dev, struct device_attribute *at
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_MMIO_STALE_DATA);
 }
+
+ssize_t cpu_show_retbleed(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_RETBLEED);
+}
 #endif
index 4730b0a..736262a 100644 (file)
@@ -1205,48 +1205,60 @@ static const __initconst struct x86_cpu_id cpu_vuln_whitelist[] = {
        {}
 };
 
+#define VULNBL(vendor, family, model, blacklist)       \
+       X86_MATCH_VENDOR_FAM_MODEL(vendor, family, model, blacklist)
+
 #define VULNBL_INTEL_STEPPINGS(model, steppings, issues)                  \
        X86_MATCH_VENDOR_FAM_MODEL_STEPPINGS_FEATURE(INTEL, 6,             \
                                            INTEL_FAM6_##model, steppings, \
                                            X86_FEATURE_ANY, issues)
 
+#define VULNBL_AMD(family, blacklist)          \
+       VULNBL(AMD, family, X86_MODEL_ANY, blacklist)
+
+#define VULNBL_HYGON(family, blacklist)                \
+       VULNBL(HYGON, family, X86_MODEL_ANY, blacklist)
+
 #define SRBDS          BIT(0)
 /* CPU is affected by X86_BUG_MMIO_STALE_DATA */
 #define MMIO           BIT(1)
 /* CPU is affected by Shared Buffers Data Sampling (SBDS), a variant of X86_BUG_MMIO_STALE_DATA */
 #define MMIO_SBDS      BIT(2)
+/* CPU is affected by RETbleed, speculating where you would not expect it */
+#define RETBLEED       BIT(3)
 
 static const struct x86_cpu_id cpu_vuln_blacklist[] __initconst = {
        VULNBL_INTEL_STEPPINGS(IVYBRIDGE,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL,         X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_L,       X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(HASWELL_G,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(HASWELL_X,       BIT(2) | BIT(4),                MMIO),
-       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPINGS(0x3, 0x5),        MMIO),
+       VULNBL_INTEL_STEPPINGS(HASWELL_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(BROADWELL_D,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL_G,     X86_STEPPING_ANY,               SRBDS),
        VULNBL_INTEL_STEPPINGS(BROADWELL_X,     X86_STEPPING_ANY,               MMIO),
        VULNBL_INTEL_STEPPINGS(BROADWELL,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       BIT(3) | BIT(4) | BIT(6) |
-                                               BIT(7) | BIT(0xB),              MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPINGS(0x3, 0x3),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x9, 0xC),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x9, 0xD),        SRBDS | MMIO),
-       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPINGS(0x0, 0x8),        SRBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPINGS(0x5, 0x5),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPINGS(0x4, 0x6),        MMIO),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE,       BIT(2) | BIT(3) | BIT(5),       MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO),
-       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
-       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPINGS(0x1, 0x1),        MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPINGS(0x1, 0x1),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_L,       X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE_X,       X86_STEPPING_ANY,               MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(SKYLAKE,         X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE_L,      X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(KABYLAKE,        X86_STEPPING_ANY,               SRBDS | MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(CANNONLAKE_L,    X86_STEPPING_ANY,               RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_L,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_D,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(ICELAKE_X,       X86_STEPPING_ANY,               MMIO),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPINGS(0x0, 0x0),        MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(COMETLAKE_L,     X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(LAKEFIELD,       X86_STEPPING_ANY,               MMIO | MMIO_SBDS | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ROCKETLAKE,      X86_STEPPING_ANY,               MMIO | RETBLEED),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT,    X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
        VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_D,  X86_STEPPING_ANY,               MMIO),
-       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPINGS(0x0, 0x0),        MMIO | MMIO_SBDS),
+       VULNBL_INTEL_STEPPINGS(ATOM_TREMONT_L,  X86_STEPPING_ANY,               MMIO | MMIO_SBDS),
+
+       VULNBL_AMD(0x15, RETBLEED),
+       VULNBL_AMD(0x16, RETBLEED),
+       VULNBL_AMD(0x17, RETBLEED),
+       VULNBL_HYGON(0x18, RETBLEED),
        {}
 };
 
@@ -1348,6 +1360,11 @@ static void __init cpu_set_bug_bits(struct cpuinfo_x86 *c)
            !arch_cap_mmio_immune(ia32_cap))
                setup_force_cpu_bug(X86_BUG_MMIO_STALE_DATA);
 
+       if (!cpu_has(c, X86_FEATURE_BTC_NO)) {
+               if (cpu_matches(cpu_vuln_blacklist, RETBLEED) || (ia32_cap & ARCH_CAP_RSBA))
+                       setup_force_cpu_bug(X86_BUG_RETBLEED);
+       }
+
        if (cpu_matches(cpu_vuln_whitelist, NO_MELTDOWN))
                return;
 
index 2a8e584..7c9b589 100644 (file)
@@ -61,6 +61,8 @@ static inline void tsx_init(void) { }
 static inline void tsx_ap_init(void) { }
 #endif /* CONFIG_CPU_SUP_INTEL */
 
+extern void init_spectral_chicken(struct cpuinfo_x86 *c);
+
 extern void get_cpu_cap(struct cpuinfo_x86 *c);
 extern void get_cpu_address_sizes(struct cpuinfo_x86 *c);
 extern void cpu_detect_cache_sizes(struct cpuinfo_x86 *c);
index 3fcdda4..21fd425 100644 (file)
@@ -302,6 +302,12 @@ static void init_hygon(struct cpuinfo_x86 *c)
        /* get apicid instead of initial apic id from cpuid */
        c->apicid = hard_smp_processor_id();
 
+       /*
+        * XXX someone from Hygon needs to confirm this DTRT
+        *
+       init_spectral_chicken(c);
+        */
+
        set_cpu_cap(c, X86_FEATURE_ZEN);
        set_cpu_cap(c, X86_FEATURE_CPB);
 
index dbaa832..fd44b54 100644 (file)
@@ -27,6 +27,7 @@ static const struct cpuid_bit cpuid_bits[] = {
        { X86_FEATURE_APERFMPERF,       CPUID_ECX,  0, 0x00000006, 0 },
        { X86_FEATURE_EPB,              CPUID_ECX,  3, 0x00000006, 0 },
        { X86_FEATURE_INTEL_PPIN,       CPUID_EBX,  0, 0x00000007, 1 },
+       { X86_FEATURE_RRSBA_CTRL,       CPUID_EDX,  2, 0x00000007, 2 },
        { X86_FEATURE_CQM_LLC,          CPUID_EDX,  1, 0x0000000f, 0 },
        { X86_FEATURE_CQM_OCCUP_LLC,    CPUID_EDX,  0, 0x0000000f, 1 },
        { X86_FEATURE_CQM_MBM_TOTAL,    CPUID_EDX,  1, 0x0000000f, 1 },
index 5b4efc9..24b9fa8 100644 (file)
@@ -301,7 +301,7 @@ union ftrace_op_code_union {
        } __attribute__((packed));
 };
 
-#define RET_SIZE               1 + IS_ENABLED(CONFIG_SLS)
+#define RET_SIZE               (IS_ENABLED(CONFIG_RETPOLINE) ? 5 : 1 + IS_ENABLED(CONFIG_SLS))
 
 static unsigned long
 create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
@@ -357,7 +357,10 @@ create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
                goto fail;
 
        ip = trampoline + size;
-       memcpy(ip, retq, RET_SIZE);
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+               __text_gen_insn(ip, JMP32_INSN_OPCODE, ip, &__x86_return_thunk, JMP32_INSN_SIZE);
+       else
+               memcpy(ip, retq, sizeof(retq));
 
        /* No need to test direct calls on created trampolines */
        if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
index bd4a341..6a3cfaf 100644 (file)
@@ -426,10 +426,12 @@ void __init do_early_exception(struct pt_regs *regs, int trapnr)
 
 /* Don't add a printk in there. printk relies on the PDA which is not initialized 
    yet. */
-static void __init clear_bss(void)
+void __init clear_bss(void)
 {
        memset(__bss_start, 0,
               (unsigned long) __bss_stop - (unsigned long) __bss_start);
+       memset(__brk_base, 0,
+              (unsigned long) __brk_limit - (unsigned long) __brk_base);
 }
 
 static unsigned long get_cmd_line_ptr(void)
index eb8656b..9b7acc9 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/cpufeatures.h>
 #include <asm/percpu.h>
 #include <asm/nops.h>
+#include <asm/nospec-branch.h>
 #include <asm/bootparam.h>
 #include <asm/export.h>
 #include <asm/pgtable_32.h>
index 92c4afa..d860d43 100644 (file)
@@ -389,6 +389,8 @@ SYM_CODE_START_NOALIGN(vc_boot_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
@@ -448,6 +450,7 @@ SYM_CODE_END(early_idt_handler_array)
 
 SYM_CODE_START_LOCAL(early_idt_handler_common)
        UNWIND_HINT_IRET_REGS offset=16
+       ANNOTATE_UNRET_END
        /*
         * The stack is the hardware frame, an error code or zero, and the
         * vector number.
@@ -497,6 +500,8 @@ SYM_CODE_START_NOALIGN(vc_no_ghcb)
        UNWIND_HINT_IRET_REGS offset=8
        ENDBR
 
+       ANNOTATE_UNRET_END
+
        /* Build pt_regs */
        PUSH_AND_CLEAR_REGS
 
index b98ffcf..67828d9 100644 (file)
@@ -253,7 +253,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 {
        const Elf_Shdr *s, *text = NULL, *alt = NULL, *locks = NULL,
                *para = NULL, *orc = NULL, *orc_ip = NULL,
-               *retpolines = NULL, *ibt_endbr = NULL;
+               *retpolines = NULL, *returns = NULL, *ibt_endbr = NULL;
        char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 
        for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
@@ -271,6 +271,8 @@ int module_finalize(const Elf_Ehdr *hdr,
                        orc_ip = s;
                if (!strcmp(".retpoline_sites", secstrings + s->sh_name))
                        retpolines = s;
+               if (!strcmp(".return_sites", secstrings + s->sh_name))
+                       returns = s;
                if (!strcmp(".ibt_endbr_seal", secstrings + s->sh_name))
                        ibt_endbr = s;
        }
@@ -287,6 +289,10 @@ int module_finalize(const Elf_Ehdr *hdr,
                void *rseg = (void *)retpolines->sh_addr;
                apply_retpolines(rseg, rseg + retpolines->sh_size);
        }
+       if (returns) {
+               void *rseg = (void *)returns->sh_addr;
+               apply_returns(rseg, rseg + returns->sh_size);
+       }
        if (alt) {
                /* patch .altinstructions */
                void *aseg = (void *)alt->sh_addr;
index 9b2772b..d456ce2 100644 (file)
@@ -600,7 +600,7 @@ static __always_inline void __speculation_ctrl_update(unsigned long tifp,
        }
 
        if (updmsr)
-               wrmsrl(MSR_IA32_SPEC_CTRL, msr);
+               write_spec_ctrl_current(msr, false);
 }
 
 static unsigned long speculation_ctrl_update_tif(struct task_struct *tsk)
index fcc8a76..c7c4b19 100644 (file)
@@ -7,10 +7,12 @@
 #include <linux/linkage.h>
 #include <asm/page_types.h>
 #include <asm/kexec.h>
+#include <asm/nospec-branch.h>
 #include <asm/processor-flags.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 2)
@@ -91,7 +93,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        movl    %edi, %eax
        addl    $(identity_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -159,12 +163,15 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %edx, %edx
        xorl    %esi, %esi
        xorl    %ebp, %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 1:
        popl    %edx
        movl    CP_PA_SWAP_PAGE(%edi), %esp
        addl    $PAGE_SIZE, %esp
 2:
+       ANNOTATE_RETPOLINE_SAFE
        call    *%edx
 
        /* get the re-entry point of the peer system */
@@ -190,7 +197,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        movl    %edi, %eax
        addl    $(virtual_mapped - relocate_kernel), %eax
        pushl   %eax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -208,7 +217,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popl    %edi
        popl    %esi
        popl    %ebx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -271,7 +282,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        popl    %edi
        popl    %ebx
        popl    %ebp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index c1d8626..4809c0d 100644 (file)
@@ -13,7 +13,8 @@
 #include <asm/unwind_hints.h>
 
 /*
- * Must be relocatable PIC code callable as a C function
+ * Must be relocatable PIC code callable as a C function, in particular
+ * there must be a plain RET and not jump to return thunk.
  */
 
 #define PTR(x) (x << 3)
@@ -105,7 +106,9 @@ SYM_CODE_START_NOALIGN(relocate_kernel)
        /* jump to identity mapped page */
        addq    $(identity_mapped - relocate_kernel), %r8
        pushq   %r8
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(relocate_kernel)
 
 SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
@@ -200,7 +203,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        xorl    %r14d, %r14d
        xorl    %r15d, %r15d
 
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
 1:
        popq    %rdx
@@ -219,7 +224,9 @@ SYM_CODE_START_LOCAL_NOALIGN(identity_mapped)
        call    swap_pages
        movq    $virtual_mapped, %rax
        pushq   %rax
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(identity_mapped)
 
 SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
@@ -241,7 +248,9 @@ SYM_CODE_START_LOCAL_NOALIGN(virtual_mapped)
        popq    %r12
        popq    %rbp
        popq    %rbx
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(virtual_mapped)
 
        /* Do the copies */
@@ -298,7 +307,9 @@ SYM_CODE_START_LOCAL_NOALIGN(swap_pages)
        lea     PAGE_SIZE(%rax), %rsi
        jmp     0b
 3:
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_CODE_END(swap_pages)
 
        .globl kexec_control_code_size
index aa72cef..aaaba85 100644 (file)
@@ -12,13 +12,21 @@ enum insn_type {
 };
 
 /*
+ * ud1 %esp, %ecx - a 3 byte #UD that is unique to trampolines, chosen such
+ * that there is no false-positive trampoline identification while also being a
+ * speculation stop.
+ */
+static const u8 tramp_ud[] = { 0x0f, 0xb9, 0xcc };
+
+/*
  * cs cs cs xorl %eax, %eax - a single 5 byte instruction that clears %[er]ax
  */
 static const u8 xor5rax[] = { 0x2e, 0x2e, 0x2e, 0x31, 0xc0 };
 
 static const u8 retinsn[] = { RET_INSN_OPCODE, 0xcc, 0xcc, 0xcc, 0xcc };
 
-static void __ref __static_call_transform(void *insn, enum insn_type type, void *func)
+static void __ref __static_call_transform(void *insn, enum insn_type type,
+                                         void *func, bool modinit)
 {
        const void *emulate = NULL;
        int size = CALL_INSN_SIZE;
@@ -43,14 +51,17 @@ static void __ref __static_call_transform(void *insn, enum insn_type type, void
                break;
 
        case RET:
-               code = &retinsn;
+               if (cpu_feature_enabled(X86_FEATURE_RETHUNK))
+                       code = text_gen_insn(JMP32_INSN_OPCODE, insn, &__x86_return_thunk);
+               else
+                       code = &retinsn;
                break;
        }
 
        if (memcmp(insn, code, size) == 0)
                return;
 
-       if (unlikely(system_state == SYSTEM_BOOTING))
+       if (system_state == SYSTEM_BOOTING || modinit)
                return text_poke_early(insn, code, size);
 
        text_poke_bp(insn, code, size, emulate);
@@ -60,7 +71,7 @@ static void __static_call_validate(void *insn, bool tail, bool tramp)
 {
        u8 opcode = *(u8 *)insn;
 
-       if (tramp && memcmp(insn+5, "SCT", 3)) {
+       if (tramp && memcmp(insn+5, tramp_ud, 3)) {
                pr_err("trampoline signature fail");
                BUG();
        }
@@ -104,14 +115,42 @@ void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
 
        if (tramp) {
                __static_call_validate(tramp, true, true);
-               __static_call_transform(tramp, __sc_insn(!func, true), func);
+               __static_call_transform(tramp, __sc_insn(!func, true), func, false);
        }
 
        if (IS_ENABLED(CONFIG_HAVE_STATIC_CALL_INLINE) && site) {
                __static_call_validate(site, tail, false);
-               __static_call_transform(site, __sc_insn(!func, tail), func);
+               __static_call_transform(site, __sc_insn(!func, tail), func, false);
        }
 
        mutex_unlock(&text_mutex);
 }
 EXPORT_SYMBOL_GPL(arch_static_call_transform);
+
+#ifdef CONFIG_RETHUNK
+/*
+ * This is called by apply_returns() to fix up static call trampolines,
+ * specifically ARCH_DEFINE_STATIC_CALL_NULL_TRAMP which is recorded as
+ * having a return trampoline.
+ *
+ * The problem is that static_call() is available before determining
+ * X86_FEATURE_RETHUNK and, by implication, running alternatives.
+ *
+ * This means that __static_call_transform() above can have overwritten the
+ * return trampoline and we now need to fix things up to be consistent.
+ */
+bool __static_call_fixup(void *tramp, u8 op, void *dest)
+{
+       if (memcmp(tramp+5, tramp_ud, 3)) {
+               /* Not a trampoline site, not our problem. */
+               return false;
+       }
+
+       mutex_lock(&text_mutex);
+       if (op == RET_INSN_OPCODE || dest == &__x86_return_thunk)
+               __static_call_transform(tramp, RET, NULL, true);
+       mutex_unlock(&text_mutex);
+
+       return true;
+}
+#endif
index 81aba71..15f2905 100644 (file)
@@ -141,7 +141,7 @@ SECTIONS
 
 #ifdef CONFIG_RETPOLINE
                __indirect_thunk_start = .;
-               *(.text.__x86.indirect_thunk)
+               *(.text.__x86.*)
                __indirect_thunk_end = .;
 #endif
        } :text =0xcccc
@@ -283,6 +283,13 @@ SECTIONS
                *(.retpoline_sites)
                __retpoline_sites_end = .;
        }
+
+       . = ALIGN(8);
+       .return_sites : AT(ADDR(.return_sites) - LOAD_OFFSET) {
+               __return_sites = .;
+               *(.return_sites)
+               __return_sites_end = .;
+       }
 #endif
 
 #ifdef CONFIG_X86_KERNEL_IBT
@@ -385,7 +392,7 @@ SECTIONS
        __end_of_kernel_reserve = .;
 
        . = ALIGN(PAGE_SIZE);
-       .brk (NOLOAD) : AT(ADDR(.brk) - LOAD_OFFSET) {
+       .brk : AT(ADDR(.brk) - LOAD_OFFSET) {
                __brk_base = .;
                . += 64 * 1024;         /* 64k alignment slop space */
                *(.bss..brk)            /* areas brk users have reserved */
index 89b11e7..f8382ab 100644 (file)
 #define X8(x...) X4(x), X4(x)
 #define X16(x...) X8(x), X8(x)
 
-#define NR_FASTOP (ilog2(sizeof(ulong)) + 1)
-#define FASTOP_SIZE (8 * (1 + HAS_KERNEL_IBT))
-
 struct opcode {
        u64 flags;
        u8 intercept;
@@ -306,9 +303,15 @@ static void invalidate_registers(struct x86_emulate_ctxt *ctxt)
  * Moreover, they are all exactly FASTOP_SIZE bytes long, so functions for
  * different operand sizes can be reached by calculation, rather than a jump
  * table (which would be bigger than the code).
+ *
+ * The 16 byte alignment, considering 5 bytes for the RET thunk, 3 for ENDBR
+ * and 1 for the straight line speculation INT3, leaves 7 bytes for the
+ * body of the function.  Currently none is larger than 4.
  */
 static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 
+#define FASTOP_SIZE    16
+
 #define __FOP_FUNC(name) \
        ".align " __stringify(FASTOP_SIZE) " \n\t" \
        ".type " name ", @function \n\t" \
@@ -325,13 +328,15 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 #define FOP_RET(name) \
        __FOP_RET(#name)
 
-#define FOP_START(op) \
+#define __FOP_START(op, align) \
        extern void em_##op(struct fastop *fake); \
        asm(".pushsection .text, \"ax\" \n\t" \
            ".global em_" #op " \n\t" \
-           ".align " __stringify(FASTOP_SIZE) " \n\t" \
+           ".align " __stringify(align) " \n\t" \
            "em_" #op ":\n\t"
 
+#define FOP_START(op) __FOP_START(op, FASTOP_SIZE)
+
 #define FOP_END \
            ".popsection")
 
@@ -435,17 +440,12 @@ static int fastop(struct x86_emulate_ctxt *ctxt, fastop_t fop);
 /*
  * Depending on .config the SETcc functions look like:
  *
- * ENDBR       [4 bytes; CONFIG_X86_KERNEL_IBT]
- * SETcc %al   [3 bytes]
- * RET         [1 byte]
- * INT3        [1 byte; CONFIG_SLS]
- *
- * Which gives possible sizes 4, 5, 8 or 9.  When rounded up to the
- * next power-of-two alignment they become 4, 8 or 16 resp.
+ * ENDBR                       [4 bytes; CONFIG_X86_KERNEL_IBT]
+ * SETcc %al                   [3 bytes]
+ * RET | JMP __x86_return_thunk        [1,5 bytes; CONFIG_RETHUNK]
+ * INT3                                [1 byte; CONFIG_SLS]
  */
-#define SETCC_LENGTH   (ENDBR_INSN_SIZE + 4 + IS_ENABLED(CONFIG_SLS))
-#define SETCC_ALIGN    (4 << IS_ENABLED(CONFIG_SLS) << HAS_KERNEL_IBT)
-static_assert(SETCC_LENGTH <= SETCC_ALIGN);
+#define SETCC_ALIGN    16
 
 #define FOP_SETCC(op) \
        ".align " __stringify(SETCC_ALIGN) " \n\t" \
@@ -453,9 +453,10 @@ static_assert(SETCC_LENGTH <= SETCC_ALIGN);
        #op ": \n\t" \
        ASM_ENDBR \
        #op " %al \n\t" \
-       __FOP_RET(#op)
+       __FOP_RET(#op) \
+       ".skip " __stringify(SETCC_ALIGN) " - (.-" #op "), 0xcc \n\t"
 
-FOP_START(setcc)
+__FOP_START(setcc, SETCC_ALIGN)
 FOP_SETCC(seto)
 FOP_SETCC(setno)
 FOP_SETCC(setc)
index dfaeb47..723f853 100644 (file)
@@ -111,6 +111,15 @@ SYM_FUNC_START(__svm_vcpu_run)
 #endif
 
        /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize 'ret' if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
+       /*
         * Clear all general purpose registers except RSP and RAX to prevent
         * speculative use of the guest's values, even those that are reloaded
         * via the stack.  In theory, an L1 cache miss when restoring registers
@@ -190,6 +199,15 @@ SYM_FUNC_START(__svm_sev_es_vcpu_run)
        FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
 #endif
 
+       /*
+        * Mitigate RETBleed for AMD/Hygon Zen uarch. RET should be
+        * untrained as soon as we exit the VM and are back to the
+        * kernel. This should be done before re-enabling interrupts
+        * because interrupt handlers won't sanitize RET if the return is
+        * from the kernel.
+        */
+       UNTRAIN_RET
+
        pop %_ASM_BX
 
 #ifdef CONFIG_X86_64
index 3f430e2..c0e2482 100644 (file)
@@ -4,8 +4,8 @@
 
 #include <asm/vmx.h>
 
-#include "lapic.h"
-#include "x86.h"
+#include "../lapic.h"
+#include "../x86.h"
 
 extern bool __read_mostly enable_vpid;
 extern bool __read_mostly flexpriority_enabled;
index f5cb18e..ab135f9 100644 (file)
@@ -2278,7 +2278,6 @@ static void prepare_vmcs02_early(struct vcpu_vmx *vmx, struct loaded_vmcs *vmcs0
                                  SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY |
                                  SECONDARY_EXEC_APIC_REGISTER_VIRT |
                                  SECONDARY_EXEC_ENABLE_VMFUNC |
-                                 SECONDARY_EXEC_TSC_SCALING |
                                  SECONDARY_EXEC_DESC);
 
                if (nested_cpu_has(vmcs12,
@@ -3087,7 +3086,7 @@ static int nested_vmx_check_vmentry_hw(struct kvm_vcpu *vcpu)
        }
 
        vm_fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                vmx->loaded_vmcs->launched);
+                                __vmx_vcpu_run_flags(vmx));
 
        if (vmx->msr_autoload.host.nr)
                vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, vmx->msr_autoload.host.nr);
diff --git a/arch/x86/kvm/vmx/run_flags.h b/arch/x86/kvm/vmx/run_flags.h
new file mode 100644 (file)
index 0000000..edc3f16
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __KVM_X86_VMX_RUN_FLAGS_H
+#define __KVM_X86_VMX_RUN_FLAGS_H
+
+#define VMX_RUN_VMRESUME       (1 << 0)
+#define VMX_RUN_SAVE_SPEC_CTRL (1 << 1)
+
+#endif /* __KVM_X86_VMX_RUN_FLAGS_H */
index 435c187..4182c7f 100644 (file)
@@ -1,10 +1,13 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <linux/linkage.h>
 #include <asm/asm.h>
+#include <asm/asm-offsets.h>
 #include <asm/bitsperlong.h>
 #include <asm/kvm_vcpu_regs.h>
 #include <asm/nospec-branch.h>
+#include <asm/percpu.h>
 #include <asm/segment.h>
+#include "run_flags.h"
 
 #define WORD_SIZE (BITS_PER_LONG / 8)
 
 .section .noinstr.text, "ax"
 
 /**
- * vmx_vmenter - VM-Enter the current loaded VMCS
- *
- * %RFLAGS.ZF: !VMCS.LAUNCHED, i.e. controls VMLAUNCH vs. VMRESUME
- *
- * Returns:
- *     %RFLAGS.CF is set on VM-Fail Invalid
- *     %RFLAGS.ZF is set on VM-Fail Valid
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * Note that VMRESUME/VMLAUNCH fall-through and return directly if
- * they VM-Fail, whereas a successful VM-Enter + VM-Exit will jump
- * to vmx_vmexit.
- */
-SYM_FUNC_START_LOCAL(vmx_vmenter)
-       /* EFLAGS.ZF is set if VMCS.LAUNCHED == 0 */
-       je 2f
-
-1:     vmresume
-       RET
-
-2:     vmlaunch
-       RET
-
-3:     cmpb $0, kvm_rebooting
-       je 4f
-       RET
-4:     ud2
-
-       _ASM_EXTABLE(1b, 3b)
-       _ASM_EXTABLE(2b, 3b)
-
-SYM_FUNC_END(vmx_vmenter)
-
-/**
- * vmx_vmexit - Handle a VMX VM-Exit
- *
- * Returns:
- *     %RFLAGS.{CF,ZF} are cleared on VM-Success, i.e. VM-Exit
- *
- * This is vmx_vmenter's partner in crime.  On a VM-Exit, control will jump
- * here after hardware loads the host's state, i.e. this is the destination
- * referred to by VMCS.HOST_RIP.
- */
-SYM_FUNC_START(vmx_vmexit)
-#ifdef CONFIG_RETPOLINE
-       ALTERNATIVE "jmp .Lvmexit_skip_rsb", "", X86_FEATURE_RETPOLINE
-       /* Preserve guest's RAX, it's used to stuff the RSB. */
-       push %_ASM_AX
-
-       /* IMPORTANT: Stuff the RSB immediately after VM-Exit, before RET! */
-       FILL_RETURN_BUFFER %_ASM_AX, RSB_CLEAR_LOOPS, X86_FEATURE_RETPOLINE
-
-       /* Clear RFLAGS.CF and RFLAGS.ZF to preserve VM-Exit, i.e. !VM-Fail. */
-       or $1, %_ASM_AX
-
-       pop %_ASM_AX
-.Lvmexit_skip_rsb:
-#endif
-       RET
-SYM_FUNC_END(vmx_vmexit)
-
-/**
  * __vmx_vcpu_run - Run a vCPU via a transition to VMX guest mode
- * @vmx:       struct vcpu_vmx * (forwarded to vmx_update_host_rsp)
+ * @vmx:       struct vcpu_vmx *
  * @regs:      unsigned long * (to guest registers)
- * @launched:  %true if the VMCS has been launched
+ * @flags:     VMX_RUN_VMRESUME:       use VMRESUME instead of VMLAUNCH
+ *             VMX_RUN_SAVE_SPEC_CTRL: save guest SPEC_CTRL into vmx->spec_ctrl
  *
  * Returns:
  *     0 on VM-Exit, 1 on VM-Fail
@@ -115,24 +57,56 @@ SYM_FUNC_START(__vmx_vcpu_run)
 #endif
        push %_ASM_BX
 
+       /* Save @vmx for SPEC_CTRL handling */
+       push %_ASM_ARG1
+
+       /* Save @flags for SPEC_CTRL handling */
+       push %_ASM_ARG3
+
        /*
         * Save @regs, _ASM_ARG2 may be modified by vmx_update_host_rsp() and
         * @regs is needed after VM-Exit to save the guest's register values.
         */
        push %_ASM_ARG2
 
-       /* Copy @launched to BL, _ASM_ARG3 is volatile. */
+       /* Copy @flags to BL, _ASM_ARG3 is volatile. */
        mov %_ASM_ARG3B, %bl
 
-       /* Adjust RSP to account for the CALL to vmx_vmenter(). */
-       lea -WORD_SIZE(%_ASM_SP), %_ASM_ARG2
+       lea (%_ASM_SP), %_ASM_ARG2
        call vmx_update_host_rsp
 
+       ALTERNATIVE "jmp .Lspec_ctrl_done", "", X86_FEATURE_MSR_SPEC_CTRL
+
+       /*
+        * SPEC_CTRL handling: if the guest's SPEC_CTRL value differs from the
+        * host's, write the MSR.
+        *
+        * IMPORTANT: To avoid RSB underflow attacks and any other nastiness,
+        * there must not be any returns or indirect branches between this code
+        * and vmentry.
+        */
+       mov 2*WORD_SIZE(%_ASM_SP), %_ASM_DI
+       movl VMX_spec_ctrl(%_ASM_DI), %edi
+       movl PER_CPU_VAR(x86_spec_ctrl_current), %esi
+       cmp %edi, %esi
+       je .Lspec_ctrl_done
+       mov $MSR_IA32_SPEC_CTRL, %ecx
+       xor %edx, %edx
+       mov %edi, %eax
+       wrmsr
+
+.Lspec_ctrl_done:
+
+       /*
+        * Since vmentry is serializing on affected CPUs, there's no need for
+        * an LFENCE to stop speculation from skipping the wrmsr.
+        */
+
        /* Load @regs to RAX. */
        mov (%_ASM_SP), %_ASM_AX
 
        /* Check if vmlaunch or vmresume is needed */
-       testb %bl, %bl
+       testb $VMX_RUN_VMRESUME, %bl
 
        /* Load guest registers.  Don't clobber flags. */
        mov VCPU_RCX(%_ASM_AX), %_ASM_CX
@@ -154,11 +128,37 @@ SYM_FUNC_START(__vmx_vcpu_run)
        /* Load guest RAX.  This kills the @regs pointer! */
        mov VCPU_RAX(%_ASM_AX), %_ASM_AX
 
-       /* Enter guest mode */
-       call vmx_vmenter
+       /* Check EFLAGS.ZF from 'testb' above */
+       jz .Lvmlaunch
+
+       /*
+        * After a successful VMRESUME/VMLAUNCH, control flow "magically"
+        * resumes below at 'vmx_vmexit' due to the VMCS HOST_RIP setting.
+        * So this isn't a typical function and objtool needs to be told to
+        * save the unwind state here and restore it below.
+        */
+       UNWIND_HINT_SAVE
+
+/*
+ * If VMRESUME/VMLAUNCH and corresponding vmexit succeed, execution resumes at
+ * the 'vmx_vmexit' label below.
+ */
+.Lvmresume:
+       vmresume
+       jmp .Lvmfail
+
+.Lvmlaunch:
+       vmlaunch
+       jmp .Lvmfail
 
-       /* Jump on VM-Fail. */
-       jbe 2f
+       _ASM_EXTABLE(.Lvmresume, .Lfixup)
+       _ASM_EXTABLE(.Lvmlaunch, .Lfixup)
+
+SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
+
+       /* Restore unwind state from before the VMRESUME/VMLAUNCH. */
+       UNWIND_HINT_RESTORE
+       ENDBR
 
        /* Temporarily save guest's RAX. */
        push %_ASM_AX
@@ -185,21 +185,23 @@ SYM_FUNC_START(__vmx_vcpu_run)
        mov %r15, VCPU_R15(%_ASM_AX)
 #endif
 
-       /* Clear RAX to indicate VM-Exit (as opposed to VM-Fail). */
-       xor %eax, %eax
+       /* Clear return value to indicate VM-Exit (as opposed to VM-Fail). */
+       xor %ebx, %ebx
 
+.Lclear_regs:
        /*
-        * Clear all general purpose registers except RSP and RAX to prevent
+        * Clear all general purpose registers except RSP and RBX to prevent
         * speculative use of the guest's values, even those that are reloaded
         * via the stack.  In theory, an L1 cache miss when restoring registers
         * could lead to speculative execution with the guest's values.
         * Zeroing XORs are dirt cheap, i.e. the extra paranoia is essentially
         * free.  RSP and RAX are exempt as RSP is restored by hardware during
-        * VM-Exit and RAX is explicitly loaded with 0 or 1 to return VM-Fail.
+        * VM-Exit and RBX is explicitly loaded with 0 or 1 to hold the return
+        * value.
         */
-1:     xor %ecx, %ecx
+       xor %eax, %eax
+       xor %ecx, %ecx
        xor %edx, %edx
-       xor %ebx, %ebx
        xor %ebp, %ebp
        xor %esi, %esi
        xor %edi, %edi
@@ -216,8 +218,30 @@ SYM_FUNC_START(__vmx_vcpu_run)
 
        /* "POP" @regs. */
        add $WORD_SIZE, %_ASM_SP
-       pop %_ASM_BX
 
+       /*
+        * IMPORTANT: RSB filling and SPEC_CTRL handling must be done before
+        * the first unbalanced RET after vmexit!
+        *
+        * For retpoline or IBRS, RSB filling is needed to prevent poisoned RSB
+        * entries and (in some cases) RSB underflow.
+        *
+        * eIBRS has its own protection against poisoned RSB, so it doesn't
+        * need the RSB filling sequence.  But it does need to be enabled
+        * before the first unbalanced RET.
+         */
+
+       FILL_RETURN_BUFFER %_ASM_CX, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_VMEXIT
+
+       pop %_ASM_ARG2  /* @flags */
+       pop %_ASM_ARG1  /* @vmx */
+
+       call vmx_spec_ctrl_restore_host
+
+       /* Put return value in AX */
+       mov %_ASM_BX, %_ASM_AX
+
+       pop %_ASM_BX
 #ifdef CONFIG_X86_64
        pop %r12
        pop %r13
@@ -230,9 +254,15 @@ SYM_FUNC_START(__vmx_vcpu_run)
        pop %_ASM_BP
        RET
 
-       /* VM-Fail.  Out-of-line to avoid a taken Jcc after VM-Exit. */
-2:     mov $1, %eax
-       jmp 1b
+.Lfixup:
+       cmpb $0, kvm_rebooting
+       jne .Lvmfail
+       ud2
+.Lvmfail:
+       /* VM-Fail: set return value to 1 */
+       mov $1, %_ASM_BX
+       jmp .Lclear_regs
+
 SYM_FUNC_END(__vmx_vcpu_run)
 
 
index 3a919e4..be7c193 100644 (file)
@@ -383,9 +383,9 @@ static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
        if (!vmx->disable_fb_clear)
                return;
 
-       rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       msr = __rdmsr(MSR_IA32_MCU_OPT_CTRL);
        msr |= FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
        /* Cache the MSR value to avoid reading it later */
        vmx->msr_ia32_mcu_opt_ctrl = msr;
 }
@@ -396,7 +396,7 @@ static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
                return;
 
        vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
-       wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
+       native_wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
 }
 
 static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
@@ -839,6 +839,24 @@ static bool msr_write_intercepted(struct vcpu_vmx *vmx, u32 msr)
                                         MSR_IA32_SPEC_CTRL);
 }
 
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx)
+{
+       unsigned int flags = 0;
+
+       if (vmx->loaded_vmcs->launched)
+               flags |= VMX_RUN_VMRESUME;
+
+       /*
+        * If writes to the SPEC_CTRL MSR aren't intercepted, the guest is free
+        * to change it directly without causing a vmexit.  In that case read
+        * it after vmexit and store it in vmx->spec_ctrl.
+        */
+       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
+               flags |= VMX_RUN_SAVE_SPEC_CTRL;
+
+       return flags;
+}
+
 static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx,
                unsigned long entry, unsigned long exit)
 {
@@ -6813,6 +6831,31 @@ void noinstr vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp)
        }
 }
 
+void noinstr vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx,
+                                       unsigned int flags)
+{
+       u64 hostval = this_cpu_read(x86_spec_ctrl_current);
+
+       if (!cpu_feature_enabled(X86_FEATURE_MSR_SPEC_CTRL))
+               return;
+
+       if (flags & VMX_RUN_SAVE_SPEC_CTRL)
+               vmx->spec_ctrl = __rdmsr(MSR_IA32_SPEC_CTRL);
+
+       /*
+        * If the guest/host SPEC_CTRL values differ, restore the host value.
+        *
+        * For legacy IBRS, the IBRS bit always needs to be written after
+        * transitioning from a less privileged predictor mode, regardless of
+        * whether the guest/host values differ.
+        */
+       if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) ||
+           vmx->spec_ctrl != hostval)
+               native_wrmsrl(MSR_IA32_SPEC_CTRL, hostval);
+
+       barrier_nospec();
+}
+
 static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 {
        switch (to_vmx(vcpu)->exit_reason.basic) {
@@ -6826,7 +6869,8 @@ static fastpath_t vmx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
 }
 
 static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
-                                       struct vcpu_vmx *vmx)
+                                       struct vcpu_vmx *vmx,
+                                       unsigned long flags)
 {
        guest_state_enter_irqoff();
 
@@ -6845,7 +6889,7 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
                native_write_cr2(vcpu->arch.cr2);
 
        vmx->fail = __vmx_vcpu_run(vmx, (unsigned long *)&vcpu->arch.regs,
-                                  vmx->loaded_vmcs->launched);
+                                  flags);
 
        vcpu->arch.cr2 = native_read_cr2();
 
@@ -6944,36 +6988,8 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_wait_lapic_expire(vcpu);
 
-       /*
-        * If this vCPU has touched SPEC_CTRL, restore the guest's value if
-        * it's non-zero. Since vmentry is serialising on affected CPUs, there
-        * is no need to worry about the conditional branch over the wrmsr
-        * being speculatively taken.
-        */
-       x86_spec_ctrl_set_guest(vmx->spec_ctrl, 0);
-
        /* The actual VMENTER/EXIT is in the .noinstr.text section. */
-       vmx_vcpu_enter_exit(vcpu, vmx);
-
-       /*
-        * We do not use IBRS in the kernel. If this vCPU has used the
-        * SPEC_CTRL MSR it may have left it on; save the value and
-        * turn it off. This is much more efficient than blindly adding
-        * it to the atomic save/restore list. Especially as the former
-        * (Saving guest MSRs on vmexit) doesn't even exist in KVM.
-        *
-        * For non-nested case:
-        * If the L01 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        *
-        * For nested case:
-        * If the L02 MSR bitmap does not intercept the MSR, then we need to
-        * save it.
-        */
-       if (unlikely(!msr_write_intercepted(vmx, MSR_IA32_SPEC_CTRL)))
-               vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL);
-
-       x86_spec_ctrl_restore_host(vmx->spec_ctrl, 0);
+       vmx_vcpu_enter_exit(vcpu, vmx, __vmx_vcpu_run_flags(vmx));
 
        /* All fields are clean at this point */
        if (static_branch_unlikely(&enable_evmcs)) {
index 8d2342e..1e7f945 100644 (file)
@@ -8,11 +8,12 @@
 #include <asm/intel_pt.h>
 
 #include "capabilities.h"
-#include "kvm_cache_regs.h"
+#include "../kvm_cache_regs.h"
 #include "posted_intr.h"
 #include "vmcs.h"
 #include "vmx_ops.h"
-#include "cpuid.h"
+#include "../cpuid.h"
+#include "run_flags.h"
 
 #define MSR_TYPE_R     1
 #define MSR_TYPE_W     2
@@ -404,7 +405,10 @@ void vmx_set_virtual_apic_mode(struct kvm_vcpu *vcpu);
 struct vmx_uret_msr *vmx_find_uret_msr(struct vcpu_vmx *vmx, u32 msr);
 void pt_update_intercept_for_msr(struct kvm_vcpu *vcpu);
 void vmx_update_host_rsp(struct vcpu_vmx *vmx, unsigned long host_rsp);
-bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs, bool launched);
+void vmx_spec_ctrl_restore_host(struct vcpu_vmx *vmx, unsigned int flags);
+unsigned int __vmx_vcpu_run_flags(struct vcpu_vmx *vmx);
+bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned long *regs,
+                   unsigned int flags);
 int vmx_find_loadstore_msr_slot(struct vmx_msrs *m, u32 msr);
 void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
 
index 5e7f412..5cfc49d 100644 (file)
@@ -8,7 +8,7 @@
 
 #include "evmcs.h"
 #include "vmcs.h"
-#include "x86.h"
+#include "../x86.h"
 
 asmlinkage void vmread_error(unsigned long field, bool fault);
 __attribute__((regparm(0))) void vmread_error_trampoline(unsigned long field,
index 1910e1e..143e372 100644 (file)
@@ -298,7 +298,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
        STATS_DESC_COUNTER(VCPU, directed_yield_successful),
        STATS_DESC_COUNTER(VCPU, preemption_reported),
        STATS_DESC_COUNTER(VCPU, preemption_other),
-       STATS_DESC_ICOUNTER(VCPU, guest_mode)
+       STATS_DESC_IBOOLEAN(VCPU, guest_mode)
 };
 
 const struct kvm_stats_header kvm_vcpu_stats_header = {
@@ -9143,15 +9143,17 @@ static int kvm_pv_clock_pairing(struct kvm_vcpu *vcpu, gpa_t paddr,
  */
 static void kvm_pv_kick_cpu_op(struct kvm *kvm, int apicid)
 {
-       struct kvm_lapic_irq lapic_irq;
-
-       lapic_irq.shorthand = APIC_DEST_NOSHORT;
-       lapic_irq.dest_mode = APIC_DEST_PHYSICAL;
-       lapic_irq.level = 0;
-       lapic_irq.dest_id = apicid;
-       lapic_irq.msi_redir_hint = false;
+       /*
+        * All other fields are unused for APIC_DM_REMRD, but may be consumed by
+        * common code, e.g. for tracing. Defer initialization to the compiler.
+        */
+       struct kvm_lapic_irq lapic_irq = {
+               .delivery_mode = APIC_DM_REMRD,
+               .dest_mode = APIC_DEST_PHYSICAL,
+               .shorthand = APIC_DEST_NOSHORT,
+               .dest_id = apicid,
+       };
 
-       lapic_irq.delivery_mode = APIC_DM_REMRD;
        kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
 }
 
@@ -12631,9 +12633,9 @@ void kvm_arch_end_assignment(struct kvm *kvm)
 }
 EXPORT_SYMBOL_GPL(kvm_arch_end_assignment);
 
-bool kvm_arch_has_assigned_device(struct kvm *kvm)
+bool noinstr kvm_arch_has_assigned_device(struct kvm *kvm)
 {
-       return atomic_read(&kvm->arch.assigned_device_count);
+       return arch_atomic_read(&kvm->arch.assigned_device_count);
 }
 EXPORT_SYMBOL_GPL(kvm_arch_has_assigned_device);
 
index d83cba3..724bbf8 100644 (file)
@@ -39,7 +39,7 @@ SYM_FUNC_START(__memmove)
        /* FSRM implies ERMS => no length checks, do the copy directly */
 .Lmemmove_begin_forward:
        ALTERNATIVE "cmp $0x20, %rdx; jb 1f", "", X86_FEATURE_FSRM
-       ALTERNATIVE "", __stringify(movq %rdx, %rcx; rep movsb; RET), X86_FEATURE_ERMS
+       ALTERNATIVE "", "jmp .Lmemmove_erms", X86_FEATURE_ERMS
 
        /*
         * movsq instruction have many startup latency
@@ -205,6 +205,11 @@ SYM_FUNC_START(__memmove)
        movb %r11b, (%rdi)
 13:
        RET
+
+.Lmemmove_erms:
+       movq %rdx, %rcx
+       rep movsb
+       RET
 SYM_FUNC_END(__memmove)
 EXPORT_SYMBOL(__memmove)
 
index b2b2366..073289a 100644 (file)
@@ -33,9 +33,9 @@ SYM_INNER_LABEL(__x86_indirect_thunk_\reg, SYM_L_GLOBAL)
        UNWIND_HINT_EMPTY
        ANNOTATE_NOENDBR
 
-       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_LFENCE
+       ALTERNATIVE_2 __stringify(RETPOLINE \reg), \
+                     __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *%\reg; int3), X86_FEATURE_RETPOLINE_LFENCE, \
+                     __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *%\reg), ALT_NOT(X86_FEATURE_RETPOLINE)
 
 .endm
 
@@ -67,3 +67,76 @@ SYM_CODE_END(__x86_indirect_thunk_array)
 #define GEN(reg) EXPORT_THUNK(reg)
 #include <asm/GEN-for-each-reg.h>
 #undef GEN
+
+/*
+ * This function name is magical and is used by -mfunction-return=thunk-extern
+ * for the compiler to generate JMPs to it.
+ */
+#ifdef CONFIG_RETHUNK
+
+       .section .text.__x86.return_thunk
+
+/*
+ * Safety details here pertain to the AMD Zen{1,2} microarchitecture:
+ * 1) The RET at __x86_return_thunk must be on a 64 byte boundary, for
+ *    alignment within the BTB.
+ * 2) The instruction at zen_untrain_ret must contain, and not
+ *    end with, the 0xc3 byte of the RET.
+ * 3) STIBP must be enabled, or SMT disabled, to prevent the sibling thread
+ *    from re-poisioning the BTB prediction.
+ */
+       .align 64
+       .skip 63, 0xcc
+SYM_FUNC_START_NOALIGN(zen_untrain_ret);
+
+       /*
+        * As executed from zen_untrain_ret, this is:
+        *
+        *   TEST $0xcc, %bl
+        *   LFENCE
+        *   JMP __x86_return_thunk
+        *
+        * Executing the TEST instruction has a side effect of evicting any BTB
+        * prediction (potentially attacker controlled) attached to the RET, as
+        * __x86_return_thunk + 1 isn't an instruction boundary at the moment.
+        */
+       .byte   0xf6
+
+       /*
+        * As executed from __x86_return_thunk, this is a plain RET.
+        *
+        * As part of the TEST above, RET is the ModRM byte, and INT3 the imm8.
+        *
+        * We subsequently jump backwards and architecturally execute the RET.
+        * This creates a correct BTB prediction (type=ret), but in the
+        * meantime we suffer Straight Line Speculation (because the type was
+        * no branch) which is halted by the INT3.
+        *
+        * With SMT enabled and STIBP active, a sibling thread cannot poison
+        * RET's prediction to a type of its choice, but can evict the
+        * prediction due to competitive sharing. If the prediction is
+        * evicted, __x86_return_thunk will suffer Straight Line Speculation
+        * which will be contained safely by the INT3.
+        */
+SYM_INNER_LABEL(__x86_return_thunk, SYM_L_GLOBAL)
+       ret
+       int3
+SYM_CODE_END(__x86_return_thunk)
+
+       /*
+        * Ensure the TEST decoding / BTB invalidation is complete.
+        */
+       lfence
+
+       /*
+        * Jump back and execute the RET in the middle of the TEST instruction.
+        * INT3 is for SLS protection.
+        */
+       jmp __x86_return_thunk
+       int3
+SYM_FUNC_END(zen_untrain_ret)
+__EXPORT_THUNK(zen_untrain_ret)
+
+EXPORT_SYMBOL(__x86_return_thunk)
+
+#endif /* CONFIG_RETHUNK */
index d8cfce2..57ba550 100644 (file)
@@ -77,10 +77,20 @@ static uint8_t __pte2cachemode_tbl[8] = {
        [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
 };
 
-/* Check that the write-protect PAT entry is set for write-protect */
+/*
+ * Check that the write-protect PAT entry is set for write-protect.
+ * To do this without making assumptions how PAT has been set up (Xen has
+ * another layout than the kernel), translate the _PAGE_CACHE_MODE_WP cache
+ * mode via the __cachemode2pte_tbl[] into protection bits (those protection
+ * bits will select a cache mode of WP or better), and then translate the
+ * protection bits back into the cache mode using __pte2cm_idx() and the
+ * __pte2cachemode_tbl[] array. This will return the really used cache mode.
+ */
 bool x86_has_pat_wp(void)
 {
-       return __pte2cachemode_tbl[_PAGE_CACHE_MODE_WP] == _PAGE_CACHE_MODE_WP;
+       uint16_t prot = __cachemode2pte_tbl[_PAGE_CACHE_MODE_WP];
+
+       return __pte2cachemode_tbl[__pte2cm_idx(prot)] == _PAGE_CACHE_MODE_WP;
 }
 
 enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
index 3d1dba0..9de3d90 100644 (file)
@@ -65,7 +65,10 @@ SYM_FUNC_START(sme_encrypt_execute)
        movq    %rbp, %rsp              /* Restore original stack pointer */
        pop     %rbp
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 SYM_FUNC_END(sme_encrypt_execute)
 
 SYM_FUNC_START(__enc_copy)
@@ -151,6 +154,9 @@ SYM_FUNC_START(__enc_copy)
        pop     %r12
        pop     %r15
 
-       RET
+       /* Offset to __x86_return_thunk would be wrong here */
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 .L__enc_copy_end:
 SYM_FUNC_END(__enc_copy)
index c98b8c0..b808c9a 100644 (file)
@@ -412,16 +412,30 @@ static void emit_indirect_jump(u8 **pprog, int reg, u8 *ip)
 {
        u8 *prog = *pprog;
 
-#ifdef CONFIG_RETPOLINE
        if (cpu_feature_enabled(X86_FEATURE_RETPOLINE_LFENCE)) {
                EMIT_LFENCE();
                EMIT2(0xFF, 0xE0 + reg);
        } else if (cpu_feature_enabled(X86_FEATURE_RETPOLINE)) {
                OPTIMIZER_HIDE_VAR(reg);
                emit_jump(&prog, &__x86_indirect_thunk_array[reg], ip);
-       } else
-#endif
-       EMIT2(0xFF, 0xE0 + reg);
+       } else {
+               EMIT2(0xFF, 0xE0 + reg);
+       }
+
+       *pprog = prog;
+}
+
+static void emit_return(u8 **pprog, u8 *ip)
+{
+       u8 *prog = *pprog;
+
+       if (cpu_feature_enabled(X86_FEATURE_RETHUNK)) {
+               emit_jump(&prog, &__x86_return_thunk, ip);
+       } else {
+               EMIT1(0xC3);            /* ret */
+               if (IS_ENABLED(CONFIG_SLS))
+                       EMIT1(0xCC);    /* int3 */
+       }
 
        *pprog = prog;
 }
@@ -1686,7 +1700,7 @@ emit_jmp:
                        ctx->cleanup_addr = proglen;
                        pop_callee_regs(&prog, callee_regs_used);
                        EMIT1(0xC9);         /* leave */
-                       EMIT1(0xC3);         /* ret */
+                       emit_return(&prog, image + addrs[i - 1] + (prog - temp));
                        break;
 
                default:
@@ -2189,7 +2203,7 @@ int arch_prepare_bpf_trampoline(struct bpf_tramp_image *im, void *image, void *i
        if (flags & BPF_TRAMP_F_SKIP_FRAME)
                /* skip our return address and return to parent */
                EMIT4(0x48, 0x83, 0xC4, 8); /* add rsp, 8 */
-       EMIT1(0xC3); /* ret */
+       emit_return(&prog, prog);
        /* Make sure the trampoline generation logic doesn't overflow */
        if (WARN_ON_ONCE(prog > (u8 *)image_end - BPF_INSN_SAFETY)) {
                ret = -EFAULT;
index 9ffe2ba..4e5257a 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/objtool.h>
 #include <asm/page_types.h>
 #include <asm/segment.h>
+#include <asm/nospec-branch.h>
 
        .text
        .code64
@@ -75,7 +76,9 @@ STACK_FRAME_NON_STANDARD __efi64_thunk
 1:     movq    0x20(%rsp), %rsp
        pop     %rbx
        pop     %rbp
-       RET
+       ANNOTATE_UNRET_SAFE
+       ret
+       int3
 
        .code32
 2:     pushl   $__KERNEL_CS
index e3297b1..70fb2ea 100644 (file)
@@ -1183,15 +1183,19 @@ static void __init xen_domu_set_legacy_features(void)
 extern void early_xen_iret_patch(void);
 
 /* First C function to be called on Xen boot */
-asmlinkage __visible void __init xen_start_kernel(void)
+asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
 {
        struct physdev_set_iopl set_iopl;
        unsigned long initrd_start = 0;
        int rc;
 
-       if (!xen_start_info)
+       if (!si)
                return;
 
+       clear_bss();
+
+       xen_start_info = si;
+
        __text_gen_insn(&early_xen_iret_patch,
                        JMP32_INSN_OPCODE, &early_xen_iret_patch, &xen_iret,
                        JMP32_INSN_SIZE);
index 81aa46f..cfa99e8 100644 (file)
@@ -918,7 +918,7 @@ void xen_enable_sysenter(void)
        if (!boot_cpu_has(sysenter_feature))
                return;
 
-       ret = register_callback(CALLBACKTYPE_sysenter, xen_sysenter_target);
+       ret = register_callback(CALLBACKTYPE_sysenter, xen_entry_SYSENTER_compat);
        if(ret != 0)
                setup_clear_cpu_cap(sysenter_feature);
 }
@@ -927,7 +927,7 @@ void xen_enable_syscall(void)
 {
        int ret;
 
-       ret = register_callback(CALLBACKTYPE_syscall, xen_syscall_target);
+       ret = register_callback(CALLBACKTYPE_syscall, xen_entry_SYSCALL_64);
        if (ret != 0) {
                printk(KERN_ERR "Failed to set syscall callback: %d\n", ret);
                /* Pretty fatal; 64-bit userspace has no other
@@ -936,7 +936,7 @@ void xen_enable_syscall(void)
 
        if (boot_cpu_has(X86_FEATURE_SYSCALL32)) {
                ret = register_callback(CALLBACKTYPE_syscall32,
-                                       xen_syscall32_target);
+                                       xen_entry_SYSCALL_compat);
                if (ret != 0)
                        setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
        }
index caa9bc2..6b4fdf6 100644 (file)
@@ -121,7 +121,7 @@ SYM_FUNC_END(xen_read_cr2_direct);
 
 .macro xen_pv_trap name
 SYM_CODE_START(xen_\name)
-       UNWIND_HINT_EMPTY
+       UNWIND_HINT_ENTRY
        ENDBR
        pop %rcx
        pop %r11
@@ -234,8 +234,8 @@ SYM_CODE_END(xenpv_restore_regs_and_return_to_usermode)
  */
 
 /* Normal 64-bit system call target */
-SYM_CODE_START(xen_syscall_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_64)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -249,13 +249,13 @@ SYM_CODE_START(xen_syscall_target)
        movq $__USER_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_64_after_hwframe
-SYM_CODE_END(xen_syscall_target)
+SYM_CODE_END(xen_entry_SYSCALL_64)
 
 #ifdef CONFIG_IA32_EMULATION
 
 /* 32-bit compat syscall target */
-SYM_CODE_START(xen_syscall32_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        popq %rcx
        popq %r11
@@ -269,11 +269,11 @@ SYM_CODE_START(xen_syscall32_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSCALL_compat_after_hwframe
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 /* 32-bit compat sysenter target */
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        /*
         * NB: Xen is polite and clears TF from EFLAGS for us.  This means
@@ -291,19 +291,19 @@ SYM_CODE_START(xen_sysenter_target)
        movq $__USER32_CS, 1*8(%rsp)
 
        jmp entry_SYSENTER_compat_after_hwframe
-SYM_CODE_END(xen_sysenter_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
 
 #else /* !CONFIG_IA32_EMULATION */
 
-SYM_CODE_START(xen_syscall32_target)
-SYM_CODE_START(xen_sysenter_target)
-       UNWIND_HINT_EMPTY
+SYM_CODE_START(xen_entry_SYSCALL_compat)
+SYM_CODE_START(xen_entry_SYSENTER_compat)
+       UNWIND_HINT_ENTRY
        ENDBR
        lea 16(%rsp), %rsp      /* strip %rcx, %r11 */
        mov $-ENOSYS, %rax
        pushq $0
        jmp hypercall_iret
-SYM_CODE_END(xen_sysenter_target)
-SYM_CODE_END(xen_syscall32_target)
+SYM_CODE_END(xen_entry_SYSENTER_compat)
+SYM_CODE_END(xen_entry_SYSCALL_compat)
 
 #endif /* CONFIG_IA32_EMULATION */
index 3a2cd93..ffaa621 100644 (file)
@@ -26,6 +26,7 @@ SYM_CODE_START(hypercall_page)
        .rept (PAGE_SIZE / 32)
                UNWIND_HINT_FUNC
                ANNOTATE_NOENDBR
+               ANNOTATE_UNRET_SAFE
                ret
                /*
                 * Xen will write the hypercall page, and sort out ENDBR.
@@ -48,15 +49,6 @@ SYM_CODE_START(startup_xen)
        ANNOTATE_NOENDBR
        cld
 
-       /* Clear .bss */
-       xor %eax,%eax
-       mov $__bss_start, %rdi
-       mov $__bss_stop, %rcx
-       sub %rdi, %rcx
-       shr $3, %rcx
-       rep stosq
-
-       mov %rsi, xen_start_info
        mov initial_stack(%rip), %rsp
 
        /* Set up %gs.
@@ -71,6 +63,7 @@ SYM_CODE_START(startup_xen)
        cdq
        wrmsr
 
+       mov     %rsi, %rdi
        call xen_start_kernel
 SYM_CODE_END(startup_xen)
        __FINIT
index fd0fec6..9a8bb97 100644 (file)
 /* These are code, but not functions.  Defined in entry.S */
 extern const char xen_failsafe_callback[];
 
-void xen_sysenter_target(void);
+void xen_entry_SYSENTER_compat(void);
 #ifdef CONFIG_X86_64
-void xen_syscall_target(void);
-void xen_syscall32_target(void);
+void xen_entry_SYSCALL_64(void);
+void xen_entry_SYSCALL_compat(void);
 #endif
 
 extern void *xen_initial_gdt;
index 7771dac..f5e6527 100644 (file)
@@ -345,6 +345,7 @@ void __blk_queue_split(struct request_queue *q, struct bio **bio,
                /* there isn't chance to merge the splitted bio */
                split->bi_opf |= REQ_NOMERGE;
 
+               blkcg_bio_issue_init(split);
                bio_chain(split, *bio);
                trace_block_split(split, (*bio)->bi_iter.bi_sector);
                submit_bio_noacct(*bio);
index 1d44893..7b81685 100644 (file)
@@ -666,6 +666,18 @@ config CRYPTO_CRC32_MIPS
          CRC32c and CRC32 CRC algorithms implemented using mips crypto
          instructions, when available.
 
+config CRYPTO_CRC32_S390
+       tristate "CRC-32 algorithms"
+       depends on S390
+       select CRYPTO_HASH
+       select CRC32
+       help
+         Select this option if you want to use hardware accelerated
+         implementations of CRC algorithms.  With this option, you
+         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
+         and CRC-32C (Castagnoli).
+
+         It is available with IBM z13 or later.
 
 config CRYPTO_XXHASH
        tristate "xxHash hash algorithm"
@@ -898,6 +910,16 @@ config CRYPTO_SHA512_SSSE3
          Extensions version 1 (AVX1), or Advanced Vector Extensions
          version 2 (AVX2) instructions, when available.
 
+config CRYPTO_SHA512_S390
+       tristate "SHA384 and SHA512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA512 secure hash standard.
+
+         It is available as of z10.
+
 config CRYPTO_SHA1_OCTEON
        tristate "SHA1 digest algorithm (OCTEON)"
        depends on CPU_CAVIUM_OCTEON
@@ -930,6 +952,16 @@ config CRYPTO_SHA1_PPC_SPE
          SHA-1 secure hash standard (DFIPS 180-4) implemented
          using powerpc SPE SIMD instruction set.
 
+config CRYPTO_SHA1_S390
+       tristate "SHA1 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+         It is available as of z990.
+
 config CRYPTO_SHA256
        tristate "SHA224 and SHA256 digest algorithm"
        select CRYPTO_HASH
@@ -970,6 +1002,16 @@ config CRYPTO_SHA256_SPARC64
          SHA-256 secure hash standard (DFIPS 180-2) implemented
          using sparc64 crypto instructions, when available.
 
+config CRYPTO_SHA256_S390
+       tristate "SHA256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA256 secure hash standard (DFIPS 180-2).
+
+         It is available as of z9.
+
 config CRYPTO_SHA512
        tristate "SHA384 and SHA512 digest algorithms"
        select CRYPTO_HASH
@@ -1010,6 +1052,26 @@ config CRYPTO_SHA3
          References:
          http://keccak.noekeon.org/
 
+config CRYPTO_SHA3_256_S390
+       tristate "SHA3_224 and SHA3_256 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_256 secure hash standard.
+
+         It is available as of z14.
+
+config CRYPTO_SHA3_512_S390
+       tristate "SHA3_384 and SHA3_512 digest algorithm"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA3_512 secure hash standard.
+
+         It is available as of z14.
+
 config CRYPTO_SM3
        tristate
 
@@ -1070,6 +1132,16 @@ config CRYPTO_GHASH_CLMUL_NI_INTEL
          This is the x86_64 CLMUL-NI accelerated implementation of
          GHASH, the hash function used in GCM (Galois/Counter mode).
 
+config CRYPTO_GHASH_S390
+       tristate "GHASH hash function"
+       depends on S390
+       select CRYPTO_HASH
+       help
+         This is the s390 hardware accelerated implementation of GHASH,
+         the hash function used in GCM (Galois/Counter mode).
+
+         It is available as of z196.
+
 comment "Ciphers"
 
 config CRYPTO_AES
@@ -1185,6 +1257,23 @@ config CRYPTO_AES_PPC_SPE
          architecture specific assembler implementations that work on 1KB
          tables or 256 bytes S-boxes.
 
+config CRYPTO_AES_S390
+       tristate "AES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       help
+         This is the s390 hardware accelerated implementation of the
+         AES cipher algorithms (FIPS-197).
+
+         As of z9 the ECB and CBC modes are hardware accelerated
+         for 128 bit keys.
+         As of z10 the ECB and CBC modes are hardware accelerated
+         for all AES key sizes.
+         As of z196 the CTR mode is hardware accelerated for all AES
+         key sizes and XTS mode is hardware accelerated for 256 and
+         512 bit keys.
+
 config CRYPTO_ANUBIS
        tristate "Anubis cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
@@ -1415,6 +1504,19 @@ config CRYPTO_DES3_EDE_X86_64
          algorithm are provided; regular processing one input block and
          one that processes three blocks parallel.
 
+config CRYPTO_DES_S390
+       tristate "DES and Triple DES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_DES
+       help
+         This is the s390 hardware accelerated implementation of the
+         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+         As of z990 the ECB and CBC mode are hardware accelerated.
+         As of z196 the CTR mode is hardware accelerated.
+
 config CRYPTO_FCRYPT
        tristate "FCrypt cipher algorithm"
        select CRYPTO_ALGAPI
@@ -1474,6 +1576,18 @@ config CRYPTO_CHACHA_MIPS
        select CRYPTO_SKCIPHER
        select CRYPTO_ARCH_HAVE_LIB_CHACHA
 
+config CRYPTO_CHACHA_S390
+       tristate "ChaCha20 stream cipher"
+       depends on S390
+       select CRYPTO_SKCIPHER
+       select CRYPTO_LIB_CHACHA_GENERIC
+       select CRYPTO_ARCH_HAVE_LIB_CHACHA
+       help
+         This is the s390 SIMD implementation of the ChaCha20 stream
+         cipher (RFC 7539).
+
+         It is available as of z13.
+
 config CRYPTO_SEED
        tristate "SEED cipher algorithm"
        depends on CRYPTO_USER_API_ENABLE_OBSOLETE
index 43177c2..eaea733 100644 (file)
@@ -73,7 +73,7 @@ module_param(device_id_scheme, bool, 0444);
 static int only_lcd = -1;
 module_param(only_lcd, int, 0444);
 
-static bool has_backlight;
+static bool may_report_brightness_keys;
 static int register_count;
 static DEFINE_MUTEX(register_count_mutex);
 static DEFINE_MUTEX(video_list_lock);
@@ -1224,7 +1224,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
        acpi_video_device_find_cap(data);
 
        if (data->cap._BCM && data->cap._BCL)
-               has_backlight = true;
+               may_report_brightness_keys = true;
 
        mutex_lock(&video->device_list_lock);
        list_add_tail(&data->entry, &video->video_device_list);
@@ -1693,6 +1693,9 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
                break;
        }
 
+       if (keycode)
+               may_report_brightness_keys = true;
+
        acpi_notifier_call_chain(device, event, 0);
 
        if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) {
@@ -2253,7 +2256,7 @@ void acpi_video_unregister(void)
        if (register_count) {
                acpi_bus_unregister_driver(&acpi_video_bus);
                register_count = 0;
-               has_backlight = false;
+               may_report_brightness_keys = false;
        }
        mutex_unlock(&register_count_mutex);
 }
@@ -2275,7 +2278,7 @@ void acpi_video_unregister_backlight(void)
 
 bool acpi_video_handles_brightness_key_presses(void)
 {
-       return has_backlight &&
+       return may_report_brightness_keys &&
               (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS);
 }
 EXPORT_SYMBOL(acpi_video_handles_brightness_key_presses);
index 86fa61a..e2db1bd 100644 (file)
@@ -298,7 +298,7 @@ EXPORT_SYMBOL_GPL(osc_cpc_flexible_adr_space_confirmed);
 bool osc_sb_native_usb4_support_confirmed;
 EXPORT_SYMBOL_GPL(osc_sb_native_usb4_support_confirmed);
 
-bool osc_sb_cppc_not_supported;
+bool osc_sb_cppc2_support_acked;
 
 static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
 static void acpi_bus_osc_negotiate_platform_control(void)
@@ -358,11 +358,6 @@ static void acpi_bus_osc_negotiate_platform_control(void)
                return;
        }
 
-#ifdef CONFIG_ACPI_CPPC_LIB
-       osc_sb_cppc_not_supported = !(capbuf_ret[OSC_SUPPORT_DWORD] &
-                       (OSC_SB_CPC_SUPPORT | OSC_SB_CPCV2_SUPPORT));
-#endif
-
        /*
         * Now run _OSC again with query flag clear and with the caps
         * supported by both the OS and the platform.
@@ -376,6 +371,10 @@ static void acpi_bus_osc_negotiate_platform_control(void)
 
        capbuf_ret = context.ret.pointer;
        if (context.ret.length > OSC_SUPPORT_DWORD) {
+#ifdef CONFIG_ACPI_CPPC_LIB
+               osc_sb_cppc2_support_acked = capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_CPCV2_SUPPORT;
+#endif
+
                osc_sb_apei_support_acked =
                        capbuf_ret[OSC_SUPPORT_DWORD] & OSC_SB_APEI_SUPPORT;
                osc_pc_lpi_support_confirmed =
index 903528f..6ff1901 100644 (file)
@@ -578,6 +578,19 @@ bool __weak cpc_ffh_supported(void)
 }
 
 /**
+ * cpc_supported_by_cpu() - check if CPPC is supported by CPU
+ *
+ * Check if the architectural support for CPPC is present even
+ * if the _OSC hasn't prescribed it
+ *
+ * Return: true for supported, false for not supported
+ */
+bool __weak cpc_supported_by_cpu(void)
+{
+       return false;
+}
+
+/**
  * pcc_data_alloc() - Allocate the pcc_data memory for pcc subspace
  *
  * Check and allocate the cppc_pcc_data memory.
@@ -684,8 +697,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        acpi_status status;
        int ret = -ENODATA;
 
-       if (osc_sb_cppc_not_supported)
-               return -ENODEV;
+       if (!osc_sb_cppc2_support_acked) {
+               pr_debug("CPPC v2 _OSC not acked\n");
+               if (!cpc_supported_by_cpu())
+                       return -ENODEV;
+       }
 
        /* Parse the ACPI _CPC table for this CPU. */
        status = acpi_evaluate_object_typed(handle, "_CPC", NULL, &output,
index 0e3ed5e..0cb2032 100644 (file)
@@ -493,13 +493,8 @@ static int amba_device_try_add(struct amba_device *dev, struct resource *parent)
                goto skip_probe;
 
        ret = amba_read_periphid(dev);
-       if (ret) {
-               if (ret != -EPROBE_DEFER) {
-                       amba_device_put(dev);
-                       goto err_out;
-               }
+       if (ret)
                goto err_release;
-       }
 
 skip_probe:
        ret = device_add(&dev->dev);
@@ -546,6 +541,7 @@ static int amba_deferred_retry(void)
                        continue;
 
                list_del_init(&ddev->node);
+               amba_device_put(ddev->dev);
                kfree(ddev);
        }
 
index 7cd789c..460d6f1 100644 (file)
@@ -486,7 +486,18 @@ static void device_link_release_fn(struct work_struct *work)
        /* Ensure that all references to the link object have been dropped. */
        device_link_synchronize_removal();
 
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       /*
+        * If supplier_preactivated is set, the link has been dropped between
+        * the pm_runtime_get_suppliers() and pm_runtime_put_suppliers() calls
+        * in __driver_probe_device().  In that case, drop the supplier's
+        * PM-runtime usage counter to remove the reference taken by
+        * pm_runtime_get_suppliers().
+        */
+       if (link->supplier_preactivated)
+               pm_runtime_put_noidle(link->supplier);
+
+       pm_request_idle(link->supplier);
 
        put_device(link->consumer);
        put_device(link->supplier);
index a97776e..4c98849 100644 (file)
@@ -570,6 +570,12 @@ ssize_t __weak cpu_show_mmio_stale_data(struct device *dev,
        return sysfs_emit(buf, "Not affected\n");
 }
 
+ssize_t __weak cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       return sysfs_emit(buf, "Not affected\n");
+}
+
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
 static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
@@ -580,6 +586,7 @@ static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
 static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
 static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
 static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
+static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
@@ -592,6 +599,7 @@ static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_itlb_multihit.attr,
        &dev_attr_srbds.attr,
        &dev_attr_mmio_stale_data.attr,
+       &dev_attr_retbleed.attr,
        NULL
 };
 
index 676dc72..949907e 100644 (file)
@@ -308,13 +308,10 @@ static int rpm_get_suppliers(struct device *dev)
 /**
  * pm_runtime_release_supplier - Drop references to device link's supplier.
  * @link: Target device link.
- * @check_idle: Whether or not to check if the supplier device is idle.
  *
- * Drop all runtime PM references associated with @link to its supplier device
- * and if @check_idle is set, check if that device is idle (and so it can be
- * suspended).
+ * Drop all runtime PM references associated with @link to its supplier device.
  */
-void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
+void pm_runtime_release_supplier(struct device_link *link)
 {
        struct device *supplier = link->supplier;
 
@@ -327,9 +324,6 @@ void pm_runtime_release_supplier(struct device_link *link, bool check_idle)
        while (refcount_dec_not_one(&link->rpm_active) &&
               atomic_read(&supplier->power.usage_count) > 0)
                pm_runtime_put_noidle(supplier);
-
-       if (check_idle)
-               pm_request_idle(supplier);
 }
 
 static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
@@ -337,8 +331,11 @@ static void __rpm_put_suppliers(struct device *dev, bool try_to_suspend)
        struct device_link *link;
 
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
-                               device_links_read_lock_held())
-               pm_runtime_release_supplier(link, try_to_suspend);
+                               device_links_read_lock_held()) {
+               pm_runtime_release_supplier(link);
+               if (try_to_suspend)
+                       pm_request_idle(link->supplier);
+       }
 }
 
 static void rpm_put_suppliers(struct device *dev)
@@ -1771,7 +1768,6 @@ void pm_runtime_get_suppliers(struct device *dev)
                if (link->flags & DL_FLAG_PM_RUNTIME) {
                        link->supplier_preactivated = true;
                        pm_runtime_get_sync(link->supplier);
-                       refcount_inc(&link->rpm_active);
                }
 
        device_links_read_unlock(idx);
@@ -1791,19 +1787,8 @@ void pm_runtime_put_suppliers(struct device *dev)
        list_for_each_entry_rcu(link, &dev->links.suppliers, c_node,
                                device_links_read_lock_held())
                if (link->supplier_preactivated) {
-                       bool put;
-
                        link->supplier_preactivated = false;
-
-                       spin_lock_irq(&dev->power.lock);
-
-                       put = pm_runtime_status_suspended(dev) &&
-                             refcount_dec_not_one(&link->rpm_active);
-
-                       spin_unlock_irq(&dev->power.lock);
-
-                       if (put)
-                               pm_runtime_put(link->supplier);
+                       pm_runtime_put(link->supplier);
                }
 
        device_links_read_unlock(idx);
@@ -1838,7 +1823,8 @@ void pm_runtime_drop_link(struct device_link *link)
                return;
 
        pm_runtime_drop_link_count(link->consumer);
-       pm_runtime_release_supplier(link, true);
+       pm_runtime_release_supplier(link);
+       pm_request_idle(link->supplier);
 }
 
 static bool pm_runtime_need_not_resume(struct device *dev)
index 33f04ef..3646c0c 100644 (file)
@@ -152,6 +152,10 @@ static unsigned int xen_blkif_max_ring_order;
 module_param_named(max_ring_page_order, xen_blkif_max_ring_order, int, 0444);
 MODULE_PARM_DESC(max_ring_page_order, "Maximum order of pages to be used for the shared ring");
 
+static bool __read_mostly xen_blkif_trusted = true;
+module_param_named(trusted, xen_blkif_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define BLK_RING_SIZE(info)    \
        __CONST_RING_SIZE(blkif, XEN_PAGE_SIZE * (info)->nr_ring_pages)
 
@@ -210,6 +214,7 @@ struct blkfront_info
        unsigned int feature_discard:1;
        unsigned int feature_secdiscard:1;
        unsigned int feature_persistent:1;
+       unsigned int bounce:1;
        unsigned int discard_granularity;
        unsigned int discard_alignment;
        /* Number of 4KB segments handled */
@@ -310,8 +315,8 @@ static int fill_grant_buffer(struct blkfront_ring_info *rinfo, int num)
                if (!gnt_list_entry)
                        goto out_of_memory;
 
-               if (info->feature_persistent) {
-                       granted_page = alloc_page(GFP_NOIO);
+               if (info->bounce) {
+                       granted_page = alloc_page(GFP_NOIO | __GFP_ZERO);
                        if (!granted_page) {
                                kfree(gnt_list_entry);
                                goto out_of_memory;
@@ -330,7 +335,7 @@ out_of_memory:
        list_for_each_entry_safe(gnt_list_entry, n,
                                 &rinfo->grants, node) {
                list_del(&gnt_list_entry->node);
-               if (info->feature_persistent)
+               if (info->bounce)
                        __free_page(gnt_list_entry->page);
                kfree(gnt_list_entry);
                i--;
@@ -376,7 +381,7 @@ static struct grant *get_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (info->feature_persistent)
+       if (info->bounce)
                grant_foreign_access(gnt_list_entry, info);
        else {
                /* Grant access to the GFN passed by the caller */
@@ -400,7 +405,7 @@ static struct grant *get_indirect_grant(grant_ref_t *gref_head,
        /* Assign a gref to this page */
        gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
        BUG_ON(gnt_list_entry->gref == -ENOSPC);
-       if (!info->feature_persistent) {
+       if (!info->bounce) {
                struct page *indirect_page;
 
                /* Fetch a pre-allocated page to use for indirect grefs */
@@ -703,7 +708,7 @@ static int blkif_queue_rw_req(struct request *req, struct blkfront_ring_info *ri
                .grant_idx = 0,
                .segments = NULL,
                .rinfo = rinfo,
-               .need_copy = rq_data_dir(req) && info->feature_persistent,
+               .need_copy = rq_data_dir(req) && info->bounce,
        };
 
        /*
@@ -981,11 +986,12 @@ static void xlvbd_flush(struct blkfront_info *info)
 {
        blk_queue_write_cache(info->rq, info->feature_flush ? true : false,
                              info->feature_fua ? true : false);
-       pr_info("blkfront: %s: %s %s %s %s %s\n",
+       pr_info("blkfront: %s: %s %s %s %s %s %s %s\n",
                info->gd->disk_name, flush_info(info),
                "persistent grants:", info->feature_persistent ?
                "enabled;" : "disabled;", "indirect descriptors:",
-               info->max_indirect_segments ? "enabled;" : "disabled;");
+               info->max_indirect_segments ? "enabled;" : "disabled;",
+               "bounce buffer:", info->bounce ? "enabled" : "disabled;");
 }
 
 static int xen_translate_vdev(int vdevice, int *minor, unsigned int *offset)
@@ -1207,7 +1213,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
        if (!list_empty(&rinfo->indirect_pages)) {
                struct page *indirect_page, *n;
 
-               BUG_ON(info->feature_persistent);
+               BUG_ON(info->bounce);
                list_for_each_entry_safe(indirect_page, n, &rinfo->indirect_pages, lru) {
                        list_del(&indirect_page->lru);
                        __free_page(indirect_page);
@@ -1224,7 +1230,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                                                          NULL);
                                rinfo->persistent_gnts_c--;
                        }
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1245,7 +1251,7 @@ static void blkif_free_ring(struct blkfront_ring_info *rinfo)
                for (j = 0; j < segs; j++) {
                        persistent_gnt = rinfo->shadow[i].grants_used[j];
                        gnttab_end_foreign_access(persistent_gnt->gref, NULL);
-                       if (info->feature_persistent)
+                       if (info->bounce)
                                __free_page(persistent_gnt->page);
                        kfree(persistent_gnt);
                }
@@ -1428,7 +1434,7 @@ static int blkif_completion(unsigned long *id,
        data.s = s;
        num_sg = s->num_sg;
 
-       if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
+       if (bret->operation == BLKIF_OP_READ && info->bounce) {
                for_each_sg(s->sg, sg, num_sg, i) {
                        BUG_ON(sg->offset + sg->length > PAGE_SIZE);
 
@@ -1487,7 +1493,7 @@ static int blkif_completion(unsigned long *id,
                                 * Add the used indirect page back to the list of
                                 * available pages for indirect grefs.
                                 */
-                               if (!info->feature_persistent) {
+                               if (!info->bounce) {
                                        indirect_page = s->indirect_grants[i]->page;
                                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
                                }
@@ -1764,6 +1770,10 @@ static int talk_to_blkback(struct xenbus_device *dev,
        if (!info)
                return -ENODEV;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xen_blkif_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        max_page_order = xenbus_read_unsigned(info->xbdev->otherend,
                                              "max-ring-page-order", 0);
        ring_page_order = min(xen_blkif_max_ring_order, max_page_order);
@@ -2173,17 +2183,18 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo)
        if (err)
                goto out_of_memory;
 
-       if (!info->feature_persistent && info->max_indirect_segments) {
+       if (!info->bounce && info->max_indirect_segments) {
                /*
-                * We are using indirect descriptors but not persistent
-                * grants, we need to allocate a set of pages that can be
+                * We are using indirect descriptors but don't have a bounce
+                * buffer, we need to allocate a set of pages that can be
                 * used for mapping indirect grefs
                 */
                int num = INDIRECT_GREFS(grants) * BLK_RING_SIZE(info);
 
                BUG_ON(!list_empty(&rinfo->indirect_pages));
                for (i = 0; i < num; i++) {
-                       struct page *indirect_page = alloc_page(GFP_KERNEL);
+                       struct page *indirect_page = alloc_page(GFP_KERNEL |
+                                                               __GFP_ZERO);
                        if (!indirect_page)
                                goto out_of_memory;
                        list_add(&indirect_page->lru, &rinfo->indirect_pages);
@@ -2276,6 +2287,8 @@ static void blkfront_gather_backend_features(struct blkfront_info *info)
                info->feature_persistent =
                        !!xenbus_read_unsigned(info->xbdev->otherend,
                                               "feature-persistent", 0);
+       if (info->feature_persistent)
+               info->bounce = true;
 
        indirect_segments = xenbus_read_unsigned(info->xbdev->otherend,
                                        "feature-max-indirect-segments", 0);
@@ -2547,6 +2560,13 @@ static void blkfront_delay_work(struct work_struct *work)
        struct blkfront_info *info;
        bool need_schedule_work = false;
 
+       /*
+        * Note that when using bounce buffers but not persistent grants
+        * there's no need to run blkfront_delay_work because grants are
+        * revoked in blkif_completion or else an error is reported and the
+        * connection is closed.
+        */
+
        mutex_lock(&blkfront_mutex);
 
        list_for_each_entry(info, &info_list, info_list) {
index e3dd1dd..a1af90b 100644 (file)
@@ -1174,7 +1174,7 @@ static void __cold entropy_timer(struct timer_list *timer)
  */
 static void __cold try_to_generate_entropy(void)
 {
-       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = 32 };
+       enum { NUM_TRIAL_SAMPLES = 8192, MAX_SAMPLES_PER_BIT = HZ / 30 };
        struct entropy_timer_state stack;
        unsigned int i, num_different = 0;
        unsigned long last = random_get_entropy();
index 37a1eb2..76f6b38 100644 (file)
@@ -439,9 +439,13 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
 
        /* Both presence and absence of sram regulator are valid cases. */
        info->sram_reg = regulator_get_optional(cpu_dev, "sram");
-       if (IS_ERR(info->sram_reg))
+       if (IS_ERR(info->sram_reg)) {
+               ret = PTR_ERR(info->sram_reg);
+               if (ret == -EPROBE_DEFER)
+                       goto out_free_resources;
+
                info->sram_reg = NULL;
-       else {
+       else {
                ret = regulator_enable(info->sram_reg);
                if (ret) {
                        dev_warn(cpu_dev, "cpu%d: failed to enable vsram\n", cpu);
index ee99c02..3e6aa31 100644 (file)
@@ -133,98 +133,6 @@ config CRYPTO_PAES_S390
          Select this option if you want to use the paes cipher
          for example to use protected key encrypted devices.
 
-config CRYPTO_SHA1_S390
-       tristate "SHA1 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
-         It is available as of z990.
-
-config CRYPTO_SHA256_S390
-       tristate "SHA256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA256 secure hash standard (DFIPS 180-2).
-
-         It is available as of z9.
-
-config CRYPTO_SHA512_S390
-       tristate "SHA384 and SHA512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA512 secure hash standard.
-
-         It is available as of z10.
-
-config CRYPTO_SHA3_256_S390
-       tristate "SHA3_224 and SHA3_256 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_256 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_SHA3_512_S390
-       tristate "SHA3_384 and SHA3_512 digest algorithm"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA3_512 secure hash standard.
-
-         It is available as of z14.
-
-config CRYPTO_DES_S390
-       tristate "DES and Triple DES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_DES
-       help
-         This is the s390 hardware accelerated implementation of the
-         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
-         As of z990 the ECB and CBC mode are hardware accelerated.
-         As of z196 the CTR mode is hardware accelerated.
-
-config CRYPTO_AES_S390
-       tristate "AES cipher algorithms"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_SKCIPHER
-       help
-         This is the s390 hardware accelerated implementation of the
-         AES cipher algorithms (FIPS-197).
-
-         As of z9 the ECB and CBC modes are hardware accelerated
-         for 128 bit keys.
-         As of z10 the ECB and CBC modes are hardware accelerated
-         for all AES key sizes.
-         As of z196 the CTR mode is hardware accelerated for all AES
-         key sizes and XTS mode is hardware accelerated for 256 and
-         512 bit keys.
-
-config CRYPTO_CHACHA_S390
-       tristate "ChaCha20 stream cipher"
-       depends on S390
-       select CRYPTO_SKCIPHER
-       select CRYPTO_LIB_CHACHA_GENERIC
-       select CRYPTO_ARCH_HAVE_LIB_CHACHA
-       help
-         This is the s390 SIMD implementation of the ChaCha20 stream
-         cipher (RFC 7539).
-
-         It is available as of z13.
-
 config S390_PRNG
        tristate "Pseudo random number generator device driver"
        depends on S390
@@ -238,29 +146,6 @@ config S390_PRNG
 
          It is available as of z9.
 
-config CRYPTO_GHASH_S390
-       tristate "GHASH hash function"
-       depends on S390
-       select CRYPTO_HASH
-       help
-         This is the s390 hardware accelerated implementation of GHASH,
-         the hash function used in GCM (Galois/Counter mode).
-
-         It is available as of z196.
-
-config CRYPTO_CRC32_S390
-       tristate "CRC-32 algorithms"
-       depends on S390
-       select CRYPTO_HASH
-       select CRC32
-       help
-         Select this option if you want to use hardware accelerated
-         implementations of CRC algorithms.  With this option, you
-         can optimize the computation of CRC-32 (IEEE 802.3 Ethernet)
-         and CRC-32C (Castagnoli).
-
-         It is available with IBM z13 or later.
-
 config CRYPTO_DEV_NIAGARA2
        tristate "Niagara2 Stream Processing Unit driver"
        select CRYPTO_LIB_DES
index 0e89a7a..bfc8ee8 100644 (file)
@@ -197,7 +197,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
        else
                cxld->target_type = CXL_DECODER_ACCELERATOR;
 
-       if (is_cxl_endpoint(to_cxl_port(cxld->dev.parent)))
+       if (is_endpoint_decoder(&cxld->dev))
                return 0;
 
        target_list.value =
index 54f4347..cbf23be 100644 (file)
@@ -355,11 +355,13 @@ static int cxl_to_mem_cmd(struct cxl_mem_command *mem_cmd,
                return -EBUSY;
 
        /* Check the input buffer is the expected size */
-       if (info->size_in != send_cmd->in.size)
+       if ((info->size_in != CXL_VARIABLE_PAYLOAD) &&
+           (info->size_in != send_cmd->in.size))
                return -ENOMEM;
 
        /* Check the output buffer is at least large enough */
-       if (send_cmd->out.size < info->size_out)
+       if ((info->size_out != CXL_VARIABLE_PAYLOAD) &&
+           (send_cmd->out.size < info->size_out))
                return -ENOMEM;
 
        *mem_cmd = (struct cxl_mem_command) {
index ea60abd..dbce99b 100644 (file)
@@ -272,7 +272,7 @@ static const struct device_type cxl_decoder_root_type = {
        .groups = cxl_decoder_root_attribute_groups,
 };
 
-static bool is_endpoint_decoder(struct device *dev)
+bool is_endpoint_decoder(struct device *dev)
 {
        return dev->type == &cxl_decoder_endpoint_type;
 }
index 140dc32..6799b27 100644 (file)
@@ -340,6 +340,7 @@ struct cxl_dport *cxl_find_dport_by_dev(struct cxl_port *port,
 
 struct cxl_decoder *to_cxl_decoder(struct device *dev);
 bool is_root_decoder(struct device *dev);
+bool is_endpoint_decoder(struct device *dev);
 bool is_cxl_decoder(struct device *dev);
 struct cxl_decoder *cxl_root_decoder_alloc(struct cxl_port *port,
                                           unsigned int nr_targets);
index 60d10ee..7df0b05 100644 (file)
@@ -300,13 +300,13 @@ struct cxl_mbox_identify {
 } __packed;
 
 struct cxl_mbox_get_lsa {
-       u32 offset;
-       u32 length;
+       __le32 offset;
+       __le32 length;
 } __packed;
 
 struct cxl_mbox_set_lsa {
-       u32 offset;
-       u32 reserved;
+       __le32 offset;
+       __le32 reserved;
        u8 data[];
 } __packed;
 
index c310f1f..a979d0b 100644 (file)
@@ -29,6 +29,7 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 {
        struct cxl_dev_state *cxlds = cxlmd->cxlds;
        struct cxl_port *endpoint;
+       int rc;
 
        endpoint = devm_cxl_add_port(&parent_port->dev, &cxlmd->dev,
                                     cxlds->component_reg_phys, parent_port);
@@ -37,13 +38,17 @@ static int create_endpoint(struct cxl_memdev *cxlmd,
 
        dev_dbg(&cxlmd->dev, "add: %s\n", dev_name(&endpoint->dev));
 
+       rc = cxl_endpoint_autoremove(cxlmd, endpoint);
+       if (rc)
+               return rc;
+
        if (!endpoint->dev.driver) {
                dev_err(&cxlmd->dev, "%s failed probe\n",
                        dev_name(&endpoint->dev));
                return -ENXIO;
        }
 
-       return cxl_endpoint_autoremove(cxlmd, endpoint);
+       return 0;
 }
 
 static void enable_suspend(void *data)
index bbeef91..0aaa70b 100644 (file)
@@ -108,8 +108,8 @@ static int cxl_pmem_get_config_data(struct cxl_dev_state *cxlds,
                return -EINVAL;
 
        get_lsa = (struct cxl_mbox_get_lsa) {
-               .offset = cmd->in_offset,
-               .length = cmd->in_length,
+               .offset = cpu_to_le32(cmd->in_offset),
+               .length = cpu_to_le32(cmd->in_length),
        };
 
        rc = cxl_mbox_send_cmd(cxlds, CXL_MBOX_OP_GET_LSA, &get_lsa,
@@ -139,7 +139,7 @@ static int cxl_pmem_set_config_data(struct cxl_dev_state *cxlds,
                return -ENOMEM;
 
        *set_lsa = (struct cxl_mbox_set_lsa) {
-               .offset = cmd->in_offset,
+               .offset = cpu_to_le32(cmd->in_offset),
        };
        memcpy(set_lsa->data, cmd->in_buf, cmd->in_length);
 
index e689101..f7dcc44 100644 (file)
@@ -447,9 +447,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
                }
        }
 
-       max_state = bus->devfreq->profile->max_state;
-       min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
-       max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
+       max_state = bus->devfreq->max_state;
+       min_freq = (bus->devfreq->freq_table[0] / 1000);
+       max_freq = (bus->devfreq->freq_table[max_state - 1] / 1000);
        pr_info("exynos-bus: new bus device registered: %s (%6ld KHz ~ %6ld KHz)\n",
                        dev_name(dev), min_freq, max_freq);
 
index 0cce6e4..205acb2 100644 (file)
@@ -343,7 +343,7 @@ void dma_resv_replace_fences(struct dma_resv *obj, uint64_t context,
                if (old->context != context)
                        continue;
 
-               dma_resv_list_set(list, i, replacement, usage);
+               dma_resv_list_set(list, i, dma_fence_get(replacement), usage);
                dma_fence_put(old);
        }
 }
index 3e9d726..7b3e603 100644 (file)
@@ -1900,6 +1900,11 @@ static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
        for (i = 0; i < init_nr_desc_per_channel; i++) {
                desc = at_xdmac_alloc_desc(chan, GFP_KERNEL);
                if (!desc) {
+                       if (i == 0) {
+                               dev_warn(chan2dev(chan),
+                                        "can't allocate any descriptors\n");
+                               return -EIO;
+                       }
                        dev_warn(chan2dev(chan),
                                "only %d descriptors have been allocated\n", i);
                        break;
index 0a2168a..f696246 100644 (file)
@@ -675,16 +675,10 @@ static int dmatest_func(void *data)
        /*
         * src and dst buffers are freed by ourselves below
         */
-       if (params->polled) {
+       if (params->polled)
                flags = DMA_CTRL_ACK;
-       } else {
-               if (dma_has_cap(DMA_INTERRUPT, dev->cap_mask)) {
-                       flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
-               } else {
-                       pr_err("Channel does not support interrupt!\n");
-                       goto err_pq_array;
-               }
-       }
+       else
+               flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
 
        ktime = ktime_get();
        while (!(kthread_should_stop() ||
@@ -912,7 +906,6 @@ error_unmap_continue:
        runtime = ktime_to_us(ktime);
 
        ret = 0;
-err_pq_array:
        kfree(dma_pq);
 err_srcs_array:
        kfree(srcs);
index e9c9bcb..c741da0 100644 (file)
@@ -1164,8 +1164,9 @@ static int dma_chan_pause(struct dma_chan *dchan)
                        BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
-               val = BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
-                     BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
+               val |= BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT |
+                       BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT;
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
        }
 
@@ -1190,12 +1191,13 @@ static inline void axi_chan_resume(struct axi_dma_chan *chan)
 {
        u32 val;
 
-       val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
        if (chan->chip->dw->hdata->reg_map_8_channels) {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHEN, val);
        } else {
+               val = axi_dma_ioread32(chan->chip, DMAC_CHSUSPREG);
                val &= ~(BIT(chan->id) << DMAC_CHAN_SUSP2_SHIFT);
                val |=  (BIT(chan->id) << DMAC_CHAN_SUSP2_WE_SHIFT);
                axi_dma_iowrite32(chan->chip, DMAC_CHSUSPREG, val);
index ff0ea60..5a8cc52 100644 (file)
@@ -716,10 +716,7 @@ static void idxd_device_wqs_clear_state(struct idxd_device *idxd)
                struct idxd_wq *wq = idxd->wqs[i];
 
                mutex_lock(&wq->wq_lock);
-               if (wq->state == IDXD_WQ_ENABLED) {
-                       idxd_wq_disable_cleanup(wq);
-                       wq->state = IDXD_WQ_DISABLED;
-               }
+               idxd_wq_disable_cleanup(wq);
                idxd_wq_device_reset_cleanup(wq);
                mutex_unlock(&wq->wq_lock);
        }
index 355fb3e..aa34782 100644 (file)
@@ -512,15 +512,16 @@ static int idxd_probe(struct idxd_device *idxd)
        dev_dbg(dev, "IDXD reset complete\n");
 
        if (IS_ENABLED(CONFIG_INTEL_IDXD_SVM) && sva) {
-               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA))
+               if (iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA)) {
                        dev_warn(dev, "Unable to turn on user SVA feature.\n");
-               else
+               } else {
                        set_bit(IDXD_FLAG_USER_PASID_ENABLED, &idxd->flags);
 
-               if (idxd_enable_system_pasid(idxd))
-                       dev_warn(dev, "No in-kernel DMA with PASID.\n");
-               else
-                       set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+                       if (idxd_enable_system_pasid(idxd))
+                               dev_warn(dev, "No in-kernel DMA with PASID.\n");
+                       else
+                               set_bit(IDXD_FLAG_PASID_ENABLED, &idxd->flags);
+               }
        } else if (!sva) {
                dev_warn(dev, "User forced SVA off via module param.\n");
        }
index 8535018..f37a276 100644 (file)
@@ -891,7 +891,7 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac)
         * SDMA stops cyclic channel when DMA request triggers a channel and no SDMA
         * owned buffer is available (i.e. BD_DONE was set too late).
         */
-       if (!is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
+       if (sdmac->desc && !is_sdma_channel_enabled(sdmac->sdma, sdmac->channel)) {
                dev_warn(sdmac->sdma->dev, "restart cyclic channel %d\n", sdmac->channel);
                sdma_enable_channel(sdmac->sdma, sdmac->channel);
        }
@@ -2346,7 +2346,7 @@ MODULE_DESCRIPTION("i.MX SDMA driver");
 #if IS_ENABLED(CONFIG_SOC_IMX6Q)
 MODULE_FIRMWARE("imx/sdma/sdma-imx6q.bin");
 #endif
-#if IS_ENABLED(CONFIG_SOC_IMX7D)
+#if IS_ENABLED(CONFIG_SOC_IMX7D) || IS_ENABLED(CONFIG_SOC_IMX8M)
 MODULE_FIRMWARE("imx/sdma/sdma-imx7d.bin");
 #endif
 MODULE_LICENSE("GPL");
index efe8bd3..9b9184f 100644 (file)
@@ -1593,11 +1593,12 @@ static int intel_ldma_probe(struct platform_device *pdev)
        d->core_clk = devm_clk_get_optional(dev, NULL);
        if (IS_ERR(d->core_clk))
                return PTR_ERR(d->core_clk);
-       clk_prepare_enable(d->core_clk);
 
        d->rst = devm_reset_control_get_optional(dev, NULL);
        if (IS_ERR(d->rst))
                return PTR_ERR(d->rst);
+
+       clk_prepare_enable(d->core_clk);
        reset_control_deassert(d->rst);
 
        ret = devm_add_action_or_reset(dev, ldma_clk_disable, d);
index 858400e..09915a5 100644 (file)
@@ -2589,7 +2589,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 
        /* If the DMAC pool is empty, alloc new */
        if (!desc) {
-               DEFINE_SPINLOCK(lock);
+               static DEFINE_SPINLOCK(lock);
                LIST_HEAD(pool);
 
                if (!add_desc(&pool, &lock, GFP_ATOMIC, 1))
index 87f6ca1..2ff787d 100644 (file)
@@ -558,14 +558,6 @@ static int bam_alloc_chan(struct dma_chan *chan)
        return 0;
 }
 
-static int bam_pm_runtime_get_sync(struct device *dev)
-{
-       if (pm_runtime_enabled(dev))
-               return pm_runtime_get_sync(dev);
-
-       return 0;
-}
-
 /**
  * bam_free_chan - Frees dma resources associated with specific channel
  * @chan: specified channel
@@ -581,7 +573,7 @@ static void bam_free_chan(struct dma_chan *chan)
        unsigned long flags;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -784,7 +776,7 @@ static int bam_pause(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -810,7 +802,7 @@ static int bam_resume(struct dma_chan *chan)
        unsigned long flag;
        int ret;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return ret;
 
@@ -919,7 +911,7 @@ static irqreturn_t bam_dma_irq(int irq, void *data)
        if (srcs & P_IRQ)
                tasklet_schedule(&bdev->task);
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return IRQ_NONE;
 
@@ -1037,7 +1029,7 @@ static void bam_start_dma(struct bam_chan *bchan)
        if (!vd)
                return;
 
-       ret = bam_pm_runtime_get_sync(bdev->dev);
+       ret = pm_runtime_get_sync(bdev->dev);
        if (ret < 0)
                return;
 
@@ -1374,11 +1366,6 @@ static int bam_dma_probe(struct platform_device *pdev)
        if (ret)
                goto err_unregister_dma;
 
-       if (!bdev->bamclk) {
-               pm_runtime_disable(&pdev->dev);
-               return 0;
-       }
-
        pm_runtime_irq_safe(&pdev->dev);
        pm_runtime_set_autosuspend_delay(&pdev->dev, BAM_DMA_AUTOSUSPEND_DELAY);
        pm_runtime_use_autosuspend(&pdev->dev);
@@ -1462,10 +1449,8 @@ static int __maybe_unused bam_dma_suspend(struct device *dev)
 {
        struct bam_device *bdev = dev_get_drvdata(dev);
 
-       if (bdev->bamclk) {
-               pm_runtime_force_suspend(dev);
-               clk_unprepare(bdev->bamclk);
-       }
+       pm_runtime_force_suspend(dev);
+       clk_unprepare(bdev->bamclk);
 
        return 0;
 }
@@ -1475,13 +1460,11 @@ static int __maybe_unused bam_dma_resume(struct device *dev)
        struct bam_device *bdev = dev_get_drvdata(dev);
        int ret;
 
-       if (bdev->bamclk) {
-               ret = clk_prepare(bdev->bamclk);
-               if (ret)
-                       return ret;
+       ret = clk_prepare(bdev->bamclk);
+       if (ret)
+               return ret;
 
-               pm_runtime_force_resume(dev);
-       }
+       pm_runtime_force_resume(dev);
 
        return 0;
 }
index 71d24fc..f744ddb 100644 (file)
@@ -245,6 +245,7 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        if (dma_spec->args[0] >= xbar->xbar_requests) {
                dev_err(&pdev->dev, "Invalid XBAR request number: %d\n",
                        dma_spec->args[0]);
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
@@ -252,12 +253,14 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
        dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
        if (!dma_spec->np) {
                dev_err(&pdev->dev, "Can't get DMA master\n");
+               put_device(&pdev->dev);
                return ERR_PTR(-EINVAL);
        }
 
        map = kzalloc(sizeof(*map), GFP_KERNEL);
        if (!map) {
                of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -268,6 +271,8 @@ static void *ti_dra7_xbar_route_allocate(struct of_phandle_args *dma_spec,
                mutex_unlock(&xbar->mutex);
                dev_err(&pdev->dev, "Run out of free DMA requests\n");
                kfree(map);
+               of_node_put(dma_spec->np);
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
        }
        set_bit(map->xbar_out, xbar->dma_inuse);
index f6fe723..d4e2310 100644 (file)
@@ -181,7 +181,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
                return NULL;
        }
 
-       id = ida_simple_get(&scmi_bus_id, 1, 0, GFP_KERNEL);
+       id = ida_alloc_min(&scmi_bus_id, 1, GFP_KERNEL);
        if (id < 0) {
                kfree_const(scmi_dev->name);
                kfree(scmi_dev);
@@ -204,7 +204,7 @@ scmi_device_create(struct device_node *np, struct device *parent, int protocol,
 put_dev:
        kfree_const(scmi_dev->name);
        put_device(&scmi_dev->dev);
-       ida_simple_remove(&scmi_bus_id, id);
+       ida_free(&scmi_bus_id, id);
        return NULL;
 }
 
@@ -212,7 +212,7 @@ void scmi_device_destroy(struct scmi_device *scmi_dev)
 {
        kfree_const(scmi_dev->name);
        scmi_handle_put(scmi_dev->handle);
-       ida_simple_remove(&scmi_bus_id, scmi_dev->id);
+       ida_free(&scmi_bus_id, scmi_dev->id);
        device_unregister(&scmi_dev->dev);
 }
 
index c7a83f6..3ed7ae0 100644 (file)
@@ -194,6 +194,7 @@ static int rate_cmp_func(const void *_r1, const void *_r2)
 }
 
 struct scmi_clk_ipriv {
+       struct device *dev;
        u32 clk_id;
        struct scmi_clock_info *clk;
 };
@@ -223,6 +224,29 @@ iter_clk_describe_update_state(struct scmi_iterator_state *st,
        st->num_returned = NUM_RETURNED(flags);
        p->clk->rate_discrete = RATE_DISCRETE(flags);
 
+       /* Warn about out of spec replies ... */
+       if (!p->clk->rate_discrete &&
+           (st->num_returned != 3 || st->num_remaining != 0)) {
+               dev_warn(p->dev,
+                        "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",
+                        p->clk->name, st->num_returned, st->num_remaining,
+                        st->rx_len);
+
+               /*
+                * A known quirk: a triplet is returned but num_returned != 3
+                * Check for a safe payload size and fix.
+                */
+               if (st->num_returned != 3 && st->num_remaining == 0 &&
+                   st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {
+                       st->num_returned = 3;
+                       st->num_remaining = 0;
+               } else {
+                       dev_err(p->dev,
+                               "Cannot fix out-of-spec reply !\n");
+                       return -EPROTO;
+               }
+       }
+
        return 0;
 }
 
@@ -255,7 +279,6 @@ iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,
 
                *rate = RATE_TO_U64(r->rate[st->loop_idx]);
                p->clk->list.num_rates++;
-               //XXX dev_dbg(ph->dev, "Rate %llu Hz\n", *rate);
        }
 
        return ret;
@@ -275,6 +298,7 @@ scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,
        struct scmi_clk_ipriv cpriv = {
                .clk_id = clk_id,
                .clk = clk,
+               .dev = ph->dev,
        };
 
        iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,
index c1922bd..8b7ac66 100644 (file)
@@ -1223,6 +1223,7 @@ static int scmi_iterator_run(void *iter)
                if (ret)
                        break;
 
+               st->rx_len = i->t->rx.len;
                ret = iops->update_state(st, i->resp, i->priv);
                if (ret)
                        break;
index b503c22..8abace5 100644 (file)
@@ -117,6 +117,7 @@ struct scmi_optee_channel {
        u32 channel_id;
        u32 tee_session;
        u32 caps;
+       u32 rx_len;
        struct mutex mu;
        struct scmi_chan_info *cinfo;
        union {
@@ -302,6 +303,9 @@ static int invoke_process_msg_channel(struct scmi_optee_channel *channel, size_t
                return -EIO;
        }
 
+       /* Save response size */
+       channel->rx_len = param[2].u.memref.size;
+
        return 0;
 }
 
@@ -353,6 +357,7 @@ static int setup_dynamic_shmem(struct device *dev, struct scmi_optee_channel *ch
        shbuf = tee_shm_get_va(channel->tee_shm, 0);
        memset(shbuf, 0, msg_size);
        channel->req.msg = shbuf;
+       channel->rx_len = msg_size;
 
        return 0;
 }
@@ -508,7 +513,7 @@ static void scmi_optee_fetch_response(struct scmi_chan_info *cinfo,
        struct scmi_optee_channel *channel = cinfo->transport_info;
 
        if (channel->tee_shm)
-               msg_fetch_response(channel->req.msg, SCMI_OPTEE_MAX_MSG_SIZE, xfer);
+               msg_fetch_response(channel->req.msg, channel->rx_len, xfer);
        else
                shmem_fetch_response(channel->req.shmem, xfer);
 }
index c679f3f..51c3137 100644 (file)
@@ -179,6 +179,8 @@ struct scmi_protocol_handle {
  * @max_resources: Maximum acceptable number of items, configured by the caller
  *                depending on the underlying resources that it is querying.
  * @loop_idx: The iterator loop index in the current multi-part reply.
+ * @rx_len: Size in bytes of the currenly processed message; it can be used by
+ *         the user of the iterator to verify a reply size.
  * @priv: Optional pointer to some additional state-related private data setup
  *       by the caller during the iterations.
  */
@@ -188,6 +190,7 @@ struct scmi_iterator_state {
        unsigned int num_remaining;
        unsigned int max_resources;
        unsigned int loop_idx;
+       size_t rx_len;
        void *priv;
 };
 
index 73089a2..ceae84c 100644 (file)
@@ -6,7 +6,7 @@
 #include <linux/efi.h>
 #include <linux/reboot.h>
 
-static void (*orig_pm_power_off)(void);
+static struct sys_off_handler *efi_sys_off_handler;
 
 int efi_reboot_quirk_mode = -1;
 
@@ -51,15 +51,11 @@ bool __weak efi_poweroff_required(void)
        return false;
 }
 
-static void efi_power_off(void)
+static int efi_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
-       /*
-        * The above call should not return, if it does fall back to
-        * the original power off method (typically ACPI poweroff).
-        */
-       if (orig_pm_power_off)
-               orig_pm_power_off();
+
+       return NOTIFY_DONE;
 }
 
 static int __init efi_shutdown_init(void)
@@ -68,8 +64,13 @@ static int __init efi_shutdown_init(void)
                return -ENODEV;
 
        if (efi_poweroff_required()) {
-               orig_pm_power_off = pm_power_off;
-               pm_power_off = efi_power_off;
+               /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+               efi_sys_off_handler =
+                       register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+                                                SYS_OFF_PRIO_FIRMWARE + 1,
+                                                efi_power_off, NULL);
+               if (IS_ERR(efi_sys_off_handler))
+                       return PTR_ERR(efi_sys_off_handler);
        }
 
        return 0;
index 9810983..1020c2f 100644 (file)
@@ -991,28 +991,22 @@ static struct configfs_attribute *gpio_sim_device_config_attrs[] = {
 };
 
 struct gpio_sim_chip_name_ctx {
-       struct gpio_sim_device *dev;
+       struct fwnode_handle *swnode;
        char *page;
 };
 
 static int gpio_sim_emit_chip_name(struct device *dev, void *data)
 {
        struct gpio_sim_chip_name_ctx *ctx = data;
-       struct fwnode_handle *swnode;
-       struct gpio_sim_bank *bank;
 
        /* This would be the sysfs device exported in /sys/class/gpio. */
        if (dev->class)
                return 0;
 
-       swnode = dev_fwnode(dev);
+       if (device_match_fwnode(dev, ctx->swnode))
+               return sprintf(ctx->page, "%s\n", dev_name(dev));
 
-       list_for_each_entry(bank, &ctx->dev->bank_list, siblings) {
-               if (bank->swnode == swnode)
-                       return sprintf(ctx->page, "%s\n", dev_name(dev));
-       }
-
-       return -ENODATA;
+       return 0;
 }
 
 static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
@@ -1020,7 +1014,7 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item,
 {
        struct gpio_sim_bank *bank = to_gpio_sim_bank(item);
        struct gpio_sim_device *dev = gpio_sim_bank_get_device(bank);
-       struct gpio_sim_chip_name_ctx ctx = { dev, page };
+       struct gpio_sim_chip_name_ctx ctx = { bank->swnode, page };
        int ret;
 
        mutex_lock(&dev->lock);
index 23cddb2..9db42f6 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
+#include <linux/pinctrl/consumer.h>
 
 #define VF610_GPIO_PER_PORT            32
 
index f5aa5f9..0c9a63b 100644 (file)
@@ -1460,11 +1460,12 @@ static ssize_t linereq_read(struct file *file,
 static void linereq_free(struct linereq *lr)
 {
        unsigned int i;
-       bool hte;
+       bool hte = false;
 
        for (i = 0; i < lr->num_lines; i++) {
-               hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
-                                &lr->lines[i].desc->flags);
+               if (lr->lines[i].desc)
+                       hte = !!test_bit(FLAG_EVENT_CLOCK_HTE,
+                                        &lr->lines[i].desc->flags);
                edge_detector_stop(&lr->lines[i], hte);
                if (lr->lines[i].desc)
                        gpiod_free(lr->lines[i].desc);
index e88c497..f65656d 100644 (file)
@@ -256,7 +256,6 @@ config DRM_AMDGPU
        select HWMON
        select BACKLIGHT_CLASS_DEVICE
        select INTERVAL_TREE
-       select DRM_BUDDY
        help
          Choose this option if you have a recent AMD Radeon graphics card.
 
index 17c9bbe..4dfd672 100644 (file)
@@ -1528,6 +1528,21 @@ bool amdgpu_crtc_get_scanout_position(struct drm_crtc *crtc,
                                                  stime, etime, mode);
 }
 
+static bool
+amdgpu_display_robj_is_fb(struct amdgpu_device *adev, struct amdgpu_bo *robj)
+{
+       struct drm_device *dev = adev_to_drm(adev);
+       struct drm_fb_helper *fb_helper = dev->fb_helper;
+
+       if (!fb_helper || !fb_helper->buffer)
+               return false;
+
+       if (gem_to_amdgpu_bo(fb_helper->buffer->gem) != robj)
+               return false;
+
+       return true;
+}
+
 int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
 {
        struct drm_device *dev = adev_to_drm(adev);
@@ -1563,10 +1578,12 @@ int amdgpu_display_suspend_helper(struct amdgpu_device *adev)
                        continue;
                }
                robj = gem_to_amdgpu_bo(fb->obj[0]);
-               r = amdgpu_bo_reserve(robj, true);
-               if (r == 0) {
-                       amdgpu_bo_unpin(robj);
-                       amdgpu_bo_unreserve(robj);
+               if (!amdgpu_display_robj_is_fb(adev, robj)) {
+                       r = amdgpu_bo_reserve(robj, true);
+                       if (r == 0) {
+                               amdgpu_bo_unpin(robj);
+                               amdgpu_bo_unreserve(robj);
+                       }
                }
        }
        return 0;
index 6546552..acfa207 100644 (file)
 #include <drm/ttm/ttm_resource.h>
 #include <drm/ttm/ttm_range_manager.h>
 
-#include "amdgpu_vram_mgr.h"
-
 /* state back for walking over vram_mgr and gtt_mgr allocations */
 struct amdgpu_res_cursor {
        uint64_t                start;
        uint64_t                size;
        uint64_t                remaining;
-       void                    *node;
-       uint32_t                mem_type;
+       struct drm_mm_node      *node;
 };
 
 /**
@@ -55,63 +52,27 @@ static inline void amdgpu_res_first(struct ttm_resource *res,
                                    uint64_t start, uint64_t size,
                                    struct amdgpu_res_cursor *cur)
 {
-       struct drm_buddy_block *block;
-       struct list_head *head, *next;
        struct drm_mm_node *node;
 
-       if (!res)
-               goto fallback;
-
-       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
-
-       cur->mem_type = res->mem_type;
-
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               head = &to_amdgpu_vram_mgr_resource(res)->blocks;
-
-               block = list_first_entry_or_null(head,
-                                                struct drm_buddy_block,
-                                                link);
-               if (!block)
-                       goto fallback;
-
-               while (start >= amdgpu_vram_mgr_block_size(block)) {
-                       start -= amdgpu_vram_mgr_block_size(block);
-
-                       next = block->link.next;
-                       if (next != head)
-                               block = list_entry(next, struct drm_buddy_block, link);
-               }
-
-               cur->start = amdgpu_vram_mgr_block_start(block) + start;
-               cur->size = min(amdgpu_vram_mgr_block_size(block) - start, size);
-               cur->remaining = size;
-               cur->node = block;
-               break;
-       case TTM_PL_TT:
-               node = to_ttm_range_mgr_node(res)->mm_nodes;
-               while (start >= node->size << PAGE_SHIFT)
-                       start -= node++->size << PAGE_SHIFT;
-
-               cur->start = (node->start << PAGE_SHIFT) + start;
-               cur->size = min((node->size << PAGE_SHIFT) - start, size);
+       if (!res || res->mem_type == TTM_PL_SYSTEM) {
+               cur->start = start;
+               cur->size = size;
                cur->remaining = size;
-               cur->node = node;
-               break;
-       default:
-               goto fallback;
+               cur->node = NULL;
+               WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
+               return;
        }
 
-       return;
+       BUG_ON(start + size > res->num_pages << PAGE_SHIFT);
 
-fallback:
-       cur->start = start;
-       cur->size = size;
+       node = to_ttm_range_mgr_node(res)->mm_nodes;
+       while (start >= node->size << PAGE_SHIFT)
+               start -= node++->size << PAGE_SHIFT;
+
+       cur->start = (node->start << PAGE_SHIFT) + start;
+       cur->size = min((node->size << PAGE_SHIFT) - start, size);
        cur->remaining = size;
-       cur->node = NULL;
-       WARN_ON(res && start + size > res->num_pages << PAGE_SHIFT);
-       return;
+       cur->node = node;
 }
 
 /**
@@ -124,9 +85,7 @@ fallback:
  */
 static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
 {
-       struct drm_buddy_block *block;
-       struct drm_mm_node *node;
-       struct list_head *next;
+       struct drm_mm_node *node = cur->node;
 
        BUG_ON(size > cur->remaining);
 
@@ -140,27 +99,9 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size)
                return;
        }
 
-       switch (cur->mem_type) {
-       case TTM_PL_VRAM:
-               block = cur->node;
-
-               next = block->link.next;
-               block = list_entry(next, struct drm_buddy_block, link);
-
-               cur->node = block;
-               cur->start = amdgpu_vram_mgr_block_start(block);
-               cur->size = min(amdgpu_vram_mgr_block_size(block), cur->remaining);
-               break;
-       case TTM_PL_TT:
-               node = cur->node;
-
-               cur->node = ++node;
-               cur->start = node->start << PAGE_SHIFT;
-               cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
-               break;
-       default:
-               return;
-       }
+       cur->node = ++node;
+       cur->start = node->start << PAGE_SHIFT;
+       cur->size = min(node->size << PAGE_SHIFT, cur->remaining);
 }
 
 #endif
index 6a70818..9120ae8 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/dma-direction.h>
 #include <drm/gpu_scheduler.h>
-#include "amdgpu_vram_mgr.h"
 #include "amdgpu.h"
 
 #define AMDGPU_PL_GDS          (TTM_PL_PRIV + 0)
 
 #define AMDGPU_POISON  0xd0bed0be
 
+struct amdgpu_vram_mgr {
+       struct ttm_resource_manager manager;
+       struct drm_mm mm;
+       spinlock_t lock;
+       struct list_head reservations_pending;
+       struct list_head reserved_pages;
+       atomic64_t vis_usage;
+};
+
 struct amdgpu_gtt_mgr {
        struct ttm_resource_manager manager;
        struct drm_mm mm;
index 576849e..108e8e8 100644 (file)
@@ -496,7 +496,8 @@ static int amdgpu_vkms_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = YRES_MAX;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 49e4092..0a76116 100644 (file)
 #include "atom.h"
 
 struct amdgpu_vram_reservation {
-       u64 start;
-       u64 size;
-       struct list_head allocated;
-       struct list_head blocks;
+       struct list_head node;
+       struct drm_mm_node mm_node;
 };
 
 static inline struct amdgpu_vram_mgr *
@@ -188,18 +186,18 @@ const struct attribute_group amdgpu_vram_mgr_attr_group = {
 };
 
 /**
- * amdgpu_vram_mgr_vis_size - Calculate visible block size
+ * amdgpu_vram_mgr_vis_size - Calculate visible node size
  *
  * @adev: amdgpu_device pointer
- * @block: DRM BUDDY block structure
+ * @node: MM node structure
  *
- * Calculate how many bytes of the DRM BUDDY block are inside visible VRAM
+ * Calculate how many bytes of the MM node are inside visible VRAM
  */
 static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
-                                   struct drm_buddy_block *block)
+                                   struct drm_mm_node *node)
 {
-       u64 start = amdgpu_vram_mgr_block_start(block);
-       u64 end = start + amdgpu_vram_mgr_block_size(block);
+       uint64_t start = node->start << PAGE_SHIFT;
+       uint64_t end = (node->size + node->start) << PAGE_SHIFT;
 
        if (start >= adev->gmc.visible_vram_size)
                return 0;
@@ -220,9 +218,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
        struct ttm_resource *res = bo->tbo.resource;
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
-       struct drm_buddy_block *block;
-       u64 usage = 0;
+       unsigned pages = res->num_pages;
+       struct drm_mm_node *mm;
+       u64 usage;
 
        if (amdgpu_gmc_vram_full_visible(&adev->gmc))
                return amdgpu_bo_size(bo);
@@ -230,8 +228,9 @@ u64 amdgpu_vram_mgr_bo_visible_size(struct amdgpu_bo *bo)
        if (res->start >= adev->gmc.visible_vram_size >> PAGE_SHIFT)
                return 0;
 
-       list_for_each_entry(block, &vres->blocks, link)
-               usage += amdgpu_vram_mgr_vis_size(adev, block);
+       mm = &container_of(res, struct ttm_range_mgr_node, base)->mm_nodes[0];
+       for (usage = 0; pages; pages -= mm->size, mm++)
+               usage += amdgpu_vram_mgr_vis_size(adev, mm);
 
        return usage;
 }
@@ -241,30 +240,23 @@ static void amdgpu_vram_mgr_do_reserve(struct ttm_resource_manager *man)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
+       struct drm_mm *mm = &mgr->mm;
        struct amdgpu_vram_reservation *rsv, *temp;
-       struct drm_buddy_block *block;
        uint64_t vis_usage;
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks) {
-               if (drm_buddy_alloc_blocks(mm, rsv->start, rsv->start + rsv->size,
-                                          rsv->size, mm->chunk_size, &rsv->allocated,
-                                          DRM_BUDDY_RANGE_ALLOCATION))
-                       continue;
-
-               block = amdgpu_vram_mgr_first_block(&rsv->allocated);
-               if (!block)
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node) {
+               if (drm_mm_reserve_node(mm, &rsv->mm_node))
                        continue;
 
                dev_dbg(adev->dev, "Reservation 0x%llx - %lld, Succeeded\n",
-                       rsv->start, rsv->size);
+                       rsv->mm_node.start, rsv->mm_node.size);
 
-               vis_usage = amdgpu_vram_mgr_vis_size(adev, block);
+               vis_usage = amdgpu_vram_mgr_vis_size(adev, &rsv->mm_node);
                atomic64_add(vis_usage, &mgr->vis_usage);
                spin_lock(&man->bdev->lru_lock);
-               man->usage += rsv->size;
+               man->usage += rsv->mm_node.size << PAGE_SHIFT;
                spin_unlock(&man->bdev->lru_lock);
-               list_move(&rsv->blocks, &mgr->reserved_pages);
+               list_move(&rsv->node, &mgr->reserved_pages);
        }
 }
 
@@ -286,16 +278,14 @@ int amdgpu_vram_mgr_reserve_range(struct amdgpu_vram_mgr *mgr,
        if (!rsv)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&rsv->allocated);
-       INIT_LIST_HEAD(&rsv->blocks);
+       INIT_LIST_HEAD(&rsv->node);
+       rsv->mm_node.start = start >> PAGE_SHIFT;
+       rsv->mm_node.size = size >> PAGE_SHIFT;
 
-       rsv->start = start;
-       rsv->size = size;
-
-       mutex_lock(&mgr->lock);
-       list_add_tail(&rsv->blocks, &mgr->reservations_pending);
+       spin_lock(&mgr->lock);
+       list_add_tail(&rsv->node, &mgr->reservations_pending);
        amdgpu_vram_mgr_do_reserve(&mgr->manager);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        return 0;
 }
@@ -317,19 +307,19 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
        struct amdgpu_vram_reservation *rsv;
        int ret;
 
-       mutex_lock(&mgr->lock);
+       spin_lock(&mgr->lock);
 
-       list_for_each_entry(rsv, &mgr->reservations_pending, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reservations_pending, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = -EBUSY;
                        goto out;
                }
        }
 
-       list_for_each_entry(rsv, &mgr->reserved_pages, blocks) {
-               if (rsv->start <= start &&
-                   (start < (rsv->start + rsv->size))) {
+       list_for_each_entry(rsv, &mgr->reserved_pages, node) {
+               if ((rsv->mm_node.start <= start) &&
+                   (start < (rsv->mm_node.start + rsv->mm_node.size))) {
                        ret = 0;
                        goto out;
                }
@@ -337,11 +327,33 @@ int amdgpu_vram_mgr_query_page_status(struct amdgpu_vram_mgr *mgr,
 
        ret = -ENOENT;
 out:
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
        return ret;
 }
 
 /**
+ * amdgpu_vram_mgr_virt_start - update virtual start address
+ *
+ * @mem: ttm_resource to update
+ * @node: just allocated node
+ *
+ * Calculate a virtual BO start address to easily check if everything is CPU
+ * accessible.
+ */
+static void amdgpu_vram_mgr_virt_start(struct ttm_resource *mem,
+                                      struct drm_mm_node *node)
+{
+       unsigned long start;
+
+       start = node->start + node->size;
+       if (start > mem->num_pages)
+               start -= mem->num_pages;
+       else
+               start = 0;
+       mem->start = max(mem->start, start);
+}
+
+/**
  * amdgpu_vram_mgr_new - allocate new ranges
  *
  * @man: TTM memory type manager
@@ -356,44 +368,46 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                               const struct ttm_place *place,
                               struct ttm_resource **res)
 {
-       u64 vis_usage = 0, max_bytes, cur_size, min_block_size;
+       unsigned long lpfn, num_nodes, pages_per_node, pages_left, pages;
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct amdgpu_vram_mgr_resource *vres;
-       u64 size, remaining_size, lpfn, fpfn;
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
-       unsigned long pages_per_block;
+       uint64_t vis_usage = 0, mem_bytes, max_bytes;
+       struct ttm_range_mgr_node *node;
+       struct drm_mm *mm = &mgr->mm;
+       enum drm_mm_insert_mode mode;
+       unsigned i;
        int r;
 
-       lpfn = place->lpfn << PAGE_SHIFT;
+       lpfn = place->lpfn;
        if (!lpfn)
-               lpfn = man->size;
-
-       fpfn = place->fpfn << PAGE_SHIFT;
+               lpfn = man->size >> PAGE_SHIFT;
 
        max_bytes = adev->gmc.mc_vram_size;
        if (tbo->type != ttm_bo_type_kernel)
                max_bytes -= AMDGPU_VM_RESERVED_VRAM;
 
+       mem_bytes = tbo->base.size;
        if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-               pages_per_block = ~0ul;
+               pages_per_node = ~0ul;
+               num_nodes = 1;
        } else {
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               pages_per_block = HPAGE_PMD_NR;
+               pages_per_node = HPAGE_PMD_NR;
 #else
                /* default to 2MB */
-               pages_per_block = 2UL << (20UL - PAGE_SHIFT);
+               pages_per_node = 2UL << (20UL - PAGE_SHIFT);
 #endif
-               pages_per_block = max_t(uint32_t, pages_per_block,
-                                       tbo->page_alignment);
+               pages_per_node = max_t(uint32_t, pages_per_node,
+                                      tbo->page_alignment);
+               num_nodes = DIV_ROUND_UP_ULL(PFN_UP(mem_bytes), pages_per_node);
        }
 
-       vres = kzalloc(sizeof(*vres), GFP_KERNEL);
-       if (!vres)
+       node = kvmalloc(struct_size(node, mm_nodes, num_nodes),
+                       GFP_KERNEL | __GFP_ZERO);
+       if (!node)
                return -ENOMEM;
 
-       ttm_resource_init(tbo, place, &vres->base);
+       ttm_resource_init(tbo, place, &node->base);
 
        /* bail out quickly if there's likely not enough VRAM for this BO */
        if (ttm_resource_manager_usage(man) > max_bytes) {
@@ -401,130 +415,66 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man,
                goto error_fini;
        }
 
-       INIT_LIST_HEAD(&vres->blocks);
-
+       mode = DRM_MM_INSERT_BEST;
        if (place->flags & TTM_PL_FLAG_TOPDOWN)
-               vres->flags |= DRM_BUDDY_TOPDOWN_ALLOCATION;
-
-       if (fpfn || lpfn != man->size)
-               /* Allocate blocks in desired range */
-               vres->flags |= DRM_BUDDY_RANGE_ALLOCATION;
-
-       remaining_size = vres->base.num_pages << PAGE_SHIFT;
-
-       mutex_lock(&mgr->lock);
-       while (remaining_size) {
-               if (tbo->page_alignment)
-                       min_block_size = tbo->page_alignment << PAGE_SHIFT;
-               else
-                       min_block_size = mgr->default_page_size;
-
-               BUG_ON(min_block_size < mm->chunk_size);
-
-               /* Limit maximum size to 2GiB due to SG table limitations */
-               size = min(remaining_size, 2ULL << 30);
-
-               if (size >= pages_per_block << PAGE_SHIFT)
-                       min_block_size = pages_per_block << PAGE_SHIFT;
-
-               cur_size = size;
-
-               if (fpfn + size != place->lpfn << PAGE_SHIFT) {
-                       /*
-                        * Except for actual range allocation, modify the size and
-                        * min_block_size conforming to continuous flag enablement
-                        */
-                       if (place->flags & TTM_PL_FLAG_CONTIGUOUS) {
-                               size = roundup_pow_of_two(size);
-                               min_block_size = size;
-                       /*
-                        * Modify the size value if size is not
-                        * aligned with min_block_size
-                        */
-                       } else if (!IS_ALIGNED(size, min_block_size)) {
-                               size = round_up(size, min_block_size);
+               mode = DRM_MM_INSERT_HIGH;
+
+       pages_left = node->base.num_pages;
+
+       /* Limit maximum size to 2GB due to SG table limitations */
+       pages = min(pages_left, 2UL << (30 - PAGE_SHIFT));
+
+       i = 0;
+       spin_lock(&mgr->lock);
+       while (pages_left) {
+               uint32_t alignment = tbo->page_alignment;
+
+               if (pages >= pages_per_node)
+                       alignment = pages_per_node;
+
+               r = drm_mm_insert_node_in_range(mm, &node->mm_nodes[i], pages,
+                                               alignment, 0, place->fpfn,
+                                               lpfn, mode);
+               if (unlikely(r)) {
+                       if (pages > pages_per_node) {
+                               if (is_power_of_2(pages))
+                                       pages = pages / 2;
+                               else
+                                       pages = rounddown_pow_of_two(pages);
+                               continue;
                        }
+                       goto error_free;
                }
 
-               r = drm_buddy_alloc_blocks(mm, fpfn,
-                                          lpfn,
-                                          size,
-                                          min_block_size,
-                                          &vres->blocks,
-                                          vres->flags);
-               if (unlikely(r))
-                       goto error_free_blocks;
-
-               if (size > remaining_size)
-                       remaining_size = 0;
-               else
-                       remaining_size -= size;
-       }
-       mutex_unlock(&mgr->lock);
-
-       if (cur_size != size) {
-               struct drm_buddy_block *block;
-               struct list_head *trim_list;
-               u64 original_size;
-               LIST_HEAD(temp);
-
-               trim_list = &vres->blocks;
-               original_size = vres->base.num_pages << PAGE_SHIFT;
-
-               /*
-                * If size value is rounded up to min_block_size, trim the last
-                * block to the required size
-                */
-               if (!list_is_singular(&vres->blocks)) {
-                       block = list_last_entry(&vres->blocks, typeof(*block), link);
-                       list_move_tail(&block->link, &temp);
-                       trim_list = &temp;
-                       /*
-                        * Compute the original_size value by subtracting the
-                        * last block size with (aligned size - original size)
-                        */
-                       original_size = amdgpu_vram_mgr_block_size(block) - (size - cur_size);
-               }
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, &node->mm_nodes[i]);
+               amdgpu_vram_mgr_virt_start(&node->base, &node->mm_nodes[i]);
+               pages_left -= pages;
+               ++i;
 
-               mutex_lock(&mgr->lock);
-               drm_buddy_block_trim(mm,
-                                    original_size,
-                                    trim_list);
-               mutex_unlock(&mgr->lock);
-
-               if (!list_empty(&temp))
-                       list_splice_tail(trim_list, &vres->blocks);
-       }
-
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
-
-       block = amdgpu_vram_mgr_first_block(&vres->blocks);
-       if (!block) {
-               r = -EINVAL;
-               goto error_fini;
+               if (pages > pages_left)
+                       pages = pages_left;
        }
+       spin_unlock(&mgr->lock);
 
-       vres->base.start = amdgpu_vram_mgr_block_start(block) >> PAGE_SHIFT;
-
-       if (amdgpu_is_vram_mgr_blocks_contiguous(&vres->blocks))
-               vres->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
+       if (i == 1)
+               node->base.placement |= TTM_PL_FLAG_CONTIGUOUS;
 
        if (adev->gmc.xgmi.connected_to_cpu)
-               vres->base.bus.caching = ttm_cached;
+               node->base.bus.caching = ttm_cached;
        else
-               vres->base.bus.caching = ttm_write_combined;
+               node->base.bus.caching = ttm_write_combined;
 
        atomic64_add(vis_usage, &mgr->vis_usage);
-       *res = &vres->base;
+       *res = &node->base;
        return 0;
 
-error_free_blocks:
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+error_free:
+       while (i--)
+               drm_mm_remove_node(&node->mm_nodes[i]);
+       spin_unlock(&mgr->lock);
 error_fini:
-       ttm_resource_fini(man, &vres->base);
-       kfree(vres);
+       ttm_resource_fini(man, &node->base);
+       kvfree(node);
 
        return r;
 }
@@ -540,26 +490,27 @@ error_fini:
 static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man,
                                struct ttm_resource *res)
 {
-       struct amdgpu_vram_mgr_resource *vres = to_amdgpu_vram_mgr_resource(res);
+       struct ttm_range_mgr_node *node = to_ttm_range_mgr_node(res);
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct amdgpu_device *adev = to_amdgpu_device(mgr);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
        uint64_t vis_usage = 0;
+       unsigned i, pages;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry(block, &vres->blocks, link)
-               vis_usage += amdgpu_vram_mgr_vis_size(adev, block);
+       spin_lock(&mgr->lock);
+       for (i = 0, pages = res->num_pages; pages;
+            pages -= node->mm_nodes[i].size, ++i) {
+               struct drm_mm_node *mm = &node->mm_nodes[i];
 
+               drm_mm_remove_node(mm);
+               vis_usage += amdgpu_vram_mgr_vis_size(adev, mm);
+       }
        amdgpu_vram_mgr_do_reserve(man);
-
-       drm_buddy_free_list(mm, &vres->blocks);
-       mutex_unlock(&mgr->lock);
+       spin_unlock(&mgr->lock);
 
        atomic64_sub(vis_usage, &mgr->vis_usage);
 
        ttm_resource_fini(man, res);
-       kfree(vres);
+       kvfree(node);
 }
 
 /**
@@ -591,7 +542,7 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
        if (!*sgt)
                return -ENOMEM;
 
-       /* Determine the number of DRM_BUDDY blocks to export */
+       /* Determine the number of DRM_MM nodes to export */
        amdgpu_res_first(res, offset, length, &cursor);
        while (cursor.remaining) {
                num_entries++;
@@ -607,10 +558,10 @@ int amdgpu_vram_mgr_alloc_sgt(struct amdgpu_device *adev,
                sg->length = 0;
 
        /*
-        * Walk down DRM_BUDDY blocks to populate scatterlist nodes
-        * @note: Use iterator api to get first the DRM_BUDDY block
+        * Walk down DRM_MM nodes to populate scatterlist nodes
+        * @note: Use iterator api to get first the DRM_MM node
         * and the number of bytes from it. Access the following
-        * DRM_BUDDY block(s) if more buffer needs to exported
+        * DRM_MM node(s) if more buffer needs to exported
         */
        amdgpu_res_first(res, offset, length, &cursor);
        for_each_sgtable_sg((*sgt), sg, i) {
@@ -697,22 +648,13 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
                                  struct drm_printer *printer)
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
-       struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
 
        drm_printf(printer, "  vis usage:%llu\n",
                   amdgpu_vram_mgr_vis_usage(mgr));
 
-       mutex_lock(&mgr->lock);
-       drm_printf(printer, "default_page_size: %lluKiB\n",
-                  mgr->default_page_size >> 10);
-
-       drm_buddy_print(mm, printer);
-
-       drm_printf(printer, "reserved:\n");
-       list_for_each_entry(block, &mgr->reserved_pages, link)
-               drm_buddy_block_print(mm, block, printer);
-       mutex_unlock(&mgr->lock);
+       spin_lock(&mgr->lock);
+       drm_mm_print(&mgr->mm, printer);
+       spin_unlock(&mgr->lock);
 }
 
 static const struct ttm_resource_manager_func amdgpu_vram_mgr_func = {
@@ -732,21 +674,16 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev)
 {
        struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr;
        struct ttm_resource_manager *man = &mgr->manager;
-       int err;
 
        ttm_resource_manager_init(man, &adev->mman.bdev,
                                  adev->gmc.real_vram_size);
 
        man->func = &amdgpu_vram_mgr_func;
 
-       err = drm_buddy_init(&mgr->mm, man->size, PAGE_SIZE);
-       if (err)
-               return err;
-
-       mutex_init(&mgr->lock);
+       drm_mm_init(&mgr->mm, 0, man->size >> PAGE_SHIFT);
+       spin_lock_init(&mgr->lock);
        INIT_LIST_HEAD(&mgr->reservations_pending);
        INIT_LIST_HEAD(&mgr->reserved_pages);
-       mgr->default_page_size = PAGE_SIZE;
 
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, &mgr->manager);
        ttm_resource_manager_set_used(man, true);
@@ -774,16 +711,16 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev)
        if (ret)
                return;
 
-       mutex_lock(&mgr->lock);
-       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, blocks)
+       spin_lock(&mgr->lock);
+       list_for_each_entry_safe(rsv, temp, &mgr->reservations_pending, node)
                kfree(rsv);
 
-       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) {
-               drm_buddy_free_list(&mgr->mm, &rsv->blocks);
+       list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, node) {
+               drm_mm_remove_node(&rsv->mm_node);
                kfree(rsv);
        }
-       drm_buddy_fini(&mgr->mm);
-       mutex_unlock(&mgr->lock);
+       drm_mm_takedown(&mgr->mm);
+       spin_unlock(&mgr->lock);
 
        ttm_resource_manager_cleanup(man);
        ttm_set_driver_manager(&adev->mman.bdev, TTM_PL_VRAM, NULL);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h
deleted file mode 100644 (file)
index 9a2db87..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/* SPDX-License-Identifier: MIT
- * Copyright 2021 Advanced Micro Devices, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef __AMDGPU_VRAM_MGR_H__
-#define __AMDGPU_VRAM_MGR_H__
-
-#include <drm/drm_buddy.h>
-
-struct amdgpu_vram_mgr {
-       struct ttm_resource_manager manager;
-       struct drm_buddy mm;
-       /* protects access to buffer objects */
-       struct mutex lock;
-       struct list_head reservations_pending;
-       struct list_head reserved_pages;
-       atomic64_t vis_usage;
-       u64 default_page_size;
-};
-
-struct amdgpu_vram_mgr_resource {
-       struct ttm_resource base;
-       struct list_head blocks;
-       unsigned long flags;
-};
-
-static inline u64 amdgpu_vram_mgr_block_start(struct drm_buddy_block *block)
-{
-       return drm_buddy_block_offset(block);
-}
-
-static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block)
-{
-       return PAGE_SIZE << drm_buddy_block_order(block);
-}
-
-static inline struct drm_buddy_block *
-amdgpu_vram_mgr_first_block(struct list_head *list)
-{
-       return list_first_entry_or_null(list, struct drm_buddy_block, link);
-}
-
-static inline bool amdgpu_is_vram_mgr_blocks_contiguous(struct list_head *head)
-{
-       struct drm_buddy_block *block;
-       u64 start, size;
-
-       block = amdgpu_vram_mgr_first_block(head);
-       if (!block)
-               return false;
-
-       while (head != block->link.next) {
-               start = amdgpu_vram_mgr_block_start(block);
-               size = amdgpu_vram_mgr_block_size(block);
-
-               block = list_entry(block->link.next, struct drm_buddy_block, link);
-               if (start + size != amdgpu_vram_mgr_block_start(block))
-                       return false;
-       }
-
-       return true;
-}
-
-static inline struct amdgpu_vram_mgr_resource *
-to_amdgpu_vram_mgr_resource(struct ttm_resource *res)
-{
-       return container_of(res, struct amdgpu_vram_mgr_resource, base);
-}
-
-#endif
index 288fce7..9c964cd 100644 (file)
@@ -2796,7 +2796,8 @@ static int dce_v10_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index cbe5250..e0ad9f2 100644 (file)
@@ -2914,7 +2914,8 @@ static int dce_v11_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index 982855e..3caf6f3 100644 (file)
@@ -2673,7 +2673,8 @@ static int dce_v6_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_width = 16384;
        adev_to_drm(adev)->mode_config.max_height = 16384;
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
        adev_to_drm(adev)->mode_config.fb_base = adev->gmc.aper_base;
 
index 8444074..7c75df5 100644 (file)
@@ -2693,7 +2693,8 @@ static int dce_v8_0_sw_init(void *handle)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
 
        adev_to_drm(adev)->mode_config.fb_modifiers_not_supported = true;
 
index bf42004..a08769c 100644 (file)
@@ -184,6 +184,8 @@ static void kfd_device_info_init(struct kfd_dev *kfd,
                        /* Navi2x+, Navi1x+ */
                        if (gc_version == IP_VERSION(10, 3, 6))
                                kfd->device_info.no_atomic_fw_version = 14;
+                       else if (gc_version == IP_VERSION(10, 3, 7))
+                               kfd->device_info.no_atomic_fw_version = 3;
                        else if (gc_version >= IP_VERSION(10, 3, 0))
                                kfd->device_info.no_atomic_fw_version = 92;
                        else if (gc_version >= IP_VERSION(10, 1, 1))
index b4029c0..0ba0598 100644 (file)
@@ -6,7 +6,7 @@ config DRM_AMD_DC
        bool "AMD DC - Enable new display engine"
        default y
        select SND_HDA_COMPONENT if SND_HDA_CORE
-       select DRM_AMD_DC_DCN if (X86 || PPC64) && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
+       select DRM_AMD_DC_DCN if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS)
        help
          Choose this option if you want to use the new display engine
          support for AMDGPU. This adds required support for Vega and
index 9dd2e06..93ac33a 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/pci.h>
 #include <linux/firmware.h>
 #include <linux/component.h>
+#include <linux/dmi.h>
 
 #include <drm/display/drm_dp_mst_helper.h>
 #include <drm/display/drm_hdmi_helper.h>
@@ -462,6 +463,26 @@ static void dm_pflip_high_irq(void *interrupt_params)
                     vrr_active, (int) !e);
 }
 
+static void dm_crtc_handle_vblank(struct amdgpu_crtc *acrtc)
+{
+       struct drm_crtc *crtc = &acrtc->base;
+       struct drm_device *dev = crtc->dev;
+       unsigned long flags;
+
+       drm_crtc_handle_vblank(crtc);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+
+       /* Send completion event for cursor-only commits */
+       if (acrtc->event && acrtc->pflip_status != AMDGPU_FLIP_SUBMITTED) {
+               drm_crtc_send_vblank_event(crtc, acrtc->event);
+               drm_crtc_vblank_put(crtc);
+               acrtc->event = NULL;
+       }
+
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
 static void dm_vupdate_high_irq(void *interrupt_params)
 {
        struct common_irq_params *irq_params = interrupt_params;
@@ -500,7 +521,7 @@ static void dm_vupdate_high_irq(void *interrupt_params)
                 * if a pageflip happened inside front-porch.
                 */
                if (vrr_active) {
-                       drm_crtc_handle_vblank(&acrtc->base);
+                       dm_crtc_handle_vblank(acrtc);
 
                        /* BTR processing for pre-DCE12 ASICs */
                        if (acrtc->dm_irq_params.stream &&
@@ -552,7 +573,7 @@ static void dm_crtc_high_irq(void *interrupt_params)
         * to dm_vupdate_high_irq after end of front-porch.
         */
        if (!vrr_active)
-               drm_crtc_handle_vblank(&acrtc->base);
+               dm_crtc_handle_vblank(acrtc);
 
        /**
         * Following stuff must happen at start of vblank, for crc
@@ -1382,6 +1403,41 @@ static bool dm_should_disable_stutter(struct pci_dev *pdev)
        return false;
 }
 
+static const struct dmi_system_id hpd_disconnect_quirk_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3660"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3260"),
+               },
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Precision 3460"),
+               },
+       },
+       {}
+};
+
+static void retrieve_dmi_info(struct amdgpu_display_manager *dm)
+{
+       const struct dmi_system_id *dmi_id;
+
+       dm->aux_hpd_discon_quirk = false;
+
+       dmi_id = dmi_first_match(hpd_disconnect_quirk_table);
+       if (dmi_id) {
+               dm->aux_hpd_discon_quirk = true;
+               DRM_INFO("aux_hpd_discon_quirk attached\n");
+       }
+}
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
@@ -1508,6 +1564,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
        }
 
        INIT_LIST_HEAD(&adev->dm.da_list);
+
+       retrieve_dmi_info(&adev->dm);
+
        /* Display Core create. */
        adev->dm.dc = dc_create(&init_data);
 
@@ -3822,7 +3881,8 @@ static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
        adev_to_drm(adev)->mode_config.max_height = 16384;
 
        adev_to_drm(adev)->mode_config.preferred_depth = 24;
-       adev_to_drm(adev)->mode_config.prefer_shadow = 1;
+       /* disable prefer shadow for now due to hibernation issues */
+       adev_to_drm(adev)->mode_config.prefer_shadow = 0;
        /* indicates support for immediate flip */
        adev_to_drm(adev)->mode_config.async_page_flip = true;
 
@@ -5406,7 +5466,7 @@ fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
                        }
                }
 
-               if (per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
+               if (*per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
                        *pre_multiplied_alpha = false;
        }
 
@@ -9134,6 +9194,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
        struct amdgpu_bo *abo;
        uint32_t target_vblank, last_flip_vblank;
        bool vrr_active = amdgpu_dm_vrr_active(acrtc_state);
+       bool cursor_update = false;
        bool pflip_present = false;
        struct {
                struct dc_surface_update surface_updates[MAX_SURFACES];
@@ -9169,8 +9230,13 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
 
                /* Cursor plane is handled after stream updates */
-               if (plane->type == DRM_PLANE_TYPE_CURSOR)
+               if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+                       if ((fb && crtc == pcrtc) ||
+                           (old_plane_state->fb && old_plane_state->crtc == pcrtc))
+                               cursor_update = true;
+
                        continue;
+               }
 
                if (!fb || !crtc || pcrtc != crtc)
                        continue;
@@ -9333,6 +9399,17 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                                bundle->stream_update.vrr_infopacket =
                                        &acrtc_state->stream->vrr_infopacket;
                }
+       } else if (cursor_update && acrtc_state->active_planes > 0 &&
+                  !acrtc_state->force_dpms_off &&
+                  acrtc_attach->base.state->event) {
+               drm_crtc_vblank_get(pcrtc);
+
+               spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+
+               acrtc_attach->event = acrtc_attach->base.state->event;
+               acrtc_attach->base.state->event = NULL;
+
+               spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
        }
 
        /* Update the planes if changed or disable if we don't have any. */
index aa34c00..e80ef93 100644 (file)
@@ -540,6 +540,14 @@ struct amdgpu_display_manager {
         * last successfully applied backlight values.
         */
        u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
+
+       /**
+        * @aux_hpd_discon_quirk:
+        *
+        * quirk for hpd discon while aux is on-going.
+        * occurred on certain intel platform
+        */
+       bool aux_hpd_discon_quirk;
 };
 
 enum dsc_clock_force_state {
index 9221b66..2b9b095 100644 (file)
@@ -56,6 +56,8 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        ssize_t result = 0;
        struct aux_payload payload;
        enum aux_return_code_type operation_result;
+       struct amdgpu_device *adev;
+       struct ddc_service *ddc;
 
        if (WARN_ON(msg->size > 16))
                return -E2BIG;
@@ -74,6 +76,21 @@ static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
        result = dc_link_aux_transfer_raw(TO_DM_AUX(aux)->ddc_service, &payload,
                                      &operation_result);
 
+       /*
+        * w/a on certain intel platform where hpd is unexpected to pull low during
+        * 1st sideband message transaction by return AUX_RET_ERROR_HPD_DISCON
+        * aux transaction is succuess in such case, therefore bypass the error
+        */
+       ddc = TO_DM_AUX(aux)->ddc_service;
+       adev = ddc->ctx->driver_context;
+       if (adev->dm.aux_hpd_discon_quirk) {
+               if (msg->address == DP_SIDEBAND_MSG_DOWN_REQ_BASE &&
+                       operation_result == AUX_RET_ERROR_HPD_DISCON) {
+                       result = 0;
+                       operation_result = AUX_RET_SUCCESS;
+               }
+       }
+
        if (payload.write && result >= 0)
                result = msg->size;
 
index 6774dd8..3fe3fba 100644 (file)
@@ -1117,12 +1117,13 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
         * on certain displays, such as the Sharp 4k. 36bpp is needed
         * to support SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 and
         * SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616 with actual > 10 bpc
-        * precision on at least DCN display engines. However, at least
-        * Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
-        * so use only 30 bpp on DCE_VERSION_11_0. Testing with DCE 11.2 and 8.3
-        * did not show such problems, so this seems to be the exception.
+        * precision on DCN display engines, but apparently not for DCE, as
+        * far as testing on DCE-11.2 and DCE-8 showed. Various DCE parts have
+        * problems: Carrizo with DCE_VERSION_11_0 does not like 36 bpp lb depth,
+        * neither do DCE-8 at 4k resolution, or DCE-11.2 (broken identify pixel
+        * passthrough). Therefore only use 36 bpp on DCN where it is actually needed.
         */
-       if (plane_state->ctx->dce_version > DCE_VERSION_11_0)
+       if (plane_state->ctx->dce_version > DCE_VERSION_MAX)
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_36BPP;
        else
                pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP;
index 5f8809f..2fbd292 100644 (file)
@@ -1228,6 +1228,8 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
        uint32_t crystal_clock_freq = 2500;
        uint32_t tach_period;
 
+       if (speed == 0)
+               return -EINVAL;
        /*
         * To prevent from possible overheat, some ASICs may have requirement
         * for minimum fan speed:
index b2675c7..4b503c5 100644 (file)
@@ -74,22 +74,6 @@ static int fsl_ldb_attach(struct drm_bridge *bridge,
                                 bridge, flags);
 }
 
-static int fsl_ldb_atomic_check(struct drm_bridge *bridge,
-                               struct drm_bridge_state *bridge_state,
-                               struct drm_crtc_state *crtc_state,
-                               struct drm_connector_state *conn_state)
-{
-       /* Invert DE signal polarity. */
-       bridge_state->input_bus_cfg.flags &= ~(DRM_BUS_FLAG_DE_LOW |
-                                              DRM_BUS_FLAG_DE_HIGH);
-       if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_LOW)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_HIGH;
-       else if (bridge_state->output_bus_cfg.flags & DRM_BUS_FLAG_DE_HIGH)
-               bridge_state->input_bus_cfg.flags |= DRM_BUS_FLAG_DE_LOW;
-
-       return 0;
-}
-
 static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
                                  struct drm_bridge_state *old_bridge_state)
 {
@@ -153,7 +137,7 @@ static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
        reg = LDB_CTRL_CH0_ENABLE;
 
        if (fsl_ldb->lvds_dual_link)
-               reg |= LDB_CTRL_CH1_ENABLE;
+               reg |= LDB_CTRL_CH1_ENABLE | LDB_CTRL_SPLIT_MODE;
 
        if (lvds_format_24bpp) {
                reg |= LDB_CTRL_CH0_DATA_WIDTH;
@@ -233,7 +217,7 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 {
        struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
 
-       if (mode->clock > (fsl_ldb->lvds_dual_link ? 80000 : 160000))
+       if (mode->clock > (fsl_ldb->lvds_dual_link ? 160000 : 80000))
                return MODE_CLOCK_HIGH;
 
        return MODE_OK;
@@ -241,7 +225,6 @@ fsl_ldb_mode_valid(struct drm_bridge *bridge,
 
 static const struct drm_bridge_funcs funcs = {
        .attach = fsl_ldb_attach,
-       .atomic_check = fsl_ldb_atomic_check,
        .atomic_enable = fsl_ldb_atomic_enable,
        .atomic_disable = fsl_ldb_atomic_disable,
        .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
index 74bd4a7..059fd71 100644 (file)
@@ -329,7 +329,20 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                                                     const struct drm_driver *req_driver)
 {
        resource_size_t base, size;
-       int bar, ret = 0;
+       int bar, ret;
+
+       /*
+        * WARNING: Apparently we must kick fbdev drivers before vgacon,
+        * otherwise the vga fbdev driver falls over.
+        */
+#if IS_REACHABLE(CONFIG_FB)
+       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
+       if (ret)
+               return ret;
+#endif
+       ret = vga_remove_vgacon(pdev);
+       if (ret)
+               return ret;
 
        for (bar = 0; bar < PCI_STD_NUM_BARS; ++bar) {
                if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM))
@@ -339,15 +352,6 @@ int drm_aperture_remove_conflicting_pci_framebuffers(struct pci_dev *pdev,
                drm_aperture_detach_drivers(base, size);
        }
 
-       /*
-        * WARNING: Apparently we must kick fbdev drivers before vgacon,
-        * otherwise the vga fbdev driver falls over.
-        */
-#if IS_REACHABLE(CONFIG_FB)
-       ret = remove_conflicting_pci_framebuffers(pdev, req_driver->name);
-#endif
-       if (ret == 0)
-               ret = vga_remove_vgacon(pdev);
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL(drm_aperture_remove_conflicting_pci_framebuffers);
index df87ba9..d4e0f2e 100644 (file)
@@ -286,6 +286,21 @@ static const struct dmi_system_id orientation_data[] = {
                  DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X9"),
                },
                .driver_data = (void *)&lcd1200x1920_rightside_up,
+       }, {    /* Lenovo Yoga Tablet 2 830F / 830L */
+               .matches = {
+                /*
+                 * Note this also matches the Lenovo Yoga Tablet 2 1050F/L
+                 * since that uses the same mainboard. The resolution match
+                 * will limit this to only matching on the 830F/L. Neither has
+                 * any external video outputs so those are not a concern.
+                 */
+                DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
+                DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"),
+                DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"),
+                /* Partial match on beginning of BIOS version */
+                DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21"),
+               },
+               .driver_data = (void *)&lcd1200x1920_rightside_up,
        }, {    /* OneGX1 Pro */
                .matches = {
                  DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SYSTEM_MANUFACTURER"),
index 061b277..14d2a64 100644 (file)
@@ -839,6 +839,7 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo
        ret = drm_connector_init(dev, connector, &intel_dp_mst_connector_funcs,
                                 DRM_MODE_CONNECTOR_DisplayPort);
        if (ret) {
+               drm_dp_mst_put_port_malloc(port);
                intel_connector_free(intel_connector);
                return NULL;
        }
index 4c25d9b..d30ebca 100644 (file)
@@ -620,10 +620,15 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                         struct ttm_resource *res)
 {
        struct ttm_buffer_object *bo = i915_gem_to_ttm(obj);
+       u64 page_alignment;
 
        if (!i915_ttm_gtt_binds_lmem(res))
                return i915_ttm_tt_get_st(bo->ttm);
 
+       page_alignment = bo->page_alignment << PAGE_SHIFT;
+       if (!page_alignment)
+               page_alignment = obj->mm.region->min_page_size;
+
        /*
         * If CPU mapping differs, we need to add the ttm_tt pages to
         * the resulting st. Might make sense for GGTT.
@@ -634,7 +639,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                        struct i915_refct_sgt *rsgt;
 
                        rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                                res);
+                                                                res,
+                                                                page_alignment);
                        if (IS_ERR(rsgt))
                                return rsgt;
 
@@ -643,7 +649,8 @@ i915_ttm_resource_get_st(struct drm_i915_gem_object *obj,
                return i915_refct_sgt_get(obj->ttm.cached_io_rsgt);
        }
 
-       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res);
+       return intel_region_ttm_resource_to_rsgt(obj->mm.region, res,
+                                                page_alignment);
 }
 
 static int i915_ttm_truncate(struct drm_i915_gem_object *obj)
index 319936f..e6e01c2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/jiffies.h>
 
 #include "gt/intel_engine.h"
+#include "gt/intel_rps.h"
 
 #include "i915_gem_ioctls.h"
 #include "i915_gem_object.h"
@@ -31,6 +32,37 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
                                      timeout);
 }
 
+static void
+i915_gem_object_boost(struct dma_resv *resv, unsigned int flags)
+{
+       struct dma_resv_iter cursor;
+       struct dma_fence *fence;
+
+       /*
+        * Prescan all fences for potential boosting before we begin waiting.
+        *
+        * When we wait, we wait on outstanding fences serially. If the
+        * dma-resv contains a sequence such as 1:1, 1:2 instead of a reduced
+        * form 1:2, then as we look at each wait in turn we see that each
+        * request is currently executing and not worthy of boosting. But if
+        * we only happen to look at the final fence in the sequence (because
+        * of request coalescing or splitting between read/write arrays by
+        * the iterator), then we would boost. As such our decision to boost
+        * or not is delicately balanced on the order we wait on fences.
+        *
+        * So instead of looking for boosts sequentially, look for all boosts
+        * upfront and then wait on the outstanding fences.
+        */
+
+       dma_resv_iter_begin(&cursor, resv,
+                           dma_resv_usage_rw(flags & I915_WAIT_ALL));
+       dma_resv_for_each_fence_unlocked(&cursor, fence)
+               if (dma_fence_is_i915(fence) &&
+                   !i915_request_started(to_request(fence)))
+                       intel_rps_boost(to_request(fence));
+       dma_resv_iter_end(&cursor);
+}
+
 static long
 i915_gem_object_wait_reservation(struct dma_resv *resv,
                                 unsigned int flags,
@@ -40,6 +72,8 @@ i915_gem_object_wait_reservation(struct dma_resv *resv,
        struct dma_fence *fence;
        long ret = timeout ?: 1;
 
+       i915_gem_object_boost(resv, flags);
+
        dma_resv_iter_begin(&cursor, resv,
                            dma_resv_usage_rw(flags & I915_WAIT_ALL));
        dma_resv_for_each_fence_unlocked(&cursor, fence) {
index 51a0fe6..531af6a 100644 (file)
@@ -1209,6 +1209,20 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
        mutex_lock(&gt->tlb_invalidate_lock);
        intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
+       spin_lock_irq(&uncore->lock); /* serialise invalidate with GT reset */
+
+       for_each_engine(engine, gt, id) {
+               struct reg_and_bit rb;
+
+               rb = get_reg_and_bit(engine, regs == gen8_regs, regs, num);
+               if (!i915_mmio_reg_offset(rb.reg))
+                       continue;
+
+               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
+       }
+
+       spin_unlock_irq(&uncore->lock);
+
        for_each_engine(engine, gt, id) {
                /*
                 * HW architecture suggest typical invalidation time at 40us,
@@ -1223,7 +1237,6 @@ void intel_gt_invalidate_tlbs(struct intel_gt *gt)
                if (!i915_mmio_reg_offset(rb.reg))
                        continue;
 
-               intel_uncore_write_fw(uncore, rb.reg, rb.bit);
                if (__intel_wait_for_register_fw(uncore,
                                                 rb.reg, rb.bit, 0,
                                                 timeout_us, timeout_ms,
index a5338c3..c68d36f 100644 (file)
@@ -300,9 +300,9 @@ static int gen6_hw_domain_reset(struct intel_gt *gt, u32 hw_domain_mask)
        return err;
 }
 
-static int gen6_reset_engines(struct intel_gt *gt,
-                             intel_engine_mask_t engine_mask,
-                             unsigned int retry)
+static int __gen6_reset_engines(struct intel_gt *gt,
+                               intel_engine_mask_t engine_mask,
+                               unsigned int retry)
 {
        struct intel_engine_cs *engine;
        u32 hw_mask;
@@ -321,6 +321,20 @@ static int gen6_reset_engines(struct intel_gt *gt,
        return gen6_hw_domain_reset(gt, hw_mask);
 }
 
+static int gen6_reset_engines(struct intel_gt *gt,
+                             intel_engine_mask_t engine_mask,
+                             unsigned int retry)
+{
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+       ret = __gen6_reset_engines(gt, engine_mask, retry);
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
+       return ret;
+}
+
 static struct intel_engine_cs *find_sfc_paired_vecs_engine(struct intel_engine_cs *engine)
 {
        int vecs_id;
@@ -487,9 +501,9 @@ static void gen11_unlock_sfc(struct intel_engine_cs *engine)
        rmw_clear_fw(uncore, sfc_lock.lock_reg, sfc_lock.lock_bit);
 }
 
-static int gen11_reset_engines(struct intel_gt *gt,
-                              intel_engine_mask_t engine_mask,
-                              unsigned int retry)
+static int __gen11_reset_engines(struct intel_gt *gt,
+                                intel_engine_mask_t engine_mask,
+                                unsigned int retry)
 {
        struct intel_engine_cs *engine;
        intel_engine_mask_t tmp;
@@ -583,8 +597,11 @@ static int gen8_reset_engines(struct intel_gt *gt,
        struct intel_engine_cs *engine;
        const bool reset_non_ready = retry >= 1;
        intel_engine_mask_t tmp;
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&gt->uncore->lock, flags);
+
        for_each_engine_masked(engine, gt, engine_mask, tmp) {
                ret = gen8_engine_reset_prepare(engine);
                if (ret && !reset_non_ready)
@@ -612,17 +629,19 @@ static int gen8_reset_engines(struct intel_gt *gt,
         * This is best effort, so ignore any error from the initial reset.
         */
        if (IS_DG2(gt->i915) && engine_mask == ALL_ENGINES)
-               gen11_reset_engines(gt, gt->info.engine_mask, 0);
+               __gen11_reset_engines(gt, gt->info.engine_mask, 0);
 
        if (GRAPHICS_VER(gt->i915) >= 11)
-               ret = gen11_reset_engines(gt, engine_mask, retry);
+               ret = __gen11_reset_engines(gt, engine_mask, retry);
        else
-               ret = gen6_reset_engines(gt, engine_mask, retry);
+               ret = __gen6_reset_engines(gt, engine_mask, retry);
 
 skip_reset:
        for_each_engine_masked(engine, gt, engine_mask, tmp)
                gen8_engine_reset_cancel(engine);
 
+       spin_unlock_irqrestore(&gt->uncore->lock, flags);
+
        return ret;
 }
 
index 8b2c11d..1109088 100644 (file)
@@ -176,8 +176,8 @@ static int live_lrc_layout(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
@@ -365,8 +365,8 @@ static int live_lrc_fixed(void *arg)
                        continue;
 
                hw = shmem_pin_map(engine->default_state);
-               if (IS_ERR(hw)) {
-                       err = PTR_ERR(hw);
+               if (!hw) {
+                       err = -ENOMEM;
                        break;
                }
                hw += LRC_STATE_OFFSET / sizeof(*hw);
index f0d7b57..2ff55b9 100644 (file)
@@ -162,6 +162,15 @@ __uc_fw_auto_select(struct drm_i915_private *i915, struct intel_uc_fw *uc_fw)
        u8 rev = INTEL_REVID(i915);
        int i;
 
+       /*
+        * The only difference between the ADL GuC FWs is the HWConfig support.
+        * ADL-N does not support HWConfig, so we should use the same binary as
+        * ADL-S, otherwise the GuC might attempt to fetch a config table that
+        * does not exist.
+        */
+       if (IS_ADLP_N(i915))
+               p = INTEL_ALDERLAKE_S;
+
        GEM_BUG_ON(uc_fw->type >= ARRAY_SIZE(blobs_all));
        fw_blobs = blobs_all[uc_fw->type].blobs;
        fw_count = blobs_all[uc_fw->type].count;
index b9eb75a..1c35a41 100644 (file)
@@ -3117,9 +3117,9 @@ void intel_gvt_update_reg_whitelist(struct intel_vgpu *vgpu)
                        continue;
 
                vaddr = shmem_pin_map(engine->default_state);
-               if (IS_ERR(vaddr)) {
-                       gvt_err("failed to map %s->default state, err:%zd\n",
-                               engine->name, PTR_ERR(vaddr));
+               if (!vaddr) {
+                       gvt_err("failed to map %s->default state\n",
+                               engine->name);
                        return;
                }
 
index 159571b..f63b50b 100644 (file)
@@ -68,6 +68,7 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * drm_mm_node
  * @node: The drm_mm_node.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from a struct drm_mm_node,
  * taking a maximum segment length into account, splitting into segments
@@ -77,15 +78,18 @@ void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size)
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start)
+                                             u64 region_start,
+                                             u64 page_alignment)
 {
-       const u64 max_segment = SZ_1G; /* Do we have a limit on this? */
+       const u64 max_segment = round_down(UINT_MAX, page_alignment);
        u64 segment_pages = max_segment >> PAGE_SHIFT;
        u64 block_size, offset, prev_end;
        struct i915_refct_sgt *rsgt;
        struct sg_table *st;
        struct scatterlist *sg;
 
+       GEM_BUG_ON(!max_segment);
+
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
                return ERR_PTR(-ENOMEM);
@@ -112,6 +116,8 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
                                sg = __sg_next(sg);
 
                        sg_dma_address(sg) = region_start + offset;
+                       GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                              page_alignment));
                        sg_dma_len(sg) = 0;
                        sg->length = 0;
                        st->nents++;
@@ -138,6 +144,7 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * i915_buddy_block list
  * @res: The struct i915_ttm_buddy_resource.
  * @region_start: An offset to add to the dma addresses of the sg list.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * Create a struct sg_table, initializing it from struct i915_buddy_block list,
  * taking a maximum segment length into account, splitting into segments
@@ -147,11 +154,12 @@ struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
  * error code cast to an error pointer on failure.
  */
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start)
+                                                    u64 region_start,
+                                                    u64 page_alignment)
 {
        struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res);
        const u64 size = res->num_pages << PAGE_SHIFT;
-       const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE);
+       const u64 max_segment = round_down(UINT_MAX, page_alignment);
        struct drm_buddy *mm = bman_res->mm;
        struct list_head *blocks = &bman_res->blocks;
        struct drm_buddy_block *block;
@@ -161,6 +169,7 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
        resource_size_t prev_end;
 
        GEM_BUG_ON(list_empty(blocks));
+       GEM_BUG_ON(!max_segment);
 
        rsgt = kmalloc(sizeof(*rsgt), GFP_KERNEL);
        if (!rsgt)
@@ -191,6 +200,8 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
                                        sg = __sg_next(sg);
 
                                sg_dma_address(sg) = region_start + offset;
+                               GEM_BUG_ON(!IS_ALIGNED(sg_dma_address(sg),
+                                                      page_alignment));
                                sg_dma_len(sg) = 0;
                                sg->length = 0;
                                st->nents++;
index 12c6a16..b13e4cd 100644 (file)
@@ -213,9 +213,11 @@ static inline void __i915_refct_sgt_init(struct i915_refct_sgt *rsgt,
 void i915_refct_sgt_init(struct i915_refct_sgt *rsgt, size_t size);
 
 struct i915_refct_sgt *i915_rsgt_from_mm_node(const struct drm_mm_node *node,
-                                             u64 region_start);
+                                             u64 region_start,
+                                             u64 page_alignment);
 
 struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res,
-                                                    u64 region_start);
+                                                    u64 region_start,
+                                                    u64 page_alignment);
 
 #endif
index 0bffb70..04d12f2 100644 (file)
@@ -1637,10 +1637,10 @@ static void force_unbind(struct i915_vma *vma)
        GEM_BUG_ON(drm_mm_node_allocated(&vma->node));
 }
 
-static void release_references(struct i915_vma *vma, bool vm_ddestroy)
+static void release_references(struct i915_vma *vma, struct intel_gt *gt,
+                              bool vm_ddestroy)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       struct intel_gt *gt = vma->vm->gt;
 
        GEM_BUG_ON(i915_vma_is_active(vma));
 
@@ -1695,11 +1695,12 @@ void i915_vma_destroy_locked(struct i915_vma *vma)
 
        force_unbind(vma);
        list_del_init(&vma->vm_link);
-       release_references(vma, false);
+       release_references(vma, vma->vm->gt, false);
 }
 
 void i915_vma_destroy(struct i915_vma *vma)
 {
+       struct intel_gt *gt;
        bool vm_ddestroy;
 
        mutex_lock(&vma->vm->mutex);
@@ -1707,8 +1708,11 @@ void i915_vma_destroy(struct i915_vma *vma)
        list_del_init(&vma->vm_link);
        vm_ddestroy = vma->vm_ddestroy;
        vma->vm_ddestroy = false;
+
+       /* vma->vm may be freed when releasing vma->vm->mutex. */
+       gt = vma->vm->gt;
        mutex_unlock(&vma->vm->mutex);
-       release_references(vma, vm_ddestroy);
+       release_references(vma, gt, vm_ddestroy);
 }
 
 void i915_vma_parked(struct intel_gt *gt)
index 62ff774..6873808 100644 (file)
@@ -152,6 +152,7 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  * Convert an opaque TTM resource manager resource to a refcounted sg_table.
  * @mem: The memory region.
  * @res: The resource manager resource obtained from the TTM resource manager.
+ * @page_alignment: Required page alignment for each sg entry. Power of two.
  *
  * The gem backends typically use sg-tables for operations on the underlying
  * io_memory. So provide a way for the backends to translate the
@@ -161,16 +162,19 @@ int intel_region_ttm_fini(struct intel_memory_region *mem)
  */
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res)
+                                 struct ttm_resource *res,
+                                 u64 page_alignment)
 {
        if (mem->is_range_manager) {
                struct ttm_range_mgr_node *range_node =
                        to_ttm_range_mgr_node(res);
 
                return i915_rsgt_from_mm_node(&range_node->mm_nodes[0],
-                                             mem->region.start);
+                                             mem->region.start,
+                                             page_alignment);
        } else {
-               return i915_rsgt_from_buddy_resource(res, mem->region.start);
+               return i915_rsgt_from_buddy_resource(res, mem->region.start,
+                                                    page_alignment);
        }
 }
 
index cf9d86d..98fba51 100644 (file)
@@ -24,7 +24,8 @@ int intel_region_ttm_fini(struct intel_memory_region *mem);
 
 struct i915_refct_sgt *
 intel_region_ttm_resource_to_rsgt(struct intel_memory_region *mem,
-                                 struct ttm_resource *res);
+                                 struct ttm_resource *res,
+                                 u64 page_alignment);
 
 void intel_region_ttm_resource_free(struct intel_memory_region *mem,
                                    struct ttm_resource *res);
index 8633bec..ab9f17f 100644 (file)
@@ -742,7 +742,7 @@ static int pot_hole(struct i915_address_space *vm,
                u64 addr;
 
                for (addr = round_up(hole_start + min_alignment, step) - min_alignment;
-                    addr <= round_down(hole_end - (2 * min_alignment), step) - min_alignment;
+                    hole_end > addr && hole_end - addr >= 2 * min_alignment;
                     addr += step) {
                        err = i915_vma_pin(vma, 0, 0, addr | flags);
                        if (err) {
index 73eb53e..3b18e59 100644 (file)
@@ -451,7 +451,6 @@ out_put:
 
 static int igt_mock_max_segment(void *arg)
 {
-       const unsigned int max_segment = rounddown(UINT_MAX, PAGE_SIZE);
        struct intel_memory_region *mem = arg;
        struct drm_i915_private *i915 = mem->i915;
        struct i915_ttm_buddy_resource *res;
@@ -460,7 +459,10 @@ static int igt_mock_max_segment(void *arg)
        struct drm_buddy *mm;
        struct list_head *blocks;
        struct scatterlist *sg;
+       I915_RND_STATE(prng);
        LIST_HEAD(objects);
+       unsigned int max_segment;
+       unsigned int ps;
        u64 size;
        int err = 0;
 
@@ -472,7 +474,13 @@ static int igt_mock_max_segment(void *arg)
         */
 
        size = SZ_8G;
-       mem = mock_region_create(i915, 0, size, PAGE_SIZE, 0, 0);
+       ps = PAGE_SIZE;
+       if (i915_prandom_u64_state(&prng) & 1)
+               ps = SZ_64K; /* For something like DG2 */
+
+       max_segment = round_down(UINT_MAX, ps);
+
+       mem = mock_region_create(i915, 0, size, ps, 0, 0);
        if (IS_ERR(mem))
                return PTR_ERR(mem);
 
@@ -498,12 +506,21 @@ static int igt_mock_max_segment(void *arg)
        }
 
        for (sg = obj->mm.pages->sgl; sg; sg = sg_next(sg)) {
+               dma_addr_t daddr = sg_dma_address(sg);
+
                if (sg->length > max_segment) {
                        pr_err("%s: Created an oversized scatterlist entry, %u > %u\n",
                               __func__, sg->length, max_segment);
                        err = -EINVAL;
                        goto out_close;
                }
+
+               if (!IS_ALIGNED(daddr, ps)) {
+                       pr_err("%s: Created an unaligned scatterlist entry, addr=%pa, ps=%u\n",
+                              __func__,  &daddr, ps);
+                       err = -EINVAL;
+                       goto out_close;
+               }
        }
 
 out_close:
index 670557c..bac21fe 100644 (file)
@@ -33,7 +33,8 @@ static int mock_region_get_pages(struct drm_i915_gem_object *obj)
                return PTR_ERR(obj->mm.res);
 
        obj->mm.rsgt = intel_region_ttm_resource_to_rsgt(obj->mm.region,
-                                                        obj->mm.res);
+                                                        obj->mm.res,
+                                                        obj->mm.region->min_page_size);
        if (IS_ERR(obj->mm.rsgt)) {
                err = PTR_ERR(obj->mm.rsgt);
                goto err_free_resource;
index 087e69b..b1e6d23 100644 (file)
@@ -433,8 +433,8 @@ static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
 
        if (args->retained) {
                if (args->madv == PANFROST_MADV_DONTNEED)
-                       list_add_tail(&bo->base.madv_list,
-                                     &pfdev->shrinker_list);
+                       list_move_tail(&bo->base.madv_list,
+                                      &pfdev->shrinker_list);
                else if (args->madv == PANFROST_MADV_WILLNEED)
                        list_del_init(&bo->base.madv_list);
        }
index d3f82b2..b285a80 100644 (file)
@@ -518,7 +518,7 @@ err_map:
 err_pages:
        drm_gem_shmem_put_pages(&bo->base);
 err_bo:
-       drm_gem_object_put(&bo->base.base);
+       panfrost_gem_mapping_put(bomapping);
        return ret;
 }
 
index 67d38f5..13ed33e 100644 (file)
 #include <drm/drm_probe_helper.h>
 #include <drm/drm_vblank.h>
 
+#if defined(CONFIG_ARM_DMA_USE_IOMMU)
+#include <asm/dma-iommu.h>
+#else
+#define arm_iommu_detach_device(...)   ({ })
+#define arm_iommu_release_mapping(...) ({ })
+#define to_dma_iommu_mapping(dev) NULL
+#endif
+
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
@@ -49,6 +57,15 @@ int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
        if (!private->domain)
                return 0;
 
+       if (IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)) {
+               struct dma_iommu_mapping *mapping = to_dma_iommu_mapping(dev);
+
+               if (mapping) {
+                       arm_iommu_detach_device(dev);
+                       arm_iommu_release_mapping(mapping);
+               }
+       }
+
        ret = iommu_attach_device(private->domain, dev);
        if (ret) {
                DRM_DEV_ERROR(dev, "Failed to attach iommu device\n");
index 0839444..f4886e6 100644 (file)
@@ -350,7 +350,7 @@ static int ssd130x_init(struct ssd130x_device *ssd130x)
 
        /* Set precharge period in number of ticks from the internal clock */
        precharge = (SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep1) |
-                    SSD130X_SET_PRECHARGE_PERIOD1_SET(ssd130x->prechargep2));
+                    SSD130X_SET_PRECHARGE_PERIOD2_SET(ssd130x->prechargep2));
        ret = ssd130x_write_cmd(ssd130x, 2, SSD130X_SET_PRECHARGE_PERIOD, precharge);
        if (ret < 0)
                return ret;
index b4c1ad1..3d6f8ee 100644 (file)
@@ -1338,6 +1338,7 @@ static int cdns_i2c_probe(struct platform_device *pdev)
        return 0;
 
 err_clk_dis:
+       clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
        clk_disable_unprepare(id->clk);
        pm_runtime_disable(&pdev->dev);
        pm_runtime_set_suspended(&pdev->dev);
index ac8e7d6..39cb1b7 100644 (file)
@@ -161,7 +161,6 @@ static const char *piix4_aux_port_name_sb800 = " port 1";
 
 struct sb800_mmio_cfg {
        void __iomem *addr;
-       struct resource *res;
        bool use_mmio;
 };
 
@@ -179,13 +178,11 @@ static int piix4_sb800_region_request(struct device *dev,
                                      struct sb800_mmio_cfg *mmio_cfg)
 {
        if (mmio_cfg->use_mmio) {
-               struct resource *res;
                void __iomem *addr;
 
-               res = request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
-                                              SB800_PIIX4_FCH_PM_SIZE,
-                                              "sb800_piix4_smb");
-               if (!res) {
+               if (!request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR,
+                                             SB800_PIIX4_FCH_PM_SIZE,
+                                             "sb800_piix4_smb")) {
                        dev_err(dev,
                                "SMBus base address memory region 0x%x already in use.\n",
                                SB800_PIIX4_FCH_PM_ADDR);
@@ -195,12 +192,12 @@ static int piix4_sb800_region_request(struct device *dev,
                addr = ioremap(SB800_PIIX4_FCH_PM_ADDR,
                               SB800_PIIX4_FCH_PM_SIZE);
                if (!addr) {
-                       release_resource(res);
+                       release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                          SB800_PIIX4_FCH_PM_SIZE);
                        dev_err(dev, "SMBus base address mapping failed.\n");
                        return -ENOMEM;
                }
 
-               mmio_cfg->res = res;
                mmio_cfg->addr = addr;
 
                return 0;
@@ -222,7 +219,8 @@ static void piix4_sb800_region_release(struct device *dev,
 {
        if (mmio_cfg->use_mmio) {
                iounmap(mmio_cfg->addr);
-               release_resource(mmio_cfg->res);
+               release_mem_region(SB800_PIIX4_FCH_PM_ADDR,
+                                  SB800_PIIX4_FCH_PM_SIZE);
                return;
        }
 
index 424ef47..f5c6802 100644 (file)
 #include <linux/tick.h>
 #include <trace/events/power.h>
 #include <linux/sched.h>
+#include <linux/sched/smt.h>
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/moduleparam.h>
 #include <asm/cpu_device_id.h>
 #include <asm/intel-family.h>
+#include <asm/nospec-branch.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 
@@ -106,6 +108,12 @@ static unsigned int mwait_substates __initdata;
 #define CPUIDLE_FLAG_ALWAYS_ENABLE     BIT(15)
 
 /*
+ * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE
+ * above.
+ */
+#define CPUIDLE_FLAG_IBRS              BIT(16)
+
+/*
  * MWAIT takes an 8-bit "hint" in EAX "suggesting"
  * the C-state (top nibble) and sub-state (bottom nibble)
  * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc.
@@ -159,6 +167,24 @@ static __cpuidle int intel_idle_irq(struct cpuidle_device *dev,
        return ret;
 }
 
+static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev,
+                                    struct cpuidle_driver *drv, int index)
+{
+       bool smt_active = sched_smt_active();
+       u64 spec_ctrl = spec_ctrl_current();
+       int ret;
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, 0);
+
+       ret = __intel_idle(dev, drv, index);
+
+       if (smt_active)
+               wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl);
+
+       return ret;
+}
+
 /**
  * intel_idle_s2idle - Ask the processor to enter the given idle state.
  * @dev: cpuidle device of the target CPU.
@@ -680,7 +706,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 85,
                .target_residency = 200,
                .enter = &intel_idle,
@@ -688,7 +714,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C7s",
                .desc = "MWAIT 0x33",
-               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 124,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -696,7 +722,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C8",
                .desc = "MWAIT 0x40",
-               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 200,
                .target_residency = 800,
                .enter = &intel_idle,
@@ -704,7 +730,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C9",
                .desc = "MWAIT 0x50",
-               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 480,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -712,7 +738,7 @@ static struct cpuidle_state skl_cstates[] __initdata = {
        {
                .name = "C10",
                .desc = "MWAIT 0x60",
-               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 890,
                .target_residency = 5000,
                .enter = &intel_idle,
@@ -741,7 +767,7 @@ static struct cpuidle_state skx_cstates[] __initdata = {
        {
                .name = "C6",
                .desc = "MWAIT 0x20",
-               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
+               .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS,
                .exit_latency = 133,
                .target_residency = 600,
                .enter = &intel_idle,
@@ -1819,6 +1845,12 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
                if (cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE)
                        drv->states[drv->state_count].enter = intel_idle_irq;
 
+               if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) &&
+                   cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) {
+                       WARN_ON_ONCE(cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IRQ_ENABLE);
+                       drv->states[drv->state_count].enter = intel_idle_ibrs;
+               }
+
                if ((disabled_states_mask & BIT(drv->state_count)) ||
                    ((icpu->use_acpi || force_use_acpi) &&
                     intel_idle_off_by_default(mwait_hint) &&
index 3ad9870..aa45a9f 100644 (file)
@@ -900,6 +900,11 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
        } else {
                dev_warn(dev, "Unexpected ACPI resources: gpio_count %d, gpio_int_idx %d\n",
                         ts->gpio_count, ts->gpio_int_idx);
+               /*
+                * On some devices _PS0 does a reset for us and
+                * sometimes this is necessary for things to work.
+                */
+               acpi_device_fix_up_power(ACPI_COMPANION(dev));
                return -EINVAL;
        }
 
index 43c521f..3dda6ea 100644 (file)
@@ -1654,6 +1654,9 @@ static int usbtouch_probe(struct usb_interface *intf,
        if (id->driver_info == DEVTYPE_IGNORE)
                return -ENODEV;
 
+       if (id->driver_info >= ARRAY_SIZE(usbtouch_dev_info))
+               return -ENODEV;
+
        endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
        if (!endpoint)
                return -ENXIO;
index 2757c77..f51ab56 100644 (file)
@@ -758,7 +758,9 @@ batt_err:
 
 static int wm97xx_mfd_remove(struct platform_device *pdev)
 {
-       return wm97xx_remove(&pdev->dev);
+       wm97xx_remove(&pdev->dev);
+
+       return 0;
 }
 
 static int __maybe_unused wm97xx_suspend(struct device *dev)
index 592c1e1..9699ca1 100644 (file)
@@ -382,7 +382,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
 
 static struct notifier_block dmar_pci_bus_nb = {
        .notifier_call = dmar_pci_bus_notifier,
-       .priority = INT_MIN,
+       .priority = 1,
 };
 
 static struct dmar_drhd_unit *
index 4401659..5c0dce7 100644 (file)
@@ -320,30 +320,6 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped);
 DEFINE_SPINLOCK(device_domain_lock);
 static LIST_HEAD(device_domain_list);
 
-/*
- * Iterate over elements in device_domain_list and call the specified
- * callback @fn against each element.
- */
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data)
-{
-       int ret = 0;
-       unsigned long flags;
-       struct device_domain_info *info;
-
-       spin_lock_irqsave(&device_domain_lock, flags);
-       list_for_each_entry(info, &device_domain_list, global) {
-               ret = fn(info, data);
-               if (ret) {
-                       spin_unlock_irqrestore(&device_domain_lock, flags);
-                       return ret;
-               }
-       }
-       spin_unlock_irqrestore(&device_domain_lock, flags);
-
-       return 0;
-}
-
 const struct iommu_ops intel_iommu_ops;
 
 static bool translation_pre_enabled(struct intel_iommu *iommu)
index cb4c1d0..17cad7c 100644 (file)
@@ -86,54 +86,6 @@ void vcmd_free_pasid(struct intel_iommu *iommu, u32 pasid)
 /*
  * Per device pasid table management:
  */
-static inline void
-device_attach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = pasid_table;
-       list_add(&info->table, &pasid_table->dev);
-}
-
-static inline void
-device_detach_pasid_table(struct device_domain_info *info,
-                         struct pasid_table *pasid_table)
-{
-       info->pasid_table = NULL;
-       list_del(&info->table);
-}
-
-struct pasid_table_opaque {
-       struct pasid_table      **pasid_table;
-       int                     segment;
-       int                     bus;
-       int                     devfn;
-};
-
-static int search_pasid_table(struct device_domain_info *info, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       if (info->iommu->segment == data->segment &&
-           info->bus == data->bus &&
-           info->devfn == data->devfn &&
-           info->pasid_table) {
-               *data->pasid_table = info->pasid_table;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque)
-{
-       struct pasid_table_opaque *data = opaque;
-
-       data->segment = pci_domain_nr(pdev->bus);
-       data->bus = PCI_BUS_NUM(alias);
-       data->devfn = alias & 0xff;
-
-       return for_each_device_domain(&search_pasid_table, data);
-}
 
 /*
  * Allocate a pasid table for @dev. It should be called in a
@@ -143,28 +95,18 @@ int intel_pasid_alloc_table(struct device *dev)
 {
        struct device_domain_info *info;
        struct pasid_table *pasid_table;
-       struct pasid_table_opaque data;
        struct page *pages;
        u32 max_pasid = 0;
-       int ret, order;
-       int size;
+       int order, size;
 
        might_sleep();
        info = dev_iommu_priv_get(dev);
        if (WARN_ON(!info || !dev_is_pci(dev) || info->pasid_table))
                return -EINVAL;
 
-       /* DMA alias device already has a pasid table, use it: */
-       data.pasid_table = &pasid_table;
-       ret = pci_for_each_dma_alias(to_pci_dev(dev),
-                                    &get_alias_pasid_table, &data);
-       if (ret)
-               goto attach_out;
-
        pasid_table = kzalloc(sizeof(*pasid_table), GFP_KERNEL);
        if (!pasid_table)
                return -ENOMEM;
-       INIT_LIST_HEAD(&pasid_table->dev);
 
        if (info->pasid_supported)
                max_pasid = min_t(u32, pci_max_pasids(to_pci_dev(dev)),
@@ -182,9 +124,7 @@ int intel_pasid_alloc_table(struct device *dev)
        pasid_table->table = page_address(pages);
        pasid_table->order = order;
        pasid_table->max_pasid = 1 << (order + PAGE_SHIFT + 3);
-
-attach_out:
-       device_attach_pasid_table(info, pasid_table);
+       info->pasid_table = pasid_table;
 
        return 0;
 }
@@ -202,10 +142,7 @@ void intel_pasid_free_table(struct device *dev)
                return;
 
        pasid_table = info->pasid_table;
-       device_detach_pasid_table(info, pasid_table);
-
-       if (!list_empty(&pasid_table->dev))
-               return;
+       info->pasid_table = NULL;
 
        /* Free scalable mode PASID directory tables: */
        dir = pasid_table->table;
index 583ea67..bf5b937 100644 (file)
@@ -74,7 +74,6 @@ struct pasid_table {
        void                    *table;         /* pasid table pointer */
        int                     order;          /* page order of pasid table */
        u32                     max_pasid;      /* max pasid */
-       struct list_head        dev;            /* device list */
 };
 
 /* Get PRESENT bit of a PASID directory entry. */
index 1f23a6b..bbb11cb 100644 (file)
@@ -298,7 +298,7 @@ config XTENSA_MX
 
 config XILINX_INTC
        bool "Xilinx Interrupt Controller IP"
-       depends on OF
+       depends on OF_ADDRESS
        select IRQ_DOMAIN
        help
          Support for the Xilinx Interrupt Controller IP core.
index 5ac8318..1c2813a 100644 (file)
 #define AIC_TMR_EL02_PHYS      AIC_TMR_GUEST_PHYS
 #define AIC_TMR_EL02_VIRT      AIC_TMR_GUEST_VIRT
 
-DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
+static DEFINE_STATIC_KEY_TRUE(use_fast_ipi);
 
 struct aic_info {
        int version;
index 5c1cf90..2d25bca 100644 (file)
@@ -2042,15 +2042,40 @@ static void __init gic_of_setup_kvm_info(struct device_node *node)
        vgic_set_kvm_info(&gic_v3_kvm_info);
 }
 
+static void gic_request_region(resource_size_t base, resource_size_t size,
+                              const char *name)
+{
+       if (!request_mem_region(base, size, name))
+               pr_warn_once(FW_BUG "%s region %pa has overlapping address\n",
+                            name, &base);
+}
+
+static void __iomem *gic_of_iomap(struct device_node *node, int idx,
+                                 const char *name, struct resource *res)
+{
+       void __iomem *base;
+       int ret;
+
+       ret = of_address_to_resource(node, idx, res);
+       if (ret)
+               return IOMEM_ERR_PTR(ret);
+
+       gic_request_region(res->start, resource_size(res), name);
+       base = of_iomap(node, idx);
+
+       return base ?: IOMEM_ERR_PTR(-ENOMEM);
+}
+
 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
 {
        void __iomem *dist_base;
        struct redist_region *rdist_regs;
+       struct resource res;
        u64 redist_stride;
        u32 nr_redist_regions;
        int err, i;
 
-       dist_base = of_io_request_and_map(node, 0, "GICD");
+       dist_base = gic_of_iomap(node, 0, "GICD", &res);
        if (IS_ERR(dist_base)) {
                pr_err("%pOF: unable to map gic dist registers\n", node);
                return PTR_ERR(dist_base);
@@ -2073,12 +2098,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
        }
 
        for (i = 0; i < nr_redist_regions; i++) {
-               struct resource res;
-               int ret;
-
-               ret = of_address_to_resource(node, 1 + i, &res);
-               rdist_regs[i].redist_base = of_io_request_and_map(node, 1 + i, "GICR");
-               if (ret || IS_ERR(rdist_regs[i].redist_base)) {
+               rdist_regs[i].redist_base = gic_of_iomap(node, 1 + i, "GICR", &res);
+               if (IS_ERR(rdist_regs[i].redist_base)) {
                        pr_err("%pOF: couldn't map region %d\n", node, i);
                        err = -ENODEV;
                        goto out_unmap_rdist;
@@ -2151,7 +2172,7 @@ gic_acpi_parse_madt_redist(union acpi_subtable_headers *header,
                pr_err("Couldn't map GICR region @%llx\n", redist->base_address);
                return -ENOMEM;
        }
-       request_mem_region(redist->base_address, redist->length, "GICR");
+       gic_request_region(redist->base_address, redist->length, "GICR");
 
        gic_acpi_register_redist(redist->base_address, redist_base);
        return 0;
@@ -2174,7 +2195,7 @@ gic_acpi_parse_madt_gicc(union acpi_subtable_headers *header,
        redist_base = ioremap(gicc->gicr_base_address, size);
        if (!redist_base)
                return -ENOMEM;
-       request_mem_region(gicc->gicr_base_address, size, "GICR");
+       gic_request_region(gicc->gicr_base_address, size, "GICR");
 
        gic_acpi_register_redist(gicc->gicr_base_address, redist_base);
        return 0;
@@ -2376,7 +2397,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
                pr_err("Unable to map GICD registers\n");
                return -ENOMEM;
        }
-       request_mem_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
+       gic_request_region(dist->base_address, ACPI_GICV3_DIST_MEM_SIZE, "GICD");
 
        err = gic_validate_dist_version(acpi_data.dist_base);
        if (err) {
index 49b47e7..f289ccd 100644 (file)
@@ -66,7 +66,6 @@ static struct or1k_pic_dev or1k_pic_level = {
                .name = "or1k-PIC-level",
                .irq_unmask = or1k_pic_unmask,
                .irq_mask = or1k_pic_mask,
-               .irq_mask_ack = or1k_pic_mask_ack,
        },
        .handle = handle_level_irq,
        .flags = IRQ_LEVEL | IRQ_NOPROBE,
index 1ef9b61..f150d87 100644 (file)
@@ -631,16 +631,20 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
        ucr->pusb_dev = usb_dev;
 
-       ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
-                       GFP_KERNEL, &ucr->iobuf_dma);
-       if (!ucr->iobuf)
+       ucr->cmd_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->cmd_buf)
                return -ENOMEM;
 
+       ucr->rsp_buf = kmalloc(IOBUF_SIZE, GFP_KERNEL);
+       if (!ucr->rsp_buf) {
+               ret = -ENOMEM;
+               goto out_free_cmd_buf;
+       }
+
        usb_set_intfdata(intf, ucr);
 
        ucr->vendor_id = id->idVendor;
        ucr->product_id = id->idProduct;
-       ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
 
        mutex_init(&ucr->dev_mutex);
 
@@ -668,8 +672,11 @@ static int rtsx_usb_probe(struct usb_interface *intf,
 
 out_init_fail:
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
+out_free_cmd_buf:
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
        return ret;
 }
 
@@ -682,8 +689,12 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
        mfd_remove_devices(&intf->dev);
 
        usb_set_intfdata(ucr->pusb_intf, NULL);
-       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
-                       ucr->iobuf_dma);
+
+       kfree(ucr->cmd_buf);
+       ucr->cmd_buf = NULL;
+
+       kfree(ucr->rsp_buf);
+       ucr->rsp_buf = NULL;
 }
 
 #ifdef CONFIG_PM
index c9c56fd..bdffc65 100644 (file)
@@ -80,10 +80,9 @@ static int at25_ee_read(void *priv, unsigned int offset,
        struct at25_data *at25 = priv;
        char *buf = val;
        size_t max_chunk = spi_max_transfer_size(at25->spi);
-       size_t num_msgs = DIV_ROUND_UP(count, max_chunk);
-       size_t nr_bytes = 0;
-       unsigned int msg_offset;
-       size_t msg_count;
+       unsigned int msg_offset = offset;
+       size_t bytes_left = count;
+       size_t segment;
        u8                      *cp;
        ssize_t                 status;
        struct spi_transfer     t[2];
@@ -97,9 +96,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
        if (unlikely(!count))
                return -EINVAL;
 
-       msg_offset = (unsigned int)offset;
-       msg_count = min(count, max_chunk);
-       while (num_msgs) {
+       do {
+               segment = min(bytes_left, max_chunk);
                cp = at25->command;
 
                instr = AT25_READ;
@@ -131,8 +129,8 @@ static int at25_ee_read(void *priv, unsigned int offset,
                t[0].len = at25->addrlen + 1;
                spi_message_add_tail(&t[0], &m);
 
-               t[1].rx_buf = buf + nr_bytes;
-               t[1].len = msg_count;
+               t[1].rx_buf = buf;
+               t[1].len = segment;
                spi_message_add_tail(&t[1], &m);
 
                status = spi_sync(at25->spi, &m);
@@ -142,10 +140,10 @@ static int at25_ee_read(void *priv, unsigned int offset,
                if (status)
                        return status;
 
-               --num_msgs;
-               msg_offset += msg_count;
-               nr_bytes += msg_count;
-       }
+               msg_offset += segment;
+               buf += segment;
+               bytes_left -= segment;
+       } while (bytes_left > 0);
 
        dev_dbg(&at25->spi->dev, "read %zu bytes at %d\n",
                count, offset);
@@ -229,7 +227,7 @@ static int at25_ee_write(void *priv, unsigned int off, void *val, size_t count)
        do {
                unsigned long   timeout, retries;
                unsigned        segment;
-               unsigned        offset = (unsigned) off;
+               unsigned        offset = off;
                u8              *cp = bounce;
                int             sr;
                u8              instr;
index b2a4f99..8c1eeb5 100644 (file)
@@ -94,6 +94,7 @@ config WIREGUARD
        select CRYPTO_CURVE25519_NEON if ARM && KERNEL_MODE_NEON
        select CRYPTO_CHACHA_MIPS if CPU_MIPS32_R2
        select CRYPTO_POLY1305_MIPS if MIPS
+       select CRYPTO_CHACHA_S390 if S390
        help
          WireGuard is a secure, fast, and easy to use replacement for IPSec
          that uses modern cryptography and clever networking tricks. It's
index 76df480..4c47c10 100644 (file)
@@ -1646,7 +1646,6 @@ static int grcan_probe(struct platform_device *ofdev)
         */
        sysid_parent = of_find_node_by_path("/ambapp0");
        if (sysid_parent) {
-               of_node_get(sysid_parent);
                err = of_property_read_u32(sysid_parent, "systemid", &sysid);
                if (!err && ((sysid & GRLIB_VERSION_MASK) >=
                             GRCAN_TXBUG_SAFE_GRLIB_VERSION))
index 5d0c82d..7931f9c 100644 (file)
@@ -529,7 +529,7 @@ static int m_can_read_fifo(struct net_device *dev, u32 rxfs)
        /* acknowledge rx fifo 0 */
        m_can_write(cdev, M_CAN_RXF0A, fgi);
 
-       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc);
+       timestamp = FIELD_GET(RX_BUF_RXTS_MASK, fifo_header.dlc) << 16;
 
        m_can_receive_skb(cdev, skb, timestamp);
 
@@ -1030,7 +1030,7 @@ static int m_can_echo_tx_event(struct net_device *dev)
                }
 
                msg_mark = FIELD_GET(TX_EVENT_MM_MASK, txe);
-               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe);
+               timestamp = FIELD_GET(TX_EVENT_TXTS_MASK, txe) << 16;
 
                /* ack txe element */
                m_can_write(cdev, M_CAN_TXEFA, FIELD_PREP(TXEFA_EFAI_MASK,
@@ -1351,7 +1351,9 @@ static void m_can_chip_config(struct net_device *dev)
        /* enable internal timestamp generation, with a prescalar of 16. The
         * prescalar is applied to the nominal bit timing
         */
-       m_can_write(cdev, M_CAN_TSCC, FIELD_PREP(TSCC_TCP_MASK, 0xf));
+       m_can_write(cdev, M_CAN_TSCC,
+                   FIELD_PREP(TSCC_TCP_MASK, 0xf) |
+                   FIELD_PREP(TSCC_TSS_MASK, TSCC_TSS_INTERNAL));
 
        m_can_config_endisable(cdev, false);
 
index 40a1144..ba42cef 100644 (file)
@@ -1332,7 +1332,10 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
                cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) |
                       RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
 
-               rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
+               if (is_v3u(gpriv))
+                       rcar_canfd_write(priv->base, RCANFD_V3U_DCFG(ch), cfg);
+               else
+                       rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
                netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
                           brp, sjw, tseg1, tseg2);
        } else {
index b212523..9b47b07 100644 (file)
@@ -12,6 +12,7 @@
 // Copyright (c) 2019 Martin Sperl <kernel@martin.sperl.org>
 //
 
+#include <asm/unaligned.h>
 #include <linux/bitfield.h>
 #include <linux/clk.h>
 #include <linux/device.h>
@@ -1650,6 +1651,7 @@ static int mcp251xfd_stop(struct net_device *ndev)
        netif_stop_queue(ndev);
        set_bit(MCP251XFD_FLAGS_DOWN, priv->flags);
        hrtimer_cancel(&priv->rx_irq_timer);
+       hrtimer_cancel(&priv->tx_irq_timer);
        mcp251xfd_chip_interrupts_disable(priv);
        free_irq(ndev->irq, priv);
        can_rx_offload_disable(&priv->offload);
@@ -1777,7 +1779,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        xfer[0].len = sizeof(buf_tx->cmd);
        xfer[0].speed_hz = priv->spi_max_speed_hz_slow;
        xfer[1].rx_buf = buf_rx->data;
-       xfer[1].len = sizeof(dev_id);
+       xfer[1].len = sizeof(*dev_id);
        xfer[1].speed_hz = priv->spi_max_speed_hz_fast;
 
        mcp251xfd_spi_cmd_read_nocrc(&buf_tx->cmd, MCP251XFD_REG_DEVID);
@@ -1786,7 +1788,7 @@ mcp251xfd_register_get_dev_id(const struct mcp251xfd_priv *priv, u32 *dev_id,
        if (err)
                goto out_kfree_buf_tx;
 
-       *dev_id = be32_to_cpup((__be32 *)buf_rx->data);
+       *dev_id = get_unaligned_le32(buf_rx->data);
        *effective_speed_hz_slow = xfer[0].effective_speed_hz;
        *effective_speed_hz_fast = xfer[1].effective_speed_hz;
 
index 217510c..92b7bc7 100644 (file)
@@ -334,19 +334,21 @@ mcp251xfd_regmap_crc_read(void *context,
                 * register. It increments once per SYS clock tick,
                 * which is 20 or 40 MHz.
                 *
-                * Observation shows that if the lowest byte (which is
-                * transferred first on the SPI bus) of that register
-                * is 0x00 or 0x80 the calculated CRC doesn't always
-                * match the transferred one.
+                * Observation on the mcp2518fd shows that if the
+                * lowest byte (which is transferred first on the SPI
+                * bus) of that register is 0x00 or 0x80 the
+                * calculated CRC doesn't always match the transferred
+                * one. On the mcp2517fd this problem is not limited
+                * to the first byte being 0x00 or 0x80.
                 *
                 * If the highest bit in the lowest byte is flipped
                 * the transferred CRC matches the calculated one. We
-                * assume for now the CRC calculation in the chip
-                * works on wrong data and the transferred data is
-                * correct.
+                * assume for now the CRC operates on the correct
+                * data.
                 */
                if (reg == MCP251XFD_REG_TBC &&
-                   (buf_rx->data[0] == 0x0 || buf_rx->data[0] == 0x80)) {
+                   ((buf_rx->data[0] & 0xf8) == 0x0 ||
+                    (buf_rx->data[0] & 0xf8) == 0x80)) {
                        /* Flip highest bit in lowest byte of le32 */
                        buf_rx->data[0] ^= 0x80;
 
@@ -356,10 +358,8 @@ mcp251xfd_regmap_crc_read(void *context,
                                                                  val_len);
                        if (!err) {
                                /* If CRC is now correct, assume
-                                * transferred data was OK, flip bit
-                                * back to original value.
+                                * flipped data is OK.
                                 */
-                               buf_rx->data[0] ^= 0x80;
                                goto out;
                        }
                }
index b29ba91..d3a658b 100644 (file)
@@ -268,6 +268,8 @@ struct gs_can {
 
        struct usb_anchor tx_submitted;
        atomic_t active_tx_urbs;
+       void *rxbuf[GS_MAX_RX_URBS];
+       dma_addr_t rxbuf_dma[GS_MAX_RX_URBS];
 };
 
 /* usb interface struct */
@@ -742,6 +744,7 @@ static int gs_can_open(struct net_device *netdev)
                for (i = 0; i < GS_MAX_RX_URBS; i++) {
                        struct urb *urb;
                        u8 *buf;
+                       dma_addr_t buf_dma;
 
                        /* alloc rx urb */
                        urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -752,7 +755,7 @@ static int gs_can_open(struct net_device *netdev)
                        buf = usb_alloc_coherent(dev->udev,
                                                 dev->parent->hf_size_rx,
                                                 GFP_KERNEL,
-                                                &urb->transfer_dma);
+                                                &buf_dma);
                        if (!buf) {
                                netdev_err(netdev,
                                           "No memory left for USB buffer\n");
@@ -760,6 +763,8 @@ static int gs_can_open(struct net_device *netdev)
                                return -ENOMEM;
                        }
 
+                       urb->transfer_dma = buf_dma;
+
                        /* fill, anchor, and submit rx urb */
                        usb_fill_bulk_urb(urb,
                                          dev->udev,
@@ -781,10 +786,17 @@ static int gs_can_open(struct net_device *netdev)
                                           "usb_submit failed (err=%d)\n", rc);
 
                                usb_unanchor_urb(urb);
+                               usb_free_coherent(dev->udev,
+                                                 sizeof(struct gs_host_frame),
+                                                 buf,
+                                                 buf_dma);
                                usb_free_urb(urb);
                                break;
                        }
 
+                       dev->rxbuf[i] = buf;
+                       dev->rxbuf_dma[i] = buf_dma;
+
                        /* Drop reference,
                         * USB core will take care of freeing it
                         */
@@ -842,13 +854,20 @@ static int gs_can_close(struct net_device *netdev)
        int rc;
        struct gs_can *dev = netdev_priv(netdev);
        struct gs_usb *parent = dev->parent;
+       unsigned int i;
 
        netif_stop_queue(netdev);
 
        /* Stop polling */
        parent->active_channels--;
-       if (!parent->active_channels)
+       if (!parent->active_channels) {
                usb_kill_anchored_urbs(&parent->rx_submitted);
+               for (i = 0; i < GS_MAX_RX_URBS; i++)
+                       usb_free_coherent(dev->udev,
+                                         sizeof(struct gs_host_frame),
+                                         dev->rxbuf[i],
+                                         dev->rxbuf_dma[i]);
+       }
 
        /* Stop sending URBs */
        usb_kill_anchored_urbs(&dev->tx_submitted);
index 3a49257..eefcbe3 100644 (file)
 #define KVASER_USB_RX_BUFFER_SIZE              3072
 #define KVASER_USB_MAX_NET_DEVICES             5
 
-/* USB devices features */
-#define KVASER_USB_HAS_SILENT_MODE             BIT(0)
-#define KVASER_USB_HAS_TXRX_ERRORS             BIT(1)
+/* Kvaser USB device quirks */
+#define KVASER_USB_QUIRK_HAS_SILENT_MODE       BIT(0)
+#define KVASER_USB_QUIRK_HAS_TXRX_ERRORS       BIT(1)
+#define KVASER_USB_QUIRK_IGNORE_CLK_FREQ       BIT(2)
 
 /* Device capabilities */
 #define KVASER_USB_CAP_BERR_CAP                        0x01
@@ -65,12 +66,7 @@ struct kvaser_usb_dev_card_data_hydra {
 struct kvaser_usb_dev_card_data {
        u32 ctrlmode_supported;
        u32 capabilities;
-       union {
-               struct {
-                       enum kvaser_usb_leaf_family family;
-               } leaf;
-               struct kvaser_usb_dev_card_data_hydra hydra;
-       };
+       struct kvaser_usb_dev_card_data_hydra hydra;
 };
 
 /* Context for an outstanding, not yet ACKed, transmission */
@@ -83,7 +79,7 @@ struct kvaser_usb {
        struct usb_device *udev;
        struct usb_interface *intf;
        struct kvaser_usb_net_priv *nets[KVASER_USB_MAX_NET_DEVICES];
-       const struct kvaser_usb_dev_ops *ops;
+       const struct kvaser_usb_driver_info *driver_info;
        const struct kvaser_usb_dev_cfg *cfg;
 
        struct usb_endpoint_descriptor *bulk_in, *bulk_out;
@@ -165,6 +161,12 @@ struct kvaser_usb_dev_ops {
                                  u16 transid);
 };
 
+struct kvaser_usb_driver_info {
+       u32 quirks;
+       enum kvaser_usb_leaf_family family;
+       const struct kvaser_usb_dev_ops *ops;
+};
+
 struct kvaser_usb_dev_cfg {
        const struct can_clock clock;
        const unsigned int timestamp_freq;
@@ -184,4 +186,7 @@ int kvaser_usb_send_cmd_async(struct kvaser_usb_net_priv *priv, void *cmd,
                              int len);
 
 int kvaser_usb_can_rx_over_error(struct net_device *netdev);
+
+extern const struct can_bittiming_const kvaser_usb_flexc_bittiming_const;
+
 #endif /* KVASER_USB_H */
index e67658b..f211bfc 100644 (file)
@@ -61,8 +61,6 @@
 #define USB_USBCAN_R_V2_PRODUCT_ID             294
 #define USB_LEAF_LIGHT_R_V2_PRODUCT_ID         295
 #define USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID   296
-#define USB_LEAF_PRODUCT_ID_END \
-       USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID
 
 /* Kvaser USBCan-II devices product ids */
 #define USB_USBCAN_REVB_PRODUCT_ID             2
 #define USB_USBCAN_PRO_4HS_PRODUCT_ID          276
 #define USB_HYBRID_CANLIN_PRODUCT_ID           277
 #define USB_HYBRID_PRO_CANLIN_PRODUCT_ID       278
-#define USB_HYDRA_PRODUCT_ID_END \
-       USB_HYBRID_PRO_CANLIN_PRODUCT_ID
 
-static inline bool kvaser_is_leaf(const struct usb_device_id *id)
-{
-       return (id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
-               id->idProduct <= USB_CAN_R_PRODUCT_ID) ||
-               (id->idProduct >= USB_LEAF_LITE_V2_PRODUCT_ID &&
-                id->idProduct <= USB_LEAF_PRODUCT_ID_END);
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_hydra = {
+       .quirks = 0,
+       .ops = &kvaser_usb_hydra_dev_ops,
+};
 
-static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
-              id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_usbcan = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE,
+       .family = KVASER_USBCAN,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
-static inline bool kvaser_is_hydra(const struct usb_device_id *id)
-{
-       return id->idProduct >= USB_BLACKBIRD_V2_PRODUCT_ID &&
-              id->idProduct <= USB_HYDRA_PRODUCT_ID_END;
-}
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf = {
+       .quirks = KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leaf_err_listen = {
+       .quirks = KVASER_USB_QUIRK_HAS_TXRX_ERRORS |
+                 KVASER_USB_QUIRK_HAS_SILENT_MODE |
+                 KVASER_USB_QUIRK_IGNORE_CLK_FREQ,
+       .family = KVASER_LEAF,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
+
+static const struct kvaser_usb_driver_info kvaser_usb_driver_info_leafimx = {
+       .quirks = 0,
+       .ops = &kvaser_usb_leaf_dev_ops,
+};
 
 static const struct usb_device_id kvaser_usb_table[] = {
-       /* Leaf USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
+       /* Leaf M32C USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS |
-                              KVASER_USB_HAS_SILENT_MODE },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err_listen },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID) },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leaf_err },
+
+       /* Leaf i.MX28 USB product IDs */
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_R_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LIGHT_HS_V2_OEM2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_leafimx },
 
        /* USBCANII USB product IDs */
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
        { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
-               .driver_info = KVASER_USB_HAS_TXRX_ERRORS },
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_usbcan },
 
        /* Minihydra USB product IDs */
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID) },
-       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID) },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_5HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_LIGHT_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_2HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_USBCAN_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_ATI_MEMO_PRO_2HS_V2_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_2CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100P_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_U100S_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_PRO_4HS_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
+       { USB_DEVICE(KVASER_VENDOR_ID, USB_HYBRID_PRO_CANLIN_PRODUCT_ID),
+               .driver_info = (kernel_ulong_t)&kvaser_usb_driver_info_hydra },
        { }
 };
 MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -285,6 +320,7 @@ int kvaser_usb_can_rx_over_error(struct net_device *netdev)
 static void kvaser_usb_read_bulk_callback(struct urb *urb)
 {
        struct kvaser_usb *dev = urb->context;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
        unsigned int i;
 
@@ -301,8 +337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb)
                goto resubmit_urb;
        }
 
-       dev->ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
-                                        urb->actual_length);
+       ops->dev_read_bulk_callback(dev, urb->transfer_buffer,
+                                   urb->actual_length);
 
 resubmit_urb:
        usb_fill_bulk_urb(urb, dev->udev,
@@ -396,6 +432,7 @@ static int kvaser_usb_open(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        err = open_candev(netdev);
@@ -406,11 +443,11 @@ static int kvaser_usb_open(struct net_device *netdev)
        if (err)
                goto error;
 
-       err = dev->ops->dev_set_opt_mode(priv);
+       err = ops->dev_set_opt_mode(priv);
        if (err)
                goto error;
 
-       err = dev->ops->dev_start_chip(priv);
+       err = ops->dev_start_chip(priv);
        if (err) {
                netdev_warn(netdev, "Cannot start device, error %d\n", err);
                goto error;
@@ -467,22 +504,23 @@ static int kvaser_usb_close(struct net_device *netdev)
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        int err;
 
        netif_stop_queue(netdev);
 
-       err = dev->ops->dev_flush_queue(priv);
+       err = ops->dev_flush_queue(priv);
        if (err)
                netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, priv->channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, priv->channel);
                if (err)
                        netdev_warn(netdev, "Cannot reset card, error %d\n",
                                    err);
        }
 
-       err = dev->ops->dev_stop_chip(priv);
+       err = ops->dev_stop_chip(priv);
        if (err)
                netdev_warn(netdev, "Cannot stop device, error %d\n", err);
 
@@ -521,6 +559,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
 {
        struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
        struct kvaser_usb *dev = priv->dev;
+       const struct kvaser_usb_dev_ops *ops = dev->driver_info->ops;
        struct net_device_stats *stats = &netdev->stats;
        struct kvaser_usb_tx_urb_context *context = NULL;
        struct urb *urb;
@@ -563,8 +602,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
                goto freeurb;
        }
 
-       buf = dev->ops->dev_frame_to_cmd(priv, skb, &cmd_len,
-                                        context->echo_index);
+       buf = ops->dev_frame_to_cmd(priv, skb, &cmd_len, context->echo_index);
        if (!buf) {
                stats->tx_dropped++;
                dev_kfree_skb(skb);
@@ -648,15 +686,16 @@ static void kvaser_usb_remove_interfaces(struct kvaser_usb *dev)
        }
 }
 
-static int kvaser_usb_init_one(struct kvaser_usb *dev,
-                              const struct usb_device_id *id, int channel)
+static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
 {
        struct net_device *netdev;
        struct kvaser_usb_net_priv *priv;
+       const struct kvaser_usb_driver_info *driver_info = dev->driver_info;
+       const struct kvaser_usb_dev_ops *ops = driver_info->ops;
        int err;
 
-       if (dev->ops->dev_reset_chip) {
-               err = dev->ops->dev_reset_chip(dev, channel);
+       if (ops->dev_reset_chip) {
+               err = ops->dev_reset_chip(dev, channel);
                if (err)
                        return err;
        }
@@ -685,20 +724,19 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev,
        priv->can.state = CAN_STATE_STOPPED;
        priv->can.clock.freq = dev->cfg->clock.freq;
        priv->can.bittiming_const = dev->cfg->bittiming_const;
-       priv->can.do_set_bittiming = dev->ops->dev_set_bittiming;
-       priv->can.do_set_mode = dev->ops->dev_set_mode;
-       if ((id->driver_info & KVASER_USB_HAS_TXRX_ERRORS) ||
+       priv->can.do_set_bittiming = ops->dev_set_bittiming;
+       priv->can.do_set_mode = ops->dev_set_mode;
+       if ((driver_info->quirks & KVASER_USB_QUIRK_HAS_TXRX_ERRORS) ||
            (priv->dev->card_data.capabilities & KVASER_USB_CAP_BERR_CAP))
-               priv->can.do_get_berr_counter = dev->ops->dev_get_berr_counter;
-       if (id->driver_info & KVASER_USB_HAS_SILENT_MODE)
+               priv->can.do_get_berr_counter = ops->dev_get_berr_counter;
+       if (driver_info->quirks & KVASER_USB_QUIRK_HAS_SILENT_MODE)
                priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
 
        priv->can.ctrlmode_supported |= dev->card_data.ctrlmode_supported;
 
        if (priv->can.ctrlmode_supported & CAN_CTRLMODE_FD) {
                priv->can.data_bittiming_const = dev->cfg->data_bittiming_const;
-               priv->can.do_set_data_bittiming =
-                                       dev->ops->dev_set_data_bittiming;
+               priv->can.do_set_data_bittiming = ops->dev_set_data_bittiming;
        }
 
        netdev->flags |= IFF_ECHO;
@@ -729,29 +767,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        struct kvaser_usb *dev;
        int err;
        int i;
+       const struct kvaser_usb_driver_info *driver_info;
+       const struct kvaser_usb_dev_ops *ops;
+
+       driver_info = (const struct kvaser_usb_driver_info *)id->driver_info;
+       if (!driver_info)
+               return -ENODEV;
 
        dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
 
-       if (kvaser_is_leaf(id)) {
-               dev->card_data.leaf.family = KVASER_LEAF;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_usbcan(id)) {
-               dev->card_data.leaf.family = KVASER_USBCAN;
-               dev->ops = &kvaser_usb_leaf_dev_ops;
-       } else if (kvaser_is_hydra(id)) {
-               dev->ops = &kvaser_usb_hydra_dev_ops;
-       } else {
-               dev_err(&intf->dev,
-                       "Product ID (%d) is not a supported Kvaser USB device\n",
-                       id->idProduct);
-               return -ENODEV;
-       }
-
        dev->intf = intf;
+       dev->driver_info = driver_info;
+       ops = driver_info->ops;
 
-       err = dev->ops->dev_setup_endpoints(dev);
+       err = ops->dev_setup_endpoints(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get usb endpoint(s)");
                return err;
@@ -765,22 +796,22 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev->card_data.ctrlmode_supported = 0;
        dev->card_data.capabilities = 0;
-       err = dev->ops->dev_init_card(dev);
+       err = ops->dev_init_card(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Failed to initialize card, error %d\n", err);
                return err;
        }
 
-       err = dev->ops->dev_get_software_info(dev);
+       err = ops->dev_get_software_info(dev);
        if (err) {
                dev_err(&intf->dev,
                        "Cannot get software info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_software_details) {
-               err = dev->ops->dev_get_software_details(dev);
+       if (ops->dev_get_software_details) {
+               err = ops->dev_get_software_details(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get software details, error %d\n", err);
@@ -798,14 +829,14 @@ static int kvaser_usb_probe(struct usb_interface *intf,
 
        dev_dbg(&intf->dev, "Max outstanding tx = %d URBs\n", dev->max_tx_urbs);
 
-       err = dev->ops->dev_get_card_info(dev);
+       err = ops->dev_get_card_info(dev);
        if (err) {
                dev_err(&intf->dev, "Cannot get card info, error %d\n", err);
                return err;
        }
 
-       if (dev->ops->dev_get_capabilities) {
-               err = dev->ops->dev_get_capabilities(dev);
+       if (ops->dev_get_capabilities) {
+               err = ops->dev_get_capabilities(dev);
                if (err) {
                        dev_err(&intf->dev,
                                "Cannot get capabilities, error %d\n", err);
@@ -815,7 +846,7 @@ static int kvaser_usb_probe(struct usb_interface *intf,
        }
 
        for (i = 0; i < dev->nchannels; i++) {
-               err = kvaser_usb_init_one(dev, id, i);
+               err = kvaser_usb_init_one(dev, i);
                if (err) {
                        kvaser_usb_remove_interfaces(dev);
                        return err;
index a26823c..5d70844 100644 (file)
@@ -375,7 +375,7 @@ static const struct can_bittiming_const kvaser_usb_hydra_kcan_bittiming_c = {
        .brp_inc = 1,
 };
 
-static const struct can_bittiming_const kvaser_usb_hydra_flexc_bittiming_c = {
+const struct can_bittiming_const kvaser_usb_flexc_bittiming_const = {
        .name = "kvaser_usb_flex",
        .tseg1_min = 4,
        .tseg1_max = 16,
@@ -2052,7 +2052,7 @@ static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_flexc = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_hydra_flexc_bittiming_c,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static const struct kvaser_usb_dev_cfg kvaser_usb_hydra_dev_cfg_rt = {
index c805b99..cc809ec 100644 (file)
 #define USBCAN_ERROR_STATE_RX_ERROR    BIT(1)
 #define USBCAN_ERROR_STATE_BUSERROR    BIT(2)
 
-/* bittiming parameters */
-#define KVASER_USB_TSEG1_MIN           1
-#define KVASER_USB_TSEG1_MAX           16
-#define KVASER_USB_TSEG2_MIN           1
-#define KVASER_USB_TSEG2_MAX           8
-#define KVASER_USB_SJW_MAX             4
-#define KVASER_USB_BRP_MIN             1
-#define KVASER_USB_BRP_MAX             64
-#define KVASER_USB_BRP_INC             1
-
 /* ctrl modes */
 #define KVASER_CTRL_MODE_NORMAL                1
 #define KVASER_CTRL_MODE_SILENT                2
@@ -343,48 +333,68 @@ struct kvaser_usb_err_summary {
        };
 };
 
-static const struct can_bittiming_const kvaser_usb_leaf_bittiming_const = {
-       .name = "kvaser_usb",
-       .tseg1_min = KVASER_USB_TSEG1_MIN,
-       .tseg1_max = KVASER_USB_TSEG1_MAX,
-       .tseg2_min = KVASER_USB_TSEG2_MIN,
-       .tseg2_max = KVASER_USB_TSEG2_MAX,
-       .sjw_max = KVASER_USB_SJW_MAX,
-       .brp_min = KVASER_USB_BRP_MIN,
-       .brp_max = KVASER_USB_BRP_MAX,
-       .brp_inc = KVASER_USB_BRP_INC,
+static const struct can_bittiming_const kvaser_usb_leaf_m16c_bittiming_const = {
+       .name = "kvaser_usb_ucii",
+       .tseg1_min = 4,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 1,
+       .brp_max = 16,
+       .brp_inc = 1,
+};
+
+static const struct can_bittiming_const kvaser_usb_leaf_m32c_bittiming_const = {
+       .name = "kvaser_usb_leaf",
+       .tseg1_min = 3,
+       .tseg1_max = 16,
+       .tseg2_min = 2,
+       .tseg2_max = 8,
+       .sjw_max = 4,
+       .brp_min = 2,
+       .brp_max = 128,
+       .brp_inc = 2,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_8mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_usbcan_dev_cfg = {
        .clock = {
                .freq = 8 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_leaf_m16c_bittiming_const,
+};
+
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_m32c_dev_cfg = {
+       .clock = {
+               .freq = 16 * MEGA /* Hz */,
+       },
+       .timestamp_freq = 1,
+       .bittiming_const = &kvaser_usb_leaf_m32c_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_16mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_16mhz = {
        .clock = {
                .freq = 16 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_24mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_24mhz = {
        .clock = {
                .freq = 24 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
-static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_dev_cfg_32mhz = {
+static const struct kvaser_usb_dev_cfg kvaser_usb_leaf_imx_dev_cfg_32mhz = {
        .clock = {
                .freq = 32 * MEGA /* Hz */,
        },
        .timestamp_freq = 1,
-       .bittiming_const = &kvaser_usb_leaf_bittiming_const,
+       .bittiming_const = &kvaser_usb_flexc_bittiming_const,
 };
 
 static void *
@@ -404,7 +414,7 @@ kvaser_usb_leaf_frame_to_cmd(const struct kvaser_usb_net_priv *priv,
                                      sizeof(struct kvaser_cmd_tx_can);
                cmd->u.tx_can.channel = priv->channel;
 
-               switch (dev->card_data.leaf.family) {
+               switch (dev->driver_info->family) {
                case KVASER_LEAF:
                        cmd_tx_can_flags = &cmd->u.tx_can.leaf.flags;
                        break;
@@ -524,16 +534,23 @@ static void kvaser_usb_leaf_get_software_info_leaf(struct kvaser_usb *dev,
        dev->fw_version = le32_to_cpu(softinfo->fw_version);
        dev->max_tx_urbs = le16_to_cpu(softinfo->max_outstanding_tx);
 
-       switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
-       case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_16mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_24mhz;
-               break;
-       case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_32mhz;
-               break;
+       if (dev->driver_info->quirks & KVASER_USB_QUIRK_IGNORE_CLK_FREQ) {
+               /* Firmware expects bittiming parameters calculated for 16MHz
+                * clock, regardless of the actual clock
+                */
+               dev->cfg = &kvaser_usb_leaf_m32c_dev_cfg;
+       } else {
+               switch (sw_options & KVASER_USB_LEAF_SWOPTION_FREQ_MASK) {
+               case KVASER_USB_LEAF_SWOPTION_FREQ_16_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_16mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_24_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_24mhz;
+                       break;
+               case KVASER_USB_LEAF_SWOPTION_FREQ_32_MHZ_CLK:
+                       dev->cfg = &kvaser_usb_leaf_imx_dev_cfg_32mhz;
+                       break;
+               }
        }
 }
 
@@ -550,7 +567,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
        if (err)
                return err;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                kvaser_usb_leaf_get_software_info_leaf(dev, &cmd.u.leaf.softinfo);
                break;
@@ -558,7 +575,7 @@ static int kvaser_usb_leaf_get_software_info_inner(struct kvaser_usb *dev)
                dev->fw_version = le32_to_cpu(cmd.u.usbcan.softinfo.fw_version);
                dev->max_tx_urbs =
                        le16_to_cpu(cmd.u.usbcan.softinfo.max_outstanding_tx);
-               dev->cfg = &kvaser_usb_leaf_dev_cfg_8mhz;
+               dev->cfg = &kvaser_usb_leaf_usbcan_dev_cfg;
                break;
        }
 
@@ -597,7 +614,7 @@ static int kvaser_usb_leaf_get_card_info(struct kvaser_usb *dev)
 
        dev->nchannels = cmd.u.cardinfo.nchannels;
        if (dev->nchannels > KVASER_USB_MAX_NET_DEVICES ||
-           (dev->card_data.leaf.family == KVASER_USBCAN &&
+           (dev->driver_info->family == KVASER_USBCAN &&
             dev->nchannels > MAX_USBCAN_NET_DEVICES))
                return -EINVAL;
 
@@ -730,7 +747,7 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
            new_state < CAN_STATE_BUS_OFF)
                priv->can.can_stats.restarts++;
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        priv->can.can_stats.bus_error++;
@@ -809,7 +826,7 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
                }
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                if (es->leaf.error_factor) {
                        cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
@@ -999,7 +1016,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
        stats = &priv->netdev->stats;
 
        if ((cmd->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
-           (dev->card_data.leaf.family == KVASER_LEAF &&
+           (dev->driver_info->family == KVASER_LEAF &&
             cmd->id == CMD_LEAF_LOG_MESSAGE)) {
                kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                return;
@@ -1015,7 +1032,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       switch (dev->card_data.leaf.family) {
+       switch (dev->driver_info->family) {
        case KVASER_LEAF:
                rx_data = cmd->u.leaf.rx_can.data;
                break;
@@ -1030,7 +1047,7 @@ static void kvaser_usb_leaf_rx_can_msg(const struct kvaser_usb *dev,
                return;
        }
 
-       if (dev->card_data.leaf.family == KVASER_LEAF && cmd->id ==
+       if (dev->driver_info->family == KVASER_LEAF && cmd->id ==
            CMD_LEAF_LOG_MESSAGE) {
                cf->can_id = le32_to_cpu(cmd->u.leaf.log_message.id);
                if (cf->can_id & KVASER_EXTENDED_FRAME)
@@ -1128,14 +1145,14 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
                break;
 
        case CMD_LEAF_LOG_MESSAGE:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                kvaser_usb_leaf_rx_can_msg(dev, cmd);
                break;
 
        case CMD_CHIP_STATE_EVENT:
        case CMD_CAN_ERROR_EVENT:
-               if (dev->card_data.leaf.family == KVASER_LEAF)
+               if (dev->driver_info->family == KVASER_LEAF)
                        kvaser_usb_leaf_leaf_rx_error(dev, cmd);
                else
                        kvaser_usb_leaf_usbcan_rx_error(dev, cmd);
@@ -1147,12 +1164,12 @@ static void kvaser_usb_leaf_handle_command(const struct kvaser_usb *dev,
 
        /* Ignored commands */
        case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
-               if (dev->card_data.leaf.family != KVASER_USBCAN)
+               if (dev->driver_info->family != KVASER_USBCAN)
                        goto warn;
                break;
 
        case CMD_FLUSH_QUEUE_REPLY:
-               if (dev->card_data.leaf.family != KVASER_LEAF)
+               if (dev->driver_info->family != KVASER_LEAF)
                        goto warn;
                break;
 
index 8a3b7b1..e179d31 100644 (file)
@@ -258,7 +258,7 @@ static const struct can_bittiming_const xcan_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 128,
        .sjw_max = 128,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
@@ -271,7 +271,7 @@ static const struct can_bittiming_const xcan_data_bittiming_const_canfd2 = {
        .tseg2_min = 1,
        .tseg2_max = 16,
        .sjw_max = 16,
-       .brp_min = 2,
+       .brp_min = 1,
        .brp_max = 256,
        .brp_inc = 1,
 };
index 8318339..8647125 100644 (file)
@@ -379,7 +379,7 @@ static void aq_pci_shutdown(struct pci_dev *pdev)
        }
 }
 
-static int aq_suspend_common(struct device *dev, bool deep)
+static int aq_suspend_common(struct device *dev)
 {
        struct aq_nic_s *nic = pci_get_drvdata(to_pci_dev(dev));
 
@@ -392,17 +392,15 @@ static int aq_suspend_common(struct device *dev, bool deep)
        if (netif_running(nic->ndev))
                aq_nic_stop(nic);
 
-       if (deep) {
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-               aq_nic_set_power(nic);
-       }
+       aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
+       aq_nic_set_power(nic);
 
        rtnl_unlock();
 
        return 0;
 }
 
-static int atl_resume_common(struct device *dev, bool deep)
+static int atl_resume_common(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct aq_nic_s *nic;
@@ -415,11 +413,6 @@ static int atl_resume_common(struct device *dev, bool deep)
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
 
-       if (deep) {
-               /* Reinitialize Nic/Vecs objects */
-               aq_nic_deinit(nic, !nic->aq_hw->aq_nic_cfg->wol);
-       }
-
        if (netif_running(nic->ndev)) {
                ret = aq_nic_init(nic);
                if (ret)
@@ -444,22 +437,22 @@ err_exit:
 
 static int aq_pm_freeze(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_suspend_poweroff(struct device *dev)
 {
-       return aq_suspend_common(dev, true);
+       return aq_suspend_common(dev);
 }
 
 static int aq_pm_thaw(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static int aq_pm_resume_restore(struct device *dev)
 {
-       return atl_resume_common(dev, true);
+       return atl_resume_common(dev);
 }
 
 static const struct dev_pm_ops aq_pm_ops = {
index 56b46b8..cf9b005 100644 (file)
@@ -7790,7 +7790,7 @@ hwrm_dbg_qcaps_exit:
 
 static int bnxt_hwrm_queue_qportcfg(struct bnxt *bp);
 
-static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
+int bnxt_hwrm_func_qcaps(struct bnxt *bp)
 {
        int rc;
 
@@ -10065,7 +10065,8 @@ static int bnxt_hwrm_if_change(struct bnxt *bp, bool up)
 
        if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_RESC_CHANGE)
                resc_reinit = true;
-       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE)
+       if (flags & FUNC_DRV_IF_CHANGE_RESP_FLAGS_HOT_FW_RESET_DONE ||
+           test_bit(BNXT_STATE_FW_RESET_DET, &bp->state))
                fw_reset = true;
        else
                bnxt_remap_fw_health_regs(bp);
index a1dca8c..075c620 100644 (file)
@@ -2314,6 +2314,7 @@ int bnxt_cancel_reservations(struct bnxt *bp, bool fw_reset);
 int bnxt_hwrm_alloc_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_free_wol_fltr(struct bnxt *bp);
 int bnxt_hwrm_func_resc_qcaps(struct bnxt *bp, bool all);
+int bnxt_hwrm_func_qcaps(struct bnxt *bp);
 int bnxt_hwrm_fw_set_time(struct bnxt *);
 int bnxt_open_nic(struct bnxt *, bool, bool);
 int bnxt_half_open_nic(struct bnxt *bp);
index 3528ce9..6b3d4f4 100644 (file)
@@ -979,9 +979,11 @@ static int bnxt_dl_info_get(struct devlink *dl, struct devlink_info_req *req,
        if (rc)
                return rc;
 
-       rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
-       if (rc)
-               return rc;
+       if (BNXT_CHIP_P5(bp)) {
+               rc = bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_SRT_PATCH);
+               if (rc)
+                       return rc;
+       }
        return bnxt_dl_livepatch_info_put(bp, req, BNXT_FW_CRT_PATCH);
 
 }
index 562f8f6..7f3c087 100644 (file)
@@ -76,14 +76,23 @@ static int bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts,
                            u64 *ns)
 {
        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
+       u32 high_before, high_now, low;
 
        if (test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
                return -EIO;
 
+       high_before = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
        ptp_read_system_prets(sts);
-       *ns = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+       low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
        ptp_read_system_postts(sts);
-       *ns |= (u64)readl(bp->bar0 + ptp->refclk_mapped_regs[1]) << 32;
+       high_now = readl(bp->bar0 + ptp->refclk_mapped_regs[1]);
+       if (high_now != high_before) {
+               ptp_read_system_prets(sts);
+               low = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
+               ptp_read_system_postts(sts);
+       }
+       *ns = ((u64)high_now << 32) | low;
+
        return 0;
 }
 
index ddf2f39..a1a2c7a 100644 (file)
@@ -823,8 +823,10 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
                goto err_out2;
 
        rc = pci_enable_sriov(bp->pdev, *num_vfs);
-       if (rc)
+       if (rc) {
+               bnxt_ulp_sriov_cfg(bp, 0);
                goto err_out2;
+       }
 
        return 0;
 
@@ -832,6 +834,9 @@ err_out2:
        /* Free the resources reserved for various VF's */
        bnxt_hwrm_func_vf_resource_free(bp, *num_vfs);
 
+       /* Restore the max resources */
+       bnxt_hwrm_func_qcaps(bp);
+
 err_out1:
        bnxt_free_vf_resources(bp);
 
index f02fe90..f53387e 100644 (file)
@@ -28,7 +28,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
                                   struct xdp_buff *xdp)
 {
        struct skb_shared_info *sinfo;
-       struct bnxt_sw_tx_bd *tx_buf, *first_buf;
+       struct bnxt_sw_tx_bd *tx_buf;
        struct tx_bd *txbd;
        int num_frags = 0;
        u32 flags;
@@ -43,13 +43,14 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        /* fill up the first buffer */
        prod = txr->tx_prod;
        tx_buf = &txr->tx_buf_ring[prod];
-       first_buf = tx_buf;
        tx_buf->nr_frags = num_frags;
        if (xdp)
                tx_buf->page = virt_to_head_page(xdp->data);
 
        txbd = &txr->tx_desc_ring[TX_RING(prod)][TX_IDX(prod)];
-       flags = ((len) << TX_BD_LEN_SHIFT) | ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT);
+       flags = (len << TX_BD_LEN_SHIFT) |
+               ((num_frags + 1) << TX_BD_FLAGS_BD_CNT_SHIFT) |
+               bnxt_lhint_arr[len >> 9];
        txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
        txbd->tx_bd_opaque = prod;
        txbd->tx_bd_haddr = cpu_to_le64(mapping);
@@ -82,7 +83,6 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
 
                flags = frag_len << TX_BD_LEN_SHIFT;
                txbd->tx_bd_len_flags_type = cpu_to_le32(flags);
-               txbd->tx_bd_opaque = prod;
                txbd->tx_bd_haddr = cpu_to_le64(frag_mapping);
 
                len = frag_len;
@@ -96,7 +96,7 @@ struct bnxt_sw_tx_bd *bnxt_xmit_bd(struct bnxt *bp,
        prod = NEXT_TX(prod);
        txr->tx_prod = prod;
 
-       return first_buf;
+       return tx_buf;
 }
 
 static void __bnxt_xmit_xdp(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
index 4af5561..7c760aa 100644 (file)
@@ -1392,7 +1392,7 @@ static void chtls_pass_accept_request(struct sock *sk,
        th_ecn = tcph->ece && tcph->cwr;
        if (th_ecn) {
                ect = !INET_ECN_is_not_ect(ip_dsfield);
-               ecn_ok = sock_net(sk)->ipv4.sysctl_tcp_ecn;
+               ecn_ok = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn);
                if ((!ect && ecn_ok) || tcp_ca_needs_ecn(sk))
                        inet_rsk(oreq)->ecn_ok = 1;
        }
index 5231818..c036637 100644 (file)
@@ -1764,6 +1764,19 @@ cleanup_clk:
        return rc;
 }
 
+static bool ftgmac100_has_child_node(struct device_node *np, const char *name)
+{
+       struct device_node *child_np = of_get_child_by_name(np, name);
+       bool ret = false;
+
+       if (child_np) {
+               ret = true;
+               of_node_put(child_np);
+       }
+
+       return ret;
+}
+
 static int ftgmac100_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -1883,7 +1896,7 @@ static int ftgmac100_probe(struct platform_device *pdev)
 
                /* Display what we found */
                phy_attached_info(phy);
-       } else if (np && !of_get_child_by_name(np, "mdio")) {
+       } else if (np && !ftgmac100_has_child_node(np, "mdio")) {
                /* Support legacy ASPEED devicetree descriptions that decribe a
                 * MAC with an embedded MDIO controller but have no "mdio"
                 * child node. Automatically scan the MDIO bus for available
index 7e7fe5b..5ab7c0f 100644 (file)
@@ -5981,6 +5981,15 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *adapter, bool reset)
                        release_sub_crqs(adapter, 0);
                        rc = init_sub_crqs(adapter);
                } else {
+                       /* no need to reinitialize completely, but we do
+                        * need to clean up transmits that were in flight
+                        * when we processed the reset.  Failure to do so
+                        * will confound the upper layer, usually TCP, by
+                        * creating the illusion of transmits that are
+                        * awaiting completion.
+                        */
+                       clean_tx_pools(adapter);
+
                        rc = reset_sub_crq_queues(adapter);
                }
        } else {
index 18558a0..407fe8f 100644 (file)
@@ -37,6 +37,7 @@
 #include <net/tc_act/tc_mirred.h>
 #include <net/udp_tunnel.h>
 #include <net/xdp_sock.h>
+#include <linux/bitfield.h>
 #include "i40e_type.h"
 #include "i40e_prototype.h"
 #include <linux/net/intel/i40e_client.h>
@@ -1092,6 +1093,21 @@ static inline void i40e_write_fd_input_set(struct i40e_pf *pf,
                          (u32)(val & 0xFFFFFFFFULL));
 }
 
+/**
+ * i40e_get_pf_count - get PCI PF count.
+ * @hw: pointer to a hw.
+ *
+ * Reports the function number of the highest PCI physical
+ * function plus 1 as it is loaded from the NVM.
+ *
+ * Return: PCI PF count.
+ **/
+static inline u32 i40e_get_pf_count(struct i40e_hw *hw)
+{
+       return FIELD_GET(I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK,
+                        rd32(hw, I40E_GLGEN_PCIFCNCNT));
+}
+
 /* needed by i40e_ethtool.c */
 int i40e_up(struct i40e_vsi *vsi);
 void i40e_down(struct i40e_vsi *vsi);
index 72576bb..aa786fd 100644 (file)
@@ -551,6 +551,47 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
 }
 
 /**
+ * i40e_compute_pci_to_hw_id - compute index form PCI function.
+ * @vsi: ptr to the VSI to read from.
+ * @hw: ptr to the hardware info.
+ **/
+static u32 i40e_compute_pci_to_hw_id(struct i40e_vsi *vsi, struct i40e_hw *hw)
+{
+       int pf_count = i40e_get_pf_count(hw);
+
+       if (vsi->type == I40E_VSI_SRIOV)
+               return (hw->port * BIT(7)) / pf_count + vsi->vf_id;
+
+       return hw->port + BIT(7);
+}
+
+/**
+ * i40e_stat_update64 - read and update a 64 bit stat from the chip.
+ * @hw: ptr to the hardware info.
+ * @hireg: the high 32 bit reg to read.
+ * @loreg: the low 32 bit reg to read.
+ * @offset_loaded: has the initial offset been loaded yet.
+ * @offset: ptr to current offset value.
+ * @stat: ptr to the stat.
+ *
+ * Since the device stats are not reset at PFReset, they will not
+ * be zeroed when the driver starts.  We'll save the first values read
+ * and use them as offsets to be subtracted from the raw values in order
+ * to report stats that count from zero.
+ **/
+static void i40e_stat_update64(struct i40e_hw *hw, u32 hireg, u32 loreg,
+                              bool offset_loaded, u64 *offset, u64 *stat)
+{
+       u64 new_data;
+
+       new_data = rd64(hw, loreg);
+
+       if (!offset_loaded || new_data < *offset)
+               *offset = new_data;
+       *stat = new_data - *offset;
+}
+
+/**
  * i40e_stat_update48 - read and update a 48 bit stat from the chip
  * @hw: ptr to the hardware info
  * @hireg: the high 32 bit reg to read
@@ -622,6 +663,34 @@ static void i40e_stat_update_and_clear32(struct i40e_hw *hw, u32 reg, u64 *stat)
 }
 
 /**
+ * i40e_stats_update_rx_discards - update rx_discards.
+ * @vsi: ptr to the VSI to be updated.
+ * @hw: ptr to the hardware info.
+ * @stat_idx: VSI's stat_counter_idx.
+ * @offset_loaded: ptr to the VSI's stat_offsets_loaded.
+ * @stat_offset: ptr to stat_offset to store first read of specific register.
+ * @stat: ptr to VSI's stat to be updated.
+ **/
+static void
+i40e_stats_update_rx_discards(struct i40e_vsi *vsi, struct i40e_hw *hw,
+                             int stat_idx, bool offset_loaded,
+                             struct i40e_eth_stats *stat_offset,
+                             struct i40e_eth_stats *stat)
+{
+       u64 rx_rdpc, rx_rxerr;
+
+       i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx), offset_loaded,
+                          &stat_offset->rx_discards, &rx_rdpc);
+       i40e_stat_update64(hw,
+                          I40E_GL_RXERR1H(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          I40E_GL_RXERR1L(i40e_compute_pci_to_hw_id(vsi, hw)),
+                          offset_loaded, &stat_offset->rx_discards_other,
+                          &rx_rxerr);
+
+       stat->rx_discards = rx_rdpc + rx_rxerr;
+}
+
+/**
  * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
  * @vsi: the VSI to be updated
  **/
@@ -680,6 +749,10 @@ void i40e_update_eth_stats(struct i40e_vsi *vsi)
                           I40E_GLV_BPTCL(stat_idx),
                           vsi->stat_offsets_loaded,
                           &oes->tx_broadcast, &es->tx_broadcast);
+
+       i40e_stats_update_rx_discards(vsi, hw, stat_idx,
+                                     vsi->stat_offsets_loaded, oes, es);
+
        vsi->stat_offsets_loaded = true;
 }
 
index 1908eed..7339003 100644 (file)
 #define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0
 #define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16
 #define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT                0x001C0AB4 /* Reset: PCIR */
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK  I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK  I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT)
 #define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */
 #define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0
 #define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT)
 #define I40E_VFQF_HKEY1_MAX_INDEX 12
 #define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */
 #define I40E_VFQF_HLUT1_MAX_INDEX 15
+#define I40E_GL_RXERR1H(_i)             (0x00318004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1H_MAX_INDEX       143
+#define I40E_GL_RXERR1H_RXERR1H_SHIFT   0
+#define I40E_GL_RXERR1H_RXERR1H_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1H_RXERR1H_SHIFT)
+#define I40E_GL_RXERR1L(_i)             (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */
+#define I40E_GL_RXERR1L_MAX_INDEX       143
+#define I40E_GL_RXERR1L_RXERR1L_SHIFT   0
+#define I40E_GL_RXERR1L_RXERR1L_MASK    I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1L_RXERR1L_SHIFT)
 #define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
 #define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */
index 36a4ca1..7b3f30b 100644 (file)
@@ -1172,6 +1172,7 @@ struct i40e_eth_stats {
        u64 tx_broadcast;               /* bptc */
        u64 tx_discards;                /* tdpc */
        u64 tx_errors;                  /* tepc */
+       u64 rx_discards_other;          /* rxerr1 */
 };
 
 /* Statistics collected per VEB per TC */
index 033ea71..86b0f21 100644 (file)
@@ -2147,6 +2147,10 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
                /* VFs only use TC 0 */
                vfres->vsi_res[0].qset_handle
                                          = le16_to_cpu(vsi->info.qs_handle[0]);
+               if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_USO) && !vf->pf_set_mac) {
+                       i40e_del_mac_filter(vsi, vf->default_lan_addr.addr);
+                       eth_zero_addr(vf->default_lan_addr.addr);
+               }
                ether_addr_copy(vfres->vsi_res[0].default_mac_addr,
                                vf->default_lan_addr.addr);
        }
index 61dd2f1..b41bc3d 100644 (file)
@@ -5,6 +5,7 @@
 #define _ICE_DEVIDS_H_
 
 /* Device IDs */
+#define ICE_DEV_ID_E822_SI_DFLT         0x1888
 /* Intel(R) Ethernet Connection E823-L for backplane */
 #define ICE_DEV_ID_E823L_BACKPLANE     0x124C
 /* Intel(R) Ethernet Connection E823-L for SFP */
index 3991d62..3337314 100644 (file)
@@ -814,6 +814,8 @@ void ice_devlink_destroy_vf_port(struct ice_vf *vf)
        devlink_port_unregister(devlink_port);
 }
 
+#define ICE_DEVLINK_READ_BLK_SIZE (1024 * 1024)
+
 /**
  * ice_devlink_nvm_snapshot - Capture a snapshot of the NVM flash contents
  * @devlink: the devlink instance
@@ -840,8 +842,9 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        struct ice_pf *pf = devlink_priv(devlink);
        struct device *dev = ice_pf_to_dev(pf);
        struct ice_hw *hw = &pf->hw;
-       void *nvm_data;
-       u32 nvm_size;
+       u8 *nvm_data, *tmp, i;
+       u32 nvm_size, left;
+       s8 num_blks;
        int status;
 
        nvm_size = hw->flash.flash_size;
@@ -849,26 +852,44 @@ static int ice_devlink_nvm_snapshot(struct devlink *devlink,
        if (!nvm_data)
                return -ENOMEM;
 
-       status = ice_acquire_nvm(hw, ICE_RES_READ);
-       if (status) {
-               dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
-                       status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
-               vfree(nvm_data);
-               return status;
-       }
 
-       status = ice_read_flat_nvm(hw, 0, &nvm_size, nvm_data, false);
-       if (status) {
-               dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
-                       nvm_size, status, hw->adminq.sq_last_status);
-               NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+       num_blks = DIV_ROUND_UP(nvm_size, ICE_DEVLINK_READ_BLK_SIZE);
+       tmp = nvm_data;
+       left = nvm_size;
+
+       /* Some systems take longer to read the NVM than others which causes the
+        * FW to reclaim the NVM lock before the entire NVM has been read. Fix
+        * this by breaking the reads of the NVM into smaller chunks that will
+        * probably not take as long. This has some overhead since we are
+        * increasing the number of AQ commands, but it should always work
+        */
+       for (i = 0; i < num_blks; i++) {
+               u32 read_sz = min_t(u32, ICE_DEVLINK_READ_BLK_SIZE, left);
+
+               status = ice_acquire_nvm(hw, ICE_RES_READ);
+               if (status) {
+                       dev_dbg(dev, "ice_acquire_nvm failed, err %d aq_err %d\n",
+                               status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to acquire NVM semaphore");
+                       vfree(nvm_data);
+                       return -EIO;
+               }
+
+               status = ice_read_flat_nvm(hw, i * ICE_DEVLINK_READ_BLK_SIZE,
+                                          &read_sz, tmp, false);
+               if (status) {
+                       dev_dbg(dev, "ice_read_flat_nvm failed after reading %u bytes, err %d aq_err %d\n",
+                               read_sz, status, hw->adminq.sq_last_status);
+                       NL_SET_ERR_MSG_MOD(extack, "Failed to read NVM contents");
+                       ice_release_nvm(hw);
+                       vfree(nvm_data);
+                       return -EIO;
+               }
                ice_release_nvm(hw);
-               vfree(nvm_data);
-               return status;
-       }
 
-       ice_release_nvm(hw);
+               tmp += read_sz;
+               left -= read_sz;
+       }
 
        *data = nvm_data;
 
index 665a344..3dc5662 100644 (file)
@@ -736,7 +736,87 @@ static int ice_finalize_update(struct pldmfw *context)
        return 0;
 }
 
-static const struct pldmfw_ops ice_fwu_ops = {
+struct ice_pldm_pci_record_id {
+       u32 vendor;
+       u32 device;
+       u32 subsystem_vendor;
+       u32 subsystem_device;
+};
+
+/**
+ * ice_op_pci_match_record - Check if a PCI device matches the record
+ * @context: PLDM fw update structure
+ * @record: list of records extracted from the PLDM image
+ *
+ * Determine if the PCI device associated with this device matches the record
+ * data provided.
+ *
+ * Searches the descriptor TLVs and extracts the relevant descriptor data into
+ * a pldm_pci_record_id. This is then compared against the PCI device ID
+ * information.
+ *
+ * Returns: true if the device matches the record, false otherwise.
+ */
+static bool
+ice_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
+{
+       struct pci_dev *pdev = to_pci_dev(context->dev);
+       struct ice_pldm_pci_record_id id = {
+               .vendor = PCI_ANY_ID,
+               .device = PCI_ANY_ID,
+               .subsystem_vendor = PCI_ANY_ID,
+               .subsystem_device = PCI_ANY_ID,
+       };
+       struct pldmfw_desc_tlv *desc;
+
+       list_for_each_entry(desc, &record->descs, entry) {
+               u16 value;
+               int *ptr;
+
+               switch (desc->type) {
+               case PLDM_DESC_ID_PCI_VENDOR_ID:
+                       ptr = &id.vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_DEVICE_ID:
+                       ptr = &id.device;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
+                       ptr = &id.subsystem_vendor;
+                       break;
+               case PLDM_DESC_ID_PCI_SUBDEV_ID:
+                       ptr = &id.subsystem_device;
+                       break;
+               default:
+                       /* Skip unrelated TLVs */
+                       continue;
+               }
+
+               value = get_unaligned_le16(desc->data);
+               /* A value of zero for one of the descriptors is sometimes
+                * used when the record should ignore this field when matching
+                * device. For example if the record applies to any subsystem
+                * device or vendor.
+                */
+               if (value)
+                       *ptr = value;
+               else
+                       *ptr = PCI_ANY_ID;
+       }
+
+       /* the E822 device can have a generic device ID so check for that */
+       if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) &&
+           (id.device == PCI_ANY_ID || id.device == pdev->device ||
+           id.device == ICE_DEV_ID_E822_SI_DFLT) &&
+           (id.subsystem_vendor == PCI_ANY_ID ||
+           id.subsystem_vendor == pdev->subsystem_vendor) &&
+           (id.subsystem_device == PCI_ANY_ID ||
+           id.subsystem_device == pdev->subsystem_device))
+               return true;
+
+       return false;
+}
+
+static const struct pldmfw_ops ice_fwu_ops_e810 = {
        .match_record = &pldmfw_op_pci_match_record,
        .send_package_data = &ice_send_package_data,
        .send_component_table = &ice_send_component_table,
@@ -744,6 +824,14 @@ static const struct pldmfw_ops ice_fwu_ops = {
        .finalize_update = &ice_finalize_update,
 };
 
+static const struct pldmfw_ops ice_fwu_ops_e822 = {
+       .match_record = &ice_op_pci_match_record,
+       .send_package_data = &ice_send_package_data,
+       .send_component_table = &ice_send_component_table,
+       .flash_component = &ice_flash_component,
+       .finalize_update = &ice_finalize_update,
+};
+
 /**
  * ice_get_pending_updates - Check if the component has a pending update
  * @pf: the PF driver structure
@@ -921,7 +1009,11 @@ int ice_devlink_flash_update(struct devlink *devlink,
 
        memset(&priv, 0, sizeof(priv));
 
-       priv.context.ops = &ice_fwu_ops;
+       /* the E822 device needs a slightly different ops */
+       if (hw->mac_type == ICE_MAC_GENERIC)
+               priv.context.ops = &ice_fwu_ops_e822;
+       else
+               priv.context.ops = &ice_fwu_ops_e810;
        priv.context.dev = dev;
        priv.extack = extack;
        priv.pf = pf;
index c1ac2f7..ff2eac2 100644 (file)
@@ -5413,6 +5413,7 @@ static const struct pci_device_id ice_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_10G_BASE_T), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_1GBE), 0 },
        { PCI_VDEVICE(INTEL, ICE_DEV_ID_E823L_QSFP), 0 },
+       { PCI_VDEVICE(INTEL, ICE_DEV_ID_E822_SI_DFLT), 0 },
        /* required last entry */
        { 0, }
 };
index 3754d8a..3c8116f 100644 (file)
@@ -588,6 +588,7 @@ err_router_lib_init:
 
 void prestera_router_fini(struct prestera_switch *sw)
 {
+       unregister_fib_notifier(&init_net, &sw->router->fib_nb);
        unregister_inetaddr_notifier(&sw->router->inetaddr_nb);
        unregister_inetaddr_validator_notifier(&sw->router->inetaddr_valid_nb);
        rhashtable_destroy(&sw->router->kern_fib_cache_ht);
index 25f51f8..ba171c7 100644 (file)
@@ -76,6 +76,7 @@ struct mlx5_tc_ct_priv {
        struct mlx5_ct_fs *fs;
        struct mlx5_ct_fs_ops *fs_ops;
        spinlock_t ht_lock; /* protects ft entries */
+       struct workqueue_struct *wq;
 
        struct mlx5_tc_ct_debugfs debugfs;
 };
@@ -941,14 +942,11 @@ static void mlx5_tc_ct_entry_del_work(struct work_struct *work)
 static void
 __mlx5_tc_ct_entry_put(struct mlx5_ct_entry *entry)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&entry->refcnt))
                return;
 
-       priv = netdev_priv(entry->ct_priv->netdev);
        INIT_WORK(&entry->work, mlx5_tc_ct_entry_del_work);
-       queue_work(priv->wq, &entry->work);
+       queue_work(entry->ct_priv->wq, &entry->work);
 }
 
 static struct mlx5_ct_counter *
@@ -1759,19 +1757,16 @@ mlx5_tc_ct_flush_ft_entry(void *ptr, void *arg)
 static void
 mlx5_tc_ct_del_ft_cb(struct mlx5_tc_ct_priv *ct_priv, struct mlx5_ct_ft *ft)
 {
-       struct mlx5e_priv *priv;
-
        if (!refcount_dec_and_test(&ft->refcount))
                return;
 
+       flush_workqueue(ct_priv->wq);
        nf_flow_table_offload_del_cb(ft->nf_ft,
                                     mlx5_tc_ct_block_flow_offload, ft);
        rhashtable_remove_fast(&ct_priv->zone_ht, &ft->node, zone_params);
        rhashtable_free_and_destroy(&ft->ct_entries_ht,
                                    mlx5_tc_ct_flush_ft_entry,
                                    ct_priv);
-       priv = netdev_priv(ct_priv->netdev);
-       flush_workqueue(priv->wq);
        mlx5_tc_ct_free_pre_ct_tables(ft);
        mapping_remove(ct_priv->zone_mapping, ft->zone_restore_id);
        kfree(ft);
@@ -2176,6 +2171,12 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        if (rhashtable_init(&ct_priv->ct_tuples_nat_ht, &tuples_nat_ht_params))
                goto err_ct_tuples_nat_ht;
 
+       ct_priv->wq = alloc_ordered_workqueue("mlx5e_ct_priv_wq", 0);
+       if (!ct_priv->wq) {
+               err = -ENOMEM;
+               goto err_wq;
+       }
+
        err = mlx5_tc_ct_fs_init(ct_priv);
        if (err)
                goto err_init_fs;
@@ -2184,6 +2185,8 @@ mlx5_tc_ct_init(struct mlx5e_priv *priv, struct mlx5_fs_chains *chains,
        return ct_priv;
 
 err_init_fs:
+       destroy_workqueue(ct_priv->wq);
+err_wq:
        rhashtable_destroy(&ct_priv->ct_tuples_nat_ht);
 err_ct_tuples_nat_ht:
        rhashtable_destroy(&ct_priv->ct_tuples_ht);
@@ -2213,6 +2216,7 @@ mlx5_tc_ct_clean(struct mlx5_tc_ct_priv *ct_priv)
        if (!ct_priv)
                return;
 
+       destroy_workqueue(ct_priv->wq);
        mlx5_ct_tc_remove_dbgfs(ct_priv);
        chains = ct_priv->chains;
 
index 0bb0633..27483aa 100644 (file)
@@ -231,8 +231,7 @@ mlx5e_set_ktls_rx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_rx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_RX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_rx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_RX);
+       BUILD_BUG_ON(sizeof(priv_rx) > TLS_DRIVER_STATE_SIZE_RX);
 
        *ctx = priv_rx;
 }
index 4b6f0d1..f239fb2 100644 (file)
@@ -68,8 +68,7 @@ mlx5e_set_ktls_tx_priv_ctx(struct tls_context *tls_ctx,
        struct mlx5e_ktls_offload_context_tx **ctx =
                __tls_driver_ctx(tls_ctx, TLS_OFFLOAD_CTX_DIR_TX);
 
-       BUILD_BUG_ON(sizeof(struct mlx5e_ktls_offload_context_tx *) >
-                    TLS_OFFLOAD_CONTEXT_SIZE_TX);
+       BUILD_BUG_ON(sizeof(priv_tx) > TLS_DRIVER_STATE_SIZE_TX);
 
        *ctx = priv_tx;
 }
index 57fa048..1e87bb2 100644 (file)
@@ -688,7 +688,7 @@ static MLX5E_DECLARE_STATS_GRP_OP_UPDATE_STATS(vnic_env)
        u32 in[MLX5_ST_SZ_DW(query_vnic_env_in)] = {};
        struct mlx5_core_dev *mdev = priv->mdev;
 
-       if (!MLX5_CAP_GEN(priv->mdev, nic_receive_steering_discard))
+       if (!mlx5e_stats_grp_vnic_env_num_stats(priv))
                return;
 
        MLX5_SET(query_vnic_env_in, in, opcode, MLX5_CMD_OP_QUERY_VNIC_ENV);
index 34bf11c..9ca2c87 100644 (file)
@@ -3793,7 +3793,7 @@ static bool is_lag_dev(struct mlx5e_priv *priv,
 
 static bool is_multiport_eligible(struct mlx5e_priv *priv, struct net_device *out_dev)
 {
-       if (mlx5e_eswitch_uplink_rep(out_dev) &&
+       if (same_hw_reps(priv, out_dev) &&
            MLX5_CAP_PORT_SELECTION(priv->mdev, port_select_flow_table) &&
            MLX5_CAP_GEN(priv->mdev, create_lag_when_not_master_up))
                return true;
@@ -4529,13 +4529,6 @@ static int mlx5e_policer_validate(const struct flow_action *action,
                return -EOPNOTSUPP;
        }
 
-       if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
-           act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
-               NL_SET_ERR_MSG_MOD(extack,
-                                  "Offload not supported when conform action is not pipe or ok");
-               return -EOPNOTSUPP;
-       }
-
        if (act->police.notexceed.act_id == FLOW_ACTION_ACCEPT &&
            !flow_action_is_last_entry(action, act)) {
                NL_SET_ERR_MSG_MOD(extack,
@@ -4586,6 +4579,12 @@ static int scan_tc_matchall_fdb_actions(struct mlx5e_priv *priv,
        flow_action_for_each(i, act, flow_action) {
                switch (act->id) {
                case FLOW_ACTION_POLICE:
+                       if (act->police.notexceed.act_id != FLOW_ACTION_CONTINUE) {
+                               NL_SET_ERR_MSG_MOD(extack,
+                                                  "Offload not supported when conform action is not continue");
+                               return -EOPNOTSUPP;
+                       }
+
                        err = mlx5e_policer_validate(flow_action, act, extack);
                        if (err)
                                return err;
index 50d14ce..9a7250b 100644 (file)
@@ -341,6 +341,26 @@ static void mlx5e_tx_check_stop(struct mlx5e_txqsq *sq)
        }
 }
 
+static void mlx5e_tx_flush(struct mlx5e_txqsq *sq)
+{
+       struct mlx5e_tx_wqe_info *wi;
+       struct mlx5e_tx_wqe *wqe;
+       u16 pi;
+
+       /* Must not be called when a MPWQE session is active but empty. */
+       mlx5e_tx_mpwqe_ensure_complete(sq);
+
+       pi = mlx5_wq_cyc_ctr2ix(&sq->wq, sq->pc);
+       wi = &sq->db.wqe_info[pi];
+
+       *wi = (struct mlx5e_tx_wqe_info) {
+               .num_wqebbs = 1,
+       };
+
+       wqe = mlx5e_post_nop(&sq->wq, sq->sqn, &sq->pc);
+       mlx5e_notify_hw(&sq->wq, sq->pc, sq->uar_map, &wqe->ctrl);
+}
+
 static inline void
 mlx5e_txwqe_complete(struct mlx5e_txqsq *sq, struct sk_buff *skb,
                     const struct mlx5e_tx_attr *attr,
@@ -459,6 +479,7 @@ mlx5e_sq_xmit_wqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 static bool mlx5e_tx_skb_supports_mpwqe(struct sk_buff *skb, struct mlx5e_tx_attr *attr)
@@ -560,6 +581,13 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
        struct mlx5_wqe_ctrl_seg *cseg;
        struct mlx5e_xmit_data txd;
 
+       txd.data = skb->data;
+       txd.len = skb->len;
+
+       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
+               goto err_unmap;
+
        if (!mlx5e_tx_mpwqe_session_is_active(sq)) {
                mlx5e_tx_mpwqe_session_start(sq, eseg);
        } else if (!mlx5e_tx_mpwqe_same_eseg(sq, eseg)) {
@@ -569,18 +597,9 @@ mlx5e_sq_xmit_mpwqe(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 
        sq->stats->xmit_more += xmit_more;
 
-       txd.data = skb->data;
-       txd.len = skb->len;
-
-       txd.dma_addr = dma_map_single(sq->pdev, txd.data, txd.len, DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(sq->pdev, txd.dma_addr)))
-               goto err_unmap;
        mlx5e_dma_push(sq, txd.dma_addr, txd.len, MLX5E_DMA_MAP_SINGLE);
-
        mlx5e_skb_fifo_push(&sq->db.skb_fifo, skb);
-
        mlx5e_tx_mpwqe_add_dseg(sq, &txd);
-
        mlx5e_tx_skb_update_hwts_flags(skb);
 
        if (unlikely(mlx5e_tx_mpwqe_is_full(&sq->mpwqe, sq->max_sq_mpw_wqebbs))) {
@@ -602,6 +621,7 @@ err_unmap:
        mlx5e_dma_unmap_wqe_err(sq, 1);
        sq->stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 
 void mlx5e_tx_mpwqe_ensure_complete(struct mlx5e_txqsq *sq)
@@ -1006,5 +1026,6 @@ void mlx5i_sq_xmit(struct mlx5e_txqsq *sq, struct sk_buff *skb,
 err_drop:
        stats->dropped++;
        dev_kfree_skb_any(skb);
+       mlx5e_tx_flush(sq);
 }
 #endif
index 9d17206..fabe49a 100644 (file)
@@ -11,6 +11,7 @@
 #include "mlx5_core.h"
 #include "eswitch.h"
 #include "fs_core.h"
+#include "fs_ft_pool.h"
 #include "esw/qos.h"
 
 enum {
@@ -95,8 +96,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
        if (!flow_group_in)
                return -ENOMEM;
 
-       table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
-       ft_attr.max_fte = table_size;
+       ft_attr.max_fte = POOL_NEXT_SIZE;
        ft_attr.prio = LEGACY_FDB_PRIO;
        fdb = mlx5_create_flow_table(root_ns, &ft_attr);
        if (IS_ERR(fdb)) {
@@ -105,6 +105,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
                goto out;
        }
        esw->fdb_table.legacy.fdb = fdb;
+       table_size = fdb->max_fte;
 
        /* Addresses group : Full match unicast/multicast addresses */
        MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
index 15e41dc..b8feaf0 100644 (file)
@@ -44,7 +44,7 @@ static int port_sel_mode_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        if (__mlx5_lag_is_active(ldev))
-               mode = mlx5_get_str_port_sel_mode(ldev);
+               mode = mlx5_get_str_port_sel_mode(ldev->mode, ldev->mode_flags);
        else
                ret = -EINVAL;
        mutex_unlock(&ldev->lock);
@@ -72,6 +72,7 @@ static int state_show(struct seq_file *file, void *priv)
 static int flags_show(struct seq_file *file, void *priv)
 {
        struct mlx5_core_dev *dev = file->private;
+       bool fdb_sel_mode_native;
        struct mlx5_lag *ldev;
        bool shared_fdb;
        bool lag_active;
@@ -79,14 +80,21 @@ static int flags_show(struct seq_file *file, void *priv)
        ldev = dev->priv.lag;
        mutex_lock(&ldev->lock);
        lag_active = __mlx5_lag_is_active(ldev);
-       if (lag_active)
-               shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       if (!lag_active)
+               goto unlock;
+
+       shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &ldev->mode_flags);
+       fdb_sel_mode_native = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                      &ldev->mode_flags);
 
+unlock:
        mutex_unlock(&ldev->lock);
        if (!lag_active)
                return -EINVAL;
 
        seq_printf(file, "%s:%s\n", "shared_fdb", shared_fdb ? "on" : "off");
+       seq_printf(file, "%s:%s\n", "fdb_selection_mode",
+                  fdb_sel_mode_native ? "native" : "affinity");
        return 0;
 }
 
index 2a8fc54..5d41e19 100644 (file)
@@ -68,14 +68,15 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, u8 *ports, int mode,
                               unsigned long flags)
 {
-       bool shared_fdb = test_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, &flags);
+       bool fdb_sel_mode = test_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
+                                    &flags);
        int port_sel_mode = get_port_sel_mode(mode, flags);
        u32 in[MLX5_ST_SZ_DW(create_lag_in)] = {};
        void *lag_ctx;
 
        lag_ctx = MLX5_ADDR_OF(create_lag_in, in, ctx);
        MLX5_SET(create_lag_in, in, opcode, MLX5_CMD_OP_CREATE_LAG);
-       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, shared_fdb);
+       MLX5_SET(lagc, lag_ctx, fdb_selection_mode, fdb_sel_mode);
        if (port_sel_mode == MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY) {
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[0]);
                MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[1]);
@@ -471,8 +472,13 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        bool roce_lag = mode == MLX5_LAG_MODE_ROCE;
 
        *flags = 0;
-       if (shared_fdb)
+       if (shared_fdb) {
                set_bit(MLX5_LAG_MODE_FLAG_SHARED_FDB, flags);
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
+       }
+
+       if (mode == MLX5_LAG_MODE_MPESW)
+               set_bit(MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE, flags);
 
        if (roce_lag)
                return mlx5_lag_set_port_sel_mode_roce(ldev, flags);
@@ -481,9 +487,9 @@ static int mlx5_lag_set_flags(struct mlx5_lag *ldev, enum mlx5_lag_mode mode,
        return 0;
 }
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev)
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags)
 {
-       int port_sel_mode = get_port_sel_mode(ldev->mode, ldev->mode_flags);
+       int port_sel_mode = get_port_sel_mode(mode, flags);
 
        switch (port_sel_mode) {
        case MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY: return "queue_affinity";
@@ -507,7 +513,7 @@ static int mlx5_create_lag(struct mlx5_lag *ldev,
        if (tracker)
                mlx5_lag_print_mapping(dev0, ldev, tracker, flags);
        mlx5_core_info(dev0, "shared_fdb:%d mode:%s\n",
-                      shared_fdb, mlx5_get_str_port_sel_mode(ldev));
+                      shared_fdb, mlx5_get_str_port_sel_mode(mode, flags));
 
        err = mlx5_cmd_create_lag(dev0, ldev->v2p_map, mode, flags);
        if (err) {
index c81b173..ce2ce8c 100644 (file)
@@ -24,6 +24,7 @@ enum {
 enum {
        MLX5_LAG_MODE_FLAG_HASH_BASED,
        MLX5_LAG_MODE_FLAG_SHARED_FDB,
+       MLX5_LAG_MODE_FLAG_FDB_SEL_MODE_NATIVE,
 };
 
 enum mlx5_lag_mode {
@@ -114,7 +115,7 @@ bool mlx5_shared_fdb_supported(struct mlx5_lag *ldev);
 void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev);
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev);
 
-char *mlx5_get_str_port_sel_mode(struct mlx5_lag *ldev);
+char *mlx5_get_str_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags);
 void mlx5_infer_tx_enabled(struct lag_tracker *tracker, u8 num_ports,
                           u8 *ports, int *num_enabled);
 
index ee4b25a..f643202 100644 (file)
@@ -41,7 +41,6 @@ void mlx5_lag_del_mpesw_rule(struct mlx5_core_dev *dev)
 int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
 {
        struct mlx5_lag *ldev = dev->priv.lag;
-       bool shared_fdb;
        int err = 0;
 
        if (!ldev)
@@ -55,8 +54,8 @@ int mlx5_lag_add_mpesw_rule(struct mlx5_core_dev *dev)
                err = -EINVAL;
                goto out;
        }
-       shared_fdb = mlx5_shared_fdb_supported(ldev);
-       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, shared_fdb);
+
+       err = mlx5_activate_lag(ldev, NULL, MLX5_LAG_MODE_MPESW, false);
        if (err)
                mlx5_core_warn(dev, "Failed to create LAG in MPESW mode (%d)\n", err);
 
index 5784c41..1d6e3b6 100644 (file)
@@ -994,7 +994,7 @@ static int lan966x_probe(struct platform_device *pdev)
        struct fwnode_handle *ports, *portnp;
        struct lan966x *lan966x;
        u8 mac_addr[ETH_ALEN];
-       int err, i;
+       int err;
 
        lan966x = devm_kzalloc(&pdev->dev, sizeof(*lan966x), GFP_KERNEL);
        if (!lan966x)
@@ -1025,11 +1025,7 @@ static int lan966x_probe(struct platform_device *pdev)
        if (err)
                return dev_err_probe(&pdev->dev, err, "Reset failed");
 
-       i = 0;
-       fwnode_for_each_available_child_node(ports, portnp)
-               ++i;
-
-       lan966x->num_phys_ports = i;
+       lan966x->num_phys_ports = NUM_PHYS_PORTS;
        lan966x->ports = devm_kcalloc(&pdev->dev, lan966x->num_phys_ports,
                                      sizeof(struct lan966x_port *),
                                      GFP_KERNEL);
index 3b86ddd..2787055 100644 (file)
@@ -34,6 +34,7 @@
 /* Reserved amount for (SRC, PRIO) at index 8*SRC + PRIO */
 #define QSYS_Q_RSRV                    95
 
+#define NUM_PHYS_PORTS                 8
 #define CPU_PORT                       8
 
 /* Reserved PGIDs */
index 083fddd..8e3894c 100644 (file)
@@ -94,19 +94,18 @@ static void ocelot_fdma_activate_chan(struct ocelot *ocelot, dma_addr_t dma,
        ocelot_fdma_writel(ocelot, MSCC_FDMA_CH_ACTIVATE, BIT(chan));
 }
 
+static u32 ocelot_fdma_read_ch_safe(struct ocelot *ocelot)
+{
+       return ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
+}
+
 static int ocelot_fdma_wait_chan_safe(struct ocelot *ocelot, int chan)
 {
-       unsigned long timeout;
        u32 safe;
 
-       timeout = jiffies + usecs_to_jiffies(OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
-       do {
-               safe = ocelot_fdma_readl(ocelot, MSCC_FDMA_CH_SAFE);
-               if (safe & BIT(chan))
-                       return 0;
-       } while (time_after(jiffies, timeout));
-
-       return -ETIMEDOUT;
+       return readx_poll_timeout_atomic(ocelot_fdma_read_ch_safe, ocelot, safe,
+                                        safe & BIT(chan), 0,
+                                        OCELOT_FDMA_CH_SAFE_TIMEOUT_US);
 }
 
 static void ocelot_fdma_dcb_set_data(struct ocelot_fdma_dcb *dcb,
index 6bf3ec4..97dcf8d 100644 (file)
@@ -447,7 +447,8 @@ void nfp_tun_unlink_and_update_nn_entries(struct nfp_app *app,
 
 static void
 nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
-                   void *flow, struct neighbour *neigh, bool is_ipv6)
+                   void *flow, struct neighbour *neigh, bool is_ipv6,
+                   bool override)
 {
        bool neigh_invalid = !(neigh->nud_state & NUD_VALID) || neigh->dead;
        size_t neigh_size = is_ipv6 ? sizeof(struct nfp_tun_neigh_v6) :
@@ -546,6 +547,13 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
                if (nn_entry->flow)
                        list_del(&nn_entry->list_head);
                kfree(nn_entry);
+       } else if (nn_entry && !neigh_invalid && override) {
+               mtype = is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
+                               NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
+               nfp_tun_link_predt_entries(app, nn_entry);
+               nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
+                                        nn_entry->payload,
+                                        GFP_ATOMIC);
        }
 
        spin_unlock_bh(&priv->predt_lock);
@@ -610,7 +618,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        dst_release(dst);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow6, n, true);
+               nfp_tun_write_neigh(n->dev, app, &flow6, n, true, false);
 #else
                return NOTIFY_DONE;
 #endif /* CONFIG_IPV6 */
@@ -633,7 +641,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
 
                        ip_rt_put(rt);
                }
-               nfp_tun_write_neigh(n->dev, app, &flow4, n, false);
+               nfp_tun_write_neigh(n->dev, app, &flow4, n, false, false);
        }
 #else
        return NOTIFY_DONE;
@@ -676,7 +684,7 @@ void nfp_tunnel_request_route_v4(struct nfp_app *app, struct sk_buff *skb)
        ip_rt_put(rt);
        if (!n)
                goto fail_rcu_unlock;
-       nfp_tun_write_neigh(n->dev, app, &flow, n, false);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, false, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
@@ -718,7 +726,7 @@ void nfp_tunnel_request_route_v6(struct nfp_app *app, struct sk_buff *skb)
        if (!n)
                goto fail_rcu_unlock;
 
-       nfp_tun_write_neigh(n->dev, app, &flow, n, true);
+       nfp_tun_write_neigh(n->dev, app, &flow, n, true, true);
        neigh_release(n);
        rcu_read_unlock();
        return;
index e509d6d..805071d 100644 (file)
@@ -125,17 +125,18 @@ nfp_nfdk_tx_csum(struct nfp_net_dp *dp, struct nfp_net_r_vector *r_vec,
 
 static int
 nfp_nfdk_tx_maybe_close_block(struct nfp_net_tx_ring *tx_ring,
-                             unsigned int nr_frags, struct sk_buff *skb)
+                             struct sk_buff *skb)
 {
        unsigned int n_descs, wr_p, nop_slots;
        const skb_frag_t *frag, *fend;
        struct nfp_nfdk_tx_desc *txd;
+       unsigned int nr_frags;
        unsigned int wr_idx;
        int err;
 
 recount_descs:
        n_descs = nfp_nfdk_headlen_to_segs(skb_headlen(skb));
-
+       nr_frags = skb_shinfo(skb)->nr_frags;
        frag = skb_shinfo(skb)->frags;
        fend = frag + nr_frags;
        for (; frag < fend; frag++)
@@ -281,10 +282,13 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
        if (unlikely((int)metadata < 0))
                goto err_flush;
 
-       nr_frags = skb_shinfo(skb)->nr_frags;
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, nr_frags, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_flush;
 
+       /* nr_frags will change after skb_linearize so we get nr_frags after
+        * nfp_nfdk_tx_maybe_close_block function
+        */
+       nr_frags = skb_shinfo(skb)->nr_frags;
        /* DMA map all */
        wr_idx = D_IDX(tx_ring, tx_ring->wr_p);
        txd = &tx_ring->ktxds[wr_idx];
@@ -310,7 +314,16 @@ netdev_tx_t nfp_nfdk_tx(struct sk_buff *skb, struct net_device *netdev)
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+
+       /* We will do our best to pass as much data as we can in descriptor
+        * and we need to make sure the first descriptor includes whole head
+        * since there is limitation in firmware side. Sometimes the value of
+        * dma_len bitwise and NFDK_DESC_TX_DMA_LEN_HEAD will less than
+        * headlen.
+        */
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -925,7 +938,9 @@ nfp_nfdk_tx_xdp_buf(struct nfp_net_dp *dp, struct nfp_net_rx_ring *rx_ring,
 
        /* FIELD_PREP() implicitly truncates to chunk */
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
@@ -1303,7 +1318,7 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
                                   skb_push(skb, 4));
        }
 
-       if (nfp_nfdk_tx_maybe_close_block(tx_ring, 0, skb))
+       if (nfp_nfdk_tx_maybe_close_block(tx_ring, skb))
                goto err_free;
 
        /* DMA map all */
@@ -1328,7 +1343,9 @@ nfp_nfdk_ctrl_tx_one(struct nfp_net *nn, struct nfp_net_r_vector *r_vec,
        txbuf++;
 
        dma_len -= 1;
-       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD, dma_len) |
+       dlen_type = FIELD_PREP(NFDK_DESC_TX_DMA_LEN_HEAD,
+                              dma_len > NFDK_DESC_TX_DMA_LEN_HEAD ?
+                              NFDK_DESC_TX_DMA_LEN_HEAD : dma_len) |
                    FIELD_PREP(NFDK_DESC_TX_TYPE_HEAD, type);
 
        txd->dma_len_type = cpu_to_le16(dlen_type);
index 3098d66..1b7fdb4 100644 (file)
@@ -4190,7 +4190,6 @@ static void rtl8169_tso_csum_v1(struct sk_buff *skb, u32 *opts)
 static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                                struct sk_buff *skb, u32 *opts)
 {
-       u32 transport_offset = (u32)skb_transport_offset(skb);
        struct skb_shared_info *shinfo = skb_shinfo(skb);
        u32 mss = shinfo->gso_size;
 
@@ -4207,7 +4206,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                        WARN_ON_ONCE(1);
                }
 
-               opts[0] |= transport_offset << GTTCPHO_SHIFT;
+               opts[0] |= skb_transport_offset(skb) << GTTCPHO_SHIFT;
                opts[1] |= mss << TD1_MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 ip_protocol;
@@ -4235,7 +4234,7 @@ static bool rtl8169_tso_csum_v2(struct rtl8169_private *tp,
                else
                        WARN_ON_ONCE(1);
 
-               opts[1] |= transport_offset << TCPHO_SHIFT;
+               opts[1] |= skb_transport_offset(skb) << TCPHO_SHIFT;
        } else {
                unsigned int padto = rtl_quirk_packet_padto(tp, skb);
 
@@ -4402,14 +4401,13 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                                                struct net_device *dev,
                                                netdev_features_t features)
 {
-       int transport_offset = skb_transport_offset(skb);
        struct rtl8169_private *tp = netdev_priv(dev);
 
        if (skb_is_gso(skb)) {
                if (tp->mac_version == RTL_GIGA_MAC_VER_34)
                        features = rtl8168evl_fix_tso(skb, features);
 
-               if (transport_offset > GTTCPHO_MAX &&
+               if (skb_transport_offset(skb) > GTTCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_ALL_TSO;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -4420,7 +4418,7 @@ static netdev_features_t rtl8169_features_check(struct sk_buff *skb,
                if (rtl_quirk_packet_padto(tp, skb))
                        features &= ~NETIF_F_CSUM_MASK;
 
-               if (transport_offset > TCPHO_MAX &&
+               if (skb_transport_offset(skb) > TCPHO_MAX &&
                    rtl_chip_supports_csum_v2(tp))
                        features &= ~NETIF_F_CSUM_MASK;
        }
index 186cb28..8b62ce2 100644 (file)
@@ -1932,7 +1932,10 @@ static int efx_ef10_try_update_nic_stats_vf(struct efx_nic *efx)
 
        efx_update_sw_stats(efx, stats);
 out:
+       /* releasing a DMA coherent buffer with BH disabled can panic */
+       spin_unlock_bh(&efx->stats_lock);
        efx_nic_free_buffer(efx, &stats_buf);
+       spin_lock_bh(&efx->stats_lock);
        return rc;
 }
 
index 7f5aa4a..92550c7 100644 (file)
@@ -408,8 +408,9 @@ fail1:
 static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
 {
        struct pci_dev *dev = efx->pci_dev;
+       struct efx_ef10_nic_data *nic_data = efx->nic_data;
        unsigned int vfs_assigned = pci_vfs_assigned(dev);
-       int rc = 0;
+       int i, rc = 0;
 
        if (vfs_assigned && !force) {
                netif_info(efx, drv, efx->net_dev, "VFs are assigned to guests; "
@@ -417,10 +418,13 @@ static int efx_ef10_pci_sriov_disable(struct efx_nic *efx, bool force)
                return -EBUSY;
        }
 
-       if (!vfs_assigned)
+       if (!vfs_assigned) {
+               for (i = 0; i < efx->vf_count; i++)
+                       nic_data->vf[i].pci_dev = NULL;
                pci_disable_sriov(dev);
-       else
+       } else {
                rc = -EBUSY;
+       }
 
        efx_ef10_sriov_free_vf_vswitching(efx);
        efx->vf_count = 0;
index bc91fd8..358fc26 100644 (file)
@@ -361,6 +361,7 @@ bypass_clk_reset_gpio:
        data->fix_mac_speed = tegra_eqos_fix_speed;
        data->init = tegra_eqos_init;
        data->bsp_priv = eqos;
+       data->sph_disable = 1;
 
        err = tegra_eqos_init(pdev, eqos);
        if (err < 0)
index 9a6d819..378b4dd 100644 (file)
@@ -273,7 +273,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->tx_delay = tx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid TX clock delay: %dps\n", tx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
@@ -283,7 +284,8 @@ static int ingenic_mac_probe(struct platform_device *pdev)
                        mac->rx_delay = rx_delay_ps * 1000;
                } else {
                        dev_err(&pdev->dev, "Invalid RX clock delay: %dps\n", rx_delay_ps);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto err_remove_config_dt;
                }
        }
 
index 77e5dff..8594ee8 100644 (file)
@@ -545,43 +545,24 @@ static int try_next_permutation(struct happy_meal *hp, void __iomem *tregs)
 
 static void display_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link is up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA);
-       if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) {
-               if (hp->sw_lpa & LPA_100FULL)
-                       printk("100Mb/s, Full Duplex.\n");
-               else
-                       printk("100Mb/s, Half Duplex.\n");
-       } else {
-               if (hp->sw_lpa & LPA_10FULL)
-                       printk("10Mb/s, Full Duplex.\n");
-               else
-                       printk("10Mb/s, Half Duplex.\n");
-       }
+
+       netdev_info(hp->dev,
+                   "Link is up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_lpa & (LPA_100HALF | LPA_100FULL) ? 100 : 10,
+                   hp->sw_lpa & (LPA_100FULL | LPA_10FULL) ? "Full" : "Half");
 }
 
 static void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs)
 {
-       printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name);
-       if (hp->tcvr_type == external)
-               printk("external ");
-       else
-               printk("internal ");
-       printk("transceiver at ");
        hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
-       if (hp->sw_bmcr & BMCR_SPEED100)
-               printk("100Mb/s, ");
-       else
-               printk("10Mb/s, ");
-       if (hp->sw_bmcr & BMCR_FULLDPLX)
-               printk("Full Duplex.\n");
-       else
-               printk("Half Duplex.\n");
+
+       netdev_info(hp->dev,
+                   "Link has been forced up using %s transceiver at %dMb/s, %s Duplex.\n",
+                   hp->tcvr_type == external ? "external" : "internal",
+                   hp->sw_bmcr & BMCR_SPEED100 ? 100 : 10,
+                   hp->sw_bmcr & BMCR_FULLDPLX ? "Full" : "Half");
 }
 
 static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
index fb92d4c..f4a6b59 100644 (file)
@@ -2467,7 +2467,6 @@ static int am65_cpsw_nuss_register_devlink(struct am65_cpsw_common *common)
                                port->port_id, ret);
                        goto dl_port_unreg;
                }
-               devlink_port_type_eth_set(dl_port, port->ndev);
        }
        devlink_register(common->devlink);
        return ret;
@@ -2511,6 +2510,7 @@ static void am65_cpsw_unregister_devlink(struct am65_cpsw_common *common)
 static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
 {
        struct device *dev = common->dev;
+       struct devlink_port *dl_port;
        struct am65_cpsw_port *port;
        int ret = 0, i;
 
@@ -2527,6 +2527,10 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                return ret;
        }
 
+       ret = am65_cpsw_nuss_register_devlink(common);
+       if (ret)
+               return ret;
+
        for (i = 0; i < common->port_num; i++) {
                port = &common->ports[i];
 
@@ -2539,25 +2543,24 @@ static int am65_cpsw_nuss_register_ndevs(struct am65_cpsw_common *common)
                                i, ret);
                        goto err_cleanup_ndev;
                }
+
+               dl_port = &port->devlink_port;
+               devlink_port_type_eth_set(dl_port, port->ndev);
        }
 
        ret = am65_cpsw_register_notifiers(common);
        if (ret)
                goto err_cleanup_ndev;
 
-       ret = am65_cpsw_nuss_register_devlink(common);
-       if (ret)
-               goto clean_unregister_notifiers;
-
        /* can't auto unregister ndev using devm_add_action() due to
         * devres release sequence in DD core for DMA
         */
 
        return 0;
-clean_unregister_notifiers:
-       am65_cpsw_unregister_notifiers(common);
+
 err_cleanup_ndev:
        am65_cpsw_nuss_cleanup_ndev(common);
+       am65_cpsw_unregister_devlink(common);
 
        return ret;
 }
index e7fe9c0..1a376ed 100644 (file)
@@ -781,7 +781,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
                        intf->altsetting->desc.bInterfaceNumber, 1)) {
                dev_err(dev, "Can't set altsetting 1.\n");
                ret = -EIO;
-               goto fail_mem;;
+               goto fail_mem;
        }
 
        netdev = alloc_etherdev(sizeof(struct catc));
index 7389d6e..b082819 100644 (file)
@@ -2156,7 +2156,7 @@ static inline void rtl_rx_vlan_tag(struct rx_desc *desc, struct sk_buff *skb)
 }
 
 static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
-                        struct sk_buff *skb, u32 len, u32 transport_offset)
+                        struct sk_buff *skb, u32 len)
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        u32 opts1, opts2 = 0;
@@ -2167,6 +2167,8 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
        opts1 = len | TX_FS | TX_LS;
 
        if (mss) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
+
                if (transport_offset > GTTCPHO_MAX) {
                        netif_warn(tp, tx_err, tp->netdev,
                                   "Invalid transport offset 0x%x for TSO\n",
@@ -2197,6 +2199,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
                opts1 |= transport_offset << GTTCPHO_SHIFT;
                opts2 |= min(mss, MSS_MAX) << MSS_SHIFT;
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               u32 transport_offset = (u32)skb_transport_offset(skb);
                u8 ip_protocol;
 
                if (transport_offset > TCPHO_MAX) {
@@ -2260,7 +2263,6 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                struct tx_desc *tx_desc;
                struct sk_buff *skb;
                unsigned int len;
-               u32 offset;
 
                skb = __skb_dequeue(&skb_head);
                if (!skb)
@@ -2276,9 +2278,7 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg)
                tx_data = tx_agg_align(tx_data);
                tx_desc = (struct tx_desc *)tx_data;
 
-               offset = (u32)skb_transport_offset(skb);
-
-               if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) {
+               if (r8152_tx_csum(tp, tx_desc, skb, skb->len)) {
                        r8152_csum_workaround(tp, skb, &skb_head);
                        continue;
                }
@@ -2759,9 +2759,9 @@ rtl8152_features_check(struct sk_buff *skb, struct net_device *dev,
 {
        u32 mss = skb_shinfo(skb)->gso_size;
        int max_offset = mss ? GTTCPHO_MAX : TCPHO_MAX;
-       int offset = skb_transport_offset(skb);
 
-       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) && offset > max_offset)
+       if ((mss || skb->ip_summed == CHECKSUM_PARTIAL) &&
+           skb_transport_offset(skb) > max_offset)
                features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
        else if ((skb->len + sizeof(struct tx_desc)) > agg_buf_sz)
                features &= ~NETIF_F_GSO_MASK;
index e2135ab..78a9275 100644 (file)
@@ -2137,7 +2137,7 @@ static void usbnet_async_cmd_cb(struct urb *urb)
 int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                           u16 value, u16 index, const void *data, u16 size)
 {
-       struct usb_ctrlrequest *req = NULL;
+       struct usb_ctrlrequest *req;
        struct urb *urb;
        int err = -ENOMEM;
        void *buf = NULL;
@@ -2155,7 +2155,7 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
                if (!buf) {
                        netdev_err(dev->net, "Error allocating buffer"
                                   " in %s!\n", __func__);
-                       goto fail_free;
+                       goto fail_free_urb;
                }
        }
 
@@ -2179,14 +2179,21 @@ int usbnet_write_cmd_async(struct usbnet *dev, u8 cmd, u8 reqtype,
        if (err < 0) {
                netdev_err(dev->net, "Error submitting the control"
                           " message: status=%d\n", err);
-               goto fail_free;
+               goto fail_free_all;
        }
        return 0;
 
+fail_free_all:
+       kfree(req);
 fail_free_buf:
        kfree(buf);
-fail_free:
-       kfree(req);
+       /*
+        * avoid a double free
+        * needed because the flag can be set only
+        * after filling the URB
+        */
+       urb->transfer_flags = 0;
+fail_free_urb:
        usb_free_urb(urb);
 fail:
        return err;
index 84d1c70..7b1dc19 100644 (file)
@@ -3822,7 +3822,8 @@ ath11k_wmi_obss_color_collision_event(struct ath11k_base *ab, struct sk_buff *sk
 
        switch (ev->evt_type) {
        case WMI_BSS_COLOR_COLLISION_DETECTION:
-               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap);
+               ieeee80211_obss_color_collision_notify(arvif->vif, ev->obss_color_bitmap,
+                                                      GFP_KERNEL);
                ath11k_dbg(ab, ATH11K_DBG_WMI,
                           "OBSS color collision detected vdev:%d, event:%d, bitmap:%08llx\n",
                           ev->vdev_id, ev->evt_type, ev->obss_color_bitmap);
index 2f746eb..6f83af8 100644 (file)
@@ -4912,6 +4912,8 @@ static int hwsim_virtio_probe(struct virtio_device *vdev)
        if (err)
                return err;
 
+       virtio_device_ready(vdev);
+
        err = fill_vq(hwsim_vqs[HWSIM_VQ_RX]);
        if (err)
                goto out_remove;
index c02be4a..7db627f 100644 (file)
@@ -1233,9 +1233,6 @@ struct rtw_chip_info {
        const struct wiphy_wowlan_support *wowlan_stub;
        const u8 max_sched_scan_ssids;
 
-       /* for 8821c set channel */
-       u32 ch_param[3];
-
        /* coex paras */
        u32 coex_para_ver;
        u8 bt_desired_ver;
@@ -1937,6 +1934,9 @@ struct rtw_hal {
 
        enum rtw_sar_bands sar_band;
        struct rtw_sar sar;
+
+       /* for 8821c set channel */
+       u32 ch_param[3];
 };
 
 struct rtw_path_div {
index ffee39e..488a7dd 100644 (file)
@@ -125,6 +125,7 @@ static void rtw8821c_phy_bf_init(struct rtw_dev *rtwdev)
 
 static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u8 crystal_cap, val;
 
        /* power on BB/RF domain */
@@ -159,9 +160,9 @@ static void rtw8821c_phy_set_param(struct rtw_dev *rtwdev)
 
        /* post init after header files config */
        rtw_write32_set(rtwdev, REG_RXPSEL, BIT_RX_PSEL_RST);
-       rtwdev->chip->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
-       rtwdev->chip->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
-       rtwdev->chip->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
+       hal->ch_param[0] = rtw_read32_mask(rtwdev, REG_TXSF2, MASKDWORD);
+       hal->ch_param[1] = rtw_read32_mask(rtwdev, REG_TXSF6, MASKDWORD);
+       hal->ch_param[2] = rtw_read32_mask(rtwdev, REG_TXFILTER, MASKDWORD);
 
        rtw_phy_init(rtwdev);
        rtwdev->dm_info.cck_pd_default = rtw_read8(rtwdev, REG_CSRATIO) & 0x1f;
@@ -351,6 +352,7 @@ static void rtw8821c_set_channel_rxdfir(struct rtw_dev *rtwdev, u8 bw)
 static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                                    u8 primary_ch_idx)
 {
+       struct rtw_hal *hal = &rtwdev->hal;
        u32 val32;
 
        if (channel <= 14) {
@@ -367,11 +369,11 @@ static void rtw8821c_set_channel_bb(struct rtw_dev *rtwdev, u8 channel, u8 bw,
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD, 0x00003667);
                } else {
                        rtw_write32_mask(rtwdev, REG_TXSF2, MASKDWORD,
-                                        rtwdev->chip->ch_param[0]);
+                                        hal->ch_param[0]);
                        rtw_write32_mask(rtwdev, REG_TXSF6, MASKLWORD,
-                                        rtwdev->chip->ch_param[1] & MASKLWORD);
+                                        hal->ch_param[1] & MASKLWORD);
                        rtw_write32_mask(rtwdev, REG_TXFILTER, MASKDWORD,
-                                        rtwdev->chip->ch_param[2]);
+                                        hal->ch_param[2]);
                }
        } else if (channel > 35) {
                rtw_write32_mask(rtwdev, REG_ENTXCCK, BIT(18), 0x1);
index dbac4c0..a033540 100644 (file)
@@ -495,6 +495,7 @@ void xenvif_rx_action(struct xenvif_queue *queue)
        queue->rx_copy.completed = &completed_skbs;
 
        while (xenvif_rx_ring_slots_available(queue) &&
+              !skb_queue_empty(&queue->rx_queue) &&
               work_done < RX_BATCH_SIZE) {
                xenvif_rx_skb(queue);
                work_done++;
index 8c0b954..2409007 100644 (file)
@@ -66,6 +66,10 @@ module_param_named(max_queues, xennet_max_queues, uint, 0644);
 MODULE_PARM_DESC(max_queues,
                 "Maximum number of queues per virtual interface");
 
+static bool __read_mostly xennet_trusted = true;
+module_param_named(trusted, xennet_trusted, bool, 0644);
+MODULE_PARM_DESC(trusted, "Is the backend trusted");
+
 #define XENNET_TIMEOUT  (5 * HZ)
 
 static const struct ethtool_ops xennet_ethtool_ops;
@@ -173,6 +177,9 @@ struct netfront_info {
        /* Is device behaving sane? */
        bool broken;
 
+       /* Should skbs be bounced into a zeroed buffer? */
+       bool bounce;
+
        atomic_t rx_gso_checksum_fixup;
 };
 
@@ -271,7 +278,8 @@ static struct sk_buff *xennet_alloc_one_rx_buffer(struct netfront_queue *queue)
        if (unlikely(!skb))
                return NULL;
 
-       page = page_pool_dev_alloc_pages(queue->page_pool);
+       page = page_pool_alloc_pages(queue->page_pool,
+                                    GFP_ATOMIC | __GFP_NOWARN | __GFP_ZERO);
        if (unlikely(!page)) {
                kfree_skb(skb);
                return NULL;
@@ -665,6 +673,33 @@ static int xennet_xdp_xmit(struct net_device *dev, int n,
        return nxmit;
 }
 
+struct sk_buff *bounce_skb(const struct sk_buff *skb)
+{
+       unsigned int headerlen = skb_headroom(skb);
+       /* Align size to allocate full pages and avoid contiguous data leaks */
+       unsigned int size = ALIGN(skb_end_offset(skb) + skb->data_len,
+                                 XEN_PAGE_SIZE);
+       struct sk_buff *n = alloc_skb(size, GFP_ATOMIC | __GFP_ZERO);
+
+       if (!n)
+               return NULL;
+
+       if (!IS_ALIGNED((uintptr_t)n->head, XEN_PAGE_SIZE)) {
+               WARN_ONCE(1, "misaligned skb allocated\n");
+               kfree_skb(n);
+               return NULL;
+       }
+
+       /* Set the data pointer */
+       skb_reserve(n, headerlen);
+       /* Set the tail pointer and length */
+       skb_put(n, skb->len);
+
+       BUG_ON(skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len));
+
+       skb_copy_header(n, skb);
+       return n;
+}
 
 #define MAX_XEN_SKB_FRAGS (65536 / XEN_PAGE_SIZE + 1)
 
@@ -718,9 +753,13 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev
 
        /* The first req should be at least ETH_HLEN size or the packet will be
         * dropped by netback.
+        *
+        * If the backend is not trusted bounce all data to zeroed pages to
+        * avoid exposing contiguous data on the granted page not belonging to
+        * the skb.
         */
-       if (unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
-               nskb = skb_copy(skb, GFP_ATOMIC);
+       if (np->bounce || unlikely(PAGE_SIZE - offset < ETH_HLEN)) {
+               nskb = bounce_skb(skb);
                if (!nskb)
                        goto drop;
                dev_consume_skb_any(skb);
@@ -1053,8 +1092,10 @@ static int xennet_get_responses(struct netfront_queue *queue,
                        }
                }
                rcu_read_unlock();
-next:
+
                __skb_queue_tail(list, skb);
+
+next:
                if (!(rx->flags & XEN_NETRXF_more_data))
                        break;
 
@@ -2214,6 +2255,10 @@ static int talk_to_netback(struct xenbus_device *dev,
 
        info->netdev->irq = 0;
 
+       /* Check if backend is trusted. */
+       info->bounce = !xennet_trusted ||
+                      !xenbus_read_unsigned(dev->nodename, "trusted", 1);
+
        /* Check if backend supports multiple queues */
        max_queues = xenbus_read_unsigned(info->xbdev->otherend,
                                          "multi-queue-max-queues", 1);
@@ -2381,6 +2426,9 @@ static int xennet_connect(struct net_device *dev)
                return err;
        if (np->netback_has_xdp_headroom)
                pr_info("backend supports XDP headroom\n");
+       if (np->bounce)
+               dev_info(&np->xbdev->dev,
+                        "bouncing transmitted data to zeroed pages\n");
 
        /* talk_to_netback() sets the correct number of queues */
        num_queues = dev->real_num_tx_queues;
index ec6ac29..6a12a90 100644 (file)
@@ -3786,7 +3786,7 @@ static int nvme_add_ns_cdev(struct nvme_ns *ns)
 }
 
 static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
-               unsigned nsid, struct nvme_ns_ids *ids)
+               unsigned nsid, struct nvme_ns_ids *ids, bool is_shared)
 {
        struct nvme_ns_head *head;
        size_t size = sizeof(*head);
@@ -3810,6 +3810,7 @@ static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
        head->subsys = ctrl->subsys;
        head->ns_id = nsid;
        head->ids = *ids;
+       head->shared = is_shared;
        kref_init(&head->ref);
 
        if (head->ids.csi) {
@@ -3891,12 +3892,11 @@ static int nvme_init_ns_head(struct nvme_ns *ns, unsigned nsid,
                                nsid);
                        goto out_unlock;
                }
-               head = nvme_alloc_ns_head(ctrl, nsid, ids);
+               head = nvme_alloc_ns_head(ctrl, nsid, ids, is_shared);
                if (IS_ERR(head)) {
                        ret = PTR_ERR(head);
                        goto out_unlock;
                }
-               head->shared = is_shared;
        } else {
                ret = -EINVAL;
                if (!is_shared || !head->shared) {
index e7af223..58c72d5 100644 (file)
@@ -2690,8 +2690,13 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown)
        struct pci_dev *pdev = to_pci_dev(dev->dev);
 
        mutex_lock(&dev->shutdown_lock);
-       if (pci_device_is_present(pdev) && pci_is_enabled(pdev)) {
-               u32 csts = readl(dev->bar + NVME_REG_CSTS);
+       if (pci_is_enabled(pdev)) {
+               u32 csts;
+
+               if (pci_device_is_present(pdev))
+                       csts = readl(dev->bar + NVME_REG_CSTS);
+               else
+                       csts = ~0;
 
                if (dev->ctrl.state == NVME_CTRL_LIVE ||
                    dev->ctrl.state == NVME_CTRL_RESETTING) {
@@ -3465,7 +3470,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x1987, 0x5012),   /* Phison E12 */
                .driver_data = NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1987, 0x5016),   /* Phison E16 */
-               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
+               .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x1b4b, 0x1092),   /* Lexar 256 GB SSD */
                .driver_data = NVME_QUIRK_NO_NS_DESC_LIST |
                                NVME_QUIRK_IGNORE_DEV_SUBNQN, },
index b5f8525..37c7f4c 100644 (file)
@@ -69,7 +69,7 @@ TRACE_EVENT(nvme_setup_cmd,
                __entry->metadata = !!blk_integrity_rq(req);
                __entry->fctype = cmd->fabrics.fctype;
                __assign_disk_name(__entry->disk, req->q->disk);
-               memcpy(__entry->cdw10, &cmd->common.cdw10,
+               memcpy(__entry->cdw10, &cmd->common.cdws,
                        sizeof(__entry->cdw10));
            ),
            TP_printk("nvme%d: %sqid=%d, cmdid=%u, nsid=%u, flags=0x%x, meta=0x%x, cmd=(%s %s)",
index c94e24a..83d47ff 100644 (file)
@@ -236,11 +236,11 @@ int aspeed_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned int function,
                const struct aspeed_sig_expr **funcs;
                const struct aspeed_sig_expr ***prios;
 
-               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
-
                if (!pdesc)
                        return -EINVAL;
 
+               pr_debug("Muxing pin %s for %s\n", pdesc->name, pfunc->name);
+
                prios = pdesc->prios;
 
                if (!prios)
index c0630f6..417e41b 100644 (file)
@@ -239,6 +239,7 @@ static const struct pinctrl_pin_desc imx93_pinctrl_pads[] = {
 static const struct imx_pinctrl_soc_info imx93_pinctrl_info = {
        .pins = imx93_pinctrl_pads,
        .npins = ARRAY_SIZE(imx93_pinctrl_pads),
+       .flags = ZERO_OFFSET_VALID,
        .gpr_compatible = "fsl,imx93-iomuxc-gpr",
 };
 
index 57a33fb..14bcca7 100644 (file)
@@ -1338,16 +1338,18 @@ static int stm32_gpiolib_register_bank(struct stm32_pinctrl *pctl, struct fwnode
        bank->secure_control = pctl->match_data->secure_control;
        spin_lock_init(&bank->lock);
 
-       /* create irq hierarchical domain */
-       bank->fwnode = fwnode;
+       if (pctl->domain) {
+               /* create irq hierarchical domain */
+               bank->fwnode = fwnode;
 
-       bank->domain = irq_domain_create_hierarchy(pctl->domain, 0,
-                                       STM32_GPIO_IRQ_LINE, bank->fwnode,
-                                       &stm32_gpio_domain_ops, bank);
+               bank->domain = irq_domain_create_hierarchy(pctl->domain, 0, STM32_GPIO_IRQ_LINE,
+                                                          bank->fwnode, &stm32_gpio_domain_ops,
+                                                          bank);
 
-       if (!bank->domain) {
-               err = -ENODEV;
-               goto err_clk;
+               if (!bank->domain) {
+                       err = -ENODEV;
+                       goto err_clk;
+               }
        }
 
        err = gpiochip_add_data(&bank->gpio_chip, bank);
@@ -1510,6 +1512,8 @@ int stm32_pctl_probe(struct platform_device *pdev)
        pctl->domain = stm32_pctrl_get_irq_domain(pdev);
        if (IS_ERR(pctl->domain))
                return PTR_ERR(pctl->domain);
+       if (!pctl->domain)
+               dev_warn(dev, "pinctrl without interrupt support\n");
 
        /* hwspinlock is optional */
        hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
index 4ada803..b5c1a8f 100644 (file)
@@ -158,26 +158,26 @@ static const struct sunxi_desc_pin sun8i_a83t_pins[] = {
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ6 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ6 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D6 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQ7 */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQ7 */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* D7 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand"),          /* DQS */
+                 SUNXI_FUNCTION(0x2, "nand0"),         /* DQS */
                  SUNXI_FUNCTION(0x3, "mmc2")),         /* RST */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE2 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE2 */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
                  SUNXI_FUNCTION(0x1, "gpio_out"),
-                 SUNXI_FUNCTION(0x2, "nand")),         /* CE3 */
+                 SUNXI_FUNCTION(0x2, "nand0")),        /* CE3 */
        /* Hole */
        SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
                  SUNXI_FUNCTION(0x0, "gpio_in"),
index d9327d7..dd92840 100644 (file)
@@ -544,6 +544,8 @@ static int sunxi_pconf_set(struct pinctrl_dev *pctldev, unsigned pin,
        struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
        int i;
 
+       pin -= pctl->desc->pin_base;
+
        for (i = 0; i < num_configs; i++) {
                enum pin_config_param param;
                unsigned long flags;
index f11d18b..700eb19 100644 (file)
@@ -91,6 +91,8 @@
 #define AMD_CPU_ID_PCO                 AMD_CPU_ID_RV
 #define AMD_CPU_ID_CZN                 AMD_CPU_ID_RN
 #define AMD_CPU_ID_YC                  0x14B5
+#define AMD_CPU_ID_CB                  0x14D8
+#define AMD_CPU_ID_PS                  0x14E8
 
 #define PMC_MSG_DELAY_MIN_US           50
 #define RESPONSE_REGISTER_LOOP_MAX     20000
@@ -318,6 +320,8 @@ static int amd_pmc_idlemask_read(struct amd_pmc_dev *pdev, struct device *dev,
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_CZN);
                break;
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                val = amd_pmc_reg_read(pdev, AMD_PMC_SCRATCH_REG_YC);
                break;
        default:
@@ -491,7 +495,8 @@ static void amd_pmc_dbgfs_register(struct amd_pmc_dev *dev)
                            &amd_pmc_idlemask_fops);
        /* Enable STB only when the module_param is set */
        if (enable_stb) {
-               if (dev->cpu_id == AMD_CPU_ID_YC)
+               if (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB ||
+                   dev->cpu_id == AMD_CPU_ID_PS)
                        debugfs_create_file("stb_read", 0644, dev->dbgfs_dir, dev,
                                            &amd_pmc_stb_debugfs_fops_v2);
                else
@@ -615,6 +620,8 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
                return MSG_OS_HINT_PCO;
        case AMD_CPU_ID_RN:
        case AMD_CPU_ID_YC:
+       case AMD_CPU_ID_CB:
+       case AMD_CPU_ID_PS:
                return MSG_OS_HINT_RN;
        }
        return -EINVAL;
@@ -735,6 +742,8 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
 #endif
 
 static const struct pci_device_id pmc_pci_ids[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CB) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_YC) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_CZN) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RN) },
@@ -877,7 +886,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
 
        mutex_init(&dev->lock);
 
-       if (enable_stb && dev->cpu_id == AMD_CPU_ID_YC) {
+       if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
                err = amd_pmc_s2d_init(dev);
                if (err)
                        return err;
@@ -915,6 +924,7 @@ static const struct acpi_device_id amd_pmc_acpi_ids[] = {
        {"AMDI0005", 0},
        {"AMDI0006", 0},
        {"AMDI0007", 0},
+       {"AMDI0008", 0},
        {"AMD0004", 0},
        {"AMD0005", 0},
        { }
index 57a07db..478dd30 100644 (file)
@@ -522,6 +522,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
        { KE_KEY, 0x32, { KEY_MUTE } },
        { KE_KEY, 0x35, { KEY_SCREENLOCK } },
+       { KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */
        { KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
        { KE_KEY, 0x41, { KEY_NEXTSONG } },
        { KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
@@ -574,6 +575,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
        { KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
        { KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
        { KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
+       { KE_KEY, 0xB3, { KEY_PROG4 } }, /* AURA */
        { KE_KEY, 0xB5, { KEY_CALC } },
        { KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
        { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
index 497ad2f..5e7e665 100644 (file)
@@ -150,6 +150,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M AORUS PRO-P"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660 GAMING X DDR4"),
+       DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B660I AORUS PRO DDR4"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z490 AORUS ELITE AC"),
        DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"),
index 5935dfc..10077a6 100644 (file)
@@ -50,7 +50,8 @@ static const struct dmi_system_id atomisp2_led_systems[] __initconst = {
        {
                .matches = {
                        DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
-                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"),
+                       /* Non exact match to also match T100TAF */
+                       DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
                },
                .driver_data = &asus_t100ta_lookup,
        },
index 7ce8964..c341a27 100644 (file)
@@ -1,6 +1,9 @@
 config INTEL_IFS
        tristate "Intel In Field Scan"
        depends on X86 && CPU_SUP_INTEL && 64BIT && SMP
+       # Discussion on the list has shown that the sysfs API needs a bit
+       # more work, mark this as broken for now
+       depends on BROKEN
        select INTEL_IFS_DEVICE
        help
          Enable support for the In Field Scan capability in select
index f446be7..4803759 100644 (file)
@@ -27,8 +27,8 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/lp855x.h>
 #include <linux/platform_device.h>
-#include <linux/pm.h>
 #include <linux/power/bq24190_charger.h>
+#include <linux/reboot.h>
 #include <linux/rmi.h>
 #include <linux/serdev.h>
 #include <linux/spi/spi.h>
@@ -889,6 +889,7 @@ static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =
                          "INT33FC:02", "pmu_clk2_grp", "pmu_clk");
 
 static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
+static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;
 
 static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
 {
@@ -933,9 +934,11 @@ err_put_device:
  * followed by a normal 3 second press to recover. Avoid this by doing an EFI
  * poweroff instead.
  */
-static void lenovo_yoga_tab2_830_1050_power_off(void)
+static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
 {
        efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
+
+       return NOTIFY_DONE;
 }
 
 static int __init lenovo_yoga_tab2_830_1050_init(void)
@@ -950,13 +953,19 @@ static int __init lenovo_yoga_tab2_830_1050_init(void)
        if (ret)
                return ret;
 
-       pm_power_off = lenovo_yoga_tab2_830_1050_power_off;
+       /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+       lenovo_yoga_tab2_830_1050_sys_off_handler =
+               register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
+                                        lenovo_yoga_tab2_830_1050_power_off, NULL);
+       if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler))
+               return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler);
+
        return 0;
 }
 
 static void lenovo_yoga_tab2_830_1050_exit(void)
 {
-       pm_power_off = NULL; /* Just turn poweroff into halt on module unload */
+       unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler);
 
        if (lenovo_yoga_tab2_830_1050_codec_pinctrl) {
                pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl);
index 08d0a07..c7624d7 100644 (file)
@@ -146,6 +146,7 @@ static int __init versatile_reboot_probe(void)
        versatile_reboot_type = (enum versatile_reboot)reboot_id->data;
 
        syscon_regmap = syscon_node_to_regmap(np);
+       of_node_put(np);
        if (IS_ERR(syscon_regmap))
                return PTR_ERR(syscon_regmap);
 
index ec8a404..4339fa9 100644 (file)
@@ -3148,6 +3148,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_init_hw_registers(di);
        if (ret) {
                dev_err(dev, "failed to initialize registers\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3159,6 +3160,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        di->fg_psy = devm_power_supply_register(dev, &ab8500_fg_desc, &psy_cfg);
        if (IS_ERR(di->fg_psy)) {
                dev_err(dev, "failed to register FG psy\n");
+               destroy_workqueue(di->fg_wq);
                return PTR_ERR(di->fg_psy);
        }
 
@@ -3174,8 +3176,10 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        /* Register primary interrupt handlers */
        for (i = 0; i < ARRAY_SIZE(ab8500_fg_irq); i++) {
                irq = platform_get_irq_byname(pdev, ab8500_fg_irq[i].name);
-               if (irq < 0)
+               if (irq < 0) {
+                       destroy_workqueue(di->fg_wq);
                        return irq;
+               }
 
                ret = devm_request_threaded_irq(dev, irq, NULL,
                                  ab8500_fg_irq[i].isr,
@@ -3185,6 +3189,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
                if (ret != 0) {
                        dev_err(dev, "failed to request %s IRQ %d: %d\n",
                                ab8500_fg_irq[i].name, irq, ret);
+                       destroy_workqueue(di->fg_wq);
                        return ret;
                }
                dev_dbg(dev, "Requested %s IRQ %d: %d\n",
@@ -3200,6 +3205,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        ret = ab8500_fg_sysfs_init(di);
        if (ret) {
                dev_err(dev, "failed to create sysfs entry\n");
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
@@ -3207,6 +3213,7 @@ static int ab8500_fg_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(dev, "failed to create FG psy\n");
                ab8500_fg_sysfs_exit(di);
+               destroy_workqueue(di->fg_wq);
                return ret;
        }
 
index fad5890..470253c 100644 (file)
@@ -846,17 +846,17 @@ int power_supply_temp2resist_simple(struct power_supply_resistance_temp_table *t
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (temp > table[i].temp)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i - 1;
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].temp,
                                       table[low].resistance,
@@ -958,17 +958,17 @@ int power_supply_ocv2cap_simple(struct power_supply_battery_ocv_table *table,
 {
        int i, high, low;
 
-       /* Break loop at table_len - 1 because that is the highest index */
-       for (i = 0; i < table_len - 1; i++)
+       for (i = 0; i < table_len; i++)
                if (ocv > table[i].ocv)
                        break;
 
        /* The library function will deal with high == low */
-       if ((i == 0) || (i == (table_len - 1)))
-               high = i - 1;
+       if (i == 0)
+               high = low = i;
+       else if (i == table_len)
+               high = low = i - 1;
        else
-               high = i; /* i.e. i == 0 */
-       low = i;
+               high = (low = i) - 1;
 
        return fixp_linear_interpolate(table[low].ocv,
                                       table[low].capacity,
index 5c13d20..0a9045b 100644 (file)
@@ -1435,7 +1435,7 @@ static int __verify_queue_reservations(struct device_driver *drv, void *data)
        if (ap_drv->in_use) {
                rc = ap_drv->in_use(ap_perms.apm, newaqm);
                if (rc)
-                       return -EBUSY;
+                       rc = -EBUSY;
        }
 
        /* release the driver's module */
index c95360a..0917b05 100644 (file)
@@ -3195,6 +3195,9 @@ static int megasas_map_queues(struct Scsi_Host *shost)
        qoff += map->nr_queues;
        offset += map->nr_queues;
 
+       /* we never use READ queue, so can't cheat blk-mq */
+       shost->tag_set.map[HCTX_TYPE_READ].nr_queues = 0;
+
        /* Setup Poll hctx */
        map = &shost->tag_set.map[HCTX_TYPE_POLL];
        map->nr_queues = instance->iopoll_q_count;
index f7466a8..991eb01 100644 (file)
@@ -3145,15 +3145,6 @@ void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
        if (!phy->phy_attached)
                return;
 
-       if (sas_phy->phy) {
-               struct sas_phy *sphy = sas_phy->phy;
-               sphy->negotiated_linkrate = sas_phy->linkrate;
-               sphy->minimum_linkrate = phy->minimum_linkrate;
-               sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-               sphy->maximum_linkrate = phy->maximum_linkrate;
-               sphy->maximum_linkrate_hw = phy->maximum_linkrate;
-       }
-
        if (phy->phy_type & PORT_TYPE_SAS) {
                struct sas_identify_frame *id;
                id = (struct sas_identify_frame *)phy->frame_rcvd;
@@ -3177,26 +3168,22 @@ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
        switch (link_rate) {
        case PHY_SPEED_120:
                phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS;
                break;
        case PHY_SPEED_60:
                phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
                break;
        case PHY_SPEED_30:
                phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
                break;
        case PHY_SPEED_15:
                phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
-               phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
                break;
        }
        sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
-       sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS;
+       sas_phy->maximum_linkrate_hw = phy->maximum_linkrate;
        sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
-       sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
-       sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       sas_phy->maximum_linkrate = phy->maximum_linkrate;
+       sas_phy->minimum_linkrate = phy->minimum_linkrate;
 }
 
 /**
index 9b04f1a..01f2f41 100644 (file)
@@ -143,6 +143,8 @@ static void pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, int phy_id)
        struct asd_sas_phy *sas_phy = &phy->sas_phy;
        phy->phy_state = PHY_LINK_DISABLE;
        phy->pm8001_ha = pm8001_ha;
+       phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
+       phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
        sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0;
        sas_phy->class = SAS;
        sas_phy->iproto = SAS_PROTOCOL_ALL;
index 01c5e8f..303cd05 100644 (file)
@@ -3723,8 +3723,12 @@ static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
        pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n",
                   phyid, status);
        if (status == PHY_STOP_SUCCESS ||
-               status == PHY_STOP_ERR_DEVICE_ATTACHED)
+               status == PHY_STOP_ERR_DEVICE_ATTACHED) {
                phy->phy_state = PHY_LINK_DISABLE;
+               phy->sas_phy.phy->negotiated_linkrate = SAS_PHY_DISABLED;
+               phy->sas_phy.linkrate = SAS_PHY_DISABLED;
+       }
+
        return 0;
 }
 
index b2d365a..dae8a2e 100644 (file)
@@ -91,14 +91,14 @@ static const struct at91_soc socs[] __initconst = {
        AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
                 AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
                 "sam9x60", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D5M_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D5M_EXID_MATCH,
                 "sam9x60 64MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D1G_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D1G_EXID_MATCH,
                 "sam9x60 128MiB DDR2 SiP", "sam9x60"),
-       AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_D6K_EXID_MATCH,
-                AT91_CIDR_VERSION_MASK, SAM9X60_EXID_MATCH,
+       AT91_SOC(SAM9X60_CIDR_MATCH, AT91_CIDR_MATCH_MASK,
+                AT91_CIDR_VERSION_MASK, SAM9X60_D6K_EXID_MATCH,
                 "sam9x60 8MiB SDRAM SiP", "sam9x60"),
 #endif
 #ifdef CONFIG_SOC_SAMA5
index 613935c..58240e3 100644 (file)
@@ -758,7 +758,7 @@ static const struct of_device_id ixp4xx_npe_of_match[] = {
 static struct platform_driver ixp4xx_npe_driver = {
        .driver = {
                .name           = "ixp4xx-npe",
-               .of_match_table = of_match_ptr(ixp4xx_npe_of_match),
+               .of_match_table = ixp4xx_npe_of_match,
        },
        .probe = ixp4xx_npe_probe,
        .remove = ixp4xx_npe_remove,
index 3e95835..4f163d6 100644 (file)
@@ -926,7 +926,7 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
        struct smem_partition_header *header;
        struct smem_ptable_entry *entry;
        struct smem_ptable *ptable;
-       unsigned int remote_host;
+       u16 remote_host;
        u16 host0, host1;
        int i;
 
@@ -951,12 +951,12 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
                        continue;
 
                if (remote_host >= SMEM_HOST_COUNT) {
-                       dev_err(smem->dev, "bad host %hu\n", remote_host);
+                       dev_err(smem->dev, "bad host %u\n", remote_host);
                        return -EINVAL;
                }
 
                if (smem->partitions[remote_host].virt_base) {
-                       dev_err(smem->dev, "duplicate host %hu\n", remote_host);
+                       dev_err(smem->dev, "duplicate host %u\n", remote_host);
                        return -EINVAL;
                }
 
index cba6a44..efdcbe6 100644 (file)
@@ -33,6 +33,7 @@
 #define AMD_SPI_RX_COUNT_REG   0x4B
 #define AMD_SPI_STATUS_REG     0x4C
 
+#define AMD_SPI_FIFO_SIZE      70
 #define AMD_SPI_MEM_SIZE       200
 
 /* M_CMD OP codes for SPI */
@@ -270,6 +271,11 @@ static int amd_spi_master_transfer(struct spi_master *master,
        return 0;
 }
 
+static size_t amd_spi_max_transfer_size(struct spi_device *spi)
+{
+       return AMD_SPI_FIFO_SIZE;
+}
+
 static int amd_spi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -302,6 +308,8 @@ static int amd_spi_probe(struct platform_device *pdev)
        master->flags = SPI_MASTER_HALF_DUPLEX;
        master->setup = amd_spi_master_setup;
        master->transfer_one_message = amd_spi_master_transfer;
+       master->max_transfer_size = amd_spi_max_transfer_size;
+       master->max_message_size = amd_spi_max_transfer_size;
 
        /* Register the controller with SPI framework */
        err = devm_spi_register_master(dev, master);
index 496f3e1..3e891bf 100644 (file)
@@ -558,6 +558,14 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        u32 ctl_val;
        int ret = 0;
 
+       dev_dbg(aspi->dev,
+               "CE%d %s dirmap [ 0x%.8llx - 0x%.8llx ] OP %#x mode:%d.%d.%d.%d naddr:%#x ndummies:%#x\n",
+               chip->cs, op->data.dir == SPI_MEM_DATA_IN ? "read" : "write",
+               desc->info.offset, desc->info.offset + desc->info.length,
+               op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth,
+               op->dummy.buswidth, op->data.buswidth,
+               op->addr.nbytes, op->dummy.nbytes);
+
        chip->clk_freq = desc->mem->spi->max_speed_hz;
 
        /* Only for reads */
@@ -574,9 +582,11 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
        ctl_val = readl(chip->ctl) & ~CTRL_IO_CMD_MASK;
        ctl_val |= aspeed_spi_get_io_mode(op) |
                op->cmd.opcode << CTRL_COMMAND_SHIFT |
-               CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth) |
                CTRL_IO_MODE_READ;
 
+       if (op->dummy.nbytes)
+               ctl_val |= CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth);
+
        /* Tune 4BYTE address mode */
        if (op->addr.nbytes) {
                u32 addr_mode = readl(aspi->regs + CE_CTRL_REG);
index 2b9fc84..72b1a5a 100644 (file)
@@ -1578,8 +1578,7 @@ static int cqspi_probe(struct platform_device *pdev)
        ret = cqspi_of_get_pdata(cqspi);
        if (ret) {
                dev_err(dev, "Cannot get mandatory OF data.\n");
-               ret = -ENODEV;
-               goto probe_master_put;
+               return -ENODEV;
        }
 
        /* Obtain QSPI clock. */
@@ -1587,7 +1586,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->clk)) {
                dev_err(dev, "Cannot claim QSPI clock.\n");
                ret = PTR_ERR(cqspi->clk);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap controller address. */
@@ -1596,7 +1595,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->iobase)) {
                dev_err(dev, "Cannot remap controller address.\n");
                ret = PTR_ERR(cqspi->iobase);
-               goto probe_master_put;
+               return ret;
        }
 
        /* Obtain and remap AHB address. */
@@ -1605,7 +1604,7 @@ static int cqspi_probe(struct platform_device *pdev)
        if (IS_ERR(cqspi->ahb_base)) {
                dev_err(dev, "Cannot remap AHB address.\n");
                ret = PTR_ERR(cqspi->ahb_base);
-               goto probe_master_put;
+               return ret;
        }
        cqspi->mmap_phys_base = (dma_addr_t)res_ahb->start;
        cqspi->ahb_size = resource_size(res_ahb);
@@ -1614,15 +1613,13 @@ static int cqspi_probe(struct platform_device *pdev)
 
        /* Obtain IRQ line. */
        irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               ret = -ENXIO;
-               goto probe_master_put;
-       }
+       if (irq < 0)
+               return -ENXIO;
 
        pm_runtime_enable(dev);
        ret = pm_runtime_resume_and_get(dev);
        if (ret < 0)
-               goto probe_master_put;
+               return ret;
 
        ret = clk_prepare_enable(cqspi->clk);
        if (ret) {
@@ -1716,8 +1713,6 @@ probe_reset_failed:
 probe_clk_failed:
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
-probe_master_put:
-       spi_master_put(master);
        return ret;
 }
 
index 3384452..02fdef7 100644 (file)
@@ -2632,7 +2632,7 @@ static void hfa384x_usbctlx_reaper_task(struct work_struct *work)
  */
 static void hfa384x_usbctlx_completion_task(struct work_struct *work)
 {
-       struct hfa384x *hw = container_of(work, struct hfa384x, reaper_bh);
+       struct hfa384x *hw = container_of(work, struct hfa384x, completion_bh);
        struct hfa384x_usbctlx *ctlx, *temp;
        unsigned long flags;
 
index e68f1cc..6c8d8b0 100644 (file)
@@ -448,6 +448,9 @@ fd_execute_write_same(struct se_cmd *cmd)
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
 
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        if (cmd->t_data_nents > 1 ||
            cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) {
                pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
index 378c803..1ed9381 100644 (file)
@@ -494,6 +494,10 @@ iblock_execute_write_same(struct se_cmd *cmd)
                       " backends not supported\n");
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
+
+       if (!cmd->t_data_nents)
+               return TCM_INVALID_CDB_FIELD;
+
        sg = &cmd->t_data_sg[0];
 
        if (cmd->t_data_nents > 1 ||
index ca1b231..f613283 100644 (file)
@@ -312,6 +312,12 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char flags, struct sbc_ops *op
                pr_warn("WRITE SAME with ANCHOR not supported\n");
                return TCM_INVALID_CDB_FIELD;
        }
+
+       if (flags & 0x01) {
+               pr_warn("WRITE SAME with NDOB not supported\n");
+               return TCM_INVALID_CDB_FIELD;
+       }
+
        /*
         * Special case for WRITE_SAME w/ UNMAP=1 that ends up getting
         * translated into block discard requests within backend code.
index c60896c..73b5e77 100644 (file)
@@ -189,7 +189,7 @@ struct optee_smc_call_get_os_revision_result {
  * Have config return register usage:
  * a0  OPTEE_SMC_RETURN_OK
  * a1  Physical address of start of SHM
- * a2  Size of of SHM
+ * a2  Size of SHM
  * a3  Cache settings of memory, as defined by the
  *     OPTEE_SMC_SHM_* values above
  * a4-7        Preserved
index 385cb0a..a1c1fa1 100644 (file)
@@ -884,8 +884,8 @@ static int optee_smc_do_call_with_arg(struct tee_context *ctx,
 
                rpc_arg_offs = OPTEE_MSG_GET_ARG_SIZE(arg->num_params);
                rpc_arg = tee_shm_get_va(shm, offs + rpc_arg_offs);
-               if (IS_ERR(arg))
-                       return PTR_ERR(arg);
+               if (IS_ERR(rpc_arg))
+                       return PTR_ERR(rpc_arg);
        }
 
        if  (rpc_arg && tee_shm_is_dynamic(shm)) {
index af0f7c6..98da206 100644 (file)
@@ -1073,7 +1073,7 @@ EXPORT_SYMBOL_GPL(tee_device_unregister);
 /**
  * tee_get_drvdata() - Return driver_data pointer
  * @teedev:    Device containing the driver_data pointer
- * @returns the driver_data pointer supplied to tee_register().
+ * @returns the driver_data pointer supplied to tee_device_alloc().
  */
 void *tee_get_drvdata(struct tee_device *teedev)
 {
index 74bfabe..752dab3 100644 (file)
@@ -111,21 +111,11 @@ static void pty_unthrottle(struct tty_struct *tty)
 static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c)
 {
        struct tty_struct *to = tty->link;
-       unsigned long flags;
 
-       if (tty->flow.stopped)
+       if (tty->flow.stopped || !c)
                return 0;
 
-       if (c > 0) {
-               spin_lock_irqsave(&to->port->lock, flags);
-               /* Stuff the data into the input queue of the other end */
-               c = tty_insert_flip_string(to->port, buf, c);
-               spin_unlock_irqrestore(&to->port->lock, flags);
-               /* And shovel */
-               if (c)
-                       tty_flip_buffer_push(to->port);
-       }
-       return c;
+       return tty_insert_flip_string_and_push_buffer(to->port, buf, c);
 }
 
 /**
index cfbd2de..3f56dbc 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/sysrq.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/tty.h>
 #include <linux/ratelimit.h>
 #include <linux/tty_flip.h>
@@ -559,6 +560,9 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev)
 
                up->port.dev = dev;
 
+               if (uart_console_enabled(&up->port))
+                       pm_runtime_get_sync(up->port.dev);
+
                serial8250_apply_quirks(up);
                uart_add_one_port(drv, &up->port);
        }
index 7133fce..a8dba4a 100644 (file)
@@ -106,10 +106,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
                                   UART_XMIT_SIZE, DMA_TO_DEVICE);
 
        dma_async_issue_pending(dma->txchan);
-       if (dma->tx_err) {
+       serial8250_clear_THRI(p);
+       if (dma->tx_err)
                dma->tx_err = 0;
-               serial8250_clear_THRI(p);
-       }
+
        return 0;
 err:
        dma->tx_err = 1;
index f57bbd3..bb6aca0 100644 (file)
@@ -47,7 +47,7 @@
 #define RZN1_UART_xDMACR_DMA_EN                BIT(0)
 #define RZN1_UART_xDMACR_1_WORD_BURST  (0 << 1)
 #define RZN1_UART_xDMACR_4_WORD_BURST  (1 << 1)
-#define RZN1_UART_xDMACR_8_WORD_BURST  (3 << 1)
+#define RZN1_UART_xDMACR_8_WORD_BURST  (2 << 1)
 #define RZN1_UART_xDMACR_BLK_SZ(x)     ((x) << 3)
 
 /* Quirks */
@@ -773,18 +773,18 @@ static const struct of_device_id dw8250_of_match[] = {
 MODULE_DEVICE_TABLE(of, dw8250_of_match);
 
 static const struct acpi_device_id dw8250_acpi_match[] = {
-       { "INT33C4", 0 },
-       { "INT33C5", 0 },
-       { "INT3434", 0 },
-       { "INT3435", 0 },
-       { "80860F0A", 0 },
-       { "8086228A", 0 },
-       { "APMC0D08", 0},
-       { "AMD0020", 0 },
-       { "AMDI0020", 0 },
-       { "AMDI0022", 0 },
-       { "BRCM2032", 0 },
-       { "HISI0031", 0 },
+       { "80860F0A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "8086228A", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMD0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0020", (kernel_ulong_t)&dw8250_dw_apb },
+       { "AMDI0022", (kernel_ulong_t)&dw8250_dw_apb },
+       { "APMC0D08", (kernel_ulong_t)&dw8250_dw_apb},
+       { "BRCM2032", (kernel_ulong_t)&dw8250_dw_apb },
+       { "HISI0031", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C4", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT33C5", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3434", (kernel_ulong_t)&dw8250_dw_apb },
+       { "INT3435", (kernel_ulong_t)&dw8250_dw_apb },
        { },
 };
 MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
index 8f32fe9..3c36a06 100644 (file)
@@ -1949,7 +1949,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir)
        if ((status & UART_LSR_THRE) && (up->ier & UART_IER_THRI)) {
                if (!up->dma || up->dma->tx_err)
                        serial8250_tx_chars(up);
-               else
+               else if (!up->dma->tx_running)
                        __stop_tx(up);
        }
 
@@ -2975,8 +2975,10 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
        case UPIO_MEM32BE:
        case UPIO_MEM16:
        case UPIO_MEM:
-               if (!port->mapbase)
+               if (!port->mapbase) {
+                       ret = -EINVAL;
                        break;
+               }
 
                if (!request_mem_region(port->mapbase, size, "serial")) {
                        ret = -EBUSY;
index 97ef41c..16a2142 100644 (file)
@@ -1367,6 +1367,15 @@ static void pl011_stop_rx(struct uart_port *port)
        pl011_dma_rx_stop(uap);
 }
 
+static void pl011_throttle_rx(struct uart_port *port)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       pl011_stop_rx(port);
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
 static void pl011_enable_ms(struct uart_port *port)
 {
        struct uart_amba_port *uap =
@@ -1788,9 +1797,10 @@ static int pl011_allocate_irq(struct uart_amba_port *uap)
  */
 static void pl011_enable_interrupts(struct uart_amba_port *uap)
 {
+       unsigned long flags;
        unsigned int i;
 
-       spin_lock_irq(&uap->port.lock);
+       spin_lock_irqsave(&uap->port.lock, flags);
 
        /* Clear out any spuriously appearing RX interrupts */
        pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR);
@@ -1812,7 +1822,14 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap)
        if (!pl011_dma_rx_running(uap))
                uap->im |= UART011_RXIM;
        pl011_write(uap->im, uap, REG_IMSC);
-       spin_unlock_irq(&uap->port.lock);
+       spin_unlock_irqrestore(&uap->port.lock, flags);
+}
+
+static void pl011_unthrottle_rx(struct uart_port *port)
+{
+       struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port);
+
+       pl011_enable_interrupts(uap);
 }
 
 static int pl011_startup(struct uart_port *port)
@@ -2225,6 +2242,8 @@ static const struct uart_ops amba_pl011_pops = {
        .stop_tx        = pl011_stop_tx,
        .start_tx       = pl011_start_tx,
        .stop_rx        = pl011_stop_rx,
+       .throttle       = pl011_throttle_rx,
+       .unthrottle     = pl011_unthrottle_rx,
        .enable_ms      = pl011_enable_ms,
        .break_ctl      = pl011_break_ctl,
        .startup        = pl011_startup,
index 0429c2a..93489fe 100644 (file)
@@ -470,14 +470,14 @@ static void mvebu_uart_shutdown(struct uart_port *port)
        }
 }
 
-static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
+static unsigned int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
 {
        unsigned int d_divisor, m_divisor;
        unsigned long flags;
        u32 brdv, osamp;
 
        if (!port->uartclk)
-               return -EOPNOTSUPP;
+               return 0;
 
        /*
         * The baudrate is derived from the UART clock thanks to divisors:
@@ -548,7 +548,7 @@ static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud)
                        (m_divisor << 16) | (m_divisor << 24);
        writel(osamp, port->membase + UART_OSAMP);
 
-       return 0;
+       return DIV_ROUND_CLOSEST(port->uartclk, d_divisor * m_divisor);
 }
 
 static void mvebu_uart_set_termios(struct uart_port *port,
@@ -587,15 +587,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
        max_baud = port->uartclk / 80;
 
        baud = uart_get_baud_rate(port, termios, old, min_baud, max_baud);
-       if (mvebu_uart_baud_rate_set(port, baud)) {
-               /* No clock available, baudrate cannot be changed */
-               if (old)
-                       baud = uart_get_baud_rate(port, old, NULL,
-                                                 min_baud, max_baud);
-       } else {
-               tty_termios_encode_baud_rate(termios, baud, baud);
-               uart_update_timeout(port, termios->c_cflag, baud);
-       }
+       baud = mvebu_uart_baud_rate_set(port, baud);
+
+       /* In case baudrate cannot be changed, report previous old value */
+       if (baud == 0 && old)
+               baud = tty_termios_baud_rate(old);
 
        /* Only the following flag changes are supported */
        if (old) {
@@ -606,6 +602,11 @@ static void mvebu_uart_set_termios(struct uart_port *port,
                termios->c_cflag |= CS8;
        }
 
+       if (baud != 0) {
+               tty_termios_encode_baud_rate(termios, baud, baud);
+               uart_update_timeout(port, termios->c_cflag, baud);
+       }
+
        spin_unlock_irqrestore(&port->lock, flags);
 }
 
index d5ca904..1afe47b 100644 (file)
@@ -377,8 +377,7 @@ static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
        /* Enable tx dma mode */
        ucon = rd_regl(port, S3C2410_UCON);
        ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
-       ucon |= (dma_get_cache_alignment() >= 16) ?
-               S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+       ucon |= S3C64XX_UCON_TXBURST_1;
        ucon |= S3C64XX_UCON_TXMODE_DMA;
        wr_regl(port,  S3C2410_UCON, ucon);
 
@@ -674,7 +673,7 @@ static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
                        S3C64XX_UCON_DMASUS_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
                        S3C64XX_UCON_RXMODE_MASK);
-       ucon |= S3C64XX_UCON_RXBURST_16 |
+       ucon |= S3C64XX_UCON_RXBURST_1 |
                        0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
                        S3C64XX_UCON_EMPTYINT_EN |
                        S3C64XX_UCON_TIMEOUT_EN |
index 338ebad..3dc926d 100644 (file)
@@ -1941,11 +1941,6 @@ static int uart_proc_show(struct seq_file *m, void *v)
 }
 #endif
 
-static inline bool uart_console_enabled(struct uart_port *port)
-{
-       return uart_console(port) && (port->cons->flags & CON_ENABLED);
-}
-
 static void uart_port_spin_lock_init(struct uart_port *port)
 {
        spin_lock_init(&port->lock);
index b7b44f4..0973b03 100644 (file)
@@ -72,6 +72,8 @@ static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE,
        *cr3 |= USART_CR3_DEM;
        over8 = *cr1 & USART_CR1_OVER8;
 
+       *cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK);
+
        if (over8)
                rs485_deat_dedt = delay_ADE * baud * 8;
        else
index b710c5e..f310a82 100644 (file)
@@ -111,4 +111,7 @@ static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
 
 ssize_t redirected_tty_write(struct kiocb *, struct iov_iter *);
 
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t cnt);
+
 #endif
index bfa431a..595d8b4 100644 (file)
@@ -532,6 +532,15 @@ static void flush_to_ldisc(struct work_struct *work)
 
 }
 
+static inline void tty_flip_buffer_commit(struct tty_buffer *tail)
+{
+       /*
+        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
+        * buffer data.
+        */
+       smp_store_release(&tail->commit, tail->used);
+}
+
 /**
  * tty_flip_buffer_push                -       push terminal buffers
  * @port: tty port to push
@@ -546,16 +555,43 @@ void tty_flip_buffer_push(struct tty_port *port)
 {
        struct tty_bufhead *buf = &port->buf;
 
-       /*
-        * Paired w/ acquire in flush_to_ldisc(); ensures flush_to_ldisc() sees
-        * buffer data.
-        */
-       smp_store_release(&buf->tail->commit, buf->tail->used);
+       tty_flip_buffer_commit(buf->tail);
        queue_work(system_unbound_wq, &buf->work);
 }
 EXPORT_SYMBOL(tty_flip_buffer_push);
 
 /**
+ * tty_insert_flip_string_and_push_buffer - add characters to the tty buffer and
+ *     push
+ * @port: tty port
+ * @chars: characters
+ * @size: size
+ *
+ * The function combines tty_insert_flip_string() and tty_flip_buffer_push()
+ * with the exception of properly holding the @port->lock.
+ *
+ * To be used only internally (by pty currently).
+ *
+ * Returns: the number added.
+ */
+int tty_insert_flip_string_and_push_buffer(struct tty_port *port,
+               const unsigned char *chars, size_t size)
+{
+       struct tty_bufhead *buf = &port->buf;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+       size = tty_insert_flip_string(port, chars, size);
+       if (size)
+               tty_flip_buffer_commit(buf->tail);
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       queue_work(system_unbound_wq, &buf->work);
+
+       return size;
+}
+
+/**
  * tty_buffer_init             -       prepare a tty buffer structure
  * @port: tty port to initialise
  *
index f8c87c4..dfc1f4b 100644 (file)
@@ -855,7 +855,7 @@ static void delete_char(struct vc_data *vc, unsigned int nr)
        unsigned short *p = (unsigned short *) vc->vc_pos;
 
        vc_uniscr_delete(vc, nr);
-       scr_memcpyw(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
+       scr_memmovew(p, p + nr, (vc->vc_cols - vc->state.x - nr) * 2);
        scr_memsetw(p + vc->vc_cols - vc->state.x - nr, vc->vc_video_erase_char,
                        nr * 2);
        vc->vc_need_wrap = 0;
index ce86d1b..c7b3374 100644 (file)
@@ -5738,7 +5738,7 @@ int ufshcd_wb_toggle(struct ufs_hba *hba, bool enable)
        }
 
        hba->dev_info.wb_enabled = enable;
-       dev_info(hba->dev, "%s Write Booster %s\n",
+       dev_dbg(hba->dev, "%s Write Booster %s\n",
                        __func__, enable ? "enabled" : "disabled");
 
        return ret;
@@ -7253,7 +7253,7 @@ static int ufshcd_host_reset_and_restore(struct ufs_hba *hba)
        hba->silence_err_logs = false;
 
        /* scale up clocks to max frequency before full reinitialization */
-       ufshcd_set_clk_freq(hba, true);
+       ufshcd_scale_clks(hba, true);
 
        err = ufshcd_hba_enable(hba);
 
index fea7aca..173cf35 100644 (file)
@@ -195,8 +195,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
 
        if (i == ARRAY_SIZE(dwc3_ti_rate_table)) {
                dev_err(dev, "unsupported usb2_refclk rate: %lu KHz\n", rate);
-               ret = -EINVAL;
-               goto err_clk_disable;
+               return -EINVAL;
        }
 
        data->rate_code = i;
@@ -204,7 +203,7 @@ static int dwc3_ti_probe(struct platform_device *pdev)
        /* Read the syscon property and set the rate code */
        ret = phy_syscon_pll_refclk(data);
        if (ret)
-               goto err_clk_disable;
+               return ret;
 
        /* VBUS divider select */
        data->vbus_divider = device_property_read_bool(dev, "ti,vbus-divider");
@@ -245,8 +244,6 @@ err_pm_disable:
        clk_disable_unprepare(data->usb2_refclk);
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
-err_clk_disable:
-       clk_put(data->usb2_refclk);
        return ret;
 }
 
@@ -276,7 +273,6 @@ static int dwc3_ti_remove(struct platform_device *pdev)
        pm_runtime_disable(dev);
        pm_runtime_set_suspended(dev);
 
-       clk_put(data->usb2_refclk);
        platform_set_drvdata(pdev, NULL);
        return 0;
 }
index 8716bec..0d89dfa 100644 (file)
@@ -4249,7 +4249,6 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
        }
 
        evt->count = 0;
-       evt->flags &= ~DWC3_EVENT_PENDING;
        ret = IRQ_HANDLED;
 
        /* Unmask interrupt */
@@ -4261,6 +4260,9 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
                dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
        }
 
+       /* Keep the clearing of DWC3_EVENT_PENDING at the end */
+       evt->flags &= ~DWC3_EVENT_PENDING;
+
        return ret;
 }
 
index e5a6b6e..4303a32 100644 (file)
@@ -2371,6 +2371,7 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                                          const char *page, size_t len) \
 {                                                                      \
        struct f_uvc_opts *opts = to_f_uvc_opts(item);                  \
+       int size = min(sizeof(opts->aname), len + 1);                   \
        int ret = 0;                                                    \
                                                                        \
        mutex_lock(&opts->lock);                                        \
@@ -2379,8 +2380,9 @@ static ssize_t f_uvc_opts_string_##cname##_store(struct config_item *item,\
                goto end;                                               \
        }                                                               \
                                                                        \
-       ret = snprintf(opts->aname, min(sizeof(opts->aname), len),      \
-                       "%s", page);                                    \
+       ret = strscpy(opts->aname, page, size);                         \
+       if (ret == -E2BIG)                                              \
+               ret = size - 1;                                         \
                                                                        \
 end:                                                                   \
        mutex_unlock(&opts->lock);                                      \
index 385be30..896c0d1 100644 (file)
@@ -76,14 +76,9 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res) {
-               dev_err(&pdev->dev,
-                       "Found HC with no IRQ. Check %s setup!\n",
-                       dev_name(&pdev->dev));
-               return -ENODEV;
-       }
-       irq = res->start;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        hcd = __usb_create_hcd(&fsl_ehci_hc_driver, pdev->dev.parent,
                               &pdev->dev, dev_name(&pdev->dev), NULL);
index 44a7e58..e5df175 100644 (file)
@@ -112,6 +112,9 @@ static struct platform_device *fsl_usb2_device_register(
                        goto error;
        }
 
+       pdev->dev.of_node = ofdev->dev.of_node;
+       pdev->dev.of_node_reused = true;
+
        retval = platform_device_add(pdev);
        if (retval)
                goto error;
index b440d33..d5a3986 100644 (file)
@@ -1023,6 +1023,9 @@ static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_DISPLAY_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_LITE_PID) },
        { USB_DEVICE(FTDI_VID, CHETCO_SEASMART_ANALOG_PID) },
+       /* Belimo Automation devices */
+       { USB_DEVICE(FTDI_VID, BELIMO_ZTH_PID) },
+       { USB_DEVICE(FTDI_VID, BELIMO_ZIP_PID) },
        /* ICP DAS I-756xU devices */
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7560U_PID) },
        { USB_DEVICE(ICPDAS_VID, ICPDAS_I7561U_PID) },
index d1a9564..4e92c16 100644 (file)
 #define CHETCO_SEASMART_ANALOG_PID     0xA5AF /* SeaSmart Analog Adapter */
 
 /*
+ * Belimo Automation
+ */
+#define BELIMO_ZTH_PID                 0x8050
+#define BELIMO_ZIP_PID                 0xC811
+
+/*
  * Unjo AB
  */
 #define UNJO_VID                       0x22B7
index ee0e520..c472475 100644 (file)
@@ -1718,6 +1718,7 @@ void typec_set_pwr_opmode(struct typec_port *port,
                        partner->usb_pd = 1;
                        sysfs_notify(&partner_dev->kobj, NULL,
                                     "supports_usb_power_delivery");
+                       kobject_uevent(&partner_dev->kobj, KOBJ_CHANGE);
                }
                put_device(partner_dev);
        }
index 61e71c1..e60b06f 100644 (file)
@@ -549,6 +549,16 @@ static struct vfio_group *vfio_group_find_or_alloc(struct device *dev)
        if (!iommu_group)
                return ERR_PTR(-EINVAL);
 
+       /*
+        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
+        * restore cache coherency. It has to be checked here because it is only
+        * valid for cases where we are using iommu groups.
+        */
+       if (!iommu_capable(dev->bus, IOMMU_CAP_CACHE_COHERENCY)) {
+               iommu_group_put(iommu_group);
+               return ERR_PTR(-EINVAL);
+       }
+
        group = vfio_group_get_from_iommu(iommu_group);
        if (!group)
                group = vfio_create_group(iommu_group, VFIO_IOMMU);
@@ -601,13 +611,6 @@ static int __vfio_register_dev(struct vfio_device *device,
 
 int vfio_register_group_dev(struct vfio_device *device)
 {
-       /*
-        * VFIO always sets IOMMU_CACHE because we offer no way for userspace to
-        * restore cache coherency.
-        */
-       if (!iommu_capable(device->dev->bus, IOMMU_CAP_CACHE_COHERENCY))
-               return -EINVAL;
-
        return __vfio_register_dev(device,
                vfio_group_find_or_alloc(device->dev));
 }
index c4e9171..1a9aa12 100644 (file)
@@ -2469,6 +2469,11 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
        if (charcount != 256 && charcount != 512)
                return -EINVAL;
 
+       /* font bigger than screen resolution ? */
+       if (w > FBCON_SWAP(info->var.rotate, info->var.xres, info->var.yres) ||
+           h > FBCON_SWAP(info->var.rotate, info->var.yres, info->var.xres))
+               return -EINVAL;
+
        /* Make sure drawing engine can handle the font */
        if (!(info->pixmap.blit_x & (1 << (font->width - 1))) ||
            !(info->pixmap.blit_y & (1 << (font->height - 1))))
@@ -2731,6 +2736,34 @@ void fbcon_update_vcs(struct fb_info *info, bool all)
 }
 EXPORT_SYMBOL(fbcon_update_vcs);
 
+/* let fbcon check if it supports a new screen resolution */
+int fbcon_modechange_possible(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+       struct fbcon_ops *ops = info->fbcon_par;
+       struct vc_data *vc;
+       unsigned int i;
+
+       WARN_CONSOLE_UNLOCKED();
+
+       if (!ops)
+               return 0;
+
+       /* prevent setting a screen size which is smaller than font size */
+       for (i = first_fb_vc; i <= last_fb_vc; i++) {
+               vc = vc_cons[i].d;
+               if (!vc || vc->vc_mode != KD_TEXT ||
+                          fbcon_info_from_console(i) != info)
+                       continue;
+
+               if (vc->vc_font.width  > FBCON_SWAP(var->rotate, var->xres, var->yres) ||
+                   vc->vc_font.height > FBCON_SWAP(var->rotate, var->yres, var->xres))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(fbcon_modechange_possible);
+
 int fbcon_mode_deleted(struct fb_info *info,
                       struct fb_videomode *mode)
 {
index 8afc453..7ee6eb2 100644 (file)
@@ -511,7 +511,7 @@ static int fb_show_logo_line(struct fb_info *info, int rotate,
 
                while (n && (n * (logo->width + 8) - 8 > xres))
                        --n;
-               image.dx = (xres - n * (logo->width + 8) - 8) / 2;
+               image.dx = (xres - (n * (logo->width + 8) - 8)) / 2;
                image.dy = y ?: (yres - logo->height) / 2;
        } else {
                image.dx = 0;
@@ -1017,6 +1017,16 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
        if (ret)
                return ret;
 
+       /* verify that virtual resolution >= physical resolution */
+       if (var->xres_virtual < var->xres ||
+           var->yres_virtual < var->yres) {
+               pr_warn("WARNING: fbcon: Driver '%s' missed to adjust virtual screen size (%ux%u vs. %ux%u)\n",
+                       info->fix.id,
+                       var->xres_virtual, var->yres_virtual,
+                       var->xres, var->yres);
+               return -EINVAL;
+       }
+
        if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
                return 0;
 
@@ -1107,7 +1117,9 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
                        return -EFAULT;
                console_lock();
                lock_fb_info(info);
-               ret = fb_set_var(info, &var);
+               ret = fbcon_modechange_possible(info, &var);
+               if (!ret)
+                       ret = fb_set_var(info, &var);
                if (!ret)
                        fbcon_update_vcs(info, var.activate & FB_ACTIVATE_ALL);
                unlock_fb_info(info);
index 4b56c39..84b143e 100644 (file)
@@ -396,13 +396,15 @@ static void __unmap_grant_pages_done(int result,
        unsigned int offset = data->unmap_ops - map->unmap_ops;
 
        for (i = 0; i < data->count; i++) {
-               WARN_ON(map->unmap_ops[offset+i].status);
+               WARN_ON(map->unmap_ops[offset + i].status != GNTST_okay &&
+                       map->unmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                pr_debug("unmap handle=%d st=%d\n",
                        map->unmap_ops[offset+i].handle,
                        map->unmap_ops[offset+i].status);
                map->unmap_ops[offset+i].handle = INVALID_GRANT_HANDLE;
                if (use_ptemod) {
-                       WARN_ON(map->kunmap_ops[offset+i].status);
+                       WARN_ON(map->kunmap_ops[offset + i].status != GNTST_okay &&
+                               map->kunmap_ops[offset + i].handle != INVALID_GRANT_HANDLE);
                        pr_debug("kunmap handle=%u st=%d\n",
                                 map->kunmap_ops[offset+i].handle,
                                 map->kunmap_ops[offset+i].status);
index 42118a4..d1cfb23 100644 (file)
@@ -375,7 +375,7 @@ static int afs_begin_cache_operation(struct netfs_io_request *rreq)
 }
 
 static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata)
+                                struct folio **foliop, void **_fsdata)
 {
        struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
 
index 415bf18..9c21e21 100644 (file)
@@ -675,9 +675,8 @@ struct btrfs_fs_info {
        rwlock_t global_root_lock;
        struct rb_root global_root_tree;
 
-       /* The xarray that holds all the FS roots */
-       spinlock_t fs_roots_lock;
-       struct xarray fs_roots;
+       spinlock_t fs_roots_radix_lock;
+       struct radix_tree_root fs_roots_radix;
 
        /* block group cache stuff */
        rwlock_t block_group_cache_lock;
@@ -995,10 +994,10 @@ struct btrfs_fs_info {
 
        struct btrfs_delayed_root *delayed_root;
 
-       /* Extent buffer xarray */
+       /* Extent buffer radix tree */
        spinlock_t buffer_lock;
        /* Entries are eb->start / sectorsize */
-       struct xarray extent_buffers;
+       struct radix_tree_root buffer_radix;
 
        /* next backup root to be overwritten */
        int backup_root_index;
@@ -1119,8 +1118,7 @@ enum {
         */
        BTRFS_ROOT_SHAREABLE,
        BTRFS_ROOT_TRACK_DIRTY,
-       /* The root is tracked in fs_info::fs_roots */
-       BTRFS_ROOT_REGISTERED,
+       BTRFS_ROOT_IN_RADIX,
        BTRFS_ROOT_ORPHAN_ITEM_INSERTED,
        BTRFS_ROOT_DEFRAG_RUNNING,
        BTRFS_ROOT_FORCE_COW,
@@ -1224,10 +1222,10 @@ struct btrfs_root {
        struct rb_root inode_tree;
 
        /*
-        * Xarray that keeps track of delayed nodes of every inode, protected
-        * by inode_lock
+        * radix tree that keeps track of delayed nodes of every inode,
+        * protected by inode_lock
         */
-       struct xarray delayed_nodes;
+       struct radix_tree_root delayed_nodes_tree;
        /*
         * right now this just gets used so that a root has its own devid
         * for stat.  It may be used for more later
index 66779ab..748bf6b 100644 (file)
@@ -78,7 +78,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
        }
 
        spin_lock(&root->inode_lock);
-       node = xa_load(&root->delayed_nodes, ino);
+       node = radix_tree_lookup(&root->delayed_nodes_tree, ino);
 
        if (node) {
                if (btrfs_inode->delayed_node) {
@@ -90,9 +90,9 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
 
                /*
                 * It's possible that we're racing into the middle of removing
-                * this node from the xarray.  In this case, the refcount
+                * this node from the radix tree.  In this case, the refcount
                 * was zero and it should never go back to one.  Just return
-                * NULL like it was never in the xarray at all; our release
+                * NULL like it was never in the radix at all; our release
                 * function is in the process of removing it.
                 *
                 * Some implementations of refcount_inc refuse to bump the
@@ -100,7 +100,7 @@ static struct btrfs_delayed_node *btrfs_get_delayed_node(
                 * here, refcount_inc() may decide to just WARN_ONCE() instead
                 * of actually bumping the refcount.
                 *
-                * If this node is properly in the xarray, we want to bump the
+                * If this node is properly in the radix, we want to bump the
                 * refcount twice, once for the inode and once for this get
                 * operation.
                 */
@@ -128,30 +128,36 @@ static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node(
        u64 ino = btrfs_ino(btrfs_inode);
        int ret;
 
-       do {
-               node = btrfs_get_delayed_node(btrfs_inode);
-               if (node)
-                       return node;
+again:
+       node = btrfs_get_delayed_node(btrfs_inode);
+       if (node)
+               return node;
 
-               node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
-               if (!node)
-                       return ERR_PTR(-ENOMEM);
-               btrfs_init_delayed_node(node, root, ino);
+       node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS);
+       if (!node)
+               return ERR_PTR(-ENOMEM);
+       btrfs_init_delayed_node(node, root, ino);
 
-               /* Cached in the inode and can be accessed */
-               refcount_set(&node->refs, 2);
+       /* cached in the btrfs inode and can be accessed */
+       refcount_set(&node->refs, 2);
 
-               spin_lock(&root->inode_lock);
-               ret = xa_insert(&root->delayed_nodes, ino, node, GFP_NOFS);
-               if (ret) {
-                       spin_unlock(&root->inode_lock);
-                       kmem_cache_free(delayed_node_cache, node);
-                       if (ret != -EBUSY)
-                               return ERR_PTR(ret);
-               }
-       } while (ret);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               kmem_cache_free(delayed_node_cache, node);
+               return ERR_PTR(ret);
+       }
+
+       spin_lock(&root->inode_lock);
+       ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node);
+       if (ret == -EEXIST) {
+               spin_unlock(&root->inode_lock);
+               kmem_cache_free(delayed_node_cache, node);
+               radix_tree_preload_end();
+               goto again;
+       }
        btrfs_inode->delayed_node = node;
        spin_unlock(&root->inode_lock);
+       radix_tree_preload_end();
 
        return node;
 }
@@ -270,7 +276,8 @@ static void __btrfs_release_delayed_node(
                 * back up.  We can delete it now.
                 */
                ASSERT(refcount_read(&delayed_node->refs) == 0);
-               xa_erase(&root->delayed_nodes, delayed_node->inode_id);
+               radix_tree_delete(&root->delayed_nodes_tree,
+                                 delayed_node->inode_id);
                spin_unlock(&root->inode_lock);
                kmem_cache_free(delayed_node_cache, delayed_node);
        }
@@ -1863,35 +1870,34 @@ void btrfs_kill_delayed_inode_items(struct btrfs_inode *inode)
 
 void btrfs_kill_all_delayed_nodes(struct btrfs_root *root)
 {
-       unsigned long index = 0;
-       struct btrfs_delayed_node *delayed_node;
+       u64 inode_id = 0;
        struct btrfs_delayed_node *delayed_nodes[8];
+       int i, n;
 
        while (1) {
-               int n = 0;
-
                spin_lock(&root->inode_lock);
-               if (xa_empty(&root->delayed_nodes)) {
+               n = radix_tree_gang_lookup(&root->delayed_nodes_tree,
+                                          (void **)delayed_nodes, inode_id,
+                                          ARRAY_SIZE(delayed_nodes));
+               if (!n) {
                        spin_unlock(&root->inode_lock);
-                       return;
+                       break;
                }
 
-               xa_for_each_start(&root->delayed_nodes, index, delayed_node, index) {
+               inode_id = delayed_nodes[n - 1]->inode_id + 1;
+               for (i = 0; i < n; i++) {
                        /*
                         * Don't increase refs in case the node is dead and
                         * about to be removed from the tree in the loop below
                         */
-                       if (refcount_inc_not_zero(&delayed_node->refs)) {
-                               delayed_nodes[n] = delayed_node;
-                               n++;
-                       }
-                       if (n >= ARRAY_SIZE(delayed_nodes))
-                               break;
+                       if (!refcount_inc_not_zero(&delayed_nodes[i]->refs))
+                               delayed_nodes[i] = NULL;
                }
-               index++;
                spin_unlock(&root->inode_lock);
 
-               for (int i = 0; i < n; i++) {
+               for (i = 0; i < n; i++) {
+                       if (!delayed_nodes[i])
+                               continue;
                        __btrfs_kill_delayed_node(delayed_nodes[i]);
                        btrfs_release_delayed_node(delayed_nodes[i]);
                }
index 4ba005c..de440eb 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <linux/fs.h>
 #include <linux/blkdev.h>
+#include <linux/radix-tree.h>
 #include <linux/writeback.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
@@ -485,7 +486,7 @@ static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info,
                uptodate = btrfs_subpage_test_uptodate(fs_info, page, cur,
                                                       fs_info->nodesize);
 
-               /* A dirty eb shouldn't disappear from extent_buffers */
+               /* A dirty eb shouldn't disappear from buffer_radix */
                if (WARN_ON(!eb))
                        return -EUCLEAN;
 
@@ -1158,7 +1159,7 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        root->nr_delalloc_inodes = 0;
        root->nr_ordered_extents = 0;
        root->inode_tree = RB_ROOT;
-       xa_init_flags(&root->delayed_nodes, GFP_ATOMIC);
+       INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC);
 
        btrfs_init_root_block_rsv(root);
 
@@ -1210,9 +1211,9 @@ static void __setup_root(struct btrfs_root *root, struct btrfs_fs_info *fs_info,
        btrfs_qgroup_init_swapped_blocks(&root->swapped_blocks);
 #ifdef CONFIG_BTRFS_DEBUG
        INIT_LIST_HEAD(&root->leak_list);
-       spin_lock(&fs_info->fs_roots_lock);
+       spin_lock(&fs_info->fs_roots_radix_lock);
        list_add_tail(&root->leak_list, &fs_info->allocated_roots);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 #endif
 }
 
@@ -1659,11 +1660,12 @@ static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
 {
        struct btrfs_root *root;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       root = xa_load(&fs_info->fs_roots, (unsigned long)root_id);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                (unsigned long)root_id);
        if (root)
                root = btrfs_grab_root(root);
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return root;
 }
 
@@ -1705,14 +1707,20 @@ int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       ret = xa_insert(&fs_info->fs_roots, (unsigned long)root->root_key.objectid,
-                       root, GFP_NOFS);
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret)
+               return ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       ret = radix_tree_insert(&fs_info->fs_roots_radix,
+                               (unsigned long)root->root_key.objectid,
+                               root);
        if (ret == 0) {
                btrfs_grab_root(root);
-               set_bit(BTRFS_ROOT_REGISTERED, &root->state);
+               set_bit(BTRFS_ROOT_IN_RADIX, &root->state);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
+       radix_tree_preload_end();
 
        return ret;
 }
@@ -2342,9 +2350,9 @@ void btrfs_put_root(struct btrfs_root *root)
                btrfs_drew_lock_destroy(&root->snapshot_lock);
                free_root_extent_buffers(root);
 #ifdef CONFIG_BTRFS_DEBUG
-               spin_lock(&root->fs_info->fs_roots_lock);
+               spin_lock(&root->fs_info->fs_roots_radix_lock);
                list_del_init(&root->leak_list);
-               spin_unlock(&root->fs_info->fs_roots_lock);
+               spin_unlock(&root->fs_info->fs_roots_radix_lock);
 #endif
                kfree(root);
        }
@@ -2352,21 +2360,28 @@ void btrfs_put_root(struct btrfs_root *root)
 
 void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *root;
-       unsigned long index = 0;
+       int ret;
+       struct btrfs_root *gang[8];
+       int i;
 
        while (!list_empty(&fs_info->dead_roots)) {
-               root = list_entry(fs_info->dead_roots.next,
-                                 struct btrfs_root, root_list);
-               list_del(&root->root_list);
+               gang[0] = list_entry(fs_info->dead_roots.next,
+                                    struct btrfs_root, root_list);
+               list_del(&gang[0]->root_list);
 
-               if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
-                       btrfs_drop_and_free_fs_root(fs_info, root);
-               btrfs_put_root(root);
+               if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state))
+                       btrfs_drop_and_free_fs_root(fs_info, gang[0]);
+               btrfs_put_root(gang[0]);
        }
 
-       xa_for_each(&fs_info->fs_roots, index, root) {
-               btrfs_drop_and_free_fs_root(fs_info, root);
+       while (1) {
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, 0,
+                                            ARRAY_SIZE(gang));
+               if (!ret)
+                       break;
+               for (i = 0; i < ret; i++)
+                       btrfs_drop_and_free_fs_root(fs_info, gang[i]);
        }
 }
 
@@ -3134,8 +3149,8 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
 
 void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
 {
-       xa_init_flags(&fs_info->fs_roots, GFP_ATOMIC);
-       xa_init_flags(&fs_info->extent_buffers, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
@@ -3143,7 +3158,7 @@ void btrfs_init_fs_info(struct btrfs_fs_info *fs_info)
        INIT_LIST_HEAD(&fs_info->caching_block_groups);
        spin_lock_init(&fs_info->delalloc_root_lock);
        spin_lock_init(&fs_info->trans_lock);
-       spin_lock_init(&fs_info->fs_roots_lock);
+       spin_lock_init(&fs_info->fs_roots_radix_lock);
        spin_lock_init(&fs_info->delayed_iput_lock);
        spin_lock_init(&fs_info->defrag_inodes_lock);
        spin_lock_init(&fs_info->super_lock);
@@ -3374,7 +3389,7 @@ int btrfs_start_pre_rw_mount(struct btrfs_fs_info *fs_info)
        /*
         * btrfs_find_orphan_roots() is responsible for finding all the dead
         * roots (with 0 refs), flag them with BTRFS_ROOT_DEAD_TREE and load
-        * them into the fs_info->fs_roots. This must be done before
+        * them into the fs_info->fs_roots_radix tree. This must be done before
         * calling btrfs_orphan_cleanup() on the tree root. If we don't do it
         * first, then btrfs_orphan_cleanup() will delete a dead root's orphan
         * item before the root's tree is deleted - this means that if we unmount
@@ -4499,11 +4514,12 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 {
        bool drop_ref = false;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_erase(&fs_info->fs_roots, (unsigned long)root->root_key.objectid);
-       if (test_and_clear_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_delete(&fs_info->fs_roots_radix,
+                         (unsigned long)root->root_key.objectid);
+       if (test_and_clear_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                drop_ref = true;
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 
        if (BTRFS_FS_ERROR(fs_info)) {
                ASSERT(root->log_root == NULL);
@@ -4519,48 +4535,50 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
 
 int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
 {
-       struct btrfs_root *roots[8];
-       unsigned long index = 0;
-       int i;
+       u64 root_objectid = 0;
+       struct btrfs_root *gang[8];
+       int i = 0;
        int err = 0;
-       int grabbed;
+       unsigned int ret = 0;
 
        while (1) {
-               struct btrfs_root *root;
-
-               spin_lock(&fs_info->fs_roots_lock);
-               if (!xa_find(&fs_info->fs_roots, &index, ULONG_MAX, XA_PRESENT)) {
-                       spin_unlock(&fs_info->fs_roots_lock);
-                       return err;
+               spin_lock(&fs_info->fs_roots_radix_lock);
+               ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang));
+               if (!ret) {
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+                       break;
                }
+               root_objectid = gang[ret - 1]->root_key.objectid + 1;
 
-               grabbed = 0;
-               xa_for_each_start(&fs_info->fs_roots, index, root, index) {
-                       /* Avoid grabbing roots in dead_roots */
-                       if (btrfs_root_refs(&root->root_item) > 0)
-                               roots[grabbed++] = btrfs_grab_root(root);
-                       if (grabbed >= ARRAY_SIZE(roots))
-                               break;
+               for (i = 0; i < ret; i++) {
+                       /* Avoid to grab roots in dead_roots */
+                       if (btrfs_root_refs(&gang[i]->root_item) == 0) {
+                               gang[i] = NULL;
+                               continue;
+                       }
+                       /* grab all the search result for later use */
+                       gang[i] = btrfs_grab_root(gang[i]);
                }
-               spin_unlock(&fs_info->fs_roots_lock);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       err = btrfs_orphan_cleanup(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       err = btrfs_orphan_cleanup(gang[i]);
                        if (err)
-                               goto out;
-                       btrfs_put_root(roots[i]);
+                               break;
+                       btrfs_put_root(gang[i]);
                }
-               index++;
+               root_objectid++;
        }
 
-out:
-       /* Release the roots that remain uncleaned due to error */
-       for (; i < grabbed; i++) {
-               if (roots[i])
-                       btrfs_put_root(roots[i]);
+       /* release the uncleaned roots due to error */
+       for (; i < ret; i++) {
+               if (gang[i])
+                       btrfs_put_root(gang[i]);
        }
        return err;
 }
@@ -4879,28 +4897,31 @@ static void btrfs_error_commit_super(struct btrfs_fs_info *fs_info)
 
 static void btrfs_drop_all_logs(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index = 0;
-       int grabbed = 0;
-       struct btrfs_root *roots[8];
+       struct btrfs_root *gang[8];
+       u64 root_objectid = 0;
+       int ret;
+
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while ((ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix,
+                                            (void **)gang, root_objectid,
+                                            ARRAY_SIZE(gang))) != 0) {
+               int i;
 
-       spin_lock(&fs_info->fs_roots_lock);
-       while ((grabbed = xa_extract(&fs_info->fs_roots, (void **)roots, index,
-                                    ULONG_MAX, 8, XA_PRESENT))) {
-               for (int i = 0; i < grabbed; i++)
-                       roots[i] = btrfs_grab_root(roots[i]);
-               spin_unlock(&fs_info->fs_roots_lock);
+               for (i = 0; i < ret; i++)
+                       gang[i] = btrfs_grab_root(gang[i]);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
 
-               for (int i = 0; i < grabbed; i++) {
-                       if (!roots[i])
+               for (i = 0; i < ret; i++) {
+                       if (!gang[i])
                                continue;
-                       index = roots[i]->root_key.objectid;
-                       btrfs_free_log(NULL, roots[i]);
-                       btrfs_put_root(roots[i]);
+                       root_objectid = gang[i]->root_key.objectid;
+                       btrfs_free_log(NULL, gang[i]);
+                       btrfs_put_root(gang[i]);
                }
-               index++;
-               spin_lock(&fs_info->fs_roots_lock);
+               root_objectid++;
+               spin_lock(&fs_info->fs_roots_radix_lock);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        btrfs_free_log_root_tree(NULL, fs_info);
 }
 
index 4157ecc..a3afc15 100644 (file)
@@ -5829,7 +5829,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, int update_ref, int for_reloc)
        btrfs_qgroup_convert_reserved_meta(root, INT_MAX);
        btrfs_qgroup_free_meta_all_pertrans(root);
 
-       if (test_bit(BTRFS_ROOT_REGISTERED, &root->state))
+       if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state))
                btrfs_add_dropped_root(trans, root);
        else
                btrfs_put_root(root);
index 04e3634..f03ab5d 100644 (file)
@@ -2966,7 +2966,7 @@ static void begin_page_read(struct btrfs_fs_info *fs_info, struct page *page)
 }
 
 /*
- * Find extent buffer for a given bytenr.
+ * Find extent buffer for a givne bytenr.
  *
  * This is for end_bio_extent_readpage(), thus we can't do any unsafe locking
  * in endio context.
@@ -2985,9 +2985,11 @@ static struct extent_buffer *find_extent_buffer_readpage(
                return (struct extent_buffer *)page->private;
        }
 
-       /* For subpage case, we need to lookup extent buffer xarray */
-       eb = xa_load(&fs_info->extent_buffers,
-                    bytenr >> fs_info->sectorsize_bits);
+       /* For subpage case, we need to lookup buffer radix tree */
+       rcu_read_lock();
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              bytenr >> fs_info->sectorsize_bits);
+       rcu_read_unlock();
        ASSERT(eb);
        return eb;
 }
@@ -4435,8 +4437,8 @@ static struct extent_buffer *find_extent_buffer_nolock(
        struct extent_buffer *eb;
 
        rcu_read_lock();
-       eb = xa_load(&fs_info->extent_buffers,
-                    start >> fs_info->sectorsize_bits);
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              start >> fs_info->sectorsize_bits);
        if (eb && atomic_inc_not_zero(&eb->refs)) {
                rcu_read_unlock();
                return eb;
@@ -6129,22 +6131,24 @@ struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
        if (!eb)
                return ERR_PTR(-ENOMEM);
        eb->fs_info = fs_info;
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
 
@@ -6319,22 +6323,25 @@ struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
        }
        if (uptodate)
                set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags);
-
-       do {
-               ret = xa_insert(&fs_info->extent_buffers,
-                               start >> fs_info->sectorsize_bits,
-                               eb, GFP_NOFS);
-               if (ret == -ENOMEM) {
-                       exists = ERR_PTR(ret);
+again:
+       ret = radix_tree_preload(GFP_NOFS);
+       if (ret) {
+               exists = ERR_PTR(ret);
+               goto free_eb;
+       }
+
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> fs_info->sectorsize_bits, eb);
+       spin_unlock(&fs_info->buffer_lock);
+       radix_tree_preload_end();
+       if (ret == -EEXIST) {
+               exists = find_extent_buffer(fs_info, start);
+               if (exists)
                        goto free_eb;
-               }
-               if (ret == -EBUSY) {
-                       exists = find_extent_buffer(fs_info, start);
-                       if (exists)
-                               goto free_eb;
-               }
-       } while (ret);
-
+               else
+                       goto again;
+       }
        /* add one reference for the tree */
        check_buffer_tree_ref(eb);
        set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
@@ -6379,8 +6386,10 @@ static int release_extent_buffer(struct extent_buffer *eb)
 
                        spin_unlock(&eb->refs_lock);
 
-                       xa_erase(&fs_info->extent_buffers,
-                                eb->start >> fs_info->sectorsize_bits);
+                       spin_lock(&fs_info->buffer_lock);
+                       radix_tree_delete(&fs_info->buffer_radix,
+                                         eb->start >> fs_info->sectorsize_bits);
+                       spin_unlock(&fs_info->buffer_lock);
                } else {
                        spin_unlock(&eb->refs_lock);
                }
@@ -7325,25 +7334,42 @@ void memmove_extent_buffer(const struct extent_buffer *dst,
        }
 }
 
+#define GANG_LOOKUP_SIZE       16
 static struct extent_buffer *get_next_extent_buffer(
                struct btrfs_fs_info *fs_info, struct page *page, u64 bytenr)
 {
-       struct extent_buffer *eb;
-       unsigned long index;
+       struct extent_buffer *gang[GANG_LOOKUP_SIZE];
+       struct extent_buffer *found = NULL;
        u64 page_start = page_offset(page);
+       u64 cur = page_start;
 
        ASSERT(in_range(bytenr, page_start, PAGE_SIZE));
        lockdep_assert_held(&fs_info->buffer_lock);
 
-       xa_for_each_start(&fs_info->extent_buffers, index, eb,
-                         page_start >> fs_info->sectorsize_bits) {
-               if (in_range(eb->start, page_start, PAGE_SIZE))
-                       return eb;
-               else if (eb->start >= page_start + PAGE_SIZE)
-                       /* Already beyond page end */
-                       return NULL;
+       while (cur < page_start + PAGE_SIZE) {
+               int ret;
+               int i;
+
+               ret = radix_tree_gang_lookup(&fs_info->buffer_radix,
+                               (void **)gang, cur >> fs_info->sectorsize_bits,
+                               min_t(unsigned int, GANG_LOOKUP_SIZE,
+                                     PAGE_SIZE / fs_info->nodesize));
+               if (ret == 0)
+                       goto out;
+               for (i = 0; i < ret; i++) {
+                       /* Already beyond page end */
+                       if (gang[i]->start >= page_start + PAGE_SIZE)
+                               goto out;
+                       /* Found one */
+                       if (gang[i]->start >= bytenr) {
+                               found = gang[i];
+                               goto out;
+                       }
+               }
+               cur = gang[ret - 1]->start + gang[ret - 1]->len;
        }
-       return NULL;
+out:
+       return found;
 }
 
 static int try_release_subpage_extent_buffer(struct page *page)
index 05e0c4a..d50448b 100644 (file)
@@ -3578,7 +3578,6 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
        u64 last_objectid = 0;
        int ret = 0, nr_unlink = 0;
 
-       /* Bail out if the cleanup is already running. */
        if (test_and_set_bit(BTRFS_ROOT_ORPHAN_CLEANUP, &root->state))
                return 0;
 
@@ -3661,17 +3660,17 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                         *
                         * btrfs_find_orphan_roots() ran before us, which has
                         * found all deleted roots and loaded them into
-                        * fs_info->fs_roots. So here we can find if an
+                        * fs_info->fs_roots_radix. So here we can find if an
                         * orphan item corresponds to a deleted root by looking
-                        * up the root from that xarray.
+                        * up the root from that radix tree.
                         */
 
-                       spin_lock(&fs_info->fs_roots_lock);
-                       dead_root = xa_load(&fs_info->fs_roots,
-                                           (unsigned long)found_key.objectid);
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       dead_root = radix_tree_lookup(&fs_info->fs_roots_radix,
+                                                        (unsigned long)found_key.objectid);
                        if (dead_root && btrfs_root_refs(&dead_root->root_item) == 0)
                                is_dead_root = 1;
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
 
                        if (is_dead_root) {
                                /* prevent this orphan from being found again */
@@ -3911,7 +3910,7 @@ cache_index:
         * cache.
         *
         * This is required for both inode re-read from disk and delayed inode
-        * in the delayed_nodes xarray.
+        * in delayed_nodes_tree.
         */
        if (BTRFS_I(inode)->last_trans == fs_info->generation)
                set_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
@@ -7681,7 +7680,19 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
        if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) ||
            em->block_start == EXTENT_MAP_INLINE) {
                free_extent_map(em);
-               ret = -ENOTBLK;
+               /*
+                * If we are in a NOWAIT context, return -EAGAIN in order to
+                * fallback to buffered IO. This is not only because we can
+                * block with buffered IO (no support for NOWAIT semantics at
+                * the moment) but also to avoid returning short reads to user
+                * space - this happens if we were able to read some data from
+                * previous non-compressed extents and then when we fallback to
+                * buffered IO, at btrfs_file_read_iter() by calling
+                * filemap_read(), we fail to fault in pages for the read buffer,
+                * in which case filemap_read() returns a short read (the number
+                * of bytes previously read is > 0, so it does not return -EFAULT).
+                */
+               ret = (flags & IOMAP_NOWAIT) ? -EAGAIN : -ENOTBLK;
                goto unlock_err;
        }
 
index fa56890..c7dea63 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/mount.h>
 #include <linux/xattr.h>
 #include <linux/posix_acl_xattr.h>
+#include <linux/radix-tree.h>
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/compat.h>
@@ -127,7 +128,7 @@ struct send_ctx {
        struct list_head new_refs;
        struct list_head deleted_refs;
 
-       struct xarray name_cache;
+       struct radix_tree_root name_cache;
        struct list_head name_cache_list;
        int name_cache_size;
 
@@ -268,13 +269,14 @@ struct orphan_dir_info {
 struct name_cache_entry {
        struct list_head list;
        /*
-        * On 32bit kernels, xarray has only 32bit indices, but we need to
-        * handle 64bit inums. We use the lower 32bit of the 64bit inum to store
-        * it in the tree. If more than one inum would fall into the same entry,
-        * we use inum_aliases to store the additional entries. inum_aliases is
-        * also used to store entries with the same inum but different generations.
+        * radix_tree has only 32bit entries but we need to handle 64bit inums.
+        * We use the lower 32bit of the 64bit inum to store it in the tree. If
+        * more then one inum would fall into the same entry, we use radix_list
+        * to store the additional entries. radix_list is also used to store
+        * entries where two entries have the same inum but different
+        * generations.
         */
-       struct list_head inum_aliases;
+       struct list_head radix_list;
        u64 ino;
        u64 gen;
        u64 parent_ino;
@@ -2024,9 +2026,9 @@ out:
 }
 
 /*
- * Insert a name cache entry. On 32bit kernels the xarray index is 32bit,
+ * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit,
  * so we need to do some special handling in case we have clashes. This function
- * takes care of this with the help of name_cache_entry::inum_aliases.
+ * takes care of this with the help of name_cache_entry::radix_list.
  * In case of error, nce is kfreed.
  */
 static int name_cache_insert(struct send_ctx *sctx,
@@ -2035,7 +2037,8 @@ static int name_cache_insert(struct send_ctx *sctx,
        int ret = 0;
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                nce_head = kmalloc(sizeof(*nce_head), GFP_KERNEL);
                if (!nce_head) {
@@ -2044,14 +2047,14 @@ static int name_cache_insert(struct send_ctx *sctx,
                }
                INIT_LIST_HEAD(nce_head);
 
-               ret = xa_insert(&sctx->name_cache, nce->ino, nce_head, GFP_KERNEL);
+               ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head);
                if (ret < 0) {
                        kfree(nce_head);
                        kfree(nce);
                        return ret;
                }
        }
-       list_add_tail(&nce->inum_aliases, nce_head);
+       list_add_tail(&nce->radix_list, nce_head);
        list_add_tail(&nce->list, &sctx->name_cache_list);
        sctx->name_cache_size++;
 
@@ -2063,14 +2066,15 @@ static void name_cache_delete(struct send_ctx *sctx,
 {
        struct list_head *nce_head;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)nce->ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache,
+                       (unsigned long)nce->ino);
        if (!nce_head) {
                btrfs_err(sctx->send_root->fs_info,
              "name_cache_delete lookup failed ino %llu cache size %d, leaking memory",
                        nce->ino, sctx->name_cache_size);
        }
 
-       list_del(&nce->inum_aliases);
+       list_del(&nce->radix_list);
        list_del(&nce->list);
        sctx->name_cache_size--;
 
@@ -2078,7 +2082,7 @@ static void name_cache_delete(struct send_ctx *sctx,
         * We may not get to the final release of nce_head if the lookup fails
         */
        if (nce_head && list_empty(nce_head)) {
-               xa_erase(&sctx->name_cache, (unsigned long)nce->ino);
+               radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino);
                kfree(nce_head);
        }
 }
@@ -2089,11 +2093,11 @@ static struct name_cache_entry *name_cache_search(struct send_ctx *sctx,
        struct list_head *nce_head;
        struct name_cache_entry *cur;
 
-       nce_head = xa_load(&sctx->name_cache, (unsigned long)ino);
+       nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino);
        if (!nce_head)
                return NULL;
 
-       list_for_each_entry(cur, nce_head, inum_aliases) {
+       list_for_each_entry(cur, nce_head, radix_list) {
                if (cur->ino == ino && cur->gen == gen)
                        return cur;
        }
@@ -7518,7 +7522,7 @@ long btrfs_ioctl_send(struct inode *inode, struct btrfs_ioctl_send_args *arg)
 
        INIT_LIST_HEAD(&sctx->new_refs);
        INIT_LIST_HEAD(&sctx->deleted_refs);
-       xa_init_flags(&sctx->name_cache, GFP_KERNEL);
+       INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL);
        INIT_LIST_HEAD(&sctx->name_cache_list);
 
        sctx->flags = arg->flags;
index 1591bfa..d8e56ed 100644 (file)
@@ -150,8 +150,8 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)
 
 void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 {
-       unsigned long index;
-       struct extent_buffer *eb;
+       struct radix_tree_iter iter;
+       void **slot;
        struct btrfs_device *dev, *tmp;
 
        if (!fs_info)
@@ -163,9 +163,25 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
 
        test_mnt->mnt_sb->s_fs_info = NULL;
 
-       xa_for_each(&fs_info->extent_buffers, index, eb) {
+       spin_lock(&fs_info->buffer_lock);
+       radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
+               struct extent_buffer *eb;
+
+               eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock);
+               if (!eb)
+                       continue;
+               /* Shouldn't happen but that kind of thinking creates CVE's */
+               if (radix_tree_exception(eb)) {
+                       if (radix_tree_deref_retry(eb))
+                               slot = radix_tree_iter_retry(&iter);
+                       continue;
+               }
+               slot = radix_tree_iter_resume(slot, &iter);
+               spin_unlock(&fs_info->buffer_lock);
                free_extent_buffer_stale(eb);
+               spin_lock(&fs_info->buffer_lock);
        }
+       spin_unlock(&fs_info->buffer_lock);
 
        btrfs_mapping_tree_free(&fs_info->mapping_tree);
        list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices,
@@ -186,7 +202,7 @@ void btrfs_free_dummy_root(struct btrfs_root *root)
        if (!root)
                return;
        /* Will be freed by btrfs_free_fs_roots */
-       if (WARN_ON(test_bit(BTRFS_ROOT_REGISTERED, &root->state)))
+       if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state)))
                return;
        btrfs_global_root_delete(root);
        btrfs_put_root(root);
index 06c0a95..875b801 100644 (file)
@@ -23,7 +23,7 @@
 #include "space-info.h"
 #include "zoned.h"
 
-#define BTRFS_ROOT_TRANS_TAG                           XA_MARK_0
+#define BTRFS_ROOT_TRANS_TAG 0
 
 /*
  * Transaction states and transitions
@@ -437,15 +437,15 @@ static int record_root_in_trans(struct btrfs_trans_handle *trans,
                 */
                smp_wmb();
 
-               spin_lock(&fs_info->fs_roots_lock);
+               spin_lock(&fs_info->fs_roots_radix_lock);
                if (root->last_trans == trans->transid && !force) {
-                       spin_unlock(&fs_info->fs_roots_lock);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
                        return 0;
                }
-               xa_set_mark(&fs_info->fs_roots,
-                           (unsigned long)root->root_key.objectid,
-                           BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
+               radix_tree_tag_set(&fs_info->fs_roots_radix,
+                                  (unsigned long)root->root_key.objectid,
+                                  BTRFS_ROOT_TRANS_TAG);
+               spin_unlock(&fs_info->fs_roots_radix_lock);
                root->last_trans = trans->transid;
 
                /* this is pretty tricky.  We don't want to
@@ -487,9 +487,11 @@ void btrfs_add_dropped_root(struct btrfs_trans_handle *trans,
        spin_unlock(&cur_trans->dropped_roots_lock);
 
        /* Make sure we don't try to update the root at commit time */
-       xa_clear_mark(&fs_info->fs_roots,
-                     (unsigned long)root->root_key.objectid,
-                     BTRFS_ROOT_TRANS_TAG);
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                            (unsigned long)root->root_key.objectid,
+                            BTRFS_ROOT_TRANS_TAG);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
 }
 
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
@@ -1402,8 +1404,9 @@ void btrfs_add_dead_root(struct btrfs_root *root)
 static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
 {
        struct btrfs_fs_info *fs_info = trans->fs_info;
-       struct btrfs_root *root;
-       unsigned long index;
+       struct btrfs_root *gang[8];
+       int i;
+       int ret;
 
        /*
         * At this point no one can be using this transaction to modify any tree
@@ -1411,46 +1414,57 @@ static noinline int commit_fs_roots(struct btrfs_trans_handle *trans)
         */
        ASSERT(trans->transaction->state == TRANS_STATE_COMMIT_DOING);
 
-       spin_lock(&fs_info->fs_roots_lock);
-       xa_for_each_marked(&fs_info->fs_roots, index, root, BTRFS_ROOT_TRANS_TAG) {
-               int ret;
-
-               /*
-                * At this point we can neither have tasks logging inodes
-                * from a root nor trying to commit a log tree.
-                */
-               ASSERT(atomic_read(&root->log_writers) == 0);
-               ASSERT(atomic_read(&root->log_commit[0]) == 0);
-               ASSERT(atomic_read(&root->log_commit[1]) == 0);
-
-               xa_clear_mark(&fs_info->fs_roots,
-                             (unsigned long)root->root_key.objectid,
-                             BTRFS_ROOT_TRANS_TAG);
-               spin_unlock(&fs_info->fs_roots_lock);
-
-               btrfs_free_log(trans, root);
-               ret = btrfs_update_reloc_root(trans, root);
-               if (ret)
-                       return ret;
-
-               /* See comments in should_cow_block() */
-               clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
-               smp_mb__after_atomic();
+       spin_lock(&fs_info->fs_roots_radix_lock);
+       while (1) {
+               ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix,
+                                                (void **)gang, 0,
+                                                ARRAY_SIZE(gang),
+                                                BTRFS_ROOT_TRANS_TAG);
+               if (ret == 0)
+                       break;
+               for (i = 0; i < ret; i++) {
+                       struct btrfs_root *root = gang[i];
+                       int ret2;
+
+                       /*
+                        * At this point we can neither have tasks logging inodes
+                        * from a root nor trying to commit a log tree.
+                        */
+                       ASSERT(atomic_read(&root->log_writers) == 0);
+                       ASSERT(atomic_read(&root->log_commit[0]) == 0);
+                       ASSERT(atomic_read(&root->log_commit[1]) == 0);
+
+                       radix_tree_tag_clear(&fs_info->fs_roots_radix,
+                                       (unsigned long)root->root_key.objectid,
+                                       BTRFS_ROOT_TRANS_TAG);
+                       spin_unlock(&fs_info->fs_roots_radix_lock);
+
+                       btrfs_free_log(trans, root);
+                       ret2 = btrfs_update_reloc_root(trans, root);
+                       if (ret2)
+                               return ret2;
+
+                       /* see comments in should_cow_block() */
+                       clear_bit(BTRFS_ROOT_FORCE_COW, &root->state);
+                       smp_mb__after_atomic();
+
+                       if (root->commit_root != root->node) {
+                               list_add_tail(&root->dirty_list,
+                                       &trans->transaction->switch_commits);
+                               btrfs_set_root_node(&root->root_item,
+                                                   root->node);
+                       }
 
-               if (root->commit_root != root->node) {
-                       list_add_tail(&root->dirty_list,
-                                     &trans->transaction->switch_commits);
-                       btrfs_set_root_node(&root->root_item, root->node);
+                       ret2 = btrfs_update_root(trans, fs_info->tree_root,
+                                               &root->root_key,
+                                               &root->root_item);
+                       if (ret2)
+                               return ret2;
+                       spin_lock(&fs_info->fs_roots_radix_lock);
+                       btrfs_qgroup_free_meta_all_pertrans(root);
                }
-
-               ret = btrfs_update_root(trans, fs_info->tree_root,
-                                       &root->root_key, &root->root_item);
-               if (ret)
-                       return ret;
-               spin_lock(&fs_info->fs_roots_lock);
-               btrfs_qgroup_free_meta_all_pertrans(root);
        }
-       spin_unlock(&fs_info->fs_roots_lock);
+       spin_unlock(&fs_info->fs_roots_radix_lock);
        return 0;
 }
 
index 79e8c8c..d99026d 100644 (file)
@@ -1735,12 +1735,14 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
        ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical,
                               &mapped_length, &bioc);
        if (ret || !bioc || mapped_length < PAGE_SIZE) {
-               btrfs_put_bioc(bioc);
-               return -EIO;
+               ret = -EIO;
+               goto out_put_bioc;
        }
 
-       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK)
-               return -EINVAL;
+       if (bioc->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) {
+               ret = -EINVAL;
+               goto out_put_bioc;
+       }
 
        nofs_flag = memalloc_nofs_save();
        nmirrors = (int)bioc->num_stripes;
@@ -1759,7 +1761,8 @@ static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
                break;
        }
        memalloc_nofs_restore(nofs_flag);
-
+out_put_bioc:
+       btrfs_put_bioc(bioc);
        return ret;
 }
 
@@ -1885,7 +1888,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
 {
        struct btrfs_fs_info *fs_info = block_group->fs_info;
        struct map_lookup *map;
-       bool need_zone_finish;
        int ret = 0;
        int i;
 
@@ -1942,12 +1944,6 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                }
        }
 
-       /*
-        * The block group is not fully allocated, so not fully written yet. We
-        * need to send ZONE_FINISH command to free up an active zone.
-        */
-       need_zone_finish = !btrfs_zoned_bg_is_full(block_group);
-
        block_group->zone_is_active = 0;
        block_group->alloc_offset = block_group->zone_capacity;
        block_group->free_space_ctl->free_space = 0;
@@ -1963,15 +1959,13 @@ static int do_zone_finish(struct btrfs_block_group *block_group, bool fully_writ
                if (device->zone_info->max_active_zones == 0)
                        continue;
 
-               if (need_zone_finish) {
-                       ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
-                                              physical >> SECTOR_SHIFT,
-                                              device->zone_info->zone_size >> SECTOR_SHIFT,
-                                              GFP_NOFS);
+               ret = blkdev_zone_mgmt(device->bdev, REQ_OP_ZONE_FINISH,
+                                      physical >> SECTOR_SHIFT,
+                                      device->zone_info->zone_size >> SECTOR_SHIFT,
+                                      GFP_NOFS);
 
-                       if (ret)
-                               return ret;
-               }
+               if (ret)
+                       return ret;
 
                btrfs_dev_clear_active_zone(device, physical);
        }
index a41ae6e..1fee702 100644 (file)
@@ -21,7 +21,8 @@ static int cachefiles_ondemand_fd_release(struct inode *inode,
         * anon_fd.
         */
        xas_for_each(&xas, req, ULONG_MAX) {
-               if (req->msg.opcode == CACHEFILES_OP_READ) {
+               if (req->msg.object_id == object_id &&
+                   req->msg.opcode == CACHEFILES_OP_READ) {
                        req->error = -EIO;
                        complete(&req->done);
                        xas_store(&xas, NULL);
index 6dee888..d6e5916 100644 (file)
@@ -63,7 +63,7 @@
         (CONGESTION_ON_THRESH(congestion_kb) >> 2))
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata);
+                                       struct folio **foliop, void **_fsdata);
 
 static inline struct ceph_snap_context *page_snap_context(struct page *page)
 {
@@ -1288,18 +1288,19 @@ ceph_find_incompatible(struct page *page)
 }
 
 static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
-                                       struct folio *folio, void **_fsdata)
+                                       struct folio **foliop, void **_fsdata)
 {
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_snap_context *snapc;
 
-       snapc = ceph_find_incompatible(folio_page(folio, 0));
+       snapc = ceph_find_incompatible(folio_page(*foliop, 0));
        if (snapc) {
                int r;
 
-               folio_unlock(folio);
-               folio_put(folio);
+               folio_unlock(*foliop);
+               folio_put(*foliop);
+               *foliop = NULL;
                if (IS_ERR(snapc))
                        return PTR_ERR(snapc);
 
index fa29c9a..386bb52 100644 (file)
@@ -1918,7 +1918,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
        list_del_init(&ses->smb_ses_list);
        spin_unlock(&cifs_tcp_ses_lock);
 
-       spin_lock(&ses->chan_lock);
        chan_count = ses->chan_count;
 
        /* close any extra channels */
@@ -1934,7 +1933,6 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
                        ses->chans[i].server = NULL;
                }
        }
-       spin_unlock(&ses->chan_lock);
 
        sesInfoFree(ses);
        cifs_put_tcp_session(server, 0);
index b85718f..02c8b29 100644 (file)
@@ -474,6 +474,14 @@ cifs_ses_add_channel(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
 
 out:
        if (rc && chan->server) {
+               /*
+                * we should avoid race with these delayed works before we
+                * remove this channel
+                */
+               cancel_delayed_work_sync(&chan->server->echo);
+               cancel_delayed_work_sync(&chan->server->resolve);
+               cancel_delayed_work_sync(&chan->server->reconnect);
+
                spin_lock(&ses->chan_lock);
                /* we rely on all bits beyond chan_count to be clear */
                cifs_chan_clear_need_reconnect(ses, chan->server);
@@ -484,10 +492,9 @@ out:
                 */
                WARN_ON(ses->chan_count < 1);
                spin_unlock(&ses->chan_lock);
-       }
 
-       if (rc && chan->server)
                cifs_put_tcp_session(chan->server, 0);
+       }
 
        return rc;
 }
index 12b4ddd..c705de3 100644 (file)
@@ -571,10 +571,6 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
        *total_len += ctxt_len;
        pneg_ctxt += ctxt_len;
 
-       build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
-       *total_len += sizeof(struct smb2_posix_neg_context);
-       pneg_ctxt += sizeof(struct smb2_posix_neg_context);
-
        /*
         * secondary channels don't have the hostname field populated
         * use the hostname field in the primary channel instead
@@ -586,9 +582,14 @@ assemble_neg_contexts(struct smb2_negotiate_req *req,
                                              hostname);
                *total_len += ctxt_len;
                pneg_ctxt += ctxt_len;
-               neg_context_count = 4;
-       } else /* second channels do not have a hostname */
                neg_context_count = 3;
+       } else
+               neg_context_count = 2;
+
+       build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt);
+       *total_len += sizeof(struct smb2_posix_neg_context);
+       pneg_ctxt += sizeof(struct smb2_posix_neg_context);
+       neg_context_count++;
 
        if (server->compress_algorithm) {
                build_compression_ctxt((struct smb2_compression_capabilities_context *)
index 0989fb8..7781232 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1301,7 +1301,7 @@ int begin_new_exec(struct linux_binprm * bprm)
        bprm->mm = NULL;
 
 #ifdef CONFIG_POSIX_TIMERS
-       exit_itimers(me->signal);
+       exit_itimers(me);
        flush_itimer_signals();
 #endif
 
index 9d3cf01..7492082 100644 (file)
@@ -372,17 +372,22 @@ nomem:
        return NULL;
 }
 
+static inline bool fscache_cookie_is_dropped(struct fscache_cookie *cookie)
+{
+       return READ_ONCE(cookie->state) == FSCACHE_COOKIE_STATE_DROPPED;
+}
+
 static void fscache_wait_on_collision(struct fscache_cookie *candidate,
                                      struct fscache_cookie *wait_for)
 {
        enum fscache_cookie_state *statep = &wait_for->state;
 
-       wait_var_event_timeout(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED,
+       wait_var_event_timeout(statep, fscache_cookie_is_dropped(wait_for),
                               20 * HZ);
-       if (READ_ONCE(*statep) != FSCACHE_COOKIE_STATE_DROPPED) {
+       if (!fscache_cookie_is_dropped(wait_for)) {
                pr_notice("Potential collision c=%08x old: c=%08x",
                          candidate->debug_id, wait_for->debug_id);
-               wait_var_event(statep, READ_ONCE(*statep) == FSCACHE_COOKIE_STATE_DROPPED);
+               wait_var_event(statep, fscache_cookie_is_dropped(wait_for));
        }
 }
 
@@ -517,7 +522,14 @@ static void fscache_perform_lookup(struct fscache_cookie *cookie)
        }
 
        fscache_see_cookie(cookie, fscache_cookie_see_active);
-       fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_lock(&cookie->lock);
+       if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+               __fscache_set_cookie_state(cookie,
+                                          FSCACHE_COOKIE_STATE_INVALIDATING);
+       else
+               __fscache_set_cookie_state(cookie, FSCACHE_COOKIE_STATE_ACTIVE);
+       spin_unlock(&cookie->lock);
+       wake_up_cookie_state(cookie);
        trace = fscache_access_lookup_cookie_end;
 
 out:
@@ -752,6 +764,9 @@ again_locked:
                        spin_lock(&cookie->lock);
                }
 
+               if (test_and_clear_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags))
+                       fscache_end_cookie_access(cookie, fscache_access_invalidate_cookie_end);
+
                switch (state) {
                case FSCACHE_COOKIE_STATE_RELINQUISHING:
                        fscache_see_cookie(cookie, fscache_cookie_see_relinquish);
@@ -1048,6 +1063,9 @@ void __fscache_invalidate(struct fscache_cookie *cookie,
                return;
 
        case FSCACHE_COOKIE_STATE_LOOKING_UP:
+               __fscache_begin_cookie_access(cookie, fscache_access_invalidate_cookie);
+               set_bit(FSCACHE_COOKIE_DO_INVALIDATE, &cookie->flags);
+               fallthrough;
        case FSCACHE_COOKIE_STATE_CREATING:
                spin_unlock(&cookie->lock);
                _leave(" [look %x]", cookie->inval_counter);
index f2aa7db..a058e01 100644 (file)
@@ -143,7 +143,7 @@ static void fscache_wait_on_volume_collision(struct fscache_volume *candidate,
 {
        wait_var_event_timeout(&candidate->flags,
                               !fscache_is_acquire_pending(candidate), 20 * HZ);
-       if (!fscache_is_acquire_pending(candidate)) {
+       if (fscache_is_acquire_pending(candidate)) {
                pr_notice("Potential volume collision new=%08x old=%08x",
                          candidate->debug_id, collidee_debug_id);
                fscache_stat(&fscache_n_volumes_collision);
@@ -182,7 +182,7 @@ static bool fscache_hash_volume(struct fscache_volume *candidate)
        hlist_bl_add_head(&candidate->hash_link, h);
        hlist_bl_unlock(h);
 
-       if (test_bit(FSCACHE_VOLUME_ACQUIRE_PENDING, &candidate->flags))
+       if (fscache_is_acquire_pending(candidate))
                fscache_wait_on_volume_collision(candidate, collidee_debug_id);
        return true;
 
index 0d491ad..a01ea49 100644 (file)
@@ -5066,7 +5066,7 @@ static int io_uring_cmd_prep(struct io_kiocb *req,
 {
        struct io_uring_cmd *ioucmd = &req->uring_cmd;
 
-       if (sqe->rw_flags)
+       if (sqe->rw_flags || sqe->__pad1)
                return -EINVAL;
        ioucmd->cmd = sqe->cmd;
        ioucmd->cmd_op = READ_ONCE(sqe->cmd_op);
@@ -7973,6 +7973,9 @@ static int io_files_update_with_index_alloc(struct io_kiocb *req,
        struct file *file;
        int ret, fd;
 
+       if (!req->ctx->file_data)
+               return -ENXIO;
+
        for (done = 0; done < req->rsrc_update.nr_args; done++) {
                if (copy_from_user(&fd, &fds[done], sizeof(fd))) {
                        ret = -EFAULT;
index 0a22a2f..e1c4617 100644 (file)
@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file)
        }
 }
 
-static int nlm_unlock_files(struct nlm_file *file)
+static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner)
 {
        struct file_lock lock;
 
@@ -184,6 +184,7 @@ static int nlm_unlock_files(struct nlm_file *file)
        lock.fl_type  = F_UNLCK;
        lock.fl_start = 0;
        lock.fl_end   = OFFSET_MAX;
+       lock.fl_owner = owner;
        if (file->f_file[O_RDONLY] &&
            vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL))
                goto out_err;
@@ -225,7 +226,7 @@ again:
                if (match(lockhost, host)) {
 
                        spin_unlock(&flctx->flc_lock);
-                       if (nlm_unlock_files(file))
+                       if (nlm_unlock_files(file, fl->fl_owner))
                                return 1;
                        goto again;
                }
@@ -282,11 +283,10 @@ nlm_file_inuse(struct nlm_file *file)
 
 static void nlm_close_files(struct nlm_file *file)
 {
-       struct file *f;
-
-       for (f = file->f_file[0]; f <= file->f_file[1]; f++)
-               if (f)
-                       nlmsvc_ops->fclose(f);
+       if (file->f_file[O_RDONLY])
+               nlmsvc_ops->fclose(file->f_file[O_RDONLY]);
+       if (file->f_file[O_WRONLY])
+               nlmsvc_ops->fclose(file->f_file[O_WRONLY]);
 }
 
 /*
index 42f892c..0ce5358 100644 (file)
@@ -319,8 +319,9 @@ zero_out:
  * conflicting writes once the folio is grabbed and locked.  It is passed a
  * pointer to the fsdata cookie that gets returned to the VM to be passed to
  * write_end.  It is permitted to sleep.  It should return 0 if the request
- * should go ahead; unlock the folio and return -EAGAIN to cause the folio to
- * be regot; or return an error.
+ * should go ahead or it may return an error.  It may also unlock and put the
+ * folio, provided it sets ``*foliop`` to NULL, in which case a return of 0
+ * will cause the folio to be re-got and the process to be retried.
  *
  * The calling netfs must initialise a netfs context contiguous to the vfs
  * inode before calling this.
@@ -348,13 +349,13 @@ retry:
 
        if (ctx->ops->check_write_begin) {
                /* Allow the netfs (eg. ceph) to flush conflicts. */
-               ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata);
+               ret = ctx->ops->check_write_begin(file, pos, len, &folio, _fsdata);
                if (ret < 0) {
                        trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin);
-                       if (ret == -EAGAIN)
-                               goto retry;
                        goto error;
                }
+               if (!folio)
+                       goto retry;
        }
 
        if (folio_test_uptodate(folio))
@@ -416,8 +417,10 @@ have_folio_no_wait:
 error_put:
        netfs_put_request(rreq, false, netfs_rreq_trace_put_failed);
 error:
-       folio_unlock(folio);
-       folio_put(folio);
+       if (folio) {
+               folio_unlock(folio);
+               folio_put(folio);
+       }
        _leave(" = %d", ret);
        return ret;
 }
index 61b2aae..2acea77 100644 (file)
@@ -470,6 +470,15 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen,
                        return nfserr_bad_xdr;
                }
        }
+       if (bmval[1] & FATTR4_WORD1_TIME_CREATE) {
+               struct timespec64 ts;
+
+               /* No Linux filesystem supports setting this attribute. */
+               bmval[1] &= ~FATTR4_WORD1_TIME_CREATE;
+               status = nfsd4_decode_nfstime4(argp, &ts);
+               if (status)
+                       return status;
+       }
        if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
                u32 set_it;
 
index 847b482..9a8b09a 100644 (file)
@@ -465,7 +465,8 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval)
        (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL)
 #define NFSD_WRITEABLE_ATTRS_WORD1 \
        (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \
-       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET)
+       | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_CREATE \
+       | FATTR4_WORD1_TIME_MODIFY_SET)
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 #define MAYBE_FATTR4_WORD2_SECURITY_LABEL \
        FATTR4_WORD2_SECURITY_LABEL
index 1344f7d..aecda4f 100644 (file)
@@ -198,6 +198,9 @@ static inline int nilfs_acl_chmod(struct inode *inode)
 
 static inline int nilfs_init_acl(struct inode *inode, struct inode *dir)
 {
+       if (S_ISLNK(inode->i_mode))
+               return 0;
+
        inode->i_mode &= ~current_umask();
        return 0;
 }
index e0a2e04..1ce5c96 100644 (file)
@@ -1003,6 +1003,9 @@ ovl_posix_acl_xattr_get(const struct xattr_handler *handler,
                        struct dentry *dentry, struct inode *inode,
                        const char *name, void *buffer, size_t size)
 {
+       if (!IS_POSIXACL(inode))
+               return -EOPNOTSUPP;
+
        return ovl_xattr_get(dentry, inode, handler->name, buffer, size);
 }
 
@@ -1018,6 +1021,9 @@ ovl_posix_acl_xattr_set(const struct xattr_handler *handler,
        struct posix_acl *acl = NULL;
        int err;
 
+       if (!IS_POSIXACL(inode))
+               return -EOPNOTSUPP;
+
        /* Check that everything is OK before copy-up */
        if (value) {
                acl = posix_acl_from_xattr(&init_user_ns, value, size);
@@ -1960,6 +1966,20 @@ static struct dentry *ovl_get_root(struct super_block *sb,
        return root;
 }
 
+static bool ovl_has_idmapped_layers(struct ovl_fs *ofs)
+{
+
+       unsigned int i;
+       const struct vfsmount *mnt;
+
+       for (i = 0; i < ofs->numlayer; i++) {
+               mnt = ofs->layers[i].mnt;
+               if (mnt && is_idmapped_mnt(mnt))
+                       return true;
+       }
+       return false;
+}
+
 static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct path upperpath = { };
@@ -2129,7 +2149,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
                ovl_trusted_xattr_handlers;
        sb->s_fs_info = ofs;
-       sb->s_flags |= SB_POSIXACL;
+       if (ovl_has_idmapped_layers(ofs))
+               pr_warn("POSIX ACLs are not yet supported with idmapped layers, mounting without ACL support.\n");
+       else
+               sb->s_flags |= SB_POSIXACL;
        sb->s_iflags |= SB_I_SKIP_SYNC;
 
        err = -ENOMEM;
index e112b54..881a306 100644 (file)
@@ -71,7 +71,8 @@ static int generic_remap_checks(struct file *file_in, loff_t pos_in,
         * Otherwise, make sure the count is also block-aligned, having
         * already confirmed the starting offsets' block alignment.
         */
-       if (pos_in + count == size_in) {
+       if (pos_in + count == size_in &&
+           (!(remap_flags & REMAP_FILE_DEDUP) || pos_out + count == size_out)) {
                bcount = ALIGN(size_in, bs) - pos_in;
        } else {
                if (!IS_ALIGNED(count, bs))
index c610858..d389bab 100644 (file)
@@ -145,6 +145,7 @@ extern bool cppc_allow_fast_switch(void);
 extern int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data);
 extern unsigned int cppc_get_transition_latency(int cpu);
 extern bool cpc_ffh_supported(void);
+extern bool cpc_supported_by_cpu(void);
 extern int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val);
 extern int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val);
 #else /* !CONFIG_ACPI_CPPC_LIB */
index 4f82a5b..44975c1 100644 (file)
@@ -584,7 +584,7 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
 extern bool osc_sb_apei_support_acked;
 extern bool osc_pc_lpi_support_confirmed;
 extern bool osc_sb_native_usb4_support_confirmed;
-extern bool osc_sb_cppc_not_supported;
+extern bool osc_sb_cppc2_support_acked;
 extern bool osc_cpc_flexible_adr_space_confirmed;
 
 /* USB4 Capabilities */
index 1bfcfb1..d4427d0 100644 (file)
@@ -264,7 +264,8 @@ struct css_set {
         * List of csets participating in the on-going migration either as
         * source or destination.  Protected by cgroup_mutex.
         */
-       struct list_head mg_preload_node;
+       struct list_head mg_src_preload_node;
+       struct list_head mg_dst_preload_node;
        struct list_head mg_node;
 
        /*
index 2c74773..314802f 100644 (file)
@@ -68,6 +68,8 @@ extern ssize_t cpu_show_srbds(struct device *dev, struct device_attribute *attr,
 extern ssize_t cpu_show_mmio_stale_data(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf);
+extern ssize_t cpu_show_retbleed(struct device *dev,
+                                struct device_attribute *attr, char *buf);
 
 extern __printf(4, 5)
 struct device *cpu_device_create(struct device *parent, void *drvdata,
index ff5596d..2382dec 100644 (file)
@@ -15,6 +15,8 @@ void fbcon_new_modelist(struct fb_info *info);
 void fbcon_get_requirement(struct fb_info *info,
                           struct fb_blit_caps *caps);
 void fbcon_fb_blanked(struct fb_info *info, int blank);
+int  fbcon_modechange_possible(struct fb_info *info,
+                              struct fb_var_screeninfo *var);
 void fbcon_update_vcs(struct fb_info *info, bool all);
 void fbcon_remap_all(struct fb_info *info);
 int fbcon_set_con2fb_map_ioctl(void __user *argp);
@@ -33,6 +35,8 @@ static inline void fbcon_new_modelist(struct fb_info *info) {}
 static inline void fbcon_get_requirement(struct fb_info *info,
                                         struct fb_blit_caps *caps) {}
 static inline void fbcon_fb_blanked(struct fb_info *info, int blank) {}
+static inline int  fbcon_modechange_possible(struct fb_info *info,
+                               struct fb_var_screeninfo *var) { return 0; }
 static inline void fbcon_update_vcs(struct fb_info *info, bool all) {}
 static inline void fbcon_remap_all(struct fb_info *info) {}
 static inline int fbcon_set_con2fb_map_ioctl(void __user *argp) { return 0; }
index 72585c9..b862656 100644 (file)
@@ -130,6 +130,7 @@ struct fscache_cookie {
 #define FSCACHE_COOKIE_DO_PREP_TO_WRITE        12              /* T if cookie needs write preparation */
 #define FSCACHE_COOKIE_HAVE_DATA       13              /* T if this cookie has data stored */
 #define FSCACHE_COOKIE_IS_HASHED       14              /* T if this cookie is hashed */
+#define FSCACHE_COOKIE_DO_INVALIDATE   15              /* T if cookie needs invalidation */
 
        enum fscache_cookie_state       state;
        u8                              advice;         /* FSCACHE_ADV_* */
index 3af34de..56d6a01 100644 (file)
@@ -149,19 +149,19 @@ static inline void *kmap_local_folio(struct folio *folio, size_t offset);
  * It is used in atomic context when code wants to access the contents of a
  * page that might be allocated from high memory (see __GFP_HIGHMEM), for
  * example a page in the pagecache.  The API has two functions, and they
- * can be used in a manner similar to the following:
+ * can be used in a manner similar to the following::
  *
- * -- Find the page of interest. --
- * struct page *page = find_get_page(mapping, offset);
+ *   // Find the page of interest.
+ *   struct page *page = find_get_page(mapping, offset);
  *
- * -- Gain access to the contents of that page. --
- * void *vaddr = kmap_atomic(page);
+ *   // Gain access to the contents of that page.
+ *   void *vaddr = kmap_atomic(page);
  *
- * -- Do something to the contents of that page. --
- * memset(vaddr, 0, PAGE_SIZE);
+ *   // Do something to the contents of that page.
+ *   memset(vaddr, 0, PAGE_SIZE);
  *
- * -- Unmap that page. --
- * kunmap_atomic(vaddr);
+ *   // Unmap that page.
+ *   kunmap_atomic(vaddr);
  *
  * Note that the kunmap_atomic() call takes the result of the kmap_atomic()
  * call, not the argument.
index 4f29139..5fcf89f 100644 (file)
@@ -612,7 +612,6 @@ struct intel_iommu {
 struct device_domain_info {
        struct list_head link;  /* link to domain siblings */
        struct list_head global; /* link to global list */
-       struct list_head table; /* link to pasid table */
        u32 segment;            /* PCI segment number */
        u8 bus;                 /* PCI bus number */
        u8 devfn;               /* PCI devfn number */
@@ -729,8 +728,6 @@ extern int dmar_ir_support(void);
 void *alloc_pgtable_page(int node);
 void free_pgtable_page(void *vaddr);
 struct intel_iommu *domain_get_iommu(struct dmar_domain *domain);
-int for_each_device_domain(int (*fn)(struct device_domain_info *info,
-                                    void *data), void *data);
 void iommu_flush_write_buffer(struct intel_iommu *iommu);
 int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct device *dev);
 struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn);
index ce6536f..475683c 100644 (file)
@@ -452,6 +452,12 @@ static inline int kexec_crash_loaded(void) { return 0; }
 #define kexec_in_progress false
 #endif /* CONFIG_KEXEC_CORE */
 
+#ifdef CONFIG_KEXEC_SIG
+void set_kexec_sig_enforced(void);
+#else
+static inline void set_kexec_sig_enforced(void) {}
+#endif
+
 #endif /* !defined(__ASSEBMLY__) */
 
 #endif /* LINUX_KEXEC_H */
index c20f2d5..90a45ef 100644 (file)
@@ -1513,7 +1513,7 @@ static inline void kvm_arch_end_assignment(struct kvm *kvm)
 {
 }
 
-static inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
+static __always_inline bool kvm_arch_has_assigned_device(struct kvm *kvm)
 {
        return false;
 }
@@ -1822,6 +1822,15 @@ struct _kvm_stats_desc {
        STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_NONE,                      \
                KVM_STATS_BASE_POW10, 0)
 
+/* Instantaneous boolean value, read only */
+#define STATS_DESC_IBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_INSTANT(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                \
+               KVM_STATS_BASE_POW10, 0)
+/* Peak (sticky) boolean value, read/write */
+#define STATS_DESC_PBOOLEAN(SCOPE, name)                                      \
+       STATS_DESC_PEAK(SCOPE, name, KVM_STATS_UNIT_BOOLEAN,                   \
+               KVM_STATS_BASE_POW10, 0)
+
 /* Cumulative time in nanosecond */
 #define STATS_DESC_TIME_NSEC(SCOPE, name)                                     \
        STATS_DESC_CUMULATIVE(SCOPE, name, KVM_STATS_UNIT_SECONDS,             \
@@ -1853,7 +1862,7 @@ struct _kvm_stats_desc {
                        HALT_POLL_HIST_COUNT),                                 \
        STATS_DESC_LOGHIST_TIME_NSEC(VCPU_GENERIC, halt_wait_hist,             \
                        HALT_POLL_HIST_COUNT),                                 \
-       STATS_DESC_ICOUNTER(VCPU_GENERIC, blocking)
+       STATS_DESC_IBOOLEAN(VCPU_GENERIC, blocking)
 
 extern struct dentry *kvm_debugfs_dir;
 
index e115952..c04c4fd 100644 (file)
@@ -16,7 +16,7 @@ static inline int memregion_alloc(gfp_t gfp)
 {
        return -ENOMEM;
 }
-void memregion_free(int id)
+static inline void memregion_free(int id)
 {
 }
 #endif
index 1773e5d..1b18dfa 100644 (file)
@@ -214,7 +214,7 @@ struct netfs_request_ops {
        void (*issue_read)(struct netfs_io_subrequest *subreq);
        bool (*is_still_valid)(struct netfs_io_request *rreq);
        int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
-                                struct folio *folio, void **_fsdata);
+                                struct folio **foliop, void **_fsdata);
        void (*done)(struct netfs_io_request *rreq);
 };
 
index e393400..07cfc92 100644 (file)
@@ -906,12 +906,14 @@ struct nvme_common_command {
        __le32                  cdw2[2];
        __le64                  metadata;
        union nvme_data_ptr     dptr;
+       struct_group(cdws,
        __le32                  cdw10;
        __le32                  cdw11;
        __le32                  cdw12;
        __le32                  cdw13;
        __le32                  cdw14;
        __le32                  cdw15;
+       );
 };
 
 struct nvme_rw_command {
index 15b940e..10bc88c 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index 9e4d056..0a41b2d 100644 (file)
@@ -88,7 +88,7 @@ extern void pm_runtime_get_suppliers(struct device *dev);
 extern void pm_runtime_put_suppliers(struct device *dev);
 extern void pm_runtime_new_link(struct device *dev);
 extern void pm_runtime_drop_link(struct device_link *link);
-extern void pm_runtime_release_supplier(struct device_link *link, bool check_idle);
+extern void pm_runtime_release_supplier(struct device_link *link);
 
 extern int devm_pm_runtime_enable(struct device *dev);
 
@@ -314,8 +314,7 @@ static inline void pm_runtime_get_suppliers(struct device *dev) {}
 static inline void pm_runtime_put_suppliers(struct device *dev) {}
 static inline void pm_runtime_new_link(struct device *dev) {}
 static inline void pm_runtime_drop_link(struct device_link *link) {}
-static inline void pm_runtime_release_supplier(struct device_link *link,
-                                              bool check_idle) {}
+static inline void pm_runtime_release_supplier(struct device_link *link) {}
 
 #endif /* !CONFIG_PM */
 
index 8a21b57..514ddf0 100644 (file)
@@ -731,7 +731,7 @@ static inline int __must_check
 devm_reset_control_bulk_get_optional_exclusive(struct device *dev, int num_rstcs,
                                               struct reset_control_bulk_data *rstcs)
 {
-       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, true, false, true);
+       return __devm_reset_control_bulk_get(dev, num_rstcs, rstcs, false, true, true);
 }
 
 /**
index 159729c..3247ed8 100644 (file)
@@ -54,8 +54,6 @@ struct rtsx_ucr {
        struct usb_device       *pusb_dev;
        struct usb_interface    *pusb_intf;
        struct usb_sg_request   current_sg;
-       unsigned char           *iobuf;
-       dma_addr_t              iobuf_dma;
 
        struct timer_list       sg_timer;
        struct mutex            dev_mutex;
index 505aaf9..81cab4b 100644 (file)
@@ -85,7 +85,7 @@ static inline void exit_thread(struct task_struct *tsk)
 extern __noreturn void do_group_exit(int);
 
 extern void exit_files(struct task_struct *);
-extern void exit_itimers(struct signal_struct *);
+extern void exit_itimers(struct task_struct *);
 
 extern pid_t kernel_clone(struct kernel_clone_args *kargs);
 struct task_struct *create_io_thread(int (*fn)(void *), void *arg, int node);
index 657a0fc..fde258b 100644 (file)
@@ -390,6 +390,11 @@ static const bool earlycon_acpi_spcr_enable EARLYCON_USED_OR_UNUSED;
 static inline int setup_earlycon(char *buf) { return 0; }
 #endif
 
+static inline bool uart_console_enabled(struct uart_port *port)
+{
+       return uart_console(port) && (port->cons->flags & CON_ENABLED);
+}
+
 struct uart_port *uart_get_console(struct uart_port *ports, int nr,
                                   struct console *c);
 int uart_parse_earlycon(char *p, unsigned char *iotype, resource_size_t *addr,
index 6d02e12..80f4144 100644 (file)
@@ -8462,11 +8462,12 @@ int cfg80211_bss_color_notify(struct net_device *dev, gfp_t gfp,
  * cfg80211_obss_color_collision_notify - notify about bss color collision
  * @dev: network device
  * @color_bitmap: representations of the colors that the local BSS is aware of
+ * @gfp: allocation flags
  */
 static inline int cfg80211_obss_color_collision_notify(struct net_device *dev,
-                                                      u64 color_bitmap)
+                                                      u64 color_bitmap, gfp_t gfp)
 {
-       return cfg80211_bss_color_notify(dev, GFP_KERNEL,
+       return cfg80211_bss_color_notify(dev, gfp,
                                         NL80211_CMD_OBSS_COLOR_COLLISION,
                                         0, color_bitmap);
 }
index 6484095..7ac3138 100644 (file)
@@ -152,6 +152,7 @@ enum flow_action_id {
        FLOW_ACTION_PIPE,
        FLOW_ACTION_VLAN_PUSH_ETH,
        FLOW_ACTION_VLAN_POP_ETH,
+       FLOW_ACTION_CONTINUE,
        NUM_FLOW_ACTIONS,
 };
 
index ebadb21..47642b0 100644 (file)
@@ -6960,10 +6960,11 @@ ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
  * @vif: &struct ieee80211_vif pointer from the add_interface callback.
  * @color_bitmap: a 64 bit bitmap representing the colors that the local BSS is
  *     aware of.
+ * @gfp: allocation flags
  */
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap);
+                                      u64 color_bitmap, gfp_t gfp);
 
 /**
  * ieee80211_is_tx_data - check if frame is a data frame
index 5c4e5a9..64cf655 100644 (file)
@@ -657,18 +657,22 @@ static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl)
        tmpl->len = sizeof(struct nft_set_ext);
 }
 
-static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
-                                         unsigned int len)
+static inline int nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
+                                        unsigned int len)
 {
        tmpl->len        = ALIGN(tmpl->len, nft_set_ext_types[id].align);
-       BUG_ON(tmpl->len > U8_MAX);
+       if (tmpl->len > U8_MAX)
+               return -EINVAL;
+
        tmpl->offset[id] = tmpl->len;
        tmpl->len       += nft_set_ext_types[id].len + len;
+
+       return 0;
 }
 
-static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
+static inline int nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
 {
-       nft_set_ext_add_length(tmpl, id, 0);
+       return nft_set_ext_add_length(tmpl, id, 0);
 }
 
 static inline void nft_set_ext_init(struct nft_set_ext *ext,
index 8ad8df5..c51a635 100644 (file)
@@ -75,7 +75,7 @@ static inline bool raw_sk_bound_dev_eq(struct net *net, int bound_dev_if,
                                       int dif, int sdif)
 {
 #if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV)
-       return inet_bound_dev_eq(!!net->ipv4.sysctl_raw_l3mdev_accept,
+       return inet_bound_dev_eq(READ_ONCE(net->ipv4.sysctl_raw_l3mdev_accept),
                                 bound_dev_if, dif, sdif);
 #else
        return inet_bound_dev_eq(true, bound_dev_if, dif, sdif);
index 72ca97c..9fa5476 100644 (file)
@@ -1529,7 +1529,7 @@ void __sk_mem_reclaim(struct sock *sk, int amount);
 /* sysctl_mem values are in pages, we convert them in SK_MEM_QUANTUM units */
 static inline long sk_prot_mem_limits(const struct sock *sk, int index)
 {
-       long val = sk->sk_prot->sysctl_mem[index];
+       long val = READ_ONCE(sk->sk_prot->sysctl_mem[index]);
 
 #if PAGE_SIZE > SK_MEM_QUANTUM
        val <<= PAGE_SHIFT - SK_MEM_QUANTUM_SHIFT;
index 8017f17..8bd938f 100644 (file)
@@ -704,7 +704,7 @@ int tls_sw_fallback_init(struct sock *sk,
                         struct tls_crypto_info *crypto_info);
 
 #ifdef CONFIG_TLS_DEVICE
-void tls_device_init(void);
+int tls_device_init(void);
 void tls_device_cleanup(void);
 void tls_device_sk_destruct(struct sock *sk);
 int tls_set_device_offload(struct sock *sk, struct tls_context *ctx);
@@ -724,7 +724,7 @@ static inline bool tls_is_sk_rx_device_offloaded(struct sock *sk)
        return tls_get_ctx(sk)->rx_conf == TLS_HW;
 }
 #else
-static inline void tls_device_init(void) {}
+static inline int tls_device_init(void) { return 0; }
 static inline void tls_device_cleanup(void) {}
 
 static inline int
index f20f5f8..b276dcb 100644 (file)
@@ -408,8 +408,6 @@ struct snd_soc_jack_pin;
 
 struct snd_soc_jack_gpio;
 
-typedef int (*hw_write_t)(void *,const char* ,int);
-
 enum snd_soc_pcm_subclass {
        SND_SOC_PCM_CLASS_PCM   = 0,
        SND_SOC_PCM_CLASS_BE    = 1,
index e282ce0..6d1626e 100644 (file)
@@ -160,7 +160,7 @@ TRACE_EVENT(iocost_ioc_vrate_adj,
 
        TP_fast_assign(
                __assign_str(devname, ioc_name(ioc));
-               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);;
+               __entry->old_vrate = atomic64_read(&ioc->vtime_rate);
                __entry->new_vrate = new_vrate;
                __entry->busy_level = ioc->busy_level;
                __entry->read_missed_ppm = missed_ppm[READ];
index 12c3157..777ee6c 100644 (file)
@@ -98,7 +98,7 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_STRUCT__entry(
                __array(char, name, 32)
-               __field(long *, sysctl_mem)
+               __array(long, sysctl_mem, 3)
                __field(long, allocated)
                __field(int, sysctl_rmem)
                __field(int, rmem_alloc)
@@ -110,7 +110,9 @@ TRACE_EVENT(sock_exceed_buf_limit,
 
        TP_fast_assign(
                strncpy(__entry->name, prot->name, 32);
-               __entry->sysctl_mem = prot->sysctl_mem;
+               __entry->sysctl_mem[0] = READ_ONCE(prot->sysctl_mem[0]);
+               __entry->sysctl_mem[1] = READ_ONCE(prot->sysctl_mem[1]);
+               __entry->sysctl_mem[2] = READ_ONCE(prot->sysctl_mem[2]);
                __entry->allocated = allocated;
                __entry->sysctl_rmem = sk_get_rmem0(sk, prot);
                __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc);
index f4009db..ef78e0e 100644 (file)
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index ef4257a..2557eb7 100644 (file)
@@ -78,10 +78,13 @@ struct input_id {
  * Note that input core does not clamp reported values to the
  * [minimum, maximum] limits, such task is left to userspace.
  *
- * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z)
- * is reported in units per millimeter (units/mm), resolution
- * for rotational axes (ABS_RX, ABS_RY, ABS_RZ) is reported
- * in units per radian.
+ * The default resolution for main axes (ABS_X, ABS_Y, ABS_Z,
+ * ABS_MT_POSITION_X, ABS_MT_POSITION_Y) is reported in units
+ * per millimeter (units/mm), resolution for rotational axes
+ * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
+ * The resolution for the size axes (ABS_MT_TOUCH_MAJOR,
+ * ABS_MT_TOUCH_MINOR, ABS_MT_WIDTH_MAJOR, ABS_MT_WIDTH_MINOR)
+ * is reported in units per millimeter (units/mm).
  * When INPUT_PROP_ACCELEROMETER is set the resolution changes.
  * The main axes (ABS_X, ABS_Y, ABS_Z) are then reported in
  * units per g (units/g) and in units per degree per second
index f10b59d..0ad3da2 100644 (file)
@@ -22,7 +22,10 @@ struct io_uring_sqe {
        union {
                __u64   off;    /* offset into file */
                __u64   addr2;
-               __u32   cmd_op;
+               struct {
+                       __u32   cmd_op;
+                       __u32   __pad1;
+               };
        };
        union {
                __u64   addr;   /* pointer to buffer or iovecs */
index 5088bd9..811897d 100644 (file)
@@ -2083,6 +2083,7 @@ struct kvm_stats_header {
 #define KVM_STATS_UNIT_BYTES           (0x1 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_SECONDS         (0x2 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_CYCLES          (0x3 << KVM_STATS_UNIT_SHIFT)
+#define KVM_STATS_UNIT_BOOLEAN         (0x4 << KVM_STATS_UNIT_SHIFT)
 #define KVM_STATS_UNIT_MAX             KVM_STATS_UNIT_CYCLES
 
 #define KVM_STATS_BASE_SHIFT           8
index 9d0f06b..68aeae2 100644 (file)
@@ -38,8 +38,9 @@
 #define N_NULL         27      /* Null ldisc used for error handling */
 #define N_MCTP         28      /* MCTP-over-serial */
 #define N_DEVELOPMENT  29      /* Manual out-of-tree testing */
+#define N_CAN327       30      /* ELM327 based OBD-II interfaces */
 
 /* Always the newest line discipline + 1 */
-#define NR_LDISCS      30
+#define NR_LDISCS      31
 
 #endif /* _UAPI_LINUX_TTY_H */
index e1126a7..eff166f 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __LINUX_OF_DISPLAY_TIMING_H
 #define __LINUX_OF_DISPLAY_TIMING_H
 
+#include <linux/errno.h>
+
 struct device_node;
 struct display_timing;
 struct display_timings;
index 754f323..e1fcaed 100644 (file)
@@ -64,7 +64,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
                goto fail_put;
 
        if (!setup_ipc_sysctls(ns))
-               goto fail_put;
+               goto fail_mq;
 
        sem_init_ns(ns);
        msg_init_ns(ns);
@@ -72,6 +72,9 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns,
 
        return ns;
 
+fail_mq:
+       retire_mq_sysctls(ns);
+
 fail_put:
        put_user_ns(ns->user_ns);
        ns_free_inum(&ns->ns);
index 5f6f3f8..e796150 100644 (file)
@@ -68,11 +68,13 @@ void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, uns
 {
        u8 *ptr = NULL;
 
-       if (k >= SKF_NET_OFF)
+       if (k >= SKF_NET_OFF) {
                ptr = skb_network_header(skb) + k - SKF_NET_OFF;
-       else if (k >= SKF_LL_OFF)
+       } else if (k >= SKF_LL_OFF) {
+               if (unlikely(!skb_mac_header_was_set(skb)))
+                       return NULL;
                ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
-
+       }
        if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
                return ptr;
 
index 225806a..bb1254f 100644 (file)
@@ -1497,11 +1497,12 @@ const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
        .arg4_type      = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
 };
 
-BPF_CALL_4(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src, u32, offset)
+BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, struct bpf_dynptr_kern *, src,
+          u32, offset, u64, flags)
 {
        int err;
 
-       if (!src->data)
+       if (!src->data || flags)
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(src, offset, len);
@@ -1521,13 +1522,15 @@ const struct bpf_func_proto bpf_dynptr_read_proto = {
        .arg2_type      = ARG_CONST_SIZE_OR_ZERO,
        .arg3_type      = ARG_PTR_TO_DYNPTR,
        .arg4_type      = ARG_ANYTHING,
+       .arg5_type      = ARG_ANYTHING,
 };
 
-BPF_CALL_4(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src, u32, len)
+BPF_CALL_5(bpf_dynptr_write, struct bpf_dynptr_kern *, dst, u32, offset, void *, src,
+          u32, len, u64, flags)
 {
        int err;
 
-       if (!dst->data || bpf_dynptr_is_rdonly(dst))
+       if (!dst->data || flags || bpf_dynptr_is_rdonly(dst))
                return -EINVAL;
 
        err = bpf_dynptr_check_off_len(dst, offset, len);
@@ -1547,6 +1550,7 @@ const struct bpf_func_proto bpf_dynptr_write_proto = {
        .arg2_type      = ARG_ANYTHING,
        .arg3_type      = ARG_PTR_TO_MEM | MEM_RDONLY,
        .arg4_type      = ARG_CONST_SIZE_OR_ZERO,
+       .arg5_type      = ARG_ANYTHING,
 };
 
 BPF_CALL_3(bpf_dynptr_data, struct bpf_dynptr_kern *, ptr, u32, offset, u32, len)
index aedac2a..0efbac0 100644 (file)
@@ -1562,6 +1562,21 @@ static void __reg_bound_offset(struct bpf_reg_state *reg)
        reg->var_off = tnum_or(tnum_clear_subreg(var64_off), var32_off);
 }
 
+static void reg_bounds_sync(struct bpf_reg_state *reg)
+{
+       /* We might have learned new bounds from the var_off. */
+       __update_reg_bounds(reg);
+       /* We might have learned something about the sign bit. */
+       __reg_deduce_bounds(reg);
+       /* We might have learned some bits from the bounds. */
+       __reg_bound_offset(reg);
+       /* Intersecting with the old var_off might have improved our bounds
+        * slightly, e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
+        * then new var_off is (0; 0x7f...fc) which improves our umax.
+        */
+       __update_reg_bounds(reg);
+}
+
 static bool __reg32_bound_s64(s32 a)
 {
        return a >= 0 && a <= S32_MAX;
@@ -1603,16 +1618,8 @@ static void __reg_combine_32_into_64(struct bpf_reg_state *reg)
                 * so they do not impact tnum bounds calculation.
                 */
                __mark_reg64_unbounded(reg);
-               __update_reg_bounds(reg);
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 static bool __reg64_bound_s32(s64 a)
@@ -1628,7 +1635,6 @@ static bool __reg64_bound_u32(u64 a)
 static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
 {
        __mark_reg32_unbounded(reg);
-
        if (__reg64_bound_s32(reg->smin_value) && __reg64_bound_s32(reg->smax_value)) {
                reg->s32_min_value = (s32)reg->smin_value;
                reg->s32_max_value = (s32)reg->smax_value;
@@ -1637,14 +1643,7 @@ static void __reg_combine_64_into_32(struct bpf_reg_state *reg)
                reg->u32_min_value = (u32)reg->umin_value;
                reg->u32_max_value = (u32)reg->umax_value;
        }
-
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __reg_deduce_bounds(reg);
-       __reg_bound_offset(reg);
-       __update_reg_bounds(reg);
+       reg_bounds_sync(reg);
 }
 
 /* Mark a register as having a completely unknown (scalar) value. */
@@ -6943,9 +6942,7 @@ static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type,
        ret_reg->s32_max_value = meta->msize_max_value;
        ret_reg->smin_value = -MAX_ERRNO;
        ret_reg->s32_min_value = -MAX_ERRNO;
-       __reg_deduce_bounds(ret_reg);
-       __reg_bound_offset(ret_reg);
-       __update_reg_bounds(ret_reg);
+       reg_bounds_sync(ret_reg);
 }
 
 static int
@@ -8202,11 +8199,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
 
        if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
                return -EINVAL;
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
-
+       reg_bounds_sync(dst_reg);
        if (sanitize_check_bounds(env, insn, dst_reg) < 0)
                return -EACCES;
        if (sanitize_needed(opcode)) {
@@ -8944,10 +8937,7 @@ static int adjust_scalar_min_max_vals(struct bpf_verifier_env *env,
        /* ALU32 ops are zero extended into 64bit register */
        if (alu32)
                zext_32_to_64(dst_reg);
-
-       __update_reg_bounds(dst_reg);
-       __reg_deduce_bounds(dst_reg);
-       __reg_bound_offset(dst_reg);
+       reg_bounds_sync(dst_reg);
        return 0;
 }
 
@@ -9136,10 +9126,7 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
                                                         insn->dst_reg);
                                }
                                zext_32_to_64(dst_reg);
-
-                               __update_reg_bounds(dst_reg);
-                               __reg_deduce_bounds(dst_reg);
-                               __reg_bound_offset(dst_reg);
+                               reg_bounds_sync(dst_reg);
                        }
                } else {
                        /* case: R = imm
@@ -9577,26 +9564,33 @@ static void reg_set_min_max(struct bpf_reg_state *true_reg,
                return;
 
        switch (opcode) {
+       /* JEQ/JNE comparison doesn't change the register equivalence.
+        *
+        * r1 = r2;
+        * if (r1 == 42) goto label;
+        * ...
+        * label: // here both r1 and r2 are known to be 42.
+        *
+        * Hence when marking register as known preserve it's ID.
+        */
        case BPF_JEQ:
+               if (is_jmp32) {
+                       __mark_reg32_known(true_reg, val32);
+                       true_32off = tnum_subreg(true_reg->var_off);
+               } else {
+                       ___mark_reg_known(true_reg, val);
+                       true_64off = true_reg->var_off;
+               }
+               break;
        case BPF_JNE:
-       {
-               struct bpf_reg_state *reg =
-                       opcode == BPF_JEQ ? true_reg : false_reg;
-
-               /* JEQ/JNE comparison doesn't change the register equivalence.
-                * r1 = r2;
-                * if (r1 == 42) goto label;
-                * ...
-                * label: // here both r1 and r2 are known to be 42.
-                *
-                * Hence when marking register as known preserve it's ID.
-                */
-               if (is_jmp32)
-                       __mark_reg32_known(reg, val32);
-               else
-                       ___mark_reg_known(reg, val);
+               if (is_jmp32) {
+                       __mark_reg32_known(false_reg, val32);
+                       false_32off = tnum_subreg(false_reg->var_off);
+               } else {
+                       ___mark_reg_known(false_reg, val);
+                       false_64off = false_reg->var_off;
+               }
                break;
-       }
        case BPF_JSET:
                if (is_jmp32) {
                        false_32off = tnum_and(false_32off, tnum_const(~val32));
@@ -9735,21 +9729,8 @@ static void __reg_combine_min_max(struct bpf_reg_state *src_reg,
                                                        dst_reg->smax_value);
        src_reg->var_off = dst_reg->var_off = tnum_intersect(src_reg->var_off,
                                                             dst_reg->var_off);
-       /* We might have learned new bounds from the var_off. */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
-       /* We might have learned something about the sign bit. */
-       __reg_deduce_bounds(src_reg);
-       __reg_deduce_bounds(dst_reg);
-       /* We might have learned some bits from the bounds. */
-       __reg_bound_offset(src_reg);
-       __reg_bound_offset(dst_reg);
-       /* Intersecting with the old var_off might have improved our bounds
-        * slightly.  e.g. if umax was 0x7f...f and var_off was (0; 0xf...fc),
-        * then new var_off is (0; 0x7f...fc) which improves our umax.
-        */
-       __update_reg_bounds(src_reg);
-       __update_reg_bounds(dst_reg);
+       reg_bounds_sync(src_reg);
+       reg_bounds_sync(dst_reg);
 }
 
 static void reg_combine_min_max(struct bpf_reg_state *true_src,
index 1779ccd..13c8e91 100644 (file)
@@ -765,7 +765,8 @@ struct css_set init_css_set = {
        .task_iters             = LIST_HEAD_INIT(init_css_set.task_iters),
        .threaded_csets         = LIST_HEAD_INIT(init_css_set.threaded_csets),
        .cgrp_links             = LIST_HEAD_INIT(init_css_set.cgrp_links),
-       .mg_preload_node        = LIST_HEAD_INIT(init_css_set.mg_preload_node),
+       .mg_src_preload_node    = LIST_HEAD_INIT(init_css_set.mg_src_preload_node),
+       .mg_dst_preload_node    = LIST_HEAD_INIT(init_css_set.mg_dst_preload_node),
        .mg_node                = LIST_HEAD_INIT(init_css_set.mg_node),
 
        /*
@@ -1240,7 +1241,8 @@ static struct css_set *find_css_set(struct css_set *old_cset,
        INIT_LIST_HEAD(&cset->threaded_csets);
        INIT_HLIST_NODE(&cset->hlist);
        INIT_LIST_HEAD(&cset->cgrp_links);
-       INIT_LIST_HEAD(&cset->mg_preload_node);
+       INIT_LIST_HEAD(&cset->mg_src_preload_node);
+       INIT_LIST_HEAD(&cset->mg_dst_preload_node);
        INIT_LIST_HEAD(&cset->mg_node);
 
        /* Copy the set of subsystem state objects generated in
@@ -2597,21 +2599,27 @@ int cgroup_migrate_vet_dst(struct cgroup *dst_cgrp)
  */
 void cgroup_migrate_finish(struct cgroup_mgctx *mgctx)
 {
-       LIST_HEAD(preloaded);
        struct css_set *cset, *tmp_cset;
 
        lockdep_assert_held(&cgroup_mutex);
 
        spin_lock_irq(&css_set_lock);
 
-       list_splice_tail_init(&mgctx->preloaded_src_csets, &preloaded);
-       list_splice_tail_init(&mgctx->preloaded_dst_csets, &preloaded);
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_src_csets,
+                                mg_src_preload_node) {
+               cset->mg_src_cgrp = NULL;
+               cset->mg_dst_cgrp = NULL;
+               cset->mg_dst_cset = NULL;
+               list_del_init(&cset->mg_src_preload_node);
+               put_css_set_locked(cset);
+       }
 
-       list_for_each_entry_safe(cset, tmp_cset, &preloaded, mg_preload_node) {
+       list_for_each_entry_safe(cset, tmp_cset, &mgctx->preloaded_dst_csets,
+                                mg_dst_preload_node) {
                cset->mg_src_cgrp = NULL;
                cset->mg_dst_cgrp = NULL;
                cset->mg_dst_cset = NULL;
-               list_del_init(&cset->mg_preload_node);
+               list_del_init(&cset->mg_dst_preload_node);
                put_css_set_locked(cset);
        }
 
@@ -2651,7 +2659,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        if (src_cset->dead)
                return;
 
-       if (!list_empty(&src_cset->mg_preload_node))
+       if (!list_empty(&src_cset->mg_src_preload_node))
                return;
 
        src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root);
@@ -2664,7 +2672,7 @@ void cgroup_migrate_add_src(struct css_set *src_cset,
        src_cset->mg_src_cgrp = src_cgrp;
        src_cset->mg_dst_cgrp = dst_cgrp;
        get_css_set(src_cset);
-       list_add_tail(&src_cset->mg_preload_node, &mgctx->preloaded_src_csets);
+       list_add_tail(&src_cset->mg_src_preload_node, &mgctx->preloaded_src_csets);
 }
 
 /**
@@ -2689,7 +2697,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
        /* look up the dst cset for each src cset and link it to src */
        list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
-                                mg_preload_node) {
+                                mg_src_preload_node) {
                struct css_set *dst_cset;
                struct cgroup_subsys *ss;
                int ssid;
@@ -2708,7 +2716,7 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
                if (src_cset == dst_cset) {
                        src_cset->mg_src_cgrp = NULL;
                        src_cset->mg_dst_cgrp = NULL;
-                       list_del_init(&src_cset->mg_preload_node);
+                       list_del_init(&src_cset->mg_src_preload_node);
                        put_css_set(src_cset);
                        put_css_set(dst_cset);
                        continue;
@@ -2716,8 +2724,8 @@ int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
 
                src_cset->mg_dst_cset = dst_cset;
 
-               if (list_empty(&dst_cset->mg_preload_node))
-                       list_add_tail(&dst_cset->mg_preload_node,
+               if (list_empty(&dst_cset->mg_dst_preload_node))
+                       list_add_tail(&dst_cset->mg_dst_preload_node,
                                      &mgctx->preloaded_dst_csets);
                else
                        put_css_set(dst_cset);
@@ -2963,7 +2971,8 @@ static int cgroup_update_dfl_csses(struct cgroup *cgrp)
                goto out_finish;
 
        spin_lock_irq(&css_set_lock);
-       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets, mg_preload_node) {
+       list_for_each_entry(src_cset, &mgctx.preloaded_src_csets,
+                           mg_src_preload_node) {
                struct task_struct *task, *ntask;
 
                /* all tasks in src_csets need to be migrated */
index f072959..64c938c 100644 (file)
@@ -766,7 +766,7 @@ void __noreturn do_exit(long code)
 
 #ifdef CONFIG_POSIX_TIMERS
                hrtimer_cancel(&tsk->signal->real_timer);
-               exit_itimers(tsk->signal);
+               exit_itimers(tsk);
 #endif
                if (tsk->mm)
                        setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm);
index 145321a..f9261c0 100644 (file)
 #include <linux/vmalloc.h>
 #include "kexec_internal.h"
 
+#ifdef CONFIG_KEXEC_SIG
+static bool sig_enforce = IS_ENABLED(CONFIG_KEXEC_SIG_FORCE);
+
+void set_kexec_sig_enforced(void)
+{
+       sig_enforce = true;
+}
+#endif
+
 static int kexec_calculate_store_digests(struct kimage *image);
 
 /*
@@ -159,7 +168,7 @@ kimage_validate_signature(struct kimage *image)
                                           image->kernel_buf_len);
        if (ret) {
 
-               if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) {
+               if (sig_enforce) {
                        pr_notice("Enforced kernel signature verification failed (%d).\n", ret);
                        return ret;
                }
index bc5507a..ec104c2 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mutex.h>
 #include <linux/rculist.h>
 #include <linux/rcupdate.h>
+#include <linux/mm.h>
 
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
  * to ensure complete separation of code and data, but
  * only when CONFIG_STRICT_MODULE_RWX=y
  */
-#ifdef CONFIG_STRICT_MODULE_RWX
-# define strict_align(X) PAGE_ALIGN(X)
-#else
-# define strict_align(X) (X)
-#endif
+static inline unsigned int strict_align(unsigned int size)
+{
+       if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+               return PAGE_ALIGN(size);
+       else
+               return size;
+}
 
 extern struct mutex module_mutex;
 extern struct list_head modules;
index 3e11523..77e75be 100644 (file)
@@ -137,6 +137,7 @@ void layout_symtab(struct module *mod, struct load_info *info)
        info->symoffs = ALIGN(mod->data_layout.size, symsect->sh_addralign ?: 1);
        info->stroffs = mod->data_layout.size = info->symoffs + ndst * sizeof(Elf_Sym);
        mod->data_layout.size += strtab_size;
+       /* Note add_kallsyms() computes strtab_size as core_typeoffs - stroffs */
        info->core_typeoffs = mod->data_layout.size;
        mod->data_layout.size += ndst * sizeof(char);
        mod->data_layout.size = strict_align(mod->data_layout.size);
@@ -169,19 +170,20 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        Elf_Sym *dst;
        char *s;
        Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+       unsigned long strtab_size;
 
        /* Set up to point into init section. */
        mod->kallsyms = (void __rcu *)mod->init_layout.base +
                info->mod_kallsyms_init_off;
 
-       preempt_disable();
+       rcu_read_lock();
        /* The following is safe since this pointer cannot change */
-       rcu_dereference_sched(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+       rcu_dereference(mod->kallsyms)->symtab = (void *)symsec->sh_addr;
+       rcu_dereference(mod->kallsyms)->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
        /* Make sure we get permanent strtab: don't use info->strtab. */
-       rcu_dereference_sched(mod->kallsyms)->strtab =
+       rcu_dereference(mod->kallsyms)->strtab =
                (void *)info->sechdrs[info->index.str].sh_addr;
-       rcu_dereference_sched(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
+       rcu_dereference(mod->kallsyms)->typetab = mod->init_layout.base + info->init_typeoffs;
 
        /*
         * Now populate the cut down core kallsyms for after init
@@ -190,22 +192,29 @@ void add_kallsyms(struct module *mod, const struct load_info *info)
        mod->core_kallsyms.symtab = dst = mod->data_layout.base + info->symoffs;
        mod->core_kallsyms.strtab = s = mod->data_layout.base + info->stroffs;
        mod->core_kallsyms.typetab = mod->data_layout.base + info->core_typeoffs;
-       src = rcu_dereference_sched(mod->kallsyms)->symtab;
-       for (ndst = i = 0; i < rcu_dereference_sched(mod->kallsyms)->num_symtab; i++) {
-               rcu_dereference_sched(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
+       strtab_size = info->core_typeoffs - info->stroffs;
+       src = rcu_dereference(mod->kallsyms)->symtab;
+       for (ndst = i = 0; i < rcu_dereference(mod->kallsyms)->num_symtab; i++) {
+               rcu_dereference(mod->kallsyms)->typetab[i] = elf_type(src + i, info);
                if (i == 0 || is_livepatch_module(mod) ||
                    is_core_symbol(src + i, info->sechdrs, info->hdr->e_shnum,
                                   info->index.pcpu)) {
+                       ssize_t ret;
+
                        mod->core_kallsyms.typetab[ndst] =
-                           rcu_dereference_sched(mod->kallsyms)->typetab[i];
+                           rcu_dereference(mod->kallsyms)->typetab[i];
                        dst[ndst] = src[i];
                        dst[ndst++].st_name = s - mod->core_kallsyms.strtab;
-                       s += strscpy(s,
-                                    &rcu_dereference_sched(mod->kallsyms)->strtab[src[i].st_name],
-                                    KSYM_NAME_LEN) + 1;
+                       ret = strscpy(s,
+                                     &rcu_dereference(mod->kallsyms)->strtab[src[i].st_name],
+                                     strtab_size);
+                       if (ret < 0)
+                               break;
+                       s += ret + 1;
+                       strtab_size -= ret + 1;
                }
        }
-       preempt_enable();
+       rcu_read_unlock();
        mod->core_kallsyms.num_symtab = ndst;
 }
 
index fed58d3..0548151 100644 (file)
@@ -2939,24 +2939,25 @@ static void cfi_init(struct module *mod)
 {
 #ifdef CONFIG_CFI_CLANG
        initcall_t *init;
+#ifdef CONFIG_MODULE_UNLOAD
        exitcall_t *exit;
+#endif
 
        rcu_read_lock_sched();
        mod->cfi_check = (cfi_check_fn)
                find_kallsyms_symbol_value(mod, "__cfi_check");
        init = (initcall_t *)
                find_kallsyms_symbol_value(mod, "__cfi_jt_init_module");
-       exit = (exitcall_t *)
-               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
-       rcu_read_unlock_sched();
-
        /* Fix init/exit functions to point to the CFI jump table */
        if (init)
                mod->init = *init;
 #ifdef CONFIG_MODULE_UNLOAD
+       exit = (exitcall_t *)
+               find_kallsyms_symbol_value(mod, "__cfi_jt_cleanup_module");
        if (exit)
                mod->exit = *exit;
 #endif
+       rcu_read_unlock_sched();
 
        cfi_module_add(mod, mod_tree.addr_min);
 #endif
index b49c6ff..a1a81fd 100644 (file)
@@ -3380,6 +3380,7 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                diff = 0;
 
                console_lock();
+
                for_each_console(c) {
                        if (con && con != c)
                                continue;
@@ -3389,11 +3390,19 @@ static bool __pr_flush(struct console *con, int timeout_ms, bool reset_on_progre
                        if (printk_seq < seq)
                                diff += seq - printk_seq;
                }
-               console_unlock();
 
-               if (diff != last_diff && reset_on_progress)
+               /*
+                * If consoles are suspended, it cannot be expected that they
+                * make forward progress, so timeout immediately. @diff is
+                * still used to return a valid flush status.
+                */
+               if (console_suspended)
+                       remaining = 0;
+               else if (diff != last_diff && reset_on_progress)
                        remaining = timeout_ms;
 
+               console_unlock();
+
                if (diff == 0 || remaining == 0)
                        break;
 
index 156a992..1893d90 100644 (file)
@@ -222,7 +222,7 @@ static void ptrace_unfreeze_traced(struct task_struct *task)
        if (lock_task_sighand(task, &flags)) {
                task->jobctl &= ~JOBCTL_PTRACE_FROZEN;
                if (__fatal_signal_pending(task)) {
-                       task->jobctl &= ~TASK_TRACED;
+                       task->jobctl &= ~JOBCTL_TRACED;
                        wake_up_state(task, __TASK_TRACED);
                }
                unlock_task_sighand(task, &flags);
index edb1dc9..6f86fda 100644 (file)
@@ -2029,12 +2029,12 @@ bool do_notify_parent(struct task_struct *tsk, int sig)
        bool autoreap = false;
        u64 utime, stime;
 
-       BUG_ON(sig == -1);
+       WARN_ON_ONCE(sig == -1);
 
-       /* do_notify_parent_cldstop should have been called instead.  */
-       BUG_ON(task_is_stopped_or_traced(tsk));
+       /* do_notify_parent_cldstop should have been called instead.  */
+       WARN_ON_ONCE(task_is_stopped_or_traced(tsk));
 
-       BUG_ON(!tsk->ptrace &&
+       WARN_ON_ONCE(!tsk->ptrace &&
               (tsk->group_leader != tsk || !thread_group_empty(tsk)));
 
        /* Wake up all pidfd waiters */
index e52b6e3..35d0342 100644 (file)
@@ -446,14 +446,14 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp,
                if (*negp) {
                        if (*lvalp > (unsigned long) INT_MAX + 1)
                                return -EINVAL;
-                       *valp = -*lvalp;
+                       WRITE_ONCE(*valp, -*lvalp);
                } else {
                        if (*lvalp > (unsigned long) INT_MAX)
                                return -EINVAL;
-                       *valp = *lvalp;
+                       WRITE_ONCE(*valp, *lvalp);
                }
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                if (val < 0) {
                        *negp = true;
                        *lvalp = -(unsigned long)val;
@@ -472,9 +472,9 @@ static int do_proc_douintvec_conv(unsigned long *lvalp,
        if (write) {
                if (*lvalp > UINT_MAX)
                        return -EINVAL;
-               *valp = *lvalp;
+               WRITE_ONCE(*valp, *lvalp);
        } else {
-               unsigned int val = *valp;
+               unsigned int val = READ_ONCE(*valp);
                *lvalp = (unsigned long)val;
        }
        return 0;
@@ -857,7 +857,7 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp,
                if ((param->min && *param->min > tmp) ||
                    (param->max && *param->max < tmp))
                        return -EINVAL;
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -923,7 +923,7 @@ static int do_proc_douintvec_minmax_conv(unsigned long *lvalp,
                    (param->max && *param->max < tmp))
                        return -ERANGE;
 
-               *valp = tmp;
+               WRITE_ONCE(*valp, tmp);
        }
 
        return 0;
@@ -1007,13 +1007,13 @@ int proc_dou8vec_minmax(struct ctl_table *table, int write,
 
        tmp.maxlen = sizeof(val);
        tmp.data = &val;
-       val = *data;
+       val = READ_ONCE(*data);
        res = do_proc_douintvec(&tmp, write, buffer, lenp, ppos,
                                do_proc_douintvec_minmax_conv, &param);
        if (res)
                return res;
        if (write)
-               *data = val;
+               WRITE_ONCE(*data, val);
        return 0;
 }
 EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
@@ -1090,9 +1090,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table,
                                err = -EINVAL;
                                break;
                        }
-                       *i = val;
+                       WRITE_ONCE(*i, val);
                } else {
-                       val = convdiv * (*i) / convmul;
+                       val = convdiv * READ_ONCE(*i) / convmul;
                        if (!first)
                                proc_put_char(&buffer, &left, '\t');
                        proc_put_long(&buffer, &left, val, false);
@@ -1173,9 +1173,12 @@ static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp,
        if (write) {
                if (*lvalp > INT_MAX / HZ)
                        return 1;
-               *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ);
+               if (*negp)
+                       WRITE_ONCE(*valp, -*lvalp * HZ);
+               else
+                       WRITE_ONCE(*valp, *lvalp * HZ);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1221,9 +1224,9 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp,
 
                if (jif > INT_MAX)
                        return 1;
-               *valp = (int)jif;
+               WRITE_ONCE(*valp, (int)jif);
        } else {
-               int val = *valp;
+               int val = READ_ONCE(*valp);
                unsigned long lval;
                if (val < 0) {
                        *negp = true;
@@ -1291,8 +1294,8 @@ int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write,
  * @ppos: the current position in the file
  *
  * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
- * values from/to the user buffer, treated as an ASCII string. 
- * The values read are assumed to be in 1/1000 seconds, and 
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in 1/1000 seconds, and
  * are converted into jiffies.
  *
  * Returns 0 on success.
@@ -2091,6 +2094,17 @@ static struct ctl_table vm_table[] = {
                .extra1         = SYSCTL_ZERO,
                .extra2         = SYSCTL_TWO_HUNDRED,
        },
+#ifdef CONFIG_NUMA
+       {
+               .procname       = "numa_stat",
+               .data           = &sysctl_vm_numa_stat,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = sysctl_vm_numa_stat_handler,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
+       },
+#endif
 #ifdef CONFIG_HUGETLB_PAGE
        {
                .procname       = "nr_hugepages",
@@ -2107,15 +2121,6 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &hugetlb_mempolicy_sysctl_handler,
        },
-       {
-               .procname               = "numa_stat",
-               .data                   = &sysctl_vm_numa_stat,
-               .maxlen                 = sizeof(int),
-               .mode                   = 0644,
-               .proc_handler   = sysctl_vm_numa_stat_handler,
-               .extra1                 = SYSCTL_ZERO,
-               .extra2                 = SYSCTL_ONE,
-       },
 #endif
         {
                .procname       = "hugetlb_shm_group",
index 1cd10b1..5dead89 100644 (file)
@@ -1051,15 +1051,24 @@ retry_delete:
 }
 
 /*
- * This is called by do_exit or de_thread, only when there are no more
- * references to the shared signal_struct.
+ * This is called by do_exit or de_thread, only when nobody else can
+ * modify the signal->posix_timers list. Yet we need sighand->siglock
+ * to prevent the race with /proc/pid/timers.
  */
-void exit_itimers(struct signal_struct *sig)
+void exit_itimers(struct task_struct *tsk)
 {
+       struct list_head timers;
        struct k_itimer *tmr;
 
-       while (!list_empty(&sig->posix_timers)) {
-               tmr = list_entry(sig->posix_timers.next, struct k_itimer, list);
+       if (list_empty(&tsk->signal->posix_timers))
+               return;
+
+       spin_lock_irq(&tsk->sighand->siglock);
+       list_replace_init(&tsk->signal->posix_timers, &timers);
+       spin_unlock_irq(&tsk->sighand->siglock);
+
+       while (!list_empty(&timers)) {
+               tmr = list_first_entry(&timers, struct k_itimer, list);
                itimer_delete(tmr);
        }
 }
index debbbb0..ccd6a5a 100644 (file)
@@ -194,7 +194,8 @@ config FUNCTION_TRACER
          sequence is then dynamically patched into a tracer call when
          tracing is enabled by the administrator. If it's runtime disabled
          (the bootup default), then the overhead of the instructions is very
-         small and not measurable even in micro-benchmarks.
+         small and not measurable even in micro-benchmarks (at least on
+         x86, but may have impact on other architectures).
 
 config FUNCTION_GRAPH_TRACER
        bool "Kernel Function Graph Tracer"
index a8cfac0..b8dd546 100644 (file)
@@ -9864,6 +9864,12 @@ void trace_init_global_iter(struct trace_iterator *iter)
        /* Output in nanoseconds only if we are using a clock in nanoseconds. */
        if (trace_clocks[iter->tr->clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
+
+       /* Can not use kmalloc for iter.temp and iter.fmt */
+       iter->temp = static_temp_buf;
+       iter->temp_size = STATIC_TEMP_BUF_SIZE;
+       iter->fmt = static_fmt_buf;
+       iter->fmt_size = STATIC_FMT_BUF_SIZE;
 }
 
 void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
@@ -9896,11 +9902,6 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode)
 
        /* Simulate the iterator */
        trace_init_global_iter(&iter);
-       /* Can not use kmalloc for iter.temp and iter.fmt */
-       iter.temp = static_temp_buf;
-       iter.temp_size = STATIC_TEMP_BUF_SIZE;
-       iter.fmt = static_fmt_buf;
-       iter.fmt_size = STATIC_FMT_BUF_SIZE;
 
        for_each_tracing_cpu(cpu) {
                atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled);
index 48e82e1..e87a467 100644 (file)
@@ -4430,6 +4430,8 @@ static int parse_var_defs(struct hist_trigger_data *hist_data)
 
                        s = kstrdup(field_str, GFP_KERNEL);
                        if (!s) {
+                               kfree(hist_data->attrs->var_defs.name[n_vars]);
+                               hist_data->attrs->var_defs.name[n_vars] = NULL;
                                ret = -ENOMEM;
                                goto free;
                        }
index a9f7eb0..fd15230 100644 (file)
@@ -84,6 +84,9 @@ config UBSAN_SHIFT
 config UBSAN_DIV_ZERO
        bool "Perform checking for integer divide-by-zero"
        depends on $(cc-option,-fsanitize=integer-divide-by-zero)
+       # https://github.com/ClangBuiltLinux/linux/issues/1657
+       # https://github.com/llvm/llvm-project/issues/56289
+       depends on !CC_IS_CLANG
        help
          This option enables -fsanitize=integer-divide-by-zero which checks
          for integer division by zero. This is effectively redundant with the
index f4ab4f4..7ecdfdb 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -491,7 +491,8 @@ void ida_free(struct ida *ida, unsigned int id)
        struct ida_bitmap *bitmap;
        unsigned long flags;
 
-       BUG_ON((int)id < 0);
+       if ((int)id < 0)
+               return;
 
        xas_lock_irqsave(&xas, flags);
        bitmap = xas_load(&xas);
index 59e1653..3c7b9d6 100644 (file)
@@ -336,8 +336,7 @@ static void damon_hugetlb_mkold(pte_t *pte, struct mm_struct *mm,
        if (pte_young(entry)) {
                referenced = true;
                entry = pte_mkold(entry);
-               huge_ptep_set_access_flags(vma, addr, pte, entry,
-                                          vma->vm_flags & VM_WRITE);
+               set_huge_pte_at(mm, addr, pte, entry);
        }
 
 #ifdef CONFIG_MMU_NOTIFIER
index 7a08914..4cf7d4b 100644 (file)
@@ -4802,6 +4802,19 @@ static vm_fault_t create_huge_pud(struct vm_fault *vmf)
        defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
        /* No support for anonymous transparent PUD pages yet */
        if (vma_is_anonymous(vmf->vma))
+               return VM_FAULT_FALLBACK;
+       if (vmf->vma->vm_ops->huge_fault)
+               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+       return VM_FAULT_FALLBACK;
+}
+
+static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
+{
+#if defined(CONFIG_TRANSPARENT_HUGEPAGE) &&                    \
+       defined(CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD)
+       /* No support for anonymous transparent PUD pages yet */
+       if (vma_is_anonymous(vmf->vma))
                goto split;
        if (vmf->vma->vm_ops->huge_fault) {
                vm_fault_t ret = vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
@@ -4812,19 +4825,7 @@ static vm_fault_t create_huge_pud(struct vm_fault *vmf)
 split:
        /* COW or write-notify not handled on PUD level: split pud.*/
        __split_huge_pud(vmf->vma, vmf->pud, vmf->address);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
-       return VM_FAULT_FALLBACK;
-}
-
-static vm_fault_t wp_huge_pud(struct vm_fault *vmf, pud_t orig_pud)
-{
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-       /* No support for anonymous transparent PUD pages yet */
-       if (vma_is_anonymous(vmf->vma))
-               return VM_FAULT_FALLBACK;
-       if (vmf->vma->vm_ops->huge_fault)
-               return vmf->vma->vm_ops->huge_fault(vmf, PE_SIZE_PUD);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE && CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE_PUD */
        return VM_FAULT_FALLBACK;
 }
 
index 5bcb334..746c05a 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1899,8 +1899,23 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                /* Unexpected PMD-mapped THP? */
                VM_BUG_ON_FOLIO(!pvmw.pte, folio);
 
-               subpage = folio_page(folio,
-                               pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               if (folio_is_zone_device(folio)) {
+                       /*
+                        * Our PTE is a non-present device exclusive entry and
+                        * calculating the subpage as for the common case would
+                        * result in an invalid pointer.
+                        *
+                        * Since only PAGE_SIZE pages can currently be
+                        * migrated, just set it to page. This will need to be
+                        * changed when hugepage migrations to device private
+                        * memory are supported.
+                        */
+                       VM_BUG_ON_FOLIO(folio_nr_pages(folio) > 1, folio);
+                       subpage = &folio->page;
+               } else {
+                       subpage = folio_page(folio,
+                                       pte_pfn(*pvmw.pte) - folio_pfn(folio));
+               }
                address = pvmw.address;
                anon_exclusive = folio_test_anon(folio) &&
                                 PageAnonExclusive(subpage);
@@ -1993,15 +2008,7 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
                        /*
                         * No need to invalidate here it will synchronize on
                         * against the special swap migration pte.
-                        *
-                        * The assignment to subpage above was computed from a
-                        * swap PTE which results in an invalid pointer.
-                        * Since only PAGE_SIZE pages can currently be
-                        * migrated, just set it to page. This will need to be
-                        * changed when hugepage migrations to device private
-                        * memory are supported.
                         */
-                       subpage = &folio->page;
                } else if (PageHWPoison(subpage)) {
                        pteval = swp_entry_to_pte(make_hwpoison_entry(subpage));
                        if (folio_test_hugetlb(folio)) {
index f4fa61d..dbbd1a7 100644 (file)
@@ -78,6 +78,14 @@ static int __split_vmemmap_huge_pmd(pmd_t *pmd, unsigned long start)
 
        spin_lock(&init_mm.page_table_lock);
        if (likely(pmd_leaf(*pmd))) {
+               /*
+                * Higher order allocations from buddy allocator must be able to
+                * be treated as indepdenent small pages (as they can be freed
+                * individually).
+                */
+               if (!PageReserved(page))
+                       split_page(page, get_order(PMD_SIZE));
+
                /* Make pte visible before pmd. See comment in pmd_install(). */
                smp_wmb();
                pmd_populate_kernel(&init_mm, pmd, pgtable);
index 4f4892a..07d3bef 100644 (file)
@@ -246,7 +246,10 @@ static int mcontinue_atomic_pte(struct mm_struct *dst_mm,
        struct page *page;
        int ret;
 
-       ret = shmem_getpage(inode, pgoff, &page, SGP_READ);
+       ret = shmem_getpage(inode, pgoff, &page, SGP_NOALLOC);
+       /* Our caller expects us to return -EFAULT if we failed to find page. */
+       if (ret == -ENOENT)
+               ret = -EFAULT;
        if (ret)
                goto out;
        if (!page) {
index 53b1955..2145321 100644 (file)
@@ -182,10 +182,14 @@ static int vlan_newlink(struct net *src_net, struct net_device *dev,
        else if (dev->mtu > max_mtu)
                return -EINVAL;
 
+       /* Note: If this initial vlan_changelink() fails, we need
+        * to call vlan_dev_free_egress_priority() to free memory.
+        */
        err = vlan_changelink(dev, tb, data, extack);
-       if (err)
-               return err;
-       err = register_vlan_dev(dev, extack);
+
+       if (!err)
+               err = register_vlan_dev(dev, extack);
+
        if (err)
                vlan_dev_free_egress_priority(dev);
        return err;
index 59a5c13..a0f99ba 100644 (file)
@@ -571,6 +571,7 @@ int hci_dev_close(__u16 dev)
                goto done;
        }
 
+       cancel_work_sync(&hdev->power_on);
        if (hci_dev_test_and_clear_flag(hdev, HCI_AUTO_OFF))
                cancel_delayed_work(&hdev->power_off);
 
@@ -2675,6 +2676,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
        list_del(&hdev->list);
        write_unlock(&hci_dev_list_lock);
 
+       cancel_work_sync(&hdev->power_on);
+
        hci_cmd_sync_clear(hdev);
 
        if (!test_bit(HCI_QUIRK_NO_SUSPEND_NOTIFIER, &hdev->quirks))
index 286d676..1739e8c 100644 (file)
@@ -4088,7 +4088,6 @@ int hci_dev_close_sync(struct hci_dev *hdev)
 
        bt_dev_dbg(hdev, "");
 
-       cancel_work_sync(&hdev->power_on);
        cancel_delayed_work(&hdev->power_off);
        cancel_delayed_work(&hdev->ncmd_timer);
 
index 65ee1b7..e60161b 100644 (file)
@@ -100,6 +100,7 @@ static inline u64 get_u64(const struct canfd_frame *cp, int offset)
 
 struct bcm_op {
        struct list_head list;
+       struct rcu_head rcu;
        int ifindex;
        canid_t can_id;
        u32 flags;
@@ -718,10 +719,9 @@ static struct bcm_op *bcm_find_op(struct list_head *ops,
        return NULL;
 }
 
-static void bcm_remove_op(struct bcm_op *op)
+static void bcm_free_op_rcu(struct rcu_head *rcu_head)
 {
-       hrtimer_cancel(&op->timer);
-       hrtimer_cancel(&op->thrtimer);
+       struct bcm_op *op = container_of(rcu_head, struct bcm_op, rcu);
 
        if ((op->frames) && (op->frames != &op->sframe))
                kfree(op->frames);
@@ -732,6 +732,14 @@ static void bcm_remove_op(struct bcm_op *op)
        kfree(op);
 }
 
+static void bcm_remove_op(struct bcm_op *op)
+{
+       hrtimer_cancel(&op->timer);
+       hrtimer_cancel(&op->thrtimer);
+
+       call_rcu(&op->rcu, bcm_free_op_rcu);
+}
+
 static void bcm_rx_unreg(struct net_device *dev, struct bcm_op *op)
 {
        if (op->rx_reg_dev == dev) {
@@ -757,6 +765,9 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                if ((op->can_id == mh->can_id) && (op->ifindex == ifindex) &&
                    (op->flags & CAN_FD_FRAME) == (mh->flags & CAN_FD_FRAME)) {
 
+                       /* disable automatic timer on frame reception */
+                       op->flags |= RX_NO_AUTOTIMER;
+
                        /*
                         * Don't care if we're bound or not (due to netdev
                         * problems) can_rx_unregister() is always a save
@@ -785,7 +796,6 @@ static int bcm_delete_rx_op(struct list_head *ops, struct bcm_msg_head *mh,
                                                  bcm_rx_handler, op);
 
                        list_del(&op->list);
-                       synchronize_rcu();
                        bcm_remove_op(op);
                        return 1; /* done */
                }
index 8e6f229..30a1603 100644 (file)
@@ -4863,7 +4863,10 @@ static u32 netif_receive_generic_xdp(struct sk_buff *skb,
 }
 
 /* When doing generic XDP we have to bypass the qdisc layer and the
- * network taps in order to match in-driver-XDP behavior.
+ * network taps in order to match in-driver-XDP behavior. This also means
+ * that XDP packets are able to starve other packets going through a qdisc,
+ * and DDOS attacks will be more effective. In-driver-XDP use dedicated TX
+ * queues, so they do not have this starvation issue.
  */
 void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
 {
@@ -4875,7 +4878,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        txq = netdev_core_pick_tx(dev, skb, NULL);
        cpu = smp_processor_id();
        HARD_TX_LOCK(dev, txq, cpu);
-       if (!netif_xmit_stopped(txq)) {
+       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
                rc = netdev_start_xmit(skb, dev, txq, 0);
                if (dev_xmit_complete(rc))
                        free_skb = false;
@@ -4883,6 +4886,7 @@ void generic_xdp_tx(struct sk_buff *skb, struct bpf_prog *xdp_prog)
        HARD_TX_UNLOCK(dev, txq);
        if (free_skb) {
                trace_xdp_exception(dev, xdp_prog, XDP_TX);
+               dev_core_stats_tx_dropped_inc(dev);
                kfree_skb(skb);
        }
 }
index 5d16d66..2a6a0b0 100644 (file)
@@ -6158,7 +6158,6 @@ static int bpf_push_seg6_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len
        if (err)
                return err;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        return seg6_lookup_nexthop(skb, NULL, 0);
index 93da9f7..ac67f6b 100644 (file)
@@ -1246,7 +1246,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
        if (new_saddr == old_saddr)
                return 0;
 
-       if (sock_net(sk)->ipv4.sysctl_ip_dynaddr > 1) {
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) > 1) {
                pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n",
                        __func__, &old_saddr, &new_saddr);
        }
@@ -1301,7 +1301,7 @@ int inet_sk_rebuild_header(struct sock *sk)
                 * Other protocols have to map its equivalent state to TCP_SYN_SENT.
                 * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme
                 */
-               if (!sock_net(sk)->ipv4.sysctl_ip_dynaddr ||
+               if (!READ_ONCE(sock_net(sk)->ipv4.sysctl_ip_dynaddr) ||
                    sk->sk_state != TCP_SYN_SENT ||
                    (sk->sk_userlocks & SOCK_BINDADDR_LOCK) ||
                    (err = inet_sk_reselect_saddr(sk)) != 0)
index 62d5f99..6cd3b6c 100644 (file)
@@ -239,7 +239,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
        struct cipso_v4_map_cache_entry *prev_entry = NULL;
        u32 hash;
 
-       if (!cipso_v4_cache_enabled)
+       if (!READ_ONCE(cipso_v4_cache_enabled))
                return -ENOENT;
 
        hash = cipso_v4_map_cache_hash(key, key_len);
@@ -296,13 +296,14 @@ static int cipso_v4_cache_check(const unsigned char *key,
 int cipso_v4_cache_add(const unsigned char *cipso_ptr,
                       const struct netlbl_lsm_secattr *secattr)
 {
+       int bkt_size = READ_ONCE(cipso_v4_cache_bucketsize);
        int ret_val = -EPERM;
        u32 bkt;
        struct cipso_v4_map_cache_entry *entry = NULL;
        struct cipso_v4_map_cache_entry *old_entry = NULL;
        u32 cipso_ptr_len;
 
-       if (!cipso_v4_cache_enabled || cipso_v4_cache_bucketsize <= 0)
+       if (!READ_ONCE(cipso_v4_cache_enabled) || bkt_size <= 0)
                return 0;
 
        cipso_ptr_len = cipso_ptr[1];
@@ -322,7 +323,7 @@ int cipso_v4_cache_add(const unsigned char *cipso_ptr,
 
        bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETS - 1);
        spin_lock_bh(&cipso_v4_cache[bkt].lock);
-       if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
+       if (cipso_v4_cache[bkt].size < bkt_size) {
                list_add(&entry->list, &cipso_v4_cache[bkt].list);
                cipso_v4_cache[bkt].size += 1;
        } else {
@@ -1199,7 +1200,8 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
                /* This will send packets using the "optimized" format when
                 * possible as specified in  section 3.4.2.6 of the
                 * CIPSO draft. */
-               if (cipso_v4_rbm_optfmt && ret_val > 0 && ret_val <= 10)
+               if (READ_ONCE(cipso_v4_rbm_optfmt) && ret_val > 0 &&
+                   ret_val <= 10)
                        tag_len = 14;
                else
                        tag_len = 4 + ret_val;
@@ -1603,7 +1605,7 @@ int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option)
                         * all the CIPSO validations here but it doesn't
                         * really specify _exactly_ what we need to validate
                         * ... so, just make it a sysctl tunable. */
-                       if (cipso_v4_rbm_strictvalid) {
+                       if (READ_ONCE(cipso_v4_rbm_strictvalid)) {
                                if (cipso_v4_map_lvl_valid(doi_def,
                                                           tag[3]) < 0) {
                                        err_offset = opt_iter + 3;
index a57ba23..d9fdcba 100644 (file)
@@ -1230,7 +1230,7 @@ static int fib_check_nh_nongw(struct net *net, struct fib_nh *nh,
 
        nh->fib_nh_dev = in_dev->dev;
        dev_hold_track(nh->fib_nh_dev, &nh->fib_nh_dev_tracker, GFP_ATOMIC);
-       nh->fib_nh_scope = RT_SCOPE_HOST;
+       nh->fib_nh_scope = RT_SCOPE_LINK;
        if (!netif_carrier_ok(nh->fib_nh_dev))
                nh->fib_nh_flags |= RTNH_F_LINKDOWN;
        err = 0;
@@ -1811,7 +1811,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
                        goto nla_put_failure;
                if (nexthop_is_blackhole(fi->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
-               if (!fi->fib_net->ipv4.sysctl_nexthop_compat_mode)
+               if (!READ_ONCE(fi->fib_net->ipv4.sysctl_nexthop_compat_mode))
                        goto offload;
        }
 
index 2734c3a..46e8a51 100644 (file)
@@ -498,7 +498,7 @@ static void tnode_free(struct key_vector *tn)
                tn = container_of(head, struct tnode, rcu)->kv;
        }
 
-       if (tnode_free_size >= sysctl_fib_sync_mem) {
+       if (tnode_free_size >= READ_ONCE(sysctl_fib_sync_mem)) {
                tnode_free_size = 0;
                synchronize_rcu();
        }
index efea0e7..57c4f0d 100644 (file)
@@ -253,11 +253,12 @@ bool icmp_global_allow(void)
        spin_lock(&icmp_global.lock);
        delta = min_t(u32, now - icmp_global.stamp, HZ);
        if (delta >= HZ / 50) {
-               incr = sysctl_icmp_msgs_per_sec * delta / HZ ;
+               incr = READ_ONCE(sysctl_icmp_msgs_per_sec) * delta / HZ;
                if (incr)
                        WRITE_ONCE(icmp_global.stamp, now);
        }
-       credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst);
+       credit = min_t(u32, icmp_global.credit + incr,
+                      READ_ONCE(sysctl_icmp_msgs_burst));
        if (credit) {
                /* We want to use a credit of one in average, but need to randomize
                 * it for security reasons.
@@ -281,7 +282,7 @@ static bool icmpv4_mask_allow(struct net *net, int type, int code)
                return true;
 
        /* Limit if icmp type is enabled in ratemask. */
-       if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask))
+       if (!((1 << type) & READ_ONCE(net->ipv4.sysctl_icmp_ratemask)))
                return true;
 
        return false;
@@ -319,7 +320,8 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt,
 
        vif = l3mdev_master_ifindex(dst->dev);
        peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1);
-       rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit);
+       rc = inet_peer_xrlim_allow(peer,
+                                  READ_ONCE(net->ipv4.sysctl_icmp_ratelimit));
        if (peer)
                inet_putpeer(peer);
 out:
@@ -692,7 +694,7 @@ void __icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info,
 
                rcu_read_lock();
                if (rt_is_input_route(rt) &&
-                   net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr)
+                   READ_ONCE(net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr))
                        dev = dev_get_by_index_rcu(net, inet_iif(skb_in));
 
                if (dev)
@@ -932,7 +934,7 @@ static enum skb_drop_reason icmp_unreach(struct sk_buff *skb)
         *      get the other vendor to fix their kit.
         */
 
-       if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses &&
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_ignore_bogus_error_responses) &&
            inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) {
                net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n",
                                     &ip_hdr(skb)->saddr,
@@ -992,7 +994,7 @@ static enum skb_drop_reason icmp_echo(struct sk_buff *skb)
 
        net = dev_net(skb_dst(skb)->dev);
        /* should there be an ICMP stat for ignored echos? */
-       if (net->ipv4.sysctl_icmp_echo_ignore_all)
+       if (READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_all))
                return SKB_NOT_DROPPED_YET;
 
        icmp_param.data.icmph      = *icmp_hdr(skb);
@@ -1027,7 +1029,7 @@ bool icmp_build_probe(struct sk_buff *skb, struct icmphdr *icmphdr)
        u16 ident_len;
        u8 status;
 
-       if (!net->ipv4.sysctl_icmp_echo_enable_probe)
+       if (!READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                return false;
 
        /* We currently only support probing interfaces on the proxy node
@@ -1248,7 +1250,7 @@ int icmp_rcv(struct sk_buff *skb)
                 */
                if ((icmph->type == ICMP_ECHO ||
                     icmph->type == ICMP_TIMESTAMP) &&
-                   net->ipv4.sysctl_icmp_echo_ignore_broadcasts) {
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_ignore_broadcasts)) {
                        reason = SKB_DROP_REASON_INVALID_PROTO;
                        goto error;
                }
index 0ec5018..47ccc34 100644 (file)
@@ -156,7 +156,8 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk,
 {
        struct inet_timewait_sock *tw;
 
-       if (refcount_read(&dr->tw_refcount) - 1 >= dr->sysctl_max_tw_buckets)
+       if (refcount_read(&dr->tw_refcount) - 1 >=
+           READ_ONCE(dr->sysctl_max_tw_buckets))
                return NULL;
 
        tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab,
index da21dfc..e9fed83 100644 (file)
@@ -141,16 +141,20 @@ static void inet_peer_gc(struct inet_peer_base *base,
                         struct inet_peer *gc_stack[],
                         unsigned int gc_cnt)
 {
+       int peer_threshold, peer_maxttl, peer_minttl;
        struct inet_peer *p;
        __u32 delta, ttl;
        int i;
 
-       if (base->total >= inet_peer_threshold)
+       peer_threshold = READ_ONCE(inet_peer_threshold);
+       peer_maxttl = READ_ONCE(inet_peer_maxttl);
+       peer_minttl = READ_ONCE(inet_peer_minttl);
+
+       if (base->total >= peer_threshold)
                ttl = 0; /* be aggressive */
        else
-               ttl = inet_peer_maxttl
-                               - (inet_peer_maxttl - inet_peer_minttl) / HZ *
-                                       base->total / inet_peer_threshold * HZ;
+               ttl = peer_maxttl - (peer_maxttl - peer_minttl) / HZ *
+                       base->total / peer_threshold * HZ;
        for (i = 0; i < gc_cnt; i++) {
                p = gc_stack[i];
 
index e459a39..853a75a 100644 (file)
@@ -1858,7 +1858,7 @@ static void __remove_nexthop_fib(struct net *net, struct nexthop *nh)
                /* __ip6_del_rt does a release, so do a hold here */
                fib6_info_hold(f6i);
                ipv6_stub->ip6_del_rt(net, f6i,
-                                     !net->ipv4.sysctl_nexthop_compat_mode);
+                                     !READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode));
        }
 }
 
@@ -2361,7 +2361,8 @@ out:
        if (!rc) {
                nh_base_seq_inc(net);
                nexthop_notify(RTM_NEWNEXTHOP, new_nh, &cfg->nlinfo);
-               if (replace_notify && net->ipv4.sysctl_nexthop_compat_mode)
+               if (replace_notify &&
+                   READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode))
                        nexthop_replace_notify(net, new_nh, &cfg->nlinfo);
        }
 
index f33c31d..b387c48 100644 (file)
@@ -273,7 +273,7 @@ bool cookie_ecn_ok(const struct tcp_options_received *tcp_opt,
        if (!ecn_ok)
                return false;
 
-       if (net->ipv4.sysctl_tcp_ecn)
+       if (READ_ONCE(net->ipv4.sysctl_tcp_ecn))
                return true;
 
        return dst_feature(dst, RTAX_FEATURE_ECN);
index cd448cd..108fd86 100644 (file)
@@ -599,6 +599,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_echo_enable_probe",
@@ -615,6 +617,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ignore_bogus_error_responses",
@@ -622,6 +626,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_errors_use_inbound_ifaddr",
@@ -629,6 +635,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE
        },
        {
                .procname       = "icmp_ratelimit",
@@ -668,6 +676,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_TWO,
        },
        {
                .procname       = "tcp_ecn_fallback",
@@ -675,6 +685,8 @@ static struct ctl_table ipv4_net_table[] = {
                .maxlen         = sizeof(u8),
                .mode           = 0644,
                .proc_handler   = proc_dou8vec_minmax,
+               .extra1         = SYSCTL_ZERO,
+               .extra2         = SYSCTL_ONE,
        },
        {
                .procname       = "ip_dynaddr",
index 028513d..2222dfd 100644 (file)
@@ -2715,7 +2715,8 @@ static void tcp_orphan_update(struct timer_list *unused)
 
 static bool tcp_too_many_orphans(int shift)
 {
-       return READ_ONCE(tcp_orphan_cache) << shift > sysctl_tcp_max_orphans;
+       return READ_ONCE(tcp_orphan_cache) << shift >
+               READ_ONCE(sysctl_tcp_max_orphans);
 }
 
 bool tcp_check_oom(struct sock *sk, int shift)
index 2e2a9ec..3ec4edc 100644 (file)
@@ -6729,7 +6729,7 @@ static void tcp_ecn_create_request(struct request_sock *req,
 
        ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield);
        ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK);
-       ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst;
+       ecn_ok = READ_ONCE(net->ipv4.sysctl_tcp_ecn) || ecn_ok_dst;
 
        if (((!ect || th->res1) && ecn_ok) || tcp_ca_needs_ecn(listen_sk) ||
            (ecn_ok_dst & DST_FEATURE_ECN_CA) ||
index 1c05443..11aa0ab 100644 (file)
@@ -324,7 +324,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        bool bpf_needs_ecn = tcp_bpf_ca_needs_ecn(sk);
-       bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 ||
+       bool use_ecn = READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn) == 1 ||
                tcp_ca_needs_ecn(sk) || bpf_needs_ecn;
 
        if (!use_ecn) {
@@ -346,7 +346,7 @@ static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb)
 
 static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb)
 {
-       if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback)
+       if (READ_ONCE(sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback))
                /* tp->ecn_flags are cleared at a later point in time when
                 * SYN ACK is ultimatively being received.
                 */
index 6177022..9d92d51 100644 (file)
@@ -925,7 +925,7 @@ static int icmpv6_rcv(struct sk_buff *skb)
                break;
        case ICMPV6_EXT_ECHO_REQUEST:
                if (!net->ipv6.sysctl.icmpv6_echo_ignore_all &&
-                   net->ipv4.sysctl_icmp_echo_enable_probe)
+                   READ_ONCE(net->ipv4.sysctl_icmp_echo_enable_probe))
                        icmpv6_echo_reply(skb);
                break;
 
index 8283557..9164179 100644 (file)
@@ -5741,7 +5741,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
                if (nexthop_is_blackhole(rt->nh))
                        rtm->rtm_type = RTN_BLACKHOLE;
 
-               if (net->ipv4.sysctl_nexthop_compat_mode &&
+               if (READ_ONCE(net->ipv4.sysctl_nexthop_compat_mode) &&
                    rt6_fill_node_nexthop(skb, rt->nh, &nh_flags) < 0)
                        goto nla_put_failure;
 
index d648550..e756ba7 100644 (file)
@@ -189,6 +189,8 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, tot_len);
 
        return 0;
@@ -241,6 +243,8 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
        }
 #endif
 
+       hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+
        skb_postpush_rcsum(skb, hdr, sizeof(struct ipv6hdr) + hdrlen);
 
        return 0;
@@ -302,7 +306,6 @@ static int seg6_do_srh(struct sk_buff *skb)
                break;
        }
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
        nf_reset_ct(skb);
 
index 98a3428..2cd4a8d 100644 (file)
@@ -826,7 +826,6 @@ static int input_action_end_b6(struct sk_buff *skb, struct seg6_local_lwt *slwt)
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
@@ -858,7 +857,6 @@ static int input_action_end_b6_encap(struct sk_buff *skb,
        if (err)
                goto drop;
 
-       ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
        skb_set_transport_header(skb, sizeof(struct ipv6hdr));
 
        seg6_lookup_nexthop(skb, NULL, 0);
index f7896f2..4ddf297 100644 (file)
@@ -4468,14 +4468,14 @@ EXPORT_SYMBOL_GPL(ieee80211_color_change_finish);
 
 void
 ieeee80211_obss_color_collision_notify(struct ieee80211_vif *vif,
-                                      u64 color_bitmap)
+                                      u64 color_bitmap, gfp_t gfp)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
 
        if (sdata->vif.color_change_active || sdata->vif.csa_active)
                return;
 
-       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap);
+       cfg80211_obss_color_collision_notify(sdata->dev, color_bitmap, gfp);
 }
 EXPORT_SYMBOL_GPL(ieeee80211_obss_color_collision_notify);
 
index 4153147..15a73b7 100644 (file)
@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
        bool cancel_scan;
        struct cfg80211_nan_func *func;
 
+       spin_lock_bh(&local->fq.lock);
        clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+       spin_unlock_bh(&local->fq.lock);
 
        cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
        if (cancel_scan)
index 3c08ae0..1675f8c 100644 (file)
@@ -3217,7 +3217,8 @@ ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
                                      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
                if (color == bss_conf->he_bss_color.color)
                        ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
-                                                              BIT_ULL(color));
+                                                              BIT_ULL(color),
+                                                              GFP_ATOMIC);
        }
 }
 
index 0e4efc0..c425f4f 100644 (file)
@@ -2818,19 +2818,10 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
        /*
         * If the skb is shared we need to obtain our own copy.
         */
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               /* can't happen -- skb is a clone if info_id != 0 */
-               WARN_ON(info_id);
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb) {
-                       ret = -ENOMEM;
-                       goto free;
-               }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb)) {
+               ret = -ENOMEM;
+               goto free;
        }
 
        hdr.frame_control = fc;
@@ -3539,15 +3530,9 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
 
        /* after this point (skb is modified) we cannot return false */
 
-       if (skb_shared(skb)) {
-               struct sk_buff *tmp_skb = skb;
-
-               skb = skb_clone(skb, GFP_ATOMIC);
-               kfree_skb(tmp_skb);
-
-               if (!skb)
-                       return true;
-       }
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return true;
 
        if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) &&
            ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb))
@@ -4437,7 +4422,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
                                struct net_device *dev, struct sta_info *sta,
                                struct ieee80211_key *key, struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_info *info;
        struct ieee80211_local *local = sdata->local;
        struct tid_ampdu_tx *tid_tx;
        u8 tid;
@@ -4452,6 +4437,11 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
            test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
                goto out_free;
 
+       skb = skb_share_check(skb, GFP_ATOMIC);
+       if (unlikely(!skb))
+               return;
+
+       info = IEEE80211_SKB_CB(skb);
        memset(info, 0, sizeof(*info));
 
        ieee80211_aggr_check(sdata, sta, skb);
index 1e26b52..dad42d4 100644 (file)
@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
        local_bh_disable();
        spin_lock(&fq->lock);
 
+       if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
+               goto out;
+
        if (sdata->vif.type == NL80211_IFTYPE_AP)
                ps = &sdata->bss->ps;
 
index 62c6733..d50480b 100644 (file)
@@ -147,8 +147,8 @@ u16 __ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        bool qos;
 
        /* all mesh/ocb stations are required to support WME */
-       if (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
-           sdata->vif.type == NL80211_IFTYPE_OCB)
+       if (sta && (sdata->vif.type == NL80211_IFTYPE_MESH_POINT ||
+                   sdata->vif.type == NL80211_IFTYPE_OCB))
                qos = true;
        else if (sta)
                qos = sta->sta.wme;
index aead331..bd8f0f4 100644 (file)
@@ -1584,6 +1584,9 @@ mp_rst:
                *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO,
                                      TCPOLEN_MPTCP_PRIO,
                                      opts->backup, TCPOPT_NOP);
+
+               MPTCP_INC_STATS(sock_net((const struct sock *)tp),
+                               MPTCP_MIB_MPPRIOTX);
        }
 
 mp_capable_done:
index e099f2a..7c7395b 100644 (file)
@@ -717,9 +717,10 @@ void mptcp_pm_nl_addr_send_ack(struct mptcp_sock *msk)
        }
 }
 
-static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
-                                       struct mptcp_addr_info *addr,
-                                       u8 bkup)
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup)
 {
        struct mptcp_subflow_context *subflow;
 
@@ -727,24 +728,29 @@ static int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
 
        mptcp_for_each_subflow(msk, subflow) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
-               struct sock *sk = (struct sock *)msk;
-               struct mptcp_addr_info local;
+               struct mptcp_addr_info local, remote;
+               bool slow;
 
                local_address((struct sock_common *)ssk, &local);
                if (!mptcp_addresses_equal(&local, addr, addr->port))
                        continue;
 
+               if (rem && rem->family != AF_UNSPEC) {
+                       remote_address((struct sock_common *)ssk, &remote);
+                       if (!mptcp_addresses_equal(&remote, rem, rem->port))
+                               continue;
+               }
+
+               slow = lock_sock_fast(ssk);
                if (subflow->backup != bkup)
                        msk->last_snd = NULL;
                subflow->backup = bkup;
                subflow->send_mp_prio = 1;
                subflow->request_bkup = bkup;
-               __MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPPRIOTX);
 
-               spin_unlock_bh(&msk->pm.lock);
                pr_debug("send ack for mp_prio");
-               mptcp_subflow_send_ack(ssk);
-               spin_lock_bh(&msk->pm.lock);
+               __mptcp_subflow_send_ack(ssk);
+               unlock_sock_fast(ssk, slow);
 
                return 0;
        }
@@ -801,7 +807,8 @@ static void mptcp_pm_nl_rm_addr_or_subflow(struct mptcp_sock *msk,
                        removed = true;
                        __MPTCP_INC_STATS(sock_net(sk), rm_type);
                }
-               __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
+               if (rm_type == MPTCP_MIB_RMSUBFLOW)
+                       __set_bit(rm_list->ids[i], msk->pm.id_avail_bitmap);
                if (!removed)
                        continue;
 
@@ -1816,8 +1823,10 @@ static void mptcp_pm_nl_fullmesh(struct mptcp_sock *msk,
 
        list.ids[list.nr++] = addr->id;
 
+       spin_lock_bh(&msk->pm.lock);
        mptcp_pm_nl_rm_subflow_received(msk, &list);
        mptcp_pm_create_subflow_or_signal_addr(msk);
+       spin_unlock_bh(&msk->pm.lock);
 }
 
 static int mptcp_nl_set_flags(struct net *net,
@@ -1835,12 +1844,10 @@ static int mptcp_nl_set_flags(struct net *net,
                        goto next;
 
                lock_sock(sk);
-               spin_lock_bh(&msk->pm.lock);
                if (changed & MPTCP_PM_ADDR_FLAG_BACKUP)
-                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, bkup);
+                       ret = mptcp_pm_nl_mp_prio_send_ack(msk, addr, NULL, bkup);
                if (changed & MPTCP_PM_ADDR_FLAG_FULLMESH)
                        mptcp_pm_nl_fullmesh(msk, addr);
-               spin_unlock_bh(&msk->pm.lock);
                release_sock(sk);
 
 next:
@@ -1854,6 +1861,9 @@ next:
 static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
 {
        struct mptcp_pm_addr_entry addr = { .addr = { .family = AF_UNSPEC }, }, *entry;
+       struct mptcp_pm_addr_entry remote = { .addr = { .family = AF_UNSPEC }, };
+       struct nlattr *attr_rem = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
+       struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
        struct nlattr *attr = info->attrs[MPTCP_PM_ATTR_ADDR];
        struct pm_nl_pernet *pernet = genl_info_pm_nl(info);
        u8 changed, mask = MPTCP_PM_ADDR_FLAG_BACKUP |
@@ -1866,6 +1876,12 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
        if (ret < 0)
                return ret;
 
+       if (attr_rem) {
+               ret = mptcp_pm_parse_entry(attr_rem, info, false, &remote);
+               if (ret < 0)
+                       return ret;
+       }
+
        if (addr.flags & MPTCP_PM_ADDR_FLAG_BACKUP)
                bkup = 1;
        if (addr.addr.family == AF_UNSPEC) {
@@ -1874,6 +1890,10 @@ static int mptcp_nl_cmd_set_flags(struct sk_buff *skb, struct genl_info *info)
                        return -EOPNOTSUPP;
        }
 
+       if (token)
+               return mptcp_userspace_pm_set_flags(sock_net(skb->sk),
+                                                   token, &addr, &remote, bkup);
+
        spin_lock_bh(&pernet->lock);
        entry = __lookup_addr(pernet, &addr.addr, lookup_by_id);
        if (!entry) {
index f56378e..9e82250 100644 (file)
@@ -5,6 +5,7 @@
  */
 
 #include "protocol.h"
+#include "mib.h"
 
 void mptcp_free_local_addr_list(struct mptcp_sock *msk)
 {
@@ -306,15 +307,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                                      const struct mptcp_addr_info *local,
                                      const struct mptcp_addr_info *remote)
 {
-       struct sock *sk = &msk->sk.icsk_inet.sk;
        struct mptcp_subflow_context *subflow;
-       struct sock *found = NULL;
 
        if (local->family != remote->family)
                return NULL;
 
-       lock_sock(sk);
-
        mptcp_for_each_subflow(msk, subflow) {
                const struct inet_sock *issk;
                struct sock *ssk;
@@ -347,16 +344,11 @@ static struct sock *mptcp_nl_find_ssk(struct mptcp_sock *msk,
                }
 
                if (issk->inet_sport == local->port &&
-                   issk->inet_dport == remote->port) {
-                       found = ssk;
-                       goto found;
-               }
+                   issk->inet_dport == remote->port)
+                       return ssk;
        }
 
-found:
-       release_sock(sk);
-
-       return found;
+       return NULL;
 }
 
 int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
@@ -412,18 +404,51 @@ int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
        }
 
        sk = &msk->sk.icsk_inet.sk;
+       lock_sock(sk);
        ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r);
        if (ssk) {
                struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
 
                mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
                mptcp_close_ssk(sk, ssk, subflow);
+               MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
                err = 0;
        } else {
                err = -ESRCH;
        }
+       release_sock(sk);
 
- destroy_err:
+destroy_err:
        sock_put((struct sock *)msk);
        return err;
 }
+
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup)
+{
+       struct mptcp_sock *msk;
+       int ret = -EINVAL;
+       u32 token_val;
+
+       token_val = nla_get_u32(token);
+
+       msk = mptcp_token_get_sock(net, token_val);
+       if (!msk)
+               return ret;
+
+       if (!mptcp_pm_is_userspace(msk))
+               goto set_flags_err;
+
+       if (loc->addr.family == AF_UNSPEC ||
+           rem->addr.family == AF_UNSPEC)
+               goto set_flags_err;
+
+       lock_sock((struct sock *)msk);
+       ret = mptcp_pm_nl_mp_prio_send_ack(msk, &loc->addr, &rem->addr, bkup);
+       release_sock((struct sock *)msk);
+
+set_flags_err:
+       sock_put((struct sock *)msk);
+       return ret;
+}
index e475212..21a3ed6 100644 (file)
@@ -506,13 +506,18 @@ static inline bool tcp_can_send_ack(const struct sock *ssk)
               (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_TIME_WAIT | TCPF_CLOSE | TCPF_LISTEN));
 }
 
+void __mptcp_subflow_send_ack(struct sock *ssk)
+{
+       if (tcp_can_send_ack(ssk))
+               tcp_send_ack(ssk);
+}
+
 void mptcp_subflow_send_ack(struct sock *ssk)
 {
        bool slow;
 
        slow = lock_sock_fast(ssk);
-       if (tcp_can_send_ack(ssk))
-               tcp_send_ack(ssk);
+       __mptcp_subflow_send_ack(ssk);
        unlock_sock_fast(ssk, slow);
 }
 
@@ -2914,12 +2919,12 @@ static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
 
 static int mptcp_disconnect(struct sock *sk, int flags)
 {
-       struct mptcp_subflow_context *subflow;
+       struct mptcp_subflow_context *subflow, *tmp;
        struct mptcp_sock *msk = mptcp_sk(sk);
 
        inet_sk_state_store(sk, TCP_CLOSE);
 
-       mptcp_for_each_subflow(msk, subflow) {
+       list_for_each_entry_safe(subflow, tmp, &msk->conn_list, node) {
                struct sock *ssk = mptcp_subflow_tcp_sock(subflow);
 
                __mptcp_close_ssk(sk, ssk, subflow, MPTCP_CF_FASTCLOSE);
index c14d70c..480c532 100644 (file)
@@ -607,6 +607,7 @@ void __init mptcp_subflow_init(void);
 void mptcp_subflow_shutdown(struct sock *sk, struct sock *ssk, int how);
 void mptcp_close_ssk(struct sock *sk, struct sock *ssk,
                     struct mptcp_subflow_context *subflow);
+void __mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_send_ack(struct sock *ssk);
 void mptcp_subflow_reset(struct sock *ssk);
 void mptcp_subflow_queue_clean(struct sock *ssk);
@@ -771,6 +772,10 @@ void mptcp_pm_rm_addr_received(struct mptcp_sock *msk,
                               const struct mptcp_rm_list *rm_list);
 void mptcp_pm_mp_prio_received(struct sock *sk, u8 bkup);
 void mptcp_pm_mp_fail_received(struct sock *sk, u64 fail_seq);
+int mptcp_pm_nl_mp_prio_send_ack(struct mptcp_sock *msk,
+                                struct mptcp_addr_info *addr,
+                                struct mptcp_addr_info *rem,
+                                u8 bkup);
 bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk,
                              const struct mptcp_pm_addr_entry *entry);
 void mptcp_pm_free_anno_list(struct mptcp_sock *msk);
@@ -787,7 +792,9 @@ int mptcp_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
 int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
                                                   unsigned int id,
                                                   u8 *flags, int *ifindex);
-
+int mptcp_userspace_pm_set_flags(struct net *net, struct nlattr *token,
+                                struct mptcp_pm_addr_entry *loc,
+                                struct mptcp_pm_addr_entry *rem, u8 bkup);
 int mptcp_pm_announce_addr(struct mptcp_sock *msk,
                           const struct mptcp_addr_info *addr,
                           bool echo);
index 082a2fd..369aeab 100644 (file)
@@ -729,6 +729,9 @@ static void nf_ct_gc_expired(struct nf_conn *ct)
        if (!refcount_inc_not_zero(&ct->ct_general.use))
                return;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct))
                nf_ct_kill(ct);
 
@@ -795,6 +798,9 @@ __nf_conntrack_find_get(struct net *net, const struct nf_conntrack_zone *zone,
                 */
                ct = nf_ct_tuplehash_to_ctrack(h);
                if (likely(refcount_inc_not_zero(&ct->ct_general.use))) {
+                       /* re-check key after refcount */
+                       smp_acquire__after_ctrl_dep();
+
                        if (likely(nf_ct_key_equal(h, tuple, zone, net)))
                                goto found;
 
@@ -1387,6 +1393,9 @@ static unsigned int early_drop_list(struct net *net,
                if (!refcount_inc_not_zero(&tmp->ct_general.use))
                        continue;
 
+               /* load ->ct_net and ->status after refcount increase */
+               smp_acquire__after_ctrl_dep();
+
                /* kill only if still in same netns -- might have moved due to
                 * SLAB_TYPESAFE_BY_RCU rules.
                 *
@@ -1536,6 +1545,9 @@ static void gc_worker(struct work_struct *work)
                        if (!refcount_inc_not_zero(&tmp->ct_general.use))
                                continue;
 
+                       /* load ->status after refcount increase */
+                       smp_acquire__after_ctrl_dep();
+
                        if (gc_worker_skip_ct(tmp)) {
                                nf_ct_put(tmp);
                                continue;
@@ -1775,6 +1787,16 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
        if (!exp)
                __nf_ct_try_assign_helper(ct, tmpl, GFP_ATOMIC);
 
+       /* Other CPU might have obtained a pointer to this object before it was
+        * released.  Because refcount is 0, refcount_inc_not_zero() will fail.
+        *
+        * After refcount_set(1) it will succeed; ensure that zeroing of
+        * ct->status and the correct ct->net pointer are visible; else other
+        * core might observe CONFIRMED bit which means the entry is valid and
+        * in the hash table, but its not (anymore).
+        */
+       smp_wmb();
+
        /* Now it is going to be associated with an sk_buff, set refcount to 1. */
        refcount_set(&ct->ct_general.use, 1);
 
index 722af5e..f5905b5 100644 (file)
@@ -1203,6 +1203,7 @@ restart:
                                           hnnode) {
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        if (nf_ct_is_expired(ct)) {
+                               /* need to defer nf_ct_kill() until lock is released */
                                if (i < ARRAY_SIZE(nf_ct_evict) &&
                                    refcount_inc_not_zero(&ct->ct_general.use))
                                        nf_ct_evict[i++] = ct;
index 6ad7bbc..0589587 100644 (file)
@@ -306,6 +306,9 @@ static int ct_seq_show(struct seq_file *s, void *v)
        if (unlikely(!refcount_inc_not_zero(&ct->ct_general.use)))
                return 0;
 
+       /* load ->status after refcount increase */
+       smp_acquire__after_ctrl_dep();
+
        if (nf_ct_should_gc(ct)) {
                nf_ct_kill(ct);
                goto release;
index 77bcb10..cb894f0 100644 (file)
@@ -67,7 +67,7 @@ dump_arp_packet(struct nf_log_buf *m,
        unsigned int logflags;
        struct arphdr _arph;
 
-       ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+       ah = skb_header_pointer(skb, nhoff, sizeof(_arph), &_arph);
        if (!ah) {
                nf_log_buf_add(m, "TRUNCATED");
                return;
@@ -96,7 +96,7 @@ dump_arp_packet(struct nf_log_buf *m,
            ah->ar_pln != sizeof(__be32))
                return;
 
-       ap = skb_header_pointer(skb, sizeof(_arph), sizeof(_arpp), &_arpp);
+       ap = skb_header_pointer(skb, nhoff + sizeof(_arph), sizeof(_arpp), &_arpp);
        if (!ap) {
                nf_log_buf_add(m, " INCOMPLETE [%zu bytes]",
                               skb->len - sizeof(_arph));
@@ -149,7 +149,7 @@ static void nf_log_arp_packet(struct net *net, u_int8_t pf,
 
        nf_log_dump_packet_common(m, pf, hooknum, skb, in, out, loginfo,
                                  prefix);
-       dump_arp_packet(m, loginfo, skb, 0);
+       dump_arp_packet(m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
@@ -850,7 +850,7 @@ static void nf_log_ip_packet(struct net *net, u_int8_t pf,
        if (in)
                dump_mac_header(m, loginfo, skb);
 
-       dump_ipv4_packet(net, m, loginfo, skb, 0);
+       dump_ipv4_packet(net, m, loginfo, skb, skb_network_offset(skb));
 
        nf_log_buf_close(m);
 }
index 51144fc..646d5fd 100644 (file)
@@ -5213,13 +5213,20 @@ static int nft_setelem_parse_data(struct nft_ctx *ctx, struct nft_set *set,
                                  struct nft_data *data,
                                  struct nlattr *attr)
 {
+       u32 dtype;
        int err;
 
        err = nft_data_init(ctx, data, NFT_DATA_VALUE_MAXLEN, desc, attr);
        if (err < 0)
                return err;
 
-       if (desc->type != NFT_DATA_VERDICT && desc->len != set->dlen) {
+       if (set->dtype == NFT_DATA_VERDICT)
+               dtype = NFT_DATA_VERDICT;
+       else
+               dtype = NFT_DATA_VALUE;
+
+       if (dtype != desc->type ||
+           set->dlen != desc->len) {
                nft_data_release(data, desc->type);
                return -EINVAL;
        }
@@ -5826,8 +5833,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        if (!nla[NFTA_SET_ELEM_KEY] && !(flags & NFT_SET_ELEM_CATCHALL))
                return -EINVAL;
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (set->flags & NFT_SET_MAP) {
                if (nla[NFTA_SET_ELEM_DATA] == NULL &&
@@ -5936,7 +5946,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_set_elem_expr;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto err_parse_key;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
@@ -5945,22 +5957,31 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        goto err_parse_key;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (timeout > 0) {
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
-               if (timeout != set->timeout)
-                       nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
+               if (err < 0)
+                       goto err_parse_key_end;
+
+               if (timeout != set->timeout) {
+                       err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
+                       if (err < 0)
+                               goto err_parse_key_end;
+               }
        }
 
        if (num_exprs) {
                for (i = 0; i < num_exprs; i++)
                        size += expr_array[i]->ops->size;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
-                                      sizeof(struct nft_set_elem_expr) +
-                                      size);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_EXPRESSIONS,
+                                            sizeof(struct nft_set_elem_expr) + size);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
@@ -5975,7 +5996,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                        err = PTR_ERR(obj);
                        goto err_parse_key_end;
                }
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
+               if (err < 0)
+                       goto err_parse_key_end;
        }
 
        if (nla[NFTA_SET_ELEM_DATA] != NULL) {
@@ -6009,7 +6032,9 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
                                                          NFT_VALIDATE_NEED);
                }
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
+               if (err < 0)
+                       goto err_parse_data;
        }
 
        /* The full maximum length of userdata can exceed the maximum
@@ -6019,9 +6044,12 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
        ulen = 0;
        if (nla[NFTA_SET_ELEM_USERDATA] != NULL) {
                ulen = nla_len(nla[NFTA_SET_ELEM_USERDATA]);
-               if (ulen > 0)
-                       nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
-                                              ulen);
+               if (ulen > 0) {
+                       err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_USERDATA,
+                                                    ulen);
+                       if (err < 0)
+                               goto err_parse_data;
+               }
        }
 
        err = -ENOMEM;
@@ -6249,8 +6277,11 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
 
        nft_set_ext_prepare(&tmpl);
 
-       if (flags != 0)
-               nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+       if (flags != 0) {
+               err = nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
+               if (err < 0)
+                       return err;
+       }
 
        if (nla[NFTA_SET_ELEM_KEY]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key.val,
@@ -6258,16 +6289,20 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                if (err < 0)
                        return err;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
+               if (err < 0)
+                       goto fail_elem;
        }
 
        if (nla[NFTA_SET_ELEM_KEY_END]) {
                err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
                                            nla[NFTA_SET_ELEM_KEY_END]);
                if (err < 0)
-                       return err;
+                       goto fail_elem;
 
-               nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               err = nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
+               if (err < 0)
+                       goto fail_elem_key_end;
        }
 
        err = -ENOMEM;
@@ -6275,7 +6310,7 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
                                      elem.key_end.val.data, NULL, 0, 0,
                                      GFP_KERNEL_ACCOUNT);
        if (elem.priv == NULL)
-               goto fail_elem;
+               goto fail_elem_key_end;
 
        ext = nft_set_elem_ext(set, elem.priv);
        if (flags)
@@ -6299,6 +6334,8 @@ fail_ops:
        kfree(trans);
 fail_trans:
        kfree(elem.priv);
+fail_elem_key_end:
+       nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
 fail_elem:
        nft_data_release(&elem.key.val, NFT_DATA_VALUE);
        return err;
index 2c8051d..4f9299b 100644 (file)
@@ -2125,6 +2125,32 @@ out_scratch:
 }
 
 /**
+ * nft_set_pipapo_match_destroy() - Destroy elements from key mapping array
+ * @set:       nftables API set representation
+ * @m:         matching data pointing to key mapping array
+ */
+static void nft_set_pipapo_match_destroy(const struct nft_set *set,
+                                        struct nft_pipapo_match *m)
+{
+       struct nft_pipapo_field *f;
+       int i, r;
+
+       for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
+               ;
+
+       for (r = 0; r < f->rules; r++) {
+               struct nft_pipapo_elem *e;
+
+               if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
+                       continue;
+
+               e = f->mt[r].e;
+
+               nft_set_elem_destroy(set, e, true);
+       }
+}
+
+/**
  * nft_pipapo_destroy() - Free private data for set and all committed elements
  * @set:       nftables API set representation
  */
@@ -2132,26 +2158,13 @@ static void nft_pipapo_destroy(const struct nft_set *set)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *m;
-       struct nft_pipapo_field *f;
-       int i, r, cpu;
+       int cpu;
 
        m = rcu_dereference_protected(priv->match, true);
        if (m) {
                rcu_barrier();
 
-               for (i = 0, f = m->f; i < m->field_count - 1; i++, f++)
-                       ;
-
-               for (r = 0; r < f->rules; r++) {
-                       struct nft_pipapo_elem *e;
-
-                       if (r < f->rules - 1 && f->mt[r + 1].e == f->mt[r].e)
-                               continue;
-
-                       e = f->mt[r].e;
-
-                       nft_set_elem_destroy(set, e, true);
-               }
+               nft_set_pipapo_match_destroy(set, m);
 
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(m->scratch_aligned);
@@ -2165,6 +2178,11 @@ static void nft_pipapo_destroy(const struct nft_set *set)
        }
 
        if (priv->clone) {
+               m = priv->clone;
+
+               if (priv->dirty)
+                       nft_set_pipapo_match_destroy(set, m);
+
 #ifdef NFT_PIPAPO_ALIGN
                free_percpu(priv->clone->scratch_aligned);
 #endif
index fee6409..eb0b819 100644 (file)
@@ -227,8 +227,8 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh)
 {
        struct rose_neigh *s;
 
-       rose_stop_ftimer(rose_neigh);
-       rose_stop_t0timer(rose_neigh);
+       del_timer_sync(&rose_neigh->ftimer);
+       del_timer_sync(&rose_neigh->t0timer);
 
        skb_queue_purge(&rose_neigh->queue);
 
index 79c8901..b759628 100644 (file)
@@ -442,7 +442,7 @@ static int tcf_police_act_to_flow_act(int tc_act, u32 *extval,
                act_id = FLOW_ACTION_JUMP;
                *extval = tc_act & TC_ACT_EXT_VAL_MASK;
        } else if (tc_act == TC_ACT_UNSPEC) {
-               NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform/exceed action is \"continue\"");
+               act_id = FLOW_ACTION_CONTINUE;
        } else {
                NL_SET_ERR_MSG_MOD(extack, "Unsupported conform/exceed action offload");
        }
index ec6f4b6..ce827e7 100644 (file)
@@ -1419,9 +1419,9 @@ static struct notifier_block tls_dev_notifier = {
        .notifier_call  = tls_dev_event,
 };
 
-void __init tls_device_init(void)
+int __init tls_device_init(void)
 {
-       register_netdevice_notifier(&tls_dev_notifier);
+       return register_netdevice_notifier(&tls_dev_notifier);
 }
 
 void __exit tls_device_cleanup(void)
index 2ffede4..d80ab3d 100644 (file)
@@ -1048,7 +1048,12 @@ static int __init tls_register(void)
        if (err)
                return err;
 
-       tls_device_init();
+       err = tls_device_init();
+       if (err) {
+               unregister_pernet_subsys(&tls_proc_ops);
+               return err;
+       }
+
        tcp_register_ulp(&tcp_tls_ulp_ops);
 
        return 0;
index 0513f82..e30649f 100644 (file)
@@ -267,9 +267,6 @@ static int tls_do_decryption(struct sock *sk,
        }
        darg->async = false;
 
-       if (ret == -EBADMSG)
-               TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
-
        return ret;
 }
 
@@ -1579,8 +1576,11 @@ static int decrypt_skb_update(struct sock *sk, struct sk_buff *skb,
        }
 
        err = decrypt_internal(sk, skb, dest, NULL, darg);
-       if (err < 0)
+       if (err < 0) {
+               if (err == -EBADMSG)
+                       TLS_INC_STATS(sock_net(sk), LINUX_MIB_TLSDECRYPTERROR);
                return err;
+       }
        if (darg->async)
                goto decrypt_next;
 
index ff4d48f..607a689 100644 (file)
@@ -1031,7 +1031,8 @@ void __cfg80211_port_authorized(struct wireless_dev *wdev, const u8 *bssid)
 {
        ASSERT_WDEV_LOCK(wdev);
 
-       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_CLIENT))
                return;
 
        if (WARN_ON(!wdev->current_bss) ||
index 87bdd71..f701121 100644 (file)
@@ -332,6 +332,7 @@ static void __xp_dma_unmap(struct xsk_dma_map *dma_map, unsigned long attrs)
        for (i = 0; i < dma_map->dma_pages_cnt; i++) {
                dma = &dma_map->dma_pages[i];
                if (*dma) {
+                       *dma &= ~XSK_NEXT_PG_CONTIG_MASK;
                        dma_unmap_page_attrs(dma_map->dev, *dma, PAGE_SIZE,
                                             DMA_BIDIRECTIONAL, attrs);
                        *dma = 0;
index 01ee6c8..e22da85 100644 (file)
 
 #define BACKTRACE_DEPTH 16
 #define MAX_SYMBOL_LEN 4096
-struct fprobe sample_probe;
+static struct fprobe sample_probe;
 static unsigned long nhit;
 
 static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
 module_param_string(symbol, symbol, sizeof(symbol), 0644);
+MODULE_PARM_DESC(symbol, "Probed symbol(s), given by comma separated symbols or a wildcard pattern.");
+
 static char nosymbol[MAX_SYMBOL_LEN] = "";
 module_param_string(nosymbol, nosymbol, sizeof(nosymbol), 0644);
+MODULE_PARM_DESC(nosymbol, "Not-probed symbols, given by a wildcard pattern.");
+
 static bool stackdump = true;
 module_param(stackdump, bool, 0644);
+MODULE_PARM_DESC(stackdump, "Enable stackdump.");
+
 static bool use_trace = false;
 module_param(use_trace, bool, 0644);
+MODULE_PARM_DESC(use_trace, "Use trace_printk instead of printk. This is only for debugging.");
 
 static void show_backtrace(void)
 {
index f991a66..fd346f5 100644 (file)
@@ -16,9 +16,8 @@
 #include <linux/module.h>
 #include <linux/kprobes.h>
 
-#define MAX_SYMBOL_LEN 64
-static char symbol[MAX_SYMBOL_LEN] = "kernel_clone";
-module_param_string(symbol, symbol, sizeof(symbol), 0644);
+static char symbol[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(symbol, symbol, KSYM_NAME_LEN, 0644);
 
 /* For each probe you need to allocate a kprobe structure */
 static struct kprobe kp = {
index 228321e..cbf1654 100644 (file)
 #include <linux/module.h>
 #include <linux/kprobes.h>
 #include <linux/ktime.h>
-#include <linux/limits.h>
 #include <linux/sched.h>
 
-static char func_name[NAME_MAX] = "kernel_clone";
-module_param_string(func, func_name, NAME_MAX, S_IRUGO);
+static char func_name[KSYM_NAME_LEN] = "kernel_clone";
+module_param_string(func, func_name, KSYM_NAME_LEN, 0644);
 MODULE_PARM_DESC(func, "Function to kretprobe; this module will report the"
                        " function's execution time");
 
index d142577..3fb6a99 100644 (file)
@@ -236,6 +236,7 @@ objtool_args =                                                              \
        $(if $(CONFIG_FTRACE_MCOUNT_USE_OBJTOOL), --mcount)             \
        $(if $(CONFIG_UNWINDER_ORC), --orc)                             \
        $(if $(CONFIG_RETPOLINE), --retpoline)                          \
+       $(if $(CONFIG_RETHUNK), --rethunk)                              \
        $(if $(CONFIG_SLS), --sls)                                      \
        $(if $(CONFIG_STACK_VALIDATION), --stackval)                    \
        $(if $(CONFIG_HAVE_STATIC_CALL_INLINE), --static-call)          \
index c2c43a0..16a02e9 100644 (file)
@@ -28,9 +28,6 @@ modules := $(patsubst $(extmod_prefix)%, $(dst)/%$(suffix-y), $(modules))
 __modinst: $(modules)
        @:
 
-quiet_cmd_none =
-      cmd_none = :
-
 #
 # Installation
 #
index 3c97a15..8401981 100644 (file)
@@ -44,7 +44,7 @@ objtool-enabled := $(or $(delay-objtool),$(CONFIG_NOINSTR_VALIDATION))
 
 objtool_args := \
        $(if $(delay-objtool),$(objtool_args)) \
-       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr) \
+       $(if $(CONFIG_NOINSTR_VALIDATION), --noinstr $(if $(CONFIG_CPU_UNRET_ENTRY), --unret)) \
        $(if $(CONFIG_GCOV_KERNEL), --no-unreachable) \
        --link
 
index 1d1bde1..47da25b 100755 (executable)
@@ -157,10 +157,10 @@ def cmdfiles_for_modorder(modorder):
             if ext != '.ko':
                 sys.exit('{}: module path must end with .ko'.format(ko))
             mod = base + '.mod'
-           # The first line of *.mod lists the objects that compose the module.
+            # Read from *.mod, to get a list of objects that compose the module.
             with open(mod) as m:
-                for obj in m.readline().split():
-                    yield to_cmdfile(obj)
+                for mod_line in m:
+                    yield to_cmdfile(mod_line.rstrip())
 
 
 def process_line(root_directory, command_prefix, file_path):
index f29e4c6..e6db09a 100644 (file)
@@ -54,17 +54,6 @@ config SECURITY_NETWORK
          implement socket and networking access controls.
          If you are unsure how to answer this question, answer N.
 
-config PAGE_TABLE_ISOLATION
-       bool "Remove the kernel mapping in user mode"
-       default y
-       depends on (X86_64 || X86_PAE) && !UML
-       help
-         This feature reduces the number of hardware side channels by
-         ensuring that the majority of kernel addresses are not mapped
-         into userspace.
-
-         See Documentation/x86/pti.rst for more details.
-
 config SECURITY_INFINIBAND
        bool "Infiniband Security Hooks"
        depends on SECURITY && INFINIBAND
index a733aff..708de96 100644 (file)
@@ -75,7 +75,7 @@ static struct shash_desc *init_desc(char type, uint8_t hash_algo)
 {
        long rc;
        const char *algo;
-       struct crypto_shash **tfm, *tmp_tfm = NULL;
+       struct crypto_shash **tfm, *tmp_tfm;
        struct shash_desc *desc;
 
        if (type == EVM_XATTR_HMAC) {
@@ -120,16 +120,13 @@ unlock:
 alloc:
        desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(*tfm),
                        GFP_KERNEL);
-       if (!desc) {
-               crypto_free_shash(tmp_tfm);
+       if (!desc)
                return ERR_PTR(-ENOMEM);
-       }
 
        desc->tfm = *tfm;
 
        rc = crypto_shash_init(desc);
        if (rc) {
-               crypto_free_shash(tmp_tfm);
                kfree(desc);
                return ERR_PTR(rc);
        }
index cdb84dc..bde74fc 100644 (file)
@@ -514,7 +514,8 @@ int ima_appraise_measurement(enum ima_hooks func,
                goto out;
        }
 
-       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value, rc, iint);
+       status = evm_verifyxattr(dentry, XATTR_NAME_IMA, xattr_value,
+                                rc < 0 ? 0 : rc, iint);
        switch (status) {
        case INTEGRITY_PASS:
        case INTEGRITY_PASS_IMMUTABLE:
index a7206cc..6449905 100644 (file)
@@ -205,6 +205,7 @@ out_array:
 
                crypto_free_shash(ima_algo_array[i].tfm);
        }
+       kfree(ima_algo_array);
 out:
        crypto_free_shash(ima_shash_tfm);
        return rc;
index 71786d0..9db66fe 100644 (file)
@@ -67,6 +67,8 @@ const char * const *arch_get_ima_policy(void)
        if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot()) {
                if (IS_ENABLED(CONFIG_MODULE_SIG))
                        set_module_sig_enforced();
+               if (IS_ENABLED(CONFIG_KEXEC_SIG))
+                       set_kexec_sig_enforced();
                return sb_arch_rules;
        }
        return NULL;
index c877f01..7bf9b15 100644 (file)
@@ -323,10 +323,10 @@ static int ima_eventdigest_init_common(const u8 *digest, u32 digestsize,
        else
                /*
                 * If digest is NULL, the event being recorded is a violation.
-                * Make room for the digest by increasing the offset of
-                * IMA_DIGEST_SIZE.
+                * Make room for the digest by increasing the offset by the
+                * hash algorithm digest size.
                 */
-               offset += IMA_DIGEST_SIZE;
+               offset += hash_digest_size[hash_algo];
 
        return ima_write_template_field_data(buffer, offset + digestsize,
                                             fmt, field_data);
index bd60308..8634004 100644 (file)
@@ -74,36 +74,36 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
        err = snd_cs46xx_create(card, pci,
                                external_amp[dev], thinkpad[dev]);
        if (err < 0)
-               return err;
+               goto error;
        card->private_data = chip;
        chip->accept_valid = mmap_valid[dev];
        err = snd_cs46xx_pcm(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        err = snd_cs46xx_pcm_rear(chip, 1);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_pcm_iec958(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #endif
        err = snd_cs46xx_mixer(chip, 2);
        if (err < 0)
-               return err;
+               goto error;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
        if (chip->nr_ac97_codecs ==2) {
                err = snd_cs46xx_pcm_center_lfe(chip, 3);
                if (err < 0)
-                       return err;
+                       goto error;
        }
 #endif
        err = snd_cs46xx_midi(chip, 0);
        if (err < 0)
-               return err;
+               goto error;
        err = snd_cs46xx_start_dsp(chip);
        if (err < 0)
-               return err;
+               goto error;
 
        snd_cs46xx_gameport(chip);
 
@@ -117,11 +117,15 @@ static int snd_card_cs46xx_probe(struct pci_dev *pci,
 
        err = snd_card_register(card);
        if (err < 0)
-               return err;
+               goto error;
 
        pci_set_drvdata(pci, card);
        dev++;
        return 0;
+
+ error:
+       snd_card_free(card);
+       return err;
 }
 
 static struct pci_driver cs46xx_driver = {
index 3e541a4..83ae21a 100644 (file)
@@ -944,6 +944,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = {
        SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
        SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
        SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
index cee69fa..2f55bc4 100644 (file)
@@ -6901,6 +6901,7 @@ enum {
        ALC298_FIXUP_LENOVO_SPK_VOLUME,
        ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
        ALC269_FIXUP_ATIV_BOOK_8,
+       ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE,
        ALC221_FIXUP_HP_MIC_NO_PRESENCE,
        ALC256_FIXUP_ASUS_HEADSET_MODE,
        ALC256_FIXUP_ASUS_MIC,
@@ -7837,6 +7838,16 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269_FIXUP_NO_SHUTUP
        },
+       [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
        [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
                .type = HDA_FIXUP_PINS,
                .v.pins = (const struct hda_pintbl[]) {
@@ -8886,6 +8897,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
        SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
@@ -8895,6 +8907,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
        SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
        SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
        SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
@@ -9010,6 +9023,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
@@ -9096,6 +9110,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
        SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -9212,6 +9230,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9354,6 +9373,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
        SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
        SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
        SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
@@ -11216,6 +11236,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
        SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
        SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
        SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
index 55e773f..93606e5 100644 (file)
@@ -868,10 +868,12 @@ static void ak4613_parse_of(struct ak4613_priv *priv,
 
        /*
         * connected STDI
+        * TDM support is assuming it is probed via Audio-Graph-Card style here.
+        * Default is SDTIx1 if it was probed via Simple-Audio-Card for now.
         */
        sdti_num = of_graph_get_endpoint_count(np);
-       if (WARN_ON((sdti_num > 3) || (sdti_num < 1)))
-               return;
+       if ((sdti_num >= SDTx_MAX) || (sdti_num < 1))
+               sdti_num = 1;
 
        AK4613_CONFIG_SDTI_set(priv, sdti_num);
 }
index e32871b..7434aee 100644 (file)
@@ -1760,8 +1760,8 @@ static bool arizona_aif_cfg_changed(struct snd_soc_component *component,
        if (bclk != (val & ARIZONA_AIF1_BCLK_FREQ_MASK))
                return true;
 
-       val = snd_soc_component_read(component, base + ARIZONA_AIF_TX_BCLK_RATE);
-       if (lrclk != (val & ARIZONA_AIF1TX_BCPF_MASK))
+       val = snd_soc_component_read(component, base + ARIZONA_AIF_RX_BCLK_RATE);
+       if (lrclk != (val & ARIZONA_AIF1RX_BCPF_MASK))
                return true;
 
        val = snd_soc_component_read(component, base + ARIZONA_AIF_FRAME_CTRL_1);
index 6d3070e..198cfe5 100644 (file)
@@ -37,8 +37,8 @@ static const struct reg_default cs35l41_reg[] = {
        { CS35L41_DAC_PCM1_SRC,                 0x00000008 },
        { CS35L41_ASP_TX1_SRC,                  0x00000018 },
        { CS35L41_ASP_TX2_SRC,                  0x00000019 },
-       { CS35L41_ASP_TX3_SRC,                  0x00000020 },
-       { CS35L41_ASP_TX4_SRC,                  0x00000021 },
+       { CS35L41_ASP_TX3_SRC,                  0x00000000 },
+       { CS35L41_ASP_TX4_SRC,                  0x00000000 },
        { CS35L41_DSP1_RX1_SRC,                 0x00000008 },
        { CS35L41_DSP1_RX2_SRC,                 0x00000009 },
        { CS35L41_DSP1_RX3_SRC,                 0x00000018 },
@@ -644,6 +644,8 @@ static const struct reg_sequence cs35l41_reva0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
@@ -655,6 +657,8 @@ static const struct reg_sequence cs35l41_revb0_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
@@ -666,6 +670,8 @@ static const struct reg_sequence cs35l41_revb2_errata_patch[] = {
        { CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },
        { CS35L41_PWR_CTRL2,             0x00000000 },
        { CS35L41_AMP_GAIN_CTRL,         0x00000000 },
+       { CS35L41_ASP_TX3_SRC,           0x00000000 },
+       { CS35L41_ASP_TX4_SRC,           0x00000000 },
 };
 
 static const struct reg_sequence cs35l41_fs_errata_patch[] = {
index 3e68a07..71ab2a5 100644 (file)
@@ -333,7 +333,7 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
        SOC_SINGLE("HW Noise Gate Enable", CS35L41_NG_CFG, 8, 63, 0),
        SOC_SINGLE("HW Noise Gate Delay", CS35L41_NG_CFG, 4, 7, 0),
        SOC_SINGLE("HW Noise Gate Threshold", CS35L41_NG_CFG, 0, 7, 0),
-       SOC_SINGLE("Aux Noise Gate CH1 Enable",
+       SOC_SINGLE("Aux Noise Gate CH1 Switch",
                   CS35L41_MIXER_NGATE_CH1_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH1 Entry Delay",
                   CS35L41_MIXER_NGATE_CH1_CFG, 8, 15, 0),
@@ -341,15 +341,15 @@ static const struct snd_kcontrol_new cs35l41_aud_controls[] = {
                   CS35L41_MIXER_NGATE_CH1_CFG, 0, 7, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Entry Delay",
                   CS35L41_MIXER_NGATE_CH2_CFG, 8, 15, 0),
-       SOC_SINGLE("Aux Noise Gate CH2 Enable",
+       SOC_SINGLE("Aux Noise Gate CH2 Switch",
                   CS35L41_MIXER_NGATE_CH2_CFG, 16, 1, 0),
        SOC_SINGLE("Aux Noise Gate CH2 Threshold",
                   CS35L41_MIXER_NGATE_CH2_CFG, 0, 7, 0),
-       SOC_SINGLE("SCLK Force", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("LRCLK Force", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
-       SOC_SINGLE("Invert Class D", CS35L41_AMP_DIG_VOL_CTRL,
+       SOC_SINGLE("SCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_SCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("LRCLK Force Switch", CS35L41_SP_FORMAT, CS35L41_LRCLK_FRC_SHIFT, 1, 0),
+       SOC_SINGLE("Invert Class D Switch", CS35L41_AMP_DIG_VOL_CTRL,
                   CS35L41_AMP_INV_PCM_SHIFT, 1, 0),
-       SOC_SINGLE("Amp Gain ZC", CS35L41_AMP_GAIN_CTRL,
+       SOC_SINGLE("Amp Gain ZC Switch", CS35L41_AMP_GAIN_CTRL,
                   CS35L41_AMP_GAIN_ZC_SHIFT, 1, 0),
        WM_ADSP2_PRELOAD_SWITCH("DSP1", 1),
        WM_ADSP_FW_CONTROL("DSP1", 0),
index 391fd7d..1c7d52b 100644 (file)
@@ -122,6 +122,9 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                snd_soc_kcontrol_component(kcontrol);
        struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component);
 
+       if (!!ucontrol->value.integer.value[0] == cs47l15->in1_lp_mode)
+               return 0;
+
        switch (ucontrol->value.integer.value[0]) {
        case 0:
                /* Set IN1 to normal mode */
@@ -150,7 +153,7 @@ static int cs47l15_in1_adc_put(struct snd_kcontrol *kcontrol,
                break;
        }
 
-       return 0;
+       return 1;
 }
 
 static const struct snd_kcontrol_new cs47l15_snd_controls[] = {
index a1b8dcd..444026b 100644 (file)
@@ -119,7 +119,13 @@ static int cs47l92_put_demux(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static SOC_ENUM_SINGLE_DECL(cs47l92_outdemux_enum,
index 272041c..b9f19fb 100644 (file)
@@ -618,7 +618,13 @@ int madera_out1_demux_put(struct snd_kcontrol *kcontrol,
 end:
        snd_soc_dapm_mutex_unlock(dapm);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol, mux, e, NULL);
+       if (ret < 0) {
+               dev_err(madera->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 EXPORT_SYMBOL_GPL(madera_out1_demux_put);
 
@@ -893,7 +899,7 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        const int adsp_num = e->shift_l;
        const unsigned int item = ucontrol->value.enumerated.item[0];
-       int ret;
+       int ret = 0;
 
        if (item >= e->items)
                return -EINVAL;
@@ -910,10 +916,10 @@ static int madera_adsp_rate_put(struct snd_kcontrol *kcontrol,
                         "Cannot change '%s' while in use by active audio paths\n",
                         kcontrol->id.name);
                ret = -EBUSY;
-       } else {
+       } else if (priv->adsp_rate_cache[adsp_num] != e->values[item]) {
                /* Volatile register so defer until the codec is powered up */
                priv->adsp_rate_cache[adsp_num] = e->values[item];
-               ret = 0;
+               ret = 1;
        }
 
        mutex_unlock(&priv->rate_lock);
index f47e956..97b6447 100644 (file)
@@ -862,6 +862,16 @@ static int max98373_sdw_probe(struct sdw_slave *slave,
        return max98373_init(slave, regmap);
 }
 
+static int max98373_sdw_remove(struct sdw_slave *slave)
+{
+       struct max98373_priv *max98373 = dev_get_drvdata(&slave->dev);
+
+       if (max98373->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 #if defined(CONFIG_OF)
 static const struct of_device_id max98373_of_match[] = {
        { .compatible = "maxim,max98373", },
@@ -893,7 +903,7 @@ static struct sdw_driver max98373_sdw_driver = {
                .pm = &max98373_pm,
        },
        .probe = max98373_sdw_probe,
-       .remove = NULL,
+       .remove = max98373_sdw_remove,
        .ops = &max98373_slave_ops,
        .id_table = max98373_id,
 };
index 56eb62b..34db388 100644 (file)
@@ -342,12 +342,15 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 {
        struct snd_soc_component *component = codec_dai->component;
        struct max98396_priv *max98396 = snd_soc_component_get_drvdata(component);
-       unsigned int format = 0;
+       unsigned int format_mask, format = 0;
        unsigned int bclk_pol = 0;
        int ret, status;
        int reg;
        bool update = false;
 
+       format_mask = MAX98396_PCM_MODE_CFG_FORMAT_MASK |
+                     MAX98396_PCM_MODE_CFG_LRCLKEDGE;
+
        dev_dbg(component->dev, "%s: fmt 0x%08X\n", __func__, fmt);
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -395,7 +398,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
                ret = regmap_read(max98396->regmap, MAX98396_R2041_PCM_MODE_CFG, &reg);
                if (ret < 0)
                        return -EINVAL;
-               if (format != (reg & MAX98396_PCM_BCLKEDGE_BSEL_MASK)) {
+               if (format != (reg & format_mask)) {
                        update = true;
                } else {
                        ret = regmap_read(max98396->regmap,
@@ -412,8 +415,7 @@ static int max98396_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2041_PCM_MODE_CFG,
-                          MAX98396_PCM_BCLKEDGE_BSEL_MASK,
-                          format);
+                          format_mask, format);
 
        regmap_update_bits(max98396->regmap,
                           MAX98396_R2042_PCM_CLK_SETUP,
index 1c11b42..72f673f 100644 (file)
@@ -691,6 +691,16 @@ static int rt1308_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt1308_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(&slave->dev);
+
+       if (rt1308->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1308_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1308, 0x2, 0, 0),
        {},
@@ -750,6 +760,7 @@ static struct sdw_driver rt1308_sdw_driver = {
                .pm = &rt1308_pm,
        },
        .probe = rt1308_sdw_probe,
+       .remove = rt1308_sdw_remove,
        .ops = &rt1308_slave_ops,
        .id_table = rt1308_id,
 };
index 60baa9f..2d6b5f9 100644 (file)
@@ -676,6 +676,16 @@ static int rt1316_sdw_probe(struct sdw_slave *slave,
        return rt1316_sdw_init(&slave->dev, regmap, slave);
 }
 
+static int rt1316_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(&slave->dev);
+
+       if (rt1316->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt1316_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x1316, 0x3, 0x1, 0),
        {},
@@ -735,6 +745,7 @@ static struct sdw_driver rt1316_sdw_driver = {
                .pm = &rt1316_pm,
        },
        .probe = rt1316_sdw_probe,
+       .remove = rt1316_sdw_remove,
        .ops = &rt1316_slave_ops,
        .id_table = rt1316_id,
 };
index 69c80d8..18b3da9 100644 (file)
@@ -1984,7 +1984,12 @@ static int rt5640_set_bias_level(struct snd_soc_component *component,
                snd_soc_component_write(component, RT5640_PWR_DIG2, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_VOL, 0x0000);
                snd_soc_component_write(component, RT5640_PWR_MIXER, 0x0000);
-               snd_soc_component_write(component, RT5640_PWR_ANLG1, 0x0000);
+               if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER)
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0018);
+               else
+                       snd_soc_component_write(component, RT5640_PWR_ANLG1,
+                               0x0000);
                snd_soc_component_write(component, RT5640_PWR_ANLG2, 0x0000);
                break;
 
@@ -2393,9 +2398,15 @@ static void rt5640_jack_work(struct work_struct *work)
 static irqreturn_t rt5640_irq(int irq, void *data)
 {
        struct rt5640_priv *rt5640 = data;
+       int delay = 0;
+
+       if (rt5640->jd_src == RT5640_JD_SRC_HDA_HEADER) {
+               cancel_delayed_work_sync(&rt5640->jack_work);
+               delay = 100;
+       }
 
        if (rt5640->jack)
-               queue_delayed_work(system_long_wq, &rt5640->jack_work, 0);
+               queue_delayed_work(system_long_wq, &rt5640->jack_work, delay);
 
        return IRQ_HANDLED;
 }
@@ -2580,6 +2591,12 @@ static void rt5640_enable_hda_jack_detect(
 
        snd_soc_component_update_bits(component, RT5640_DUMMY1, 0x400, 0x0);
 
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_VREF2, RT5640_PWR_VREF2);
+       usleep_range(10000, 15000);
+       snd_soc_component_update_bits(component, RT5640_PWR_ANLG1,
+               RT5640_PWR_FV2, RT5640_PWR_FV2);
+
        rt5640->jack = jack;
 
        ret = request_irq(rt5640->irq, rt5640_irq,
@@ -2696,16 +2713,13 @@ static int rt5640_probe(struct snd_soc_component *component)
 
        if (device_property_read_u32(component->dev,
                                     "realtek,jack-detect-source", &val) == 0) {
-               if (val <= RT5640_JD_SRC_GPIO4) {
+               if (val <= RT5640_JD_SRC_GPIO4)
                        rt5640->jd_src = val << RT5640_JD_SFT;
-               } else if (val == RT5640_JD_SRC_HDA_HEADER) {
+               else if (val == RT5640_JD_SRC_HDA_HEADER)
                        rt5640->jd_src = RT5640_JD_SRC_HDA_HEADER;
-                       snd_soc_component_update_bits(component, RT5640_DUMMY1,
-                               0x0300, 0x0);
-               } else {
+               else
                        dev_warn(component->dev, "Warning: Invalid jack-detect-source value: %d, leaving jack-detect disabled\n",
                                 val);
-               }
        }
 
        if (!device_property_read_bool(component->dev, "realtek,jack-detect-not-inverted"))
index 248257a..f04e18c 100644 (file)
@@ -719,9 +719,12 @@ static int rt5682_sdw_remove(struct sdw_slave *slave)
 {
        struct rt5682_priv *rt5682 = dev_get_drvdata(&slave->dev);
 
-       if (rt5682 && rt5682->hw_init)
+       if (rt5682->hw_init)
                cancel_delayed_work_sync(&rt5682->jack_detect_work);
 
+       if (rt5682->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index bda5948..f7439e4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt700.h"
@@ -463,11 +464,14 @@ static int rt700_sdw_remove(struct sdw_slave *slave)
 {
        struct rt700_priv *rt700 = dev_get_drvdata(&slave->dev);
 
-       if (rt700 && rt700->hw_init) {
+       if (rt700->hw_init) {
                cancel_delayed_work_sync(&rt700->jack_detect_work);
                cancel_delayed_work_sync(&rt700->jack_btn_check_work);
        }
 
+       if (rt700->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
        return 0;
 }
 
index af32295..9bceeeb 100644 (file)
@@ -162,7 +162,7 @@ static void rt700_jack_detect_handler(struct work_struct *work)
        if (!rt700->hs_jack)
                return;
 
-       if (!rt700->component->card->instantiated)
+       if (!rt700->component->card || !rt700->component->card->instantiated)
                return;
 
        reg = RT700_VERB_GET_PIN_SENSE | RT700_HP_OUT;
@@ -315,17 +315,27 @@ static int rt700_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt700_priv *rt700 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt700->hs_jack = hs_jack;
 
-       if (!rt700->hw_init) {
-               dev_dbg(&rt700->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt700_jack_init(rt700);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1115,6 +1125,11 @@ int rt700_init(struct device *dev, struct regmap *sdw_regmap,
 
        mutex_init(&rt700->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt700->jack_detect_work,
+                         rt700_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
+                         rt700_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1209,13 +1224,6 @@ int rt700_io_init(struct device *dev, struct sdw_slave *slave)
        /* Finish Initial Settings, set power to D3 */
        regmap_write(rt700->regmap, RT700_SET_AUDIO_POWER_STATE, AC_PWRST_D3);
 
-       if (!rt700->first_hw_init) {
-               INIT_DELAYED_WORK(&rt700->jack_detect_work,
-                       rt700_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt700->jack_btn_check_work,
-                       rt700_btn_check_handler);
-       }
-
        /*
         * if set_jack callback occurred early than io_init,
         * we set up the jack detection function now
index aaf5af1..a085b2f 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mod_devicetable.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 
 #include "rt711-sdca.h"
 #include "rt711-sdca-sdw.h"
@@ -364,11 +365,17 @@ static int rt711_sdca_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_sdca_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 57629c1..5ad53bb 100644 (file)
@@ -34,7 +34,7 @@ static int rt711_sdca_index_write(struct rt711_sdca_priv *rt711,
 
        ret = regmap_write(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to set private value: %06x <= %04x ret=%d\n",
                        addr, value, ret);
 
@@ -50,7 +50,7 @@ static int rt711_sdca_index_read(struct rt711_sdca_priv *rt711,
 
        ret = regmap_read(regmap, addr, value);
        if (ret < 0)
-               dev_err(rt711->component->dev,
+               dev_err(&rt711->slave->dev,
                        "Failed to get private value: %06x => %04x ret=%d\n",
                        addr, *value, ret);
 
@@ -294,7 +294,7 @@ static void rt711_sdca_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        /* SDW_SCP_SDCA_INT_SDCA_0 is used for jack detection */
@@ -487,16 +487,27 @@ static int rt711_sdca_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_sdca_jack_init(rt711);
+
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -1190,14 +1201,6 @@ static int rt711_sdca_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_sdca_remove(struct snd_soc_component *component)
-{
-       struct rt711_sdca_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-       regcache_cache_only(rt711->mbq_regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .probe = rt711_sdca_probe,
        .controls = rt711_sdca_snd_controls,
@@ -1207,7 +1210,6 @@ static const struct snd_soc_component_driver soc_sdca_dev_rt711 = {
        .dapm_routes = rt711_sdca_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_sdca_audio_map),
        .set_jack = rt711_sdca_set_jack_detect,
-       .remove = rt711_sdca_remove,
        .endianness = 1,
 };
 
@@ -1412,8 +1414,12 @@ int rt711_sdca_init(struct device *dev, struct regmap *regmap,
        rt711->regmap = regmap;
        rt711->mbq_regmap = mbq_regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_sdca_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_sdca_btn_check_handler);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1545,14 +1551,6 @@ int rt711_sdca_io_init(struct device *dev, struct sdw_slave *slave)
        rt711_sdca_index_update_bits(rt711, RT711_VENDOR_HDA_CTL,
                RT711_PUSH_BTN_INT_CTL0, 0x20, 0x00);
 
-       if (!rt711->first_hw_init) {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_sdca_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_sdca_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-       }
-
        /* calibration */
        ret = rt711_sdca_calibration(rt711);
        if (ret < 0)
index bda2cc9..4fe68bc 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt711.h"
@@ -464,12 +465,18 @@ static int rt711_sdw_remove(struct sdw_slave *slave)
 {
        struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev);
 
-       if (rt711 && rt711->hw_init) {
+       if (rt711->hw_init) {
                cancel_delayed_work_sync(&rt711->jack_detect_work);
                cancel_delayed_work_sync(&rt711->jack_btn_check_work);
                cancel_work_sync(&rt711->calibration_work);
        }
 
+       if (rt711->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       mutex_destroy(&rt711->calibrate_mutex);
+       mutex_destroy(&rt711->disable_irq_lock);
+
        return 0;
 }
 
index 9838fb4..9df800a 100644 (file)
@@ -242,7 +242,7 @@ static void rt711_jack_detect_handler(struct work_struct *work)
        if (!rt711->hs_jack)
                return;
 
-       if (!rt711->component->card->instantiated)
+       if (!rt711->component->card || !rt711->component->card->instantiated)
                return;
 
        if (pm_runtime_status_suspended(rt711->slave->dev.parent)) {
@@ -457,17 +457,27 @@ static int rt711_set_jack_detect(struct snd_soc_component *component,
        struct snd_soc_jack *hs_jack, void *data)
 {
        struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
+       int ret;
 
        rt711->hs_jack = hs_jack;
 
-       if (!rt711->hw_init) {
-               dev_dbg(&rt711->slave->dev,
-                       "%s hw_init not ready yet\n", __func__);
+       ret = pm_runtime_resume_and_get(component->dev);
+       if (ret < 0) {
+               if (ret != -EACCES) {
+                       dev_err(component->dev, "%s: failed to resume %d\n", __func__, ret);
+                       return ret;
+               }
+
+               /* pm_runtime not enabled yet */
+               dev_dbg(component->dev, "%s: skipping jack init for now\n", __func__);
                return 0;
        }
 
        rt711_jack_init(rt711);
 
+       pm_runtime_mark_last_busy(component->dev);
+       pm_runtime_put_autosuspend(component->dev);
+
        return 0;
 }
 
@@ -932,13 +942,6 @@ static int rt711_probe(struct snd_soc_component *component)
        return 0;
 }
 
-static void rt711_remove(struct snd_soc_component *component)
-{
-       struct rt711_priv *rt711 = snd_soc_component_get_drvdata(component);
-
-       regcache_cache_only(rt711->regmap, true);
-}
-
 static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .probe = rt711_probe,
        .set_bias_level = rt711_set_bias_level,
@@ -949,7 +952,6 @@ static const struct snd_soc_component_driver soc_codec_dev_rt711 = {
        .dapm_routes = rt711_audio_map,
        .num_dapm_routes = ARRAY_SIZE(rt711_audio_map),
        .set_jack = rt711_set_jack_detect,
-       .remove = rt711_remove,
        .endianness = 1,
 };
 
@@ -1204,8 +1206,13 @@ int rt711_init(struct device *dev, struct regmap *sdw_regmap,
        rt711->sdw_regmap = sdw_regmap;
        rt711->regmap = regmap;
 
+       mutex_init(&rt711->calibrate_mutex);
        mutex_init(&rt711->disable_irq_lock);
 
+       INIT_DELAYED_WORK(&rt711->jack_detect_work, rt711_jack_detect_handler);
+       INIT_DELAYED_WORK(&rt711->jack_btn_check_work, rt711_btn_check_handler);
+       INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+
        /*
         * Mark hw_init to false
         * HW init will be performed when device reports present
@@ -1313,15 +1320,8 @@ int rt711_io_init(struct device *dev, struct sdw_slave *slave)
 
        if (rt711->first_hw_init)
                rt711_calibration(rt711);
-       else {
-               INIT_DELAYED_WORK(&rt711->jack_detect_work,
-                       rt711_jack_detect_handler);
-               INIT_DELAYED_WORK(&rt711->jack_btn_check_work,
-                       rt711_btn_check_handler);
-               mutex_init(&rt711->calibrate_mutex);
-               INIT_WORK(&rt711->calibration_work, rt711_calibration_work);
+       else
                schedule_work(&rt711->calibration_work);
-       }
 
        /*
         * if set_jack callback occurred early than io_init,
index 0ecd294..13e731d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include "rt715-sdca.h"
@@ -193,6 +194,16 @@ static int rt715_sdca_sdw_probe(struct sdw_slave *slave,
        return rt715_sdca_init(&slave->dev, mbq_regmap, regmap, slave);
 }
 
+static int rt715_sdca_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_sdca_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_sdca_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x3, 0x1, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x3, 0x1, 0),
@@ -267,6 +278,7 @@ static struct sdw_driver rt715_sdw_driver = {
                .pm = &rt715_pm,
        },
        .probe = rt715_sdca_sdw_probe,
+       .remove = rt715_sdca_sdw_remove,
        .ops = &rt715_sdca_slave_ops,
        .id_table = rt715_sdca_id,
 };
index a7b21b0..b047bf8 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/soundwire/sdw_type.h>
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/of.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
@@ -514,6 +515,16 @@ static int rt715_sdw_probe(struct sdw_slave *slave,
        return 0;
 }
 
+static int rt715_sdw_remove(struct sdw_slave *slave)
+{
+       struct rt715_priv *rt715 = dev_get_drvdata(&slave->dev);
+
+       if (rt715->first_hw_init)
+               pm_runtime_disable(&slave->dev);
+
+       return 0;
+}
+
 static const struct sdw_device_id rt715_id[] = {
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x714, 0x2, 0, 0),
        SDW_SLAVE_ENTRY_EXT(0x025d, 0x715, 0x2, 0, 0),
@@ -575,6 +586,7 @@ static struct sdw_driver rt715_sdw_driver = {
                   .pm = &rt715_pm,
                   },
        .probe = rt715_sdw_probe,
+       .remove = rt715_sdw_remove,
        .ops = &rt715_slave_ops,
        .id_table = rt715_id,
 };
index 2aa48ae..3363d16 100644 (file)
@@ -1795,6 +1795,9 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
 {
        struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client);
 
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_DIG_POWER, SGTL5000_DIG_POWER_DEFAULT);
+       regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, SGTL5000_ANA_POWER_DEFAULT);
+
        clk_disable_unprepare(sgtl5000->mclk);
        regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies);
        regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies);
@@ -1802,6 +1805,11 @@ static int sgtl5000_i2c_remove(struct i2c_client *client)
        return 0;
 }
 
+static void sgtl5000_i2c_shutdown(struct i2c_client *client)
+{
+       sgtl5000_i2c_remove(client);
+}
+
 static const struct i2c_device_id sgtl5000_id[] = {
        {"sgtl5000", 0},
        {},
@@ -1822,6 +1830,7 @@ static struct i2c_driver sgtl5000_i2c_driver = {
        },
        .probe_new = sgtl5000_i2c_probe,
        .remove = sgtl5000_i2c_remove,
+       .shutdown = sgtl5000_i2c_shutdown,
        .id_table = sgtl5000_id,
 };
 
index 56ec586..3a808c7 100644 (file)
@@ -80,6 +80,7 @@
 /*
  * SGTL5000_CHIP_DIG_POWER
  */
+#define SGTL5000_DIG_POWER_DEFAULT             0x0000
 #define SGTL5000_ADC_EN                                0x0040
 #define SGTL5000_DAC_EN                                0x0020
 #define SGTL5000_DAP_POWERUP                   0x0010
index d395fef..4cb788f 100644 (file)
@@ -42,10 +42,12 @@ static void tas2764_reset(struct tas2764_priv *tas2764)
                gpiod_set_value_cansleep(tas2764->reset_gpio, 0);
                msleep(20);
                gpiod_set_value_cansleep(tas2764->reset_gpio, 1);
+               usleep_range(1000, 2000);
        }
 
        snd_soc_component_write(tas2764->component, TAS2764_SW_RST,
                                TAS2764_RST);
+       usleep_range(1000, 2000);
 }
 
 static int tas2764_set_bias_level(struct snd_soc_component *component,
@@ -107,8 +109,10 @@ static int tas2764_codec_resume(struct snd_soc_component *component)
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
        int ret;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL,
                                            TAS2764_PWR_CTRL_MASK,
@@ -131,7 +135,8 @@ static const char * const tas2764_ASI1_src[] = {
 };
 
 static SOC_ENUM_SINGLE_DECL(
-       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, 4, tas2764_ASI1_src);
+       tas2764_ASI1_src_enum, TAS2764_TDM_CFG2, TAS2764_TDM_CFG2_SCFG_SHIFT,
+       tas2764_ASI1_src);
 
 static const struct snd_kcontrol_new tas2764_asi1_mux =
        SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum);
@@ -329,20 +334,22 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
        struct snd_soc_component *component = dai->component;
        struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component);
-       u8 tdm_rx_start_slot = 0, asi_cfg_1 = 0;
-       int iface;
+       u8 tdm_rx_start_slot = 0, asi_cfg_0 = 0, asi_cfg_1 = 0;
        int ret;
 
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+       case SND_SOC_DAIFMT_NB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_NB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_RISING;
                break;
+       case SND_SOC_DAIFMT_IB_IF:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_IB_NF:
                asi_cfg_1 = TAS2764_TDM_CFG1_RX_FALLING;
                break;
-       default:
-               dev_err(tas2764->dev, "ASI format Inverse is not found\n");
-               return -EINVAL;
        }
 
        ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
@@ -353,13 +360,13 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
+               asi_cfg_0 ^= TAS2764_TDM_CFG0_FRAME_START;
+               fallthrough;
        case SND_SOC_DAIFMT_DSP_A:
-               iface = TAS2764_TDM_CFG2_SCFG_I2S;
                tdm_rx_start_slot = 1;
                break;
        case SND_SOC_DAIFMT_DSP_B:
        case SND_SOC_DAIFMT_LEFT_J:
-               iface = TAS2764_TDM_CFG2_SCFG_LEFT_J;
                tdm_rx_start_slot = 0;
                break;
        default:
@@ -368,14 +375,15 @@ static int tas2764_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                return -EINVAL;
        }
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
-                                           TAS2764_TDM_CFG1_MASK,
-                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG0,
+                                           TAS2764_TDM_CFG0_FRAME_START,
+                                           asi_cfg_0);
        if (ret < 0)
                return ret;
 
-       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG2,
-                                           TAS2764_TDM_CFG2_SCFG_MASK, iface);
+       ret = snd_soc_component_update_bits(component, TAS2764_TDM_CFG1,
+                                           TAS2764_TDM_CFG1_MASK,
+                                           (tdm_rx_start_slot << TAS2764_TDM_CFG1_51_SHIFT));
        if (ret < 0)
                return ret;
 
@@ -501,8 +509,10 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 
        tas2764->component = component;
 
-       if (tas2764->sdz_gpio)
+       if (tas2764->sdz_gpio) {
                gpiod_set_value_cansleep(tas2764->sdz_gpio, 1);
+               usleep_range(1000, 2000);
+       }
 
        tas2764_reset(tas2764);
 
@@ -526,12 +536,12 @@ static int tas2764_codec_probe(struct snd_soc_component *component)
 }
 
 static DECLARE_TLV_DB_SCALE(tas2764_digital_tlv, 1100, 50, 0);
-static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10000, 50, 0);
+static DECLARE_TLV_DB_SCALE(tas2764_playback_volume, -10050, 50, 1);
 
 static const struct snd_kcontrol_new tas2764_snd_controls[] = {
        SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0,
                       TAS2764_DVC_MAX, 1, tas2764_playback_volume),
-       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 0, 0x14, 0,
+       SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0,
                       tas2764_digital_tlv),
 };
 
@@ -556,7 +566,7 @@ static const struct reg_default tas2764_reg_defaults[] = {
        { TAS2764_SW_RST, 0x00 },
        { TAS2764_PWR_CTRL, 0x1a },
        { TAS2764_DVC, 0x00 },
-       { TAS2764_CHNL_0, 0x00 },
+       { TAS2764_CHNL_0, 0x28 },
        { TAS2764_TDM_CFG0, 0x09 },
        { TAS2764_TDM_CFG1, 0x02 },
        { TAS2764_TDM_CFG2, 0x0a },
index 67d6fd9..f015f22 100644 (file)
@@ -47,6 +47,7 @@
 #define TAS2764_TDM_CFG0_MASK          GENMASK(3, 1)
 #define TAS2764_TDM_CFG0_44_1_48KHZ    BIT(3)
 #define TAS2764_TDM_CFG0_88_2_96KHZ    (BIT(3) | BIT(1))
+#define TAS2764_TDM_CFG0_FRAME_START   BIT(0)
 
 /* TDM Configuration Reg1 */
 #define TAS2764_TDM_CFG1               TAS2764_REG(0X0, 0x09)
 #define TAS2764_TDM_CFG2_RXS_16BITS    0x0
 #define TAS2764_TDM_CFG2_RXS_24BITS    BIT(0)
 #define TAS2764_TDM_CFG2_RXS_32BITS    BIT(1)
-#define TAS2764_TDM_CFG2_SCFG_MASK     GENMASK(5, 4)
-#define TAS2764_TDM_CFG2_SCFG_I2S      0x0
-#define TAS2764_TDM_CFG2_SCFG_LEFT_J   BIT(4)
-#define TAS2764_TDM_CFG2_SCFG_RIGHT_J  BIT(5)
+#define TAS2764_TDM_CFG2_SCFG_SHIFT    4
 
 /* TDM Configuration Reg3 */
 #define TAS2764_TDM_CFG3               TAS2764_REG(0X0, 0x0c)
index b55f0b8..0b72965 100644 (file)
@@ -33,7 +33,6 @@ struct adcx140_priv {
        bool micbias_vg;
 
        unsigned int dai_fmt;
-       unsigned int tdm_delay;
        unsigned int slot_width;
 };
 
@@ -792,12 +791,13 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
 {
        struct snd_soc_component *component = codec_dai->component;
        struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
-       unsigned int lsb;
 
-       /* TDM based on DSP mode requires slots to be adjacent */
-       lsb = __ffs(tx_mask);
-       if ((lsb + 1) != __fls(tx_mask)) {
-               dev_err(component->dev, "Invalid mask, slots must be adjacent\n");
+       /*
+        * The chip itself supports arbitrary masks, but the driver currently
+        * only supports adjacent slots beginning at the first slot.
+        */
+       if (tx_mask != GENMASK(__fls(tx_mask), 0)) {
+               dev_err(component->dev, "Only lower adjacent slots are supported\n");
                return -EINVAL;
        }
 
@@ -812,7 +812,6 @@ static int adcx140_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
                return -EINVAL;
        }
 
-       adcx140->tdm_delay = lsb;
        adcx140->slot_width = slot_width;
 
        return 0;
index 617a36a..3cb7a3e 100644 (file)
@@ -342,7 +342,7 @@ struct wcd9335_codec {
        struct regulator_bulk_data supplies[WCD9335_MAX_SUPPLY];
 
        unsigned int rx_port_value[WCD9335_RX_MAX];
-       unsigned int tx_port_value;
+       unsigned int tx_port_value[WCD9335_TX_MAX];
        int hph_l_gain;
        int hph_r_gain;
        u32 rx_bias_count;
@@ -1287,11 +1287,17 @@ static int slim_rx_mux_put(struct snd_kcontrol *kc,
        struct snd_soc_dapm_update *update = NULL;
        u32 port_id = w->shift;
 
+       if (wcd->rx_port_value[port_id] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd->rx_port_value[port_id] = ucontrol->value.enumerated.item[0];
 
+       /* Remove channel from any list it's in before adding it to a new one */
+       list_del_init(&wcd->rx_chs[port_id].list);
+
        switch (wcd->rx_port_value[port_id]) {
        case 0:
-               list_del_init(&wcd->rx_chs[port_id].list);
+               /* Channel already removed from lists. Nothing to do here */
                break;
        case 1:
                list_add_tail(&wcd->rx_chs[port_id].list,
@@ -1328,8 +1334,13 @@ static int slim_tx_mixer_get(struct snd_kcontrol *kc,
 
        struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kc);
        struct wcd9335_codec *wcd = dev_get_drvdata(dapm->dev);
+       struct snd_soc_dapm_widget *widget = snd_soc_dapm_kcontrol_widget(kc);
+       struct soc_mixer_control *mixer =
+                       (struct soc_mixer_control *)kc->private_value;
+       int dai_id = widget->shift;
+       int port_id = mixer->shift;
 
-       ucontrol->value.integer.value[0] = wcd->tx_port_value;
+       ucontrol->value.integer.value[0] = wcd->tx_port_value[port_id] == dai_id;
 
        return 0;
 }
@@ -1352,12 +1363,12 @@ static int slim_tx_mixer_put(struct snd_kcontrol *kc,
        case AIF2_CAP:
        case AIF3_CAP:
                /* only add to the list if value not set */
-               if (enable && !(wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value |= BIT(port_id);
+               if (enable && wcd->tx_port_value[port_id] != dai_id) {
+                       wcd->tx_port_value[port_id] = dai_id;
                        list_add_tail(&wcd->tx_chs[port_id].list,
                                        &wcd->dai[dai_id].slim_ch_list);
-               } else if (!enable && (wcd->tx_port_value & BIT(port_id))) {
-                       wcd->tx_port_value &= ~BIT(port_id);
+               } else if (!enable && wcd->tx_port_value[port_id] == dai_id) {
+                       wcd->tx_port_value[port_id] = -1;
                        list_del_init(&wcd->tx_chs[port_id].list);
                }
                break;
index c1b61b9..781ae56 100644 (file)
@@ -2519,6 +2519,9 @@ static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        int path = e->shift_l;
 
+       if (wcd938x->tx_mode[path] == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->tx_mode[path] = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2541,6 +2544,9 @@ static int wcd938x_rx_hph_mode_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->hph_mode == ucontrol->value.enumerated.item[0])
+               return 0;
+
        wcd938x->hph_mode = ucontrol->value.enumerated.item[0];
 
        return 1;
@@ -2632,6 +2638,9 @@ static int wcd938x_ldoh_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->ldoh == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->ldoh = ucontrol->value.integer.value[0];
 
        return 1;
@@ -2654,6 +2663,9 @@ static int wcd938x_bcs_put(struct snd_kcontrol *kcontrol,
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component);
 
+       if (wcd938x->bcs_dis == ucontrol->value.integer.value[0])
+               return 0;
+
        wcd938x->bcs_dis = ucontrol->value.integer.value[0];
 
        return 1;
index da2f899..b034df4 100644 (file)
@@ -680,12 +680,17 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       uint16_t dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       int ret = 0;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_coeff = get_unaligned_be16(ucontrol->value.bytes.data);
+       if (arizona->dac_comp_coeff != dac_comp_coeff) {
+               arizona->dac_comp_coeff = dac_comp_coeff;
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
@@ -706,12 +711,20 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
        struct arizona *arizona = dev_get_drvdata(component->dev->parent);
+       struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
+       int ret = 0;
+
+       if (ucontrol->value.integer.value[0] > mc->max)
+               return -EINVAL;
 
        mutex_lock(&arizona->dac_comp_lock);
-       arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+       if (arizona->dac_comp_enabled != ucontrol->value.integer.value[0]) {
+               arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
+               ret = 1;
+       }
        mutex_unlock(&arizona->dac_comp_lock);
 
-       return 0;
+       return ret;
 }
 
 static const char * const wm5102_osr_text[] = {
index 4973ba1..4ab7a67 100644 (file)
@@ -413,6 +413,7 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift;
        unsigned int lold, rold;
        unsigned int lena, rena;
+       bool change = false;
        int ret;
 
        snd_soc_dapm_mutex_lock(dapm);
@@ -440,8 +441,8 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
                goto err;
        }
 
-       ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE,
-                                mask, lnew | rnew);
+       ret = regmap_update_bits_check(arizona->regmap, ARIZONA_DRE_ENABLE,
+                                      mask, lnew | rnew, &change);
        if (ret) {
                dev_err(arizona->dev, "Failed to set DRE: %d\n", ret);
                goto err;
@@ -454,6 +455,9 @@ static int wm5110_put_dre(struct snd_kcontrol *kcontrol,
        if (!rnew && rold)
                wm5110_clear_pga_volume(arizona, mc->rshift);
 
+       if (change)
+               ret = 1;
+
 err:
        snd_soc_dapm_mutex_unlock(dapm);
 
index 00b59fc..ab54811 100644 (file)
@@ -108,6 +108,7 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
        unsigned int mode_reg, mode_index;
        unsigned int mux, inmode, src_val, mode_val;
+       int change, ret;
 
        mux = ucontrol->value.enumerated.item[0];
        if (mux > 1)
@@ -137,14 +138,20 @@ static int wm8998_inmux_put(struct snd_kcontrol *kcontrol,
        snd_soc_component_update_bits(component, mode_reg,
                                      ARIZONA_IN1_MODE_MASK, mode_val);
 
-       snd_soc_component_update_bits(component, e->reg,
-                                     ARIZONA_IN1L_SRC_MASK |
-                                     ARIZONA_IN1L_SRC_SE_MASK,
-                                     src_val);
+       change = snd_soc_component_update_bits(component, e->reg,
+                                              ARIZONA_IN1L_SRC_MASK |
+                                              ARIZONA_IN1L_SRC_SE_MASK,
+                                              src_val);
 
-       return snd_soc_dapm_mux_update_power(dapm, kcontrol,
-                                            ucontrol->value.enumerated.item[0],
-                                            e, NULL);
+       ret = snd_soc_dapm_mux_update_power(dapm, kcontrol,
+                                           ucontrol->value.enumerated.item[0],
+                                           e, NULL);
+       if (ret < 0) {
+               dev_err(arizona->dev, "Failed to update demux power state: %d\n", ret);
+               return ret;
+       }
+
+       return change;
 }
 
 static const char * const wm8998_inmux_texts[] = {
index 6d7fd88..a7784ac 100644 (file)
@@ -997,7 +997,7 @@ int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol,
                snd_soc_dapm_sync(dapm);
        }
 
-       return 0;
+       return 1;
 }
 EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put);
 
index 77ac405..d34b29a 100644 (file)
@@ -90,12 +90,12 @@ links indicates connection part of CPU side (= A).
                        ports@0 {
 (X) (A)                        mcpu:   port@0 { mcpu0_ep: endpoint { remote-endpoint = <&mcodec0_ep>; }; };
 (y)                            port@1 { mcpu1_ep: endpoint { remote-endpoint = <&cpu1_ep>; }; };
-(y)                            port@1 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
+(y)                            port@2 { mcpu2_ep: endpoint { remote-endpoint = <&cpu2_ep>; }; };
                        };
                        ports@1 {
 (X)                            port@0 { mcodec0_ep: endpoint { remote-endpoint = <&mcpu0_ep>; }; };
-(y)                            port@0 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
-(y)                            port@1 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
+(y)                            port@1 { mcodec1_ep: endpoint { remote-endpoint = <&codec1_ep>; }; };
+(y)                            port@2 { mcodec2_ep: endpoint { remote-endpoint = <&codec2_ep>; }; };
                        };
                };
        };
index 0d11cc8..6a06fe3 100644 (file)
@@ -128,10 +128,10 @@ struct avs_tplg_token_parser {
 static int
 avs_parse_uuid_token(struct snd_soc_component *comp, void *elem, void *object, u32 offset)
 {
-       struct snd_soc_tplg_vendor_value_elem *tuple = elem;
+       struct snd_soc_tplg_vendor_uuid_elem *tuple = elem;
        guid_t *val = (guid_t *)((u8 *)object + offset);
 
-       guid_copy((guid_t *)val, (const guid_t *)&tuple->value);
+       guid_copy((guid_t *)val, (const guid_t *)&tuple->uuid);
 
        return 0;
 }
index 00384c6..330c0ac 100644 (file)
@@ -421,8 +421,17 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev)
        priv->spkvdd_en_gpio = gpiod_get(codec_dev, "wlf,spkvdd-ena", GPIOD_OUT_LOW);
        put_device(codec_dev);
 
-       if (IS_ERR(priv->spkvdd_en_gpio))
-               return dev_err_probe(dev, PTR_ERR(priv->spkvdd_en_gpio), "getting spkvdd-GPIO\n");
+       if (IS_ERR(priv->spkvdd_en_gpio)) {
+               ret = PTR_ERR(priv->spkvdd_en_gpio);
+               /*
+                * The spkvdd gpio-lookup is registered by: drivers/mfd/arizona-spi.c,
+                * so -ENOENT means that arizona-spi hasn't probed yet.
+                */
+               if (ret == -ENOENT)
+                       ret = -EPROBE_DEFER;
+
+               return dev_err_probe(dev, ret, "getting spkvdd-GPIO\n");
+       }
 
        /* override platform name, if required */
        byt_wm5102_card.dev = dev;
index 5d67a2c..4a90a0a 100644 (file)
@@ -69,11 +69,10 @@ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN |
 
 static int is_legacy_cpu;
 
-static struct snd_soc_jack sof_hdmi[3];
-
 struct sof_hdmi_pcm {
        struct list_head head;
        struct snd_soc_dai *codec_dai;
+       struct snd_soc_jack hdmi_jack;
        int device;
 };
 
@@ -434,7 +433,6 @@ static int sof_card_late_probe(struct snd_soc_card *card)
        char jack_name[NAME_SIZE];
        struct sof_hdmi_pcm *pcm;
        int err;
-       int i = 0;
 
        /* HDMI is not supported by SOF on Baytrail/CherryTrail */
        if (is_legacy_cpu || !ctx->idisp_codec)
@@ -455,17 +453,15 @@ static int sof_card_late_probe(struct snd_soc_card *card)
                snprintf(jack_name, sizeof(jack_name),
                         "HDMI/DP, pcm=%d Jack", pcm->device);
                err = snd_soc_card_jack_new(card, jack_name,
-                                           SND_JACK_AVOUT, &sof_hdmi[i]);
+                                           SND_JACK_AVOUT, &pcm->hdmi_jack);
 
                if (err)
                        return err;
 
                err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device,
-                                         &sof_hdmi[i]);
+                                         &pcm->hdmi_jack);
                if (err < 0)
                        return err;
-
-               i++;
        }
 
        if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) {
index 1f00679..ad826ad 100644 (file)
@@ -1398,6 +1398,33 @@ static struct snd_soc_card card_sof_sdw = {
        .late_probe = sof_sdw_card_late_probe,
 };
 
+static void mc_dailink_exit_loop(struct snd_soc_card *card)
+{
+       struct snd_soc_dai_link *link;
+       int ret;
+       int i, j;
+
+       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
+               if (!codec_info_list[i].exit)
+                       continue;
+               /*
+                * We don't need to call .exit function if there is no matched
+                * dai link found.
+                */
+               for_each_card_prelinks(card, j, link) {
+                       if (!strcmp(link->codecs[0].dai_name,
+                                   codec_info_list[i].dai_name)) {
+                               ret = codec_info_list[i].exit(card, link);
+                               if (ret)
+                                       dev_warn(card->dev,
+                                                "codec exit failed %d\n",
+                                                ret);
+                               break;
+                       }
+               }
+       }
+}
+
 static int mc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = &card_sof_sdw;
@@ -1462,6 +1489,7 @@ static int mc_probe(struct platform_device *pdev)
        ret = devm_snd_soc_register_card(&pdev->dev, card);
        if (ret) {
                dev_err(card->dev, "snd_soc_register_card failed %d\n", ret);
+               mc_dailink_exit_loop(card);
                return ret;
        }
 
@@ -1473,29 +1501,8 @@ static int mc_probe(struct platform_device *pdev)
 static int mc_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       struct snd_soc_dai_link *link;
-       int ret;
-       int i, j;
 
-       for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) {
-               if (!codec_info_list[i].exit)
-                       continue;
-               /*
-                * We don't need to call .exit function if there is no matched
-                * dai link found.
-                */
-               for_each_card_prelinks(card, j, link) {
-                       if (!strcmp(link->codecs[0].dai_name,
-                                   codec_info_list[i].dai_name)) {
-                               ret = codec_info_list[i].exit(card, link);
-                               if (ret)
-                                       dev_warn(&pdev->dev,
-                                                "codec exit failed %d\n",
-                                                ret);
-                               break;
-                       }
-               }
-       }
+       mc_dailink_exit_loop(card);
 
        return 0;
 }
index 2439a57..deb7b82 100644 (file)
@@ -99,7 +99,6 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        struct nhlt_fmt_cfg *fmt_cfg;
        struct wav_fmt_ext *wav_fmt;
        unsigned long rate;
-       bool present = false;
        int rate_index = 0;
        u16 channels, bps;
        u8 clk_src;
@@ -112,9 +111,12 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
        if (fmt->fmt_count == 0)
                return;
 
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
        for (i = 0; i < fmt->fmt_count; i++) {
-               fmt_cfg = &fmt->fmt_config[i];
-               wav_fmt = &fmt_cfg->fmt_ext;
+               struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg;
+               bool present = false;
+
+               wav_fmt = &saved_fmt_cfg->fmt_ext;
 
                channels = wav_fmt->fmt.channels;
                bps = wav_fmt->fmt.bits_per_sample;
@@ -132,12 +134,18 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                 * derive the rate.
                 */
                for (j = i; j < fmt->fmt_count; j++) {
-                       fmt_cfg = &fmt->fmt_config[j];
-                       wav_fmt = &fmt_cfg->fmt_ext;
+                       struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg;
+
+                       wav_fmt = &tmp_fmt_cfg->fmt_ext;
                        if ((fs == wav_fmt->fmt.samples_per_sec) &&
-                          (bps == wav_fmt->fmt.bits_per_sample))
+                          (bps == wav_fmt->fmt.bits_per_sample)) {
                                channels = max_t(u16, channels,
                                                wav_fmt->fmt.channels);
+                               saved_fmt_cfg = tmp_fmt_cfg;
+                       }
+                       /* Move to the next nhlt_fmt_cfg */
+                       tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps +
+                                                             tmp_fmt_cfg->config.size);
                }
 
                rate = channels * bps * fs;
@@ -153,8 +161,11 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                /* Fill rate and parent for sclk/sclkfs */
                if (!present) {
+                       struct nhlt_fmt_cfg *first_fmt_cfg;
+
+                       first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
                        i2s_config_ext = (struct skl_i2s_config_blob_ext *)
-                                               fmt->fmt_config[0].config.caps;
+                                               first_fmt_cfg->config.caps;
 
                        /* MCLK Divider Source Select */
                        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -168,6 +179,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
 
                        parent = skl_get_parent_clk(clk_src);
 
+                       /* Move to the next nhlt_fmt_cfg */
+                       fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps +
+                                                         fmt_cfg->config.size);
                        /*
                         * Do not copy the config data if there is no parent
                         * clock available for this clock source select
@@ -176,9 +190,9 @@ static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks,
                                continue;
 
                        sclk[id].rate_cfg[rate_index].rate = rate;
-                       sclk[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclkfs[id].rate_cfg[rate_index].rate = rate;
-                       sclkfs[id].rate_cfg[rate_index].config = fmt_cfg;
+                       sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg;
                        sclk[id].parent_name = parent->name;
                        sclkfs[id].parent_name = parent->name;
 
@@ -192,13 +206,13 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
 {
        struct skl_i2s_config_blob_ext *i2s_config_ext;
        struct skl_i2s_config_blob_legacy *i2s_config;
-       struct nhlt_specific_cfg *fmt_cfg;
+       struct nhlt_fmt_cfg *fmt_cfg;
        struct skl_clk_parent_src *parent;
        u32 clkdiv, div_ratio;
        u8 clk_src;
 
-       fmt_cfg = &fmt->fmt_config[0].config;
-       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->caps;
+       fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config;
+       i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps;
 
        /* MCLK Divider Source Select and divider */
        if (is_legacy_blob(i2s_config_ext->hdr.sig)) {
@@ -227,7 +241,7 @@ static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk,
                return;
 
        mclk[id].rate_cfg[0].rate = parent->rate/div_ratio;
-       mclk[id].rate_cfg[0].config = &fmt->fmt_config[0];
+       mclk[id].rate_cfg[0].config = fmt_cfg;
        mclk[id].parent_name = parent->name;
 }
 
index 19c4a90..ee59ef3 100644 (file)
@@ -147,6 +147,12 @@ static int q6apm_dai_prepare(struct snd_soc_component *component,
        cfg.num_channels = runtime->channels;
        cfg.bit_width = prtd->bits_per_sample;
 
+       if (prtd->state) {
+               /* clear the previous setup if any  */
+               q6apm_graph_stop(prtd->graph);
+               q6apm_unmap_memory_regions(prtd->graph, substream->stream);
+       }
+
        prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
        prtd->pos = 0;
        /* rate and channels are sent to audio driver */
index f424d7a..7940192 100644 (file)
@@ -75,6 +75,7 @@ static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, ui
        id = idr_alloc(&apm->graph_idr, graph, graph_id, graph_id + 1, GFP_KERNEL);
        if (id < 0) {
                dev_err(apm->dev, "Unable to allocate graph id (%d)\n", graph_id);
+               kfree(graph->graph);
                kfree(graph);
                mutex_unlock(&apm->lock);
                return ERR_PTR(id);
index 4ce5d25..99a128a 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
 #include <linux/clk.h>
+#include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/regmap.h>
 #include <linux/spinlock.h>
@@ -54,8 +55,40 @@ struct rk_i2s_dev {
        const struct rk_i2s_pins *pins;
        unsigned int bclk_ratio;
        spinlock_t lock; /* tx/rx lock */
+       struct pinctrl *pinctrl;
+       struct pinctrl_state *bclk_on;
+       struct pinctrl_state *bclk_off;
 };
 
+static int i2s_pinctrl_select_bclk_on(struct rk_i2s_dev *i2s)
+{
+       int ret = 0;
+
+       if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_on))
+               ret = pinctrl_select_state(i2s->pinctrl,
+                                    i2s->bclk_on);
+
+       if (ret)
+               dev_err(i2s->dev, "bclk enable failed %d\n", ret);
+
+       return ret;
+}
+
+static int i2s_pinctrl_select_bclk_off(struct rk_i2s_dev *i2s)
+{
+
+       int ret = 0;
+
+       if (!IS_ERR(i2s->pinctrl) && !IS_ERR_OR_NULL(i2s->bclk_off))
+               ret = pinctrl_select_state(i2s->pinctrl,
+                                    i2s->bclk_off);
+
+       if (ret)
+               dev_err(i2s->dev, "bclk disable failed %d\n", ret);
+
+       return ret;
+}
+
 static int i2s_runtime_suspend(struct device *dev)
 {
        struct rk_i2s_dev *i2s = dev_get_drvdata(dev);
@@ -92,38 +125,49 @@ static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai)
        return snd_soc_dai_get_drvdata(dai);
 }
 
-static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
+static int rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 {
        unsigned int val = 0;
        int retry = 10;
+       int ret = 0;
 
        spin_lock(&i2s->lock);
        if (on) {
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                               I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
+               if (ret < 0)
+                       goto end;
 
-               regmap_update_bits(i2s->regmap, I2S_XFER,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
-                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+               ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                               I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+                               I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+               if (ret < 0)
+                       goto end;
 
                i2s->tx_start = true;
        } else {
                i2s->tx_start = false;
 
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
-                                  I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
+                               I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
+               if (ret < 0)
+                       goto end;
 
                if (!i2s->rx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
-                                          I2S_XFER_TXS_START |
-                                          I2S_XFER_RXS_START,
-                                          I2S_XFER_TXS_STOP |
-                                          I2S_XFER_RXS_STOP);
+                       ret = regmap_update_bits(i2s->regmap, I2S_XFER,
+                                       I2S_XFER_TXS_START |
+                                       I2S_XFER_RXS_START,
+                                       I2S_XFER_TXS_STOP |
+                                       I2S_XFER_RXS_STOP);
+                       if (ret < 0)
+                               goto end;
 
                        udelay(150);
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
-                                          I2S_CLR_TXC | I2S_CLR_RXC,
-                                          I2S_CLR_TXC | I2S_CLR_RXC);
+                       ret = regmap_update_bits(i2s->regmap, I2S_CLR,
+                                       I2S_CLR_TXC | I2S_CLR_RXC,
+                                       I2S_CLR_TXC | I2S_CLR_RXC);
+                       if (ret < 0)
+                               goto end;
 
                        regmap_read(i2s->regmap, I2S_CLR, &val);
 
@@ -138,44 +182,57 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
                        }
                }
        }
+end:
        spin_unlock(&i2s->lock);
+       if (ret < 0)
+               dev_err(i2s->dev, "lrclk update failed\n");
+
+       return ret;
 }
 
-static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
+static int rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 {
        unsigned int val = 0;
        int retry = 10;
+       int ret = 0;
 
        spin_lock(&i2s->lock);
        if (on) {
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
+               if (ret < 0)
+                       goto end;
 
-               regmap_update_bits(i2s->regmap, I2S_XFER,
+               ret = regmap_update_bits(i2s->regmap, I2S_XFER,
                                   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
                                   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
+               if (ret < 0)
+                       goto end;
 
                i2s->rx_start = true;
        } else {
                i2s->rx_start = false;
 
-               regmap_update_bits(i2s->regmap, I2S_DMACR,
+               ret = regmap_update_bits(i2s->regmap, I2S_DMACR,
                                   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
+               if (ret < 0)
+                       goto end;
 
                if (!i2s->tx_start) {
-                       regmap_update_bits(i2s->regmap, I2S_XFER,
+                       ret = regmap_update_bits(i2s->regmap, I2S_XFER,
                                           I2S_XFER_TXS_START |
                                           I2S_XFER_RXS_START,
                                           I2S_XFER_TXS_STOP |
                                           I2S_XFER_RXS_STOP);
-
+                       if (ret < 0)
+                               goto end;
                        udelay(150);
-                       regmap_update_bits(i2s->regmap, I2S_CLR,
+                       ret = regmap_update_bits(i2s->regmap, I2S_CLR,
                                           I2S_CLR_TXC | I2S_CLR_RXC,
                                           I2S_CLR_TXC | I2S_CLR_RXC);
-
+                       if (ret < 0)
+                               goto end;
                        regmap_read(i2s->regmap, I2S_CLR, &val);
-
                        /* Should wait for clear operation to finish */
                        while (val) {
                                regmap_read(i2s->regmap, I2S_CLR, &val);
@@ -187,7 +244,12 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
                        }
                }
        }
+end:
        spin_unlock(&i2s->lock);
+       if (ret < 0)
+               dev_err(i2s->dev, "lrclk update failed\n");
+
+       return ret;
 }
 
 static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
@@ -425,17 +487,26 @@ static int rockchip_i2s_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       rockchip_snd_rxctrl(i2s, 1);
+                       ret = rockchip_snd_rxctrl(i2s, 1);
                else
-                       rockchip_snd_txctrl(i2s, 1);
+                       ret = rockchip_snd_txctrl(i2s, 1);
+               /* Do not turn on bclk if lrclk open fails. */
+               if (ret < 0)
+                       return ret;
+               i2s_pinctrl_select_bclk_on(i2s);
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
        case SNDRV_PCM_TRIGGER_STOP:
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
-                       rockchip_snd_rxctrl(i2s, 0);
-               else
-                       rockchip_snd_txctrl(i2s, 0);
+               if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+                       if (!i2s->tx_start)
+                               i2s_pinctrl_select_bclk_off(i2s);
+                       ret = rockchip_snd_rxctrl(i2s, 0);
+               } else {
+                       if (!i2s->rx_start)
+                               i2s_pinctrl_select_bclk_off(i2s);
+                       ret = rockchip_snd_txctrl(i2s, 0);
+               }
                break;
        default:
                ret = -EINVAL;
@@ -736,6 +807,33 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
        }
 
        i2s->bclk_ratio = 64;
+       i2s->pinctrl = devm_pinctrl_get(&pdev->dev);
+       if (IS_ERR(i2s->pinctrl))
+               dev_err(&pdev->dev, "failed to find i2s pinctrl\n");
+
+       i2s->bclk_on = pinctrl_lookup_state(i2s->pinctrl,
+                                  "bclk_on");
+       if (IS_ERR_OR_NULL(i2s->bclk_on))
+               dev_err(&pdev->dev, "failed to find i2s default state\n");
+       else
+               dev_dbg(&pdev->dev, "find i2s bclk state\n");
+
+       i2s->bclk_off = pinctrl_lookup_state(i2s->pinctrl,
+                                 "bclk_off");
+       if (IS_ERR_OR_NULL(i2s->bclk_off))
+               dev_err(&pdev->dev, "failed to find i2s gpio state\n");
+       else
+               dev_dbg(&pdev->dev, "find i2s bclk_off state\n");
+
+       i2s_pinctrl_select_bclk_off(i2s);
+
+       i2s->playback_dma_data.addr = res->start + I2S_TXDR;
+       i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       i2s->playback_dma_data.maxburst = 4;
+
+       i2s->capture_dma_data.addr = res->start + I2S_RXDR;
+       i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       i2s->capture_dma_data.maxburst = 4;
 
        dev_set_drvdata(&pdev->dev, i2s);
 
index 869c765..a8e842e 100644 (file)
@@ -62,6 +62,8 @@ struct snd_soc_dapm_widget *
 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
                         const struct snd_soc_dapm_widget *widget);
 
+static unsigned int soc_dapm_read(struct snd_soc_dapm_context *dapm, int reg);
+
 /* dapm power sequences - make this per codec in the future */
 static int dapm_up_seq[] = {
        [snd_soc_dapm_pre] = 1,
@@ -442,6 +444,9 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget,
 
                        snd_soc_dapm_add_path(widget->dapm, data->widget,
                                              widget, NULL, NULL);
+               } else if (e->reg != SND_SOC_NOPM) {
+                       data->value = soc_dapm_read(widget->dapm, e->reg) &
+                                     (e->mask << e->shift_l);
                }
                break;
        default:
index e693070..d867f44 100644 (file)
@@ -526,7 +526,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                return -EINVAL;
        if (mc->platform_max && tmp > mc->platform_max)
                return -EINVAL;
-       if (tmp > mc->max - mc->min + 1)
+       if (tmp > mc->max - mc->min)
                return -EINVAL;
 
        if (invert)
@@ -547,7 +547,7 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
                        return -EINVAL;
                if (mc->platform_max && tmp > mc->platform_max)
                        return -EINVAL;
-               if (tmp > mc->max - mc->min + 1)
+               if (tmp > mc->max - mc->min)
                        return -EINVAL;
 
                if (invert)
index 000ea90..e24eea7 100644 (file)
@@ -181,12 +181,20 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
  * Power Management.
  */
 
-static int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
 {
+       struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+       const struct sof_intel_dsp_desc *chip = hda->desc;
        unsigned int cpa;
        u32 adspcs;
        int ret;
 
+       /* restrict core_mask to host managed cores mask */
+       core_mask &= chip->host_managed_cores_mask;
+       /* return if core_mask is not valid */
+       if (!core_mask)
+               return 0;
+
        /* update bits */
        snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPCS,
                                HDA_DSP_ADSPCS_SPA_MASK(core_mask),
index 6429012..145d483 100644 (file)
@@ -95,9 +95,9 @@ out_put:
 }
 
 /*
- * first boot sequence has some extra steps. core 0 waits for power
- * status on core 1, so power up core 1 also momentarily, keep it in
- * reset/stall and then turn it off
+ * first boot sequence has some extra steps.
+ * power on all host managed cores and only unstall/run the boot core to boot the
+ * DSP then turn off all non boot cores (if any) is powered on.
  */
 static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
 {
@@ -110,7 +110,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        int ret;
 
        /* step 1: power up corex */
-       ret = hda_dsp_enable_core(sdev, chip->host_managed_cores_mask);
+       ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -127,7 +127,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
        snd_sof_dsp_write(sdev, HDA_DSP_BAR, chip->ipc_req, ipc_hdr);
 
        /* step 3: unset core 0 reset state & unstall/run core 0 */
-       ret = hda_dsp_core_run(sdev, BIT(0));
+       ret = hda_dsp_core_run(sdev, chip->init_core_mask);
        if (ret < 0) {
                if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
                        dev_err(sdev->dev,
@@ -389,7 +389,8 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
        struct snd_dma_buffer dmab;
        int ret, ret1, i;
 
-       if (hda->imrboot_supported && !sdev->first_boot) {
+       if (sdev->system_suspend_target < SOF_SUSPEND_S4 &&
+           hda->imrboot_supported && !sdev->first_boot) {
                dev_dbg(sdev->dev, "IMR restore supported, booting from IMR directly\n");
                hda->boot_iteration = 0;
                ret = hda_dsp_boot_imr(sdev);
index dc1f743..6888e0a 100644 (file)
@@ -192,79 +192,7 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
                goto found;
        }
 
-       switch (sof_hda_position_quirk) {
-       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
-               /*
-                * This legacy code, inherited from the Skylake driver,
-                * mixes DPIB registers and DPIB DDR updates and
-                * does not seem to follow any known hardware recommendations.
-                * It's not clear e.g. why there is a different flow
-                * for capture and playback, the only information that matters is
-                * what traffic class is used, and on all SOF-enabled platforms
-                * only VC0 is supported so the work-around was likely not necessary
-                * and quite possibly wrong.
-                */
-
-               /* DPIB/posbuf position mode:
-                * For Playback, Use DPIB register from HDA space which
-                * reflects the actual data transferred.
-                * For Capture, Use the position buffer for pointer, as DPIB
-                * is not accurate enough, its update may be completed
-                * earlier than the data written to DDR.
-                */
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                              AZX_REG_VS_SDXDPIB_XBASE +
-                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                               hstream->index));
-               } else {
-                       /*
-                        * For capture stream, we need more workaround to fix the
-                        * position incorrect issue:
-                        *
-                        * 1. Wait at least 20us before reading position buffer after
-                        * the interrupt generated(IOC), to make sure position update
-                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
-                        * 2. Perform a dummy Read to DPIB register to flush DMA
-                        * position value.
-                        * 3. Read the DMA Position from posbuf. Now the readback
-                        * value should be >= period boundary.
-                        */
-                       usleep_range(20, 21);
-                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                        AZX_REG_VS_SDXDPIB_XBASE +
-                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                         hstream->index));
-                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               }
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
-               /*
-                * In case VC1 traffic is disabled this is the recommended option
-                */
-               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
-                                      AZX_REG_VS_SDXDPIB_XBASE +
-                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
-                                       hstream->index));
-               break;
-       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
-               /*
-                * This is the recommended option when VC1 is enabled.
-                * While this isn't needed for SOF platforms it's added for
-                * consistency and debug.
-                */
-               pos = snd_hdac_stream_get_pos_posbuf(hstream);
-               break;
-       default:
-               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
-                            sof_hda_position_quirk);
-               pos = 0;
-               break;
-       }
-
-       if (pos >= hstream->bufsize)
-               pos = 0;
-
+       pos = hda_dsp_stream_get_position(hstream, substream->stream, true);
 found:
        pos = bytes_to_frames(substream->runtime, pos);
 
index daeb64c..d95ae17 100644 (file)
@@ -707,12 +707,13 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
 }
 
 static void
-hda_dsp_set_bytes_transferred(struct hdac_stream *hstream, u64 buffer_size)
+hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
 {
+       u64 buffer_size = hstream->bufsize;
        u64 prev_pos, pos, num_bytes;
 
        div64_u64_rem(hstream->curr_pos, buffer_size, &prev_pos);
-       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+       pos = hda_dsp_stream_get_position(hstream, direction, false);
 
        if (pos < prev_pos)
                num_bytes = (buffer_size - prev_pos) +  pos;
@@ -748,8 +749,7 @@ static bool hda_dsp_stream_check(struct hdac_bus *bus, u32 status)
                        if (s->substream && sof_hda->no_ipc_position) {
                                snd_sof_pcm_period_elapsed(s->substream);
                        } else if (s->cstream) {
-                               hda_dsp_set_bytes_transferred(s,
-                                       s->cstream->runtime->buffer_size);
+                               hda_dsp_compr_bytes_transferred(s, s->cstream->direction);
                                snd_compr_fragment_elapsed(s->cstream);
                        }
                }
@@ -1009,3 +1009,89 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
                devm_kfree(sdev->dev, hda_stream);
        }
 }
+
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep)
+{
+       struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+       struct sof_intel_hda_stream *hda_stream = hstream_to_sof_hda_stream(hext_stream);
+       struct snd_sof_dev *sdev = hda_stream->sdev;
+       snd_pcm_uframes_t pos;
+
+       switch (sof_hda_position_quirk) {
+       case SOF_HDA_POSITION_QUIRK_USE_SKYLAKE_LEGACY:
+               /*
+                * This legacy code, inherited from the Skylake driver,
+                * mixes DPIB registers and DPIB DDR updates and
+                * does not seem to follow any known hardware recommendations.
+                * It's not clear e.g. why there is a different flow
+                * for capture and playback, the only information that matters is
+                * what traffic class is used, and on all SOF-enabled platforms
+                * only VC0 is supported so the work-around was likely not necessary
+                * and quite possibly wrong.
+                */
+
+               /* DPIB/posbuf position mode:
+                * For Playback, Use DPIB register from HDA space which
+                * reflects the actual data transferred.
+                * For Capture, Use the position buffer for pointer, as DPIB
+                * is not accurate enough, its update may be completed
+                * earlier than the data written to DDR.
+                */
+               if (direction == SNDRV_PCM_STREAM_PLAYBACK) {
+                       pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                              AZX_REG_VS_SDXDPIB_XBASE +
+                                              (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                               hstream->index));
+               } else {
+                       /*
+                        * For capture stream, we need more workaround to fix the
+                        * position incorrect issue:
+                        *
+                        * 1. Wait at least 20us before reading position buffer after
+                        * the interrupt generated(IOC), to make sure position update
+                        * happens on frame boundary i.e. 20.833uSec for 48KHz.
+                        * 2. Perform a dummy Read to DPIB register to flush DMA
+                        * position value.
+                        * 3. Read the DMA Position from posbuf. Now the readback
+                        * value should be >= period boundary.
+                        */
+                       if (can_sleep)
+                               usleep_range(20, 21);
+
+                       snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                        AZX_REG_VS_SDXDPIB_XBASE +
+                                        (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                         hstream->index));
+                       pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               }
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS:
+               /*
+                * In case VC1 traffic is disabled this is the recommended option
+                */
+               pos = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR,
+                                      AZX_REG_VS_SDXDPIB_XBASE +
+                                      (AZX_REG_VS_SDXDPIB_XINTERVAL *
+                                       hstream->index));
+               break;
+       case SOF_HDA_POSITION_QUIRK_USE_DPIB_DDR_UPDATE:
+               /*
+                * This is the recommended option when VC1 is enabled.
+                * While this isn't needed for SOF platforms it's added for
+                * consistency and debug.
+                */
+               pos = snd_hdac_stream_get_pos_posbuf(hstream);
+               break;
+       default:
+               dev_err_once(sdev->dev, "hda_position_quirk value %d not supported\n",
+                            sof_hda_position_quirk);
+               pos = 0;
+               break;
+       }
+
+       if (pos >= hstream->bufsize)
+               pos = 0;
+
+       return pos;
+}
index 3e0f7b0..06476ff 100644 (file)
@@ -497,6 +497,7 @@ struct sof_intel_hda_stream {
  */
 int hda_dsp_probe(struct snd_sof_dev *sdev);
 int hda_dsp_remove(struct snd_sof_dev *sdev);
+int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask);
 int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
@@ -564,6 +565,9 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
 bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
 bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
 
+snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
+                                             int direction, bool can_sleep);
+
 struct hdac_ext_stream *
        hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
 int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
index 043554d..10740c5 100644 (file)
@@ -1577,24 +1577,23 @@ static int sof_ipc3_control_load_bytes(struct snd_sof_dev *sdev, struct snd_sof_
        struct sof_ipc_ctrl_data *cdata;
        int ret;
 
-       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
-       if (!scontrol->ipc_control_data)
-               return -ENOMEM;
-
-       if (scontrol->max_size < sizeof(*cdata) ||
-           scontrol->max_size < sizeof(struct sof_abi_hdr)) {
-               ret = -EINVAL;
-               goto err;
+       if (scontrol->max_size < (sizeof(*cdata) + sizeof(struct sof_abi_hdr))) {
+               dev_err(sdev->dev, "%s: insufficient size for a bytes control: %zu.\n",
+                       __func__, scontrol->max_size);
+               return -EINVAL;
        }
 
-       /* init the get/put bytes data */
        if (scontrol->priv_size > scontrol->max_size - sizeof(*cdata)) {
-               dev_err(sdev->dev, "err: bytes data size %zu exceeds max %zu.\n",
+               dev_err(sdev->dev,
+                       "%s: bytes data size %zu exceeds max %zu.\n", __func__,
                        scontrol->priv_size, scontrol->max_size - sizeof(*cdata));
-               ret = -EINVAL;
-               goto err;
+               return -EINVAL;
        }
 
+       scontrol->ipc_control_data = kzalloc(scontrol->max_size, GFP_KERNEL);
+       if (!scontrol->ipc_control_data)
+               return -ENOMEM;
+
        scontrol->size = sizeof(struct sof_ipc_ctrl_data) + scontrol->priv_size;
 
        cdata = scontrol->ipc_control_data;
index 3333a06..e006532 100644 (file)
@@ -392,7 +392,7 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
                                                      PLATFORM_DEVID_NONE,
                                                      pdev, sizeof(*pdev));
        if (IS_ERR(priv->ipc_dev)) {
-               ret = IS_ERR(priv->ipc_dev);
+               ret = PTR_ERR(priv->ipc_dev);
                dev_err(sdev->dev, "failed to create mtk-adsp-ipc device\n");
                goto err_adsp_off;
        }
index 18eb327..df740be 100644 (file)
@@ -23,6 +23,9 @@ static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
        u32 target_dsp_state;
 
        switch (sdev->system_suspend_target) {
+       case SOF_SUSPEND_S5:
+       case SOF_SUSPEND_S4:
+               /* DSP should be in D3 if the system is suspending to S3+ */
        case SOF_SUSPEND_S3:
                /* DSP should be in D3 if the system is suspending to S3 */
                target_dsp_state = SOF_DSP_PM_D3;
@@ -335,8 +338,24 @@ int snd_sof_prepare(struct device *dev)
                return 0;
 
 #if defined(CONFIG_ACPI)
-       if (acpi_target_system_state() == ACPI_STATE_S0)
+       switch (acpi_target_system_state()) {
+       case ACPI_STATE_S0:
                sdev->system_suspend_target = SOF_SUSPEND_S0IX;
+               break;
+       case ACPI_STATE_S1:
+       case ACPI_STATE_S2:
+       case ACPI_STATE_S3:
+               sdev->system_suspend_target = SOF_SUSPEND_S3;
+               break;
+       case ACPI_STATE_S4:
+               sdev->system_suspend_target = SOF_SUSPEND_S4;
+               break;
+       case ACPI_STATE_S5:
+               sdev->system_suspend_target = SOF_SUSPEND_S5;
+               break;
+       default:
+               break;
+       }
 #endif
 
        return 0;
index 9d7f53f..f0f3d72 100644 (file)
@@ -85,6 +85,8 @@ enum sof_system_suspend_state {
        SOF_SUSPEND_NONE = 0,
        SOF_SUSPEND_S0IX,
        SOF_SUSPEND_S3,
+       SOF_SUSPEND_S4,
+       SOF_SUSPEND_S5,
 };
 
 enum sof_dfsentry_type {
index 7865cda..da519ea 100644 (file)
@@ -316,8 +316,6 @@ static inline int omap_mcbsp_read(struct omap_mcbsp *mcbsp, u16 reg,
 
 /* Sidetone specific API */
 int omap_mcbsp_st_init(struct platform_device *pdev);
-void omap_mcbsp_st_cleanup(struct platform_device *pdev);
-
 int omap_mcbsp_st_start(struct omap_mcbsp *mcbsp);
 int omap_mcbsp_st_stop(struct omap_mcbsp *mcbsp);
 
index 0bc7d26..7e8179c 100644 (file)
@@ -347,7 +347,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data)
                return -ENOMEM;
 
-       st_data->mcbsp_iclk = clk_get(mcbsp->dev, "ick");
+       st_data->mcbsp_iclk = devm_clk_get(mcbsp->dev, "ick");
        if (IS_ERR(st_data->mcbsp_iclk)) {
                dev_warn(mcbsp->dev,
                         "Failed to get ick, sidetone might be broken\n");
@@ -359,7 +359,7 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        if (!st_data->io_base_st)
                return -ENOMEM;
 
-       ret = sysfs_create_group(&mcbsp->dev->kobj, &sidetone_attr_group);
+       ret = devm_device_add_group(mcbsp->dev, &sidetone_attr_group);
        if (ret)
                return ret;
 
@@ -368,16 +368,6 @@ int omap_mcbsp_st_init(struct platform_device *pdev)
        return 0;
 }
 
-void omap_mcbsp_st_cleanup(struct platform_device *pdev)
-{
-       struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev);
-
-       if (mcbsp->st_data) {
-               sysfs_remove_group(&mcbsp->dev->kobj, &sidetone_attr_group);
-               clk_put(mcbsp->st_data->mcbsp_iclk);
-       }
-}
-
 static int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol,
                                    struct snd_ctl_elem_info *uinfo)
 {
index 4479d74..9933b33 100644 (file)
@@ -702,8 +702,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
                mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
 
-               ret = sysfs_create_group(&mcbsp->dev->kobj,
-                                        &additional_attr_group);
+               ret = devm_device_add_group(mcbsp->dev, &additional_attr_group);
                if (ret) {
                        dev_err(mcbsp->dev,
                                "Unable to create additional controls\n");
@@ -711,16 +710,7 @@ static int omap_mcbsp_init(struct platform_device *pdev)
                }
        }
 
-       ret = omap_mcbsp_st_init(pdev);
-       if (ret)
-               goto err_st;
-
-       return 0;
-
-err_st:
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-       return ret;
+       return omap_mcbsp_st_init(pdev);
 }
 
 /*
@@ -1431,11 +1421,6 @@ static int asoc_mcbsp_remove(struct platform_device *pdev)
        if (cpu_latency_qos_request_active(&mcbsp->pm_qos_req))
                cpu_latency_qos_remove_request(&mcbsp->pm_qos_req);
 
-       if (mcbsp->pdata->buffer_size)
-               sysfs_remove_group(&mcbsp->dev->kobj, &additional_attr_group);
-
-       omap_mcbsp_st_cleanup(pdev);
-
        return 0;
 }
 
index 4f56e17..f93201a 100644 (file)
@@ -3803,6 +3803,54 @@ YAMAHA_DEVICE(0x7010, "UB99"),
 },
 
 /*
+ * MacroSilicon MS2100/MS2106 based AV capture cards
+ *
+ * These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
+ * They also need QUIRK_FLAG_ALIGN_TRANSFER, which makes one wonder if
+ * they pretend to be 96kHz mono as a workaround for stereo being broken
+ * by that...
+ *
+ * They also have an issue with initial stream alignment that causes the
+ * channels to be swapped and out of phase, which is dealt with in quirks.c.
+ */
+{
+       USB_AUDIO_DEVICE(0x534d, 0x0021),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "MacroSilicon",
+               .product_name = "MS210x",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_STANDARD_MIXER,
+                       },
+                       {
+                               .ifnum = 3,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                       .channels = 2,
+                                       .iface = 3,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .attributes = 0,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                               USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_CONTINUOUS,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+
+/*
  * MacroSilicon MS2109 based HDMI capture cards
  *
  * These claim 96kHz 1ch in the descriptors, but are actually 48kHz 2ch.
@@ -4119,6 +4167,206 @@ YAMAHA_DEVICE(0x7010, "UB99"),
                }
        }
 },
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 48 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0023),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000,
+                                       .rate_min = 48000,
+                                       .rate_max = 48000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 48000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.0.0 @ 96 kHz)
+        */
+       USB_DEVICE(0x2b53, 0x0024),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_96000,
+                                       .rate_min = 96000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 1,
+                                       .rate_table = (unsigned int[]) { 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
+{
+       /*
+        * Fiero SC-01 (firmware v1.1.0)
+        */
+       USB_DEVICE(0x2b53, 0x0031),
+       .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+               .vendor_name = "Fiero",
+               .product_name = "SC-01",
+               .ifnum = QUIRK_ANY_INTERFACE,
+               .type = QUIRK_COMPOSITE,
+               .data = &(const struct snd_usb_audio_quirk[]) {
+                       {
+                               .ifnum = 0,
+                               .type = QUIRK_AUDIO_STANDARD_INTERFACE
+                       },
+                       /* Playback */
+                       {
+                               .ifnum = 1,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 1,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x01,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       /* Capture */
+                       {
+                               .ifnum = 2,
+                               .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+                               .data = &(const struct audioformat) {
+                                       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+                                       .channels = 2,
+                                       .fmt_bits = 24,
+                                       .iface = 2,
+                                       .altsetting = 1,
+                                       .altset_idx = 1,
+                                       .endpoint = 0x82,
+                                       .ep_attr = USB_ENDPOINT_XFER_ISOC |
+                                                  USB_ENDPOINT_SYNC_ASYNC |
+                                                  USB_ENDPOINT_USAGE_IMPLICIT_FB,
+                                       .rates = SNDRV_PCM_RATE_48000 |
+                                                SNDRV_PCM_RATE_96000,
+                                       .rate_min = 48000,
+                                       .rate_max = 96000,
+                                       .nr_rates = 2,
+                                       .rate_table = (unsigned int[]) { 48000, 96000 },
+                                       .clock = 0x29
+                               }
+                       },
+                       {
+                               .ifnum = -1
+                       }
+               }
+       }
+},
 
 #undef USB_DEVICE_VENDOR_SPEC
 #undef USB_AUDIO_DEVICE
index e8468f9..968d90c 100644 (file)
@@ -1478,6 +1478,7 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
        case USB_ID(0x041e, 0x3f19): /* E-Mu 0204 USB */
                set_format_emu_quirk(subs, fmt);
                break;
+       case USB_ID(0x534d, 0x0021): /* MacroSilicon MS2100/MS2106 */
        case USB_ID(0x534d, 0x2109): /* MacroSilicon MS2109 */
                subs->stream_offset_adj = 2;
                break;
@@ -1842,6 +1843,10 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1395, 0x740a, /* Sennheiser DECT */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x1397, 0x0508, /* Behringer UMC204HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x1397, 0x0509, /* Behringer UMC404HD */
+                  QUIRK_FLAG_PLAYBACK_FIRST | QUIRK_FLAG_GENERIC_IMPLICIT_FB),
        DEVICE_FLG(0x13e5, 0x0001, /* Serato Phono */
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x154e, 0x1002, /* Denon DCD-1500RE */
@@ -1904,10 +1909,18 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_IGNORE_CTL_ERROR),
        DEVICE_FLG(0x413c, 0xa506, /* Dell AE515 sound bar */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x534d, 0x0021, /* MacroSilicon MS2100/MS2106 */
+                  QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x534d, 0x2109, /* MacroSilicon MS2109 */
                   QUIRK_FLAG_ALIGN_TRANSFER),
        DEVICE_FLG(0x1224, 0x2a25, /* Jieli Technology USB PHY 2.0 */
                   QUIRK_FLAG_GET_SAMPLE_RATE),
+       DEVICE_FLG(0x2b53, 0x0023, /* Fiero SC-01 (firmware v1.0.0 @ 48 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0024, /* Fiero SC-01 (firmware v1.0.0 @ 96 kHz) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
+       DEVICE_FLG(0x2b53, 0x0031, /* Fiero SC-01 (firmware v1.1.0) */
+                  QUIRK_FLAG_GENERIC_IMPLICIT_FB),
 
        /* Vendor matches */
        VENDOR_FLG(0x045e, /* MS Lifecam */
index d27e058..2eab6a3 100644 (file)
@@ -51,6 +51,8 @@
 #define SPEC_CTRL_STIBP                        BIT(SPEC_CTRL_STIBP_SHIFT)      /* STIBP mask */
 #define SPEC_CTRL_SSBD_SHIFT           2          /* Speculative Store Bypass Disable bit */
 #define SPEC_CTRL_SSBD                 BIT(SPEC_CTRL_SSBD_SHIFT)       /* Speculative Store Bypass Disable */
+#define SPEC_CTRL_RRSBA_DIS_S_SHIFT    6          /* Disable RRSBA behavior */
+#define SPEC_CTRL_RRSBA_DIS_S          BIT(SPEC_CTRL_RRSBA_DIS_S_SHIFT)
 
 #define MSR_IA32_PRED_CMD              0x00000049 /* Prediction Command */
 #define PRED_CMD_IBPB                  BIT(0)     /* Indirect Branch Prediction Barrier */
                                                 * bit available to control VERW
                                                 * behavior.
                                                 */
+#define ARCH_CAP_RRSBA                 BIT(19) /*
+                                                * Indicates RET may use predictors
+                                                * other than the RSB. With eIBRS
+                                                * enabled predictions in kernel mode
+                                                * are restricted to targets in
+                                                * kernel.
+                                                */
 
 #define MSR_IA32_FLUSH_CMD             0x0000010b
 #define L1D_FLUSH                      BIT(0)  /*
index 15b940e..10bc88c 100644 (file)
@@ -32,11 +32,16 @@ struct unwind_hint {
  *
  * UNWIND_HINT_FUNC: Generate the unwind metadata of a callable function.
  * Useful for code which doesn't have an ELF function annotation.
+ *
+ * UNWIND_HINT_ENTRY: machine entry without stack, SYSCALL/SYSENTER etc.
  */
 #define UNWIND_HINT_TYPE_CALL          0
 #define UNWIND_HINT_TYPE_REGS          1
 #define UNWIND_HINT_TYPE_REGS_PARTIAL  2
 #define UNWIND_HINT_TYPE_FUNC          3
+#define UNWIND_HINT_TYPE_ENTRY         4
+#define UNWIND_HINT_TYPE_SAVE          5
+#define UNWIND_HINT_TYPE_RESTORE       6
 
 #ifdef CONFIG_OBJTOOL
 
@@ -124,7 +129,7 @@ struct unwind_hint {
  * the debuginfo as necessary.  It will also warn if it sees any
  * inconsistencies.
  */
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .Lunwind_hint_ip_\@:
        .pushsection .discard.unwind_hints
                /* struct unwind_hint */
@@ -177,7 +182,7 @@ struct unwind_hint {
 #define ASM_REACHABLE
 #else
 #define ANNOTATE_INTRA_FUNCTION_CALL
-.macro UNWIND_HINT sp_reg:req sp_offset=0 type:req end=0
+.macro UNWIND_HINT type:req sp_reg=0 sp_offset=0 end=0
 .endm
 .macro STACK_FRAME_NON_STANDARD func:req
 .endm
index f4009db..ef78e0e 100644 (file)
@@ -5222,22 +5222,25 @@ union bpf_attr {
  *     Return
  *             Nothing. Always succeeds.
  *
- * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset)
+ * long bpf_dynptr_read(void *dst, u32 len, struct bpf_dynptr *src, u32 offset, u64 flags)
  *     Description
  *             Read *len* bytes from *src* into *dst*, starting from *offset*
  *             into *src*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
- *             of *src*'s data, -EINVAL if *src* is an invalid dynptr.
+ *             of *src*'s data, -EINVAL if *src* is an invalid dynptr or if
+ *             *flags* is not 0.
  *
- * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len)
+ * long bpf_dynptr_write(struct bpf_dynptr *dst, u32 offset, void *src, u32 len, u64 flags)
  *     Description
  *             Write *len* bytes from *src* into *dst*, starting from *offset*
  *             into *dst*.
+ *             *flags* is currently unused.
  *     Return
  *             0 on success, -E2BIG if *offset* + *len* exceeds the length
  *             of *dst*'s data, -EINVAL if *dst* is an invalid dynptr or if *dst*
- *             is a read-only dynptr.
+ *             is a read-only dynptr or if *flags* is not 0.
  *
  * void *bpf_dynptr_data(struct bpf_dynptr *ptr, u32 offset, u32 len)
  *     Description
index 8b990a5..c260006 100644 (file)
@@ -787,3 +787,8 @@ bool arch_is_retpoline(struct symbol *sym)
 {
        return !strncmp(sym->name, "__x86_indirect_", 15);
 }
+
+bool arch_is_rethunk(struct symbol *sym)
+{
+       return !strcmp(sym->name, "__x86_return_thunk");
+}
index f4c3a50..24fbe80 100644 (file)
@@ -68,6 +68,8 @@ const struct option check_options[] = {
        OPT_BOOLEAN('n', "noinstr", &opts.noinstr, "validate noinstr rules"),
        OPT_BOOLEAN('o', "orc", &opts.orc, "generate ORC metadata"),
        OPT_BOOLEAN('r', "retpoline", &opts.retpoline, "validate and annotate retpoline usage"),
+       OPT_BOOLEAN(0,   "rethunk", &opts.rethunk, "validate and annotate rethunk usage"),
+       OPT_BOOLEAN(0,   "unret", &opts.unret, "validate entry unret placement"),
        OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mitigations"),
        OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rules"),
        OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls"),
@@ -123,6 +125,7 @@ static bool opts_valid(void)
            opts.noinstr                ||
            opts.orc                    ||
            opts.retpoline              ||
+           opts.rethunk                ||
            opts.sls                    ||
            opts.stackval               ||
            opts.static_call            ||
@@ -135,6 +138,11 @@ static bool opts_valid(void)
                return true;
        }
 
+       if (opts.unret && !opts.rethunk) {
+               ERROR("--unret requires --rethunk");
+               return false;
+       }
+
        if (opts.dump_orc)
                return true;
 
@@ -163,6 +171,11 @@ static bool link_opts_valid(struct objtool_file *file)
                return false;
        }
 
+       if (opts.unret) {
+               ERROR("--unret requires --link");
+               return false;
+       }
+
        return true;
 }
 
index 864bb9d..b341f8a 100644 (file)
@@ -376,7 +376,8 @@ static int decode_instructions(struct objtool_file *file)
                        sec->text = true;
 
                if (!strcmp(sec->name, ".noinstr.text") ||
-                   !strcmp(sec->name, ".entry.text"))
+                   !strcmp(sec->name, ".entry.text") ||
+                   !strncmp(sec->name, ".text.__x86.", 12))
                        sec->noinstr = true;
 
                for (offset = 0; offset < sec->sh.sh_size; offset += insn->len) {
@@ -749,6 +750,52 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
        return 0;
 }
 
+static int create_return_sites_sections(struct objtool_file *file)
+{
+       struct instruction *insn;
+       struct section *sec;
+       int idx;
+
+       sec = find_section_by_name(file->elf, ".return_sites");
+       if (sec) {
+               WARN("file already has .return_sites, skipping");
+               return 0;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node)
+               idx++;
+
+       if (!idx)
+               return 0;
+
+       sec = elf_create_section(file->elf, ".return_sites", 0,
+                                sizeof(int), idx);
+       if (!sec) {
+               WARN("elf_create_section: .return_sites");
+               return -1;
+       }
+
+       idx = 0;
+       list_for_each_entry(insn, &file->return_thunk_list, call_node) {
+
+               int *site = (int *)sec->data->d_buf + idx;
+               *site = 0;
+
+               if (elf_add_reloc_to_insn(file->elf, sec,
+                                         idx * sizeof(int),
+                                         R_X86_64_PC32,
+                                         insn->sec, insn->offset)) {
+                       WARN("elf_add_reloc_to_insn: .return_sites");
+                       return -1;
+               }
+
+               idx++;
+       }
+
+       return 0;
+}
+
 static int create_ibt_endbr_seal_sections(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -1083,6 +1130,11 @@ __weak bool arch_is_retpoline(struct symbol *sym)
        return false;
 }
 
+__weak bool arch_is_rethunk(struct symbol *sym)
+{
+       return false;
+}
+
 #define NEGATIVE_RELOC ((void *)-1L)
 
 static struct reloc *insn_reloc(struct objtool_file *file, struct instruction *insn)
@@ -1250,6 +1302,19 @@ static void add_retpoline_call(struct objtool_file *file, struct instruction *in
        annotate_call_site(file, insn, false);
 }
 
+static void add_return_call(struct objtool_file *file, struct instruction *insn, bool add)
+{
+       /*
+        * Return thunk tail calls are really just returns in disguise,
+        * so convert them accordingly.
+        */
+       insn->type = INSN_RETURN;
+       insn->retpoline_safe = true;
+
+       if (add)
+               list_add_tail(&insn->call_node, &file->return_thunk_list);
+}
+
 static bool same_function(struct instruction *insn1, struct instruction *insn2)
 {
        return insn1->func->pfunc == insn2->func->pfunc;
@@ -1302,6 +1367,9 @@ static int add_jump_destinations(struct objtool_file *file)
                } else if (reloc->sym->retpoline_thunk) {
                        add_retpoline_call(file, insn);
                        continue;
+               } else if (reloc->sym->return_thunk) {
+                       add_return_call(file, insn, true);
+                       continue;
                } else if (insn->func) {
                        /*
                         * External sibling call or internal sibling call with
@@ -1320,6 +1388,21 @@ static int add_jump_destinations(struct objtool_file *file)
 
                jump_dest = find_insn(file, dest_sec, dest_off);
                if (!jump_dest) {
+                       struct symbol *sym = find_symbol_by_offset(dest_sec, dest_off);
+
+                       /*
+                        * This is a special case for zen_untrain_ret().
+                        * It jumps to __x86_return_thunk(), but objtool
+                        * can't find the thunk's starting RET
+                        * instruction, because the RET is also in the
+                        * middle of another instruction.  Objtool only
+                        * knows about the outer instruction.
+                        */
+                       if (sym && sym->return_thunk) {
+                               add_return_call(file, insn, false);
+                               continue;
+                       }
+
                        WARN_FUNC("can't find jump dest instruction at %s+0x%lx",
                                  insn->sec, insn->offset, dest_sec->name,
                                  dest_off);
@@ -1949,16 +2032,35 @@ static int read_unwind_hints(struct objtool_file *file)
 
                insn->hint = true;
 
-               if (opts.ibt && hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
+               if (hint->type == UNWIND_HINT_TYPE_SAVE) {
+                       insn->hint = false;
+                       insn->save = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_RESTORE) {
+                       insn->restore = true;
+                       continue;
+               }
+
+               if (hint->type == UNWIND_HINT_TYPE_REGS_PARTIAL) {
                        struct symbol *sym = find_symbol_by_offset(insn->sec, insn->offset);
 
-                       if (sym && sym->bind == STB_GLOBAL &&
-                           insn->type != INSN_ENDBR && !insn->noendbr) {
-                               WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
-                                         insn->sec, insn->offset);
+                       if (sym && sym->bind == STB_GLOBAL) {
+                               if (opts.ibt && insn->type != INSN_ENDBR && !insn->noendbr) {
+                                       WARN_FUNC("UNWIND_HINT_IRET_REGS without ENDBR",
+                                                 insn->sec, insn->offset);
+                               }
+
+                               insn->entry = 1;
                        }
                }
 
+               if (hint->type == UNWIND_HINT_TYPE_ENTRY) {
+                       hint->type = UNWIND_HINT_TYPE_CALL;
+                       insn->entry = 1;
+               }
+
                if (hint->type == UNWIND_HINT_TYPE_FUNC) {
                        insn->cfi = &func_cfi;
                        continue;
@@ -2032,8 +2134,10 @@ static int read_retpoline_hints(struct objtool_file *file)
                }
 
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC) {
-                       WARN_FUNC("retpoline_safe hint not an indirect jump/call",
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN &&
+                   insn->type != INSN_NOP) {
+                       WARN_FUNC("retpoline_safe hint not an indirect jump/call/ret/nop",
                                  insn->sec, insn->offset);
                        return -1;
                }
@@ -2184,6 +2288,9 @@ static int classify_symbols(struct objtool_file *file)
                        if (arch_is_retpoline(func))
                                func->retpoline_thunk = true;
 
+                       if (arch_is_rethunk(func))
+                               func->return_thunk = true;
+
                        if (!strcmp(func->name, "__fentry__"))
                                func->fentry = true;
 
@@ -3218,8 +3325,8 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        return 1;
                }
 
-               visited = 1 << state.uaccess;
-               if (insn->visited) {
+               visited = VISITED_BRANCH << state.uaccess;
+               if (insn->visited & VISITED_BRANCH_MASK) {
                        if (!insn->hint && !insn_cfi_match(insn, &state.cfi))
                                return 1;
 
@@ -3233,6 +3340,35 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
                        state.instr += insn->instr;
 
                if (insn->hint) {
+                       if (insn->restore) {
+                               struct instruction *save_insn, *i;
+
+                               i = insn;
+                               save_insn = NULL;
+
+                               sym_for_each_insn_continue_reverse(file, func, i) {
+                                       if (i->save) {
+                                               save_insn = i;
+                                               break;
+                                       }
+                               }
+
+                               if (!save_insn) {
+                                       WARN_FUNC("no corresponding CFI save for CFI restore",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               if (!save_insn->visited) {
+                                       WARN_FUNC("objtool isn't smart enough to handle this CFI save/restore combo",
+                                                 sec, insn->offset);
+                                       return 1;
+                               }
+
+                               insn->cfi = save_insn->cfi;
+                               nr_cfi_reused++;
+                       }
+
                        state.cfi = *insn->cfi;
                } else {
                        /* XXX track if we actually changed state.cfi */
@@ -3433,6 +3569,145 @@ static int validate_unwind_hints(struct objtool_file *file, struct section *sec)
        return warnings;
 }
 
+/*
+ * Validate rethunk entry constraint: must untrain RET before the first RET.
+ *
+ * Follow every branch (intra-function) and ensure ANNOTATE_UNRET_END comes
+ * before an actual RET instruction.
+ */
+static int validate_entry(struct objtool_file *file, struct instruction *insn)
+{
+       struct instruction *next, *dest;
+       int ret, warnings = 0;
+
+       for (;;) {
+               next = next_insn_to_validate(file, insn);
+
+               if (insn->visited & VISITED_ENTRY)
+                       return 0;
+
+               insn->visited |= VISITED_ENTRY;
+
+               if (!insn->ignore_alts && !list_empty(&insn->alts)) {
+                       struct alternative *alt;
+                       bool skip_orig = false;
+
+                       list_for_each_entry(alt, &insn->alts, list) {
+                               if (alt->skip_orig)
+                                       skip_orig = true;
+
+                               ret = validate_entry(file, alt->insn);
+                               if (ret) {
+                                       if (opts.backtrace)
+                                               BT_FUNC("(alt)", insn);
+                                       return ret;
+                               }
+                       }
+
+                       if (skip_orig)
+                               return 0;
+               }
+
+               switch (insn->type) {
+
+               case INSN_CALL_DYNAMIC:
+               case INSN_JUMP_DYNAMIC:
+               case INSN_JUMP_DYNAMIC_CONDITIONAL:
+                       WARN_FUNC("early indirect call", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_JUMP_UNCONDITIONAL:
+               case INSN_JUMP_CONDITIONAL:
+                       if (!is_sibling_call(insn)) {
+                               if (!insn->jump_dest) {
+                                       WARN_FUNC("unresolved jump target after linking?!?",
+                                                 insn->sec, insn->offset);
+                                       return -1;
+                               }
+                               ret = validate_entry(file, insn->jump_dest);
+                               if (ret) {
+                                       if (opts.backtrace) {
+                                               BT_FUNC("(branch%s)", insn,
+                                                       insn->type == INSN_JUMP_CONDITIONAL ? "-cond" : "");
+                                       }
+                                       return ret;
+                               }
+
+                               if (insn->type == INSN_JUMP_UNCONDITIONAL)
+                                       return 0;
+
+                               break;
+                       }
+
+                       /* fallthrough */
+               case INSN_CALL:
+                       dest = find_insn(file, insn->call_dest->sec,
+                                        insn->call_dest->offset);
+                       if (!dest) {
+                               WARN("Unresolved function after linking!?: %s",
+                                    insn->call_dest->name);
+                               return -1;
+                       }
+
+                       ret = validate_entry(file, dest);
+                       if (ret) {
+                               if (opts.backtrace)
+                                       BT_FUNC("(call)", insn);
+                               return ret;
+                       }
+                       /*
+                        * If a call returns without error, it must have seen UNTRAIN_RET.
+                        * Therefore any non-error return is a success.
+                        */
+                       return 0;
+
+               case INSN_RETURN:
+                       WARN_FUNC("RET before UNTRAIN", insn->sec, insn->offset);
+                       return 1;
+
+               case INSN_NOP:
+                       if (insn->retpoline_safe)
+                               return 0;
+                       break;
+
+               default:
+                       break;
+               }
+
+               if (!next) {
+                       WARN_FUNC("teh end!", insn->sec, insn->offset);
+                       return -1;
+               }
+               insn = next;
+       }
+
+       return warnings;
+}
+
+/*
+ * Validate that all branches starting at 'insn->entry' encounter UNRET_END
+ * before RET.
+ */
+static int validate_unret(struct objtool_file *file)
+{
+       struct instruction *insn;
+       int ret, warnings = 0;
+
+       for_each_insn(file, insn) {
+               if (!insn->entry)
+                       continue;
+
+               ret = validate_entry(file, insn);
+               if (ret < 0) {
+                       WARN_FUNC("Failed UNRET validation", insn->sec, insn->offset);
+                       return ret;
+               }
+               warnings += ret;
+       }
+
+       return warnings;
+}
+
 static int validate_retpoline(struct objtool_file *file)
 {
        struct instruction *insn;
@@ -3440,7 +3715,8 @@ static int validate_retpoline(struct objtool_file *file)
 
        for_each_insn(file, insn) {
                if (insn->type != INSN_JUMP_DYNAMIC &&
-                   insn->type != INSN_CALL_DYNAMIC)
+                   insn->type != INSN_CALL_DYNAMIC &&
+                   insn->type != INSN_RETURN)
                        continue;
 
                if (insn->retpoline_safe)
@@ -3455,9 +3731,17 @@ static int validate_retpoline(struct objtool_file *file)
                if (!strcmp(insn->sec->name, ".init.text") && !opts.module)
                        continue;
 
-               WARN_FUNC("indirect %s found in RETPOLINE build",
-                         insn->sec, insn->offset,
-                         insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               if (insn->type == INSN_RETURN) {
+                       if (opts.rethunk) {
+                               WARN_FUNC("'naked' return found in RETHUNK build",
+                                         insn->sec, insn->offset);
+                       } else
+                               continue;
+               } else {
+                       WARN_FUNC("indirect %s found in RETPOLINE build",
+                                 insn->sec, insn->offset,
+                                 insn->type == INSN_JUMP_DYNAMIC ? "jump" : "call");
+               }
 
                warnings++;
        }
@@ -3826,8 +4110,7 @@ static int validate_ibt(struct objtool_file *file)
                    !strcmp(sec->name, "__bug_table")                   ||
                    !strcmp(sec->name, "__ex_table")                    ||
                    !strcmp(sec->name, "__jump_table")                  ||
-                   !strcmp(sec->name, "__mcount_loc")                  ||
-                   !strcmp(sec->name, "__tracepoints"))
+                   !strcmp(sec->name, "__mcount_loc"))
                        continue;
 
                list_for_each_entry(reloc, &sec->reloc->reloc_list, list)
@@ -3946,6 +4229,17 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.unret) {
+               /*
+                * Must be after validate_branch() and friends, it plays
+                * further games with insn->visited.
+                */
+               ret = validate_unret(file);
+               if (ret < 0)
+                       return ret;
+               warnings += ret;
+       }
+
        if (opts.ibt) {
                ret = validate_ibt(file);
                if (ret < 0)
@@ -3974,6 +4268,13 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.rethunk) {
+               ret = create_return_sites_sections(file);
+               if (ret < 0)
+                       goto out;
+               warnings += ret;
+       }
+
        if (opts.mcount) {
                ret = create_mcount_loc_sections(file);
                if (ret < 0)
index 9b19cc3..beb2f3a 100644 (file)
@@ -89,6 +89,7 @@ const char *arch_ret_insn(int len);
 int arch_decode_hint_reg(u8 sp_reg, int *base);
 
 bool arch_is_retpoline(struct symbol *sym);
+bool arch_is_rethunk(struct symbol *sym);
 
 int arch_rewrite_retpolines(struct objtool_file *file);
 
index 280ea18..42a52f1 100644 (file)
@@ -19,6 +19,8 @@ struct opts {
        bool noinstr;
        bool orc;
        bool retpoline;
+       bool rethunk;
+       bool unret;
        bool sls;
        bool stackval;
        bool static_call;
index f10d737..036129c 100644 (file)
@@ -46,16 +46,19 @@ struct instruction {
        enum insn_type type;
        unsigned long immediate;
 
-       u8 dead_end     : 1,
-          ignore       : 1,
-          ignore_alts  : 1,
-          hint         : 1,
-          retpoline_safe : 1,
-          noendbr      : 1;
-               /* 2 bit hole */
+       u16 dead_end            : 1,
+          ignore               : 1,
+          ignore_alts          : 1,
+          hint                 : 1,
+          save                 : 1,
+          restore              : 1,
+          retpoline_safe       : 1,
+          noendbr              : 1,
+          entry                : 1;
+               /* 7 bit hole */
+
        s8 instr;
        u8 visited;
-       /* u8 hole */
 
        struct alt_group *alt_group;
        struct symbol *call_dest;
@@ -69,6 +72,11 @@ struct instruction {
        struct cfi_state *cfi;
 };
 
+#define VISITED_BRANCH         0x01
+#define VISITED_BRANCH_UACCESS 0x02
+#define VISITED_BRANCH_MASK    0x03
+#define VISITED_ENTRY          0x04
+
 static inline bool is_static_jump(struct instruction *insn)
 {
        return insn->type == INSN_JUMP_CONDITIONAL ||
index adebfbc..16f4067 100644 (file)
@@ -57,6 +57,7 @@ struct symbol {
        u8 uaccess_safe      : 1;
        u8 static_call_tramp : 1;
        u8 retpoline_thunk   : 1;
+       u8 return_thunk      : 1;
        u8 fentry            : 1;
        u8 profiling_func    : 1;
        struct list_head pv_target;
index a6e72d9..7f2d1b0 100644 (file)
@@ -24,6 +24,7 @@ struct objtool_file {
        struct list_head insn_list;
        DECLARE_HASHTABLE(insn_hash, 20);
        struct list_head retpoline_call_list;
+       struct list_head return_thunk_list;
        struct list_head static_call_list;
        struct list_head mcount_loc_list;
        struct list_head endbr_list;
index 512669c..a7ecc32 100644 (file)
@@ -102,6 +102,7 @@ struct objtool_file *objtool_open_read(const char *_objname)
        INIT_LIST_HEAD(&file.insn_list);
        hash_init(file.insn_hash);
        INIT_LIST_HEAD(&file.retpoline_call_list);
+       INIT_LIST_HEAD(&file.return_thunk_list);
        INIT_LIST_HEAD(&file.static_call_list);
        INIT_LIST_HEAD(&file.mcount_loc_list);
        INIT_LIST_HEAD(&file.endbr_list);
index d811cff..0a26c24 100644 (file)
@@ -140,12 +140,12 @@ int use_after_invalid(void *ctx)
 
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
 
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        return 0;
 }
@@ -338,7 +338,7 @@ int invalid_helper2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
 
        return 0;
 }
@@ -377,7 +377,7 @@ int invalid_write2(void *ctx)
        memcpy((void *)&ptr + 8, &x, sizeof(x));
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        bpf_ringbuf_submit_dynptr(&ptr, 0);
 
@@ -473,7 +473,7 @@ int invalid_read2(void *ctx)
        get_map_val_dynptr(&ptr);
 
        /* this should fail */
-       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0);
+       bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
 
        return 0;
 }
index d67be48..a3a6103 100644 (file)
@@ -43,10 +43,10 @@ int test_read_write(void *ctx)
        bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);
 
        /* Write data into the dynptr */
-       err = err ?: bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data));
+       err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
 
        /* Read the data that was written into the dynptr */
-       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0);
+       err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
 
        /* Ensure the data we read matches the data we wrote */
        for (i = 0; i < sizeof(read_data); i++) {
index 6ddc418..1a27a62 100644 (file)
        .result = ACCEPT,
        .flags = F_NEEDS_EFFICIENT_UNALIGNED_ACCESS,
 },
+{
+       "jeq32/jne32: bounds checking",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_6, 563),
+       BPF_MOV64_IMM(BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_2, 0),
+       BPF_ALU32_REG(BPF_OR, BPF_REG_2, BPF_REG_6),
+       BPF_JMP32_IMM(BPF_JNE, BPF_REG_2, 8, 5),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_2, 500, 2),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 1,
+},
index 6f951d1..497fe17 100644 (file)
        .result = ACCEPT,
        .retval = 3,
 },
+{
+       "jump & dead code elimination",
+       .insns = {
+       BPF_MOV64_IMM(BPF_REG_0, 1),
+       BPF_MOV64_IMM(BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_NEG, BPF_REG_3, 0),
+       BPF_ALU64_IMM(BPF_OR, BPF_REG_3, 32767),
+       BPF_JMP_IMM(BPF_JSGE, BPF_REG_3, 0, 1),
+       BPF_EXIT_INSN(),
+       BPF_JMP_IMM(BPF_JSLE, BPF_REG_3, 0x8000, 1),
+       BPF_EXIT_INSN(),
+       BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -32767),
+       BPF_MOV64_IMM(BPF_REG_0, 2),
+       BPF_JMP_IMM(BPF_JLE, BPF_REG_3, 0, 1),
+       BPF_MOV64_REG(BPF_REG_0, BPF_REG_4),
+       BPF_EXIT_INSN(),
+       },
+       .prog_type = BPF_PROG_TYPE_SCHED_CLS,
+       .result = ACCEPT,
+       .retval = 2,
+},
index a29f796..ffc35a2 100644 (file)
@@ -36,4 +36,5 @@ test_unix_oob
 gro
 ioam6_parser
 toeplitz
+tun
 cmsg_sender
index ddad703..db05b37 100644 (file)
@@ -11,7 +11,7 @@ TEST_PROGS += udpgso_bench.sh fib_rule_tests.sh msg_zerocopy.sh psock_snd.sh
 TEST_PROGS += udpgro_bench.sh udpgro.sh test_vxlan_under_vrf.sh reuseport_addr_any.sh
 TEST_PROGS += test_vxlan_fdb_changelink.sh so_txtime.sh ipv6_flowlabel.sh
 TEST_PROGS += tcp_fastopen_backup_key.sh fcnal-test.sh l2tp.sh traceroute.sh
-TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh
+TEST_PROGS += fin_ack_lat.sh fib_nexthop_multiprefix.sh fib_nexthops.sh fib_nexthop_nongw.sh
 TEST_PROGS += altnames.sh icmp.sh icmp_redirect.sh ip6_gre_headroom.sh
 TEST_PROGS += route_localnet.sh
 TEST_PROGS += reuseaddr_ports_exhausted.sh
diff --git a/tools/testing/selftests/net/fib_nexthop_nongw.sh b/tools/testing/selftests/net/fib_nexthop_nongw.sh
new file mode 100755 (executable)
index 0000000..b7b928b
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# ns: h1               | ns: h2
+#   192.168.0.1/24     |
+#            eth0      |
+#                      |       192.168.1.1/32
+#            veth0 <---|---> veth1
+# Validate source address selection for route without gateway
+
+PAUSE_ON_FAIL=no
+VERBOSE=0
+ret=0
+
+################################################################################
+# helpers
+
+log_test()
+{
+       local rc=$1
+       local expected=$2
+       local msg="$3"
+
+       if [ ${rc} -eq ${expected} ]; then
+               printf "TEST: %-60s  [ OK ]\n" "${msg}"
+               nsuccess=$((nsuccess+1))
+       else
+               ret=1
+               nfail=$((nfail+1))
+               printf "TEST: %-60s  [FAIL]\n" "${msg}"
+               if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
+                       echo
+                       echo "hit enter to continue, 'q' to quit"
+                       read a
+                       [ "$a" = "q" ] && exit 1
+               fi
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+}
+
+run_cmd()
+{
+       local cmd="$*"
+       local out
+       local rc
+
+       if [ "$VERBOSE" = "1" ]; then
+               echo "COMMAND: $cmd"
+       fi
+
+       out=$(eval $cmd 2>&1)
+       rc=$?
+       if [ "$VERBOSE" = "1" -a -n "$out" ]; then
+               echo "$out"
+       fi
+
+       [ "$VERBOSE" = "1" ] && echo
+
+       return $rc
+}
+
+################################################################################
+# config
+setup()
+{
+       ip netns add h1
+       ip -n h1 link set lo up
+       ip netns add h2
+       ip -n h2 link set lo up
+
+       # Add a fake eth0 to support an ip address
+       ip -n h1 link add name eth0 type dummy
+       ip -n h1 link set eth0 up
+       ip -n h1 address add 192.168.0.1/24 dev eth0
+
+       # Configure veths (same @mac, arp off)
+       ip -n h1 link add name veth0 type veth peer name veth1 netns h2
+       ip -n h1 link set veth0 up
+
+       ip -n h2 link set veth1 up
+
+       # Configure @IP in the peer netns
+       ip -n h2 address add 192.168.1.1/32 dev veth1
+       ip -n h2 route add default dev veth1
+
+       # Add a nexthop without @gw and use it in a route
+       ip -n h1 nexthop add id 1 dev veth0
+       ip -n h1 route add 192.168.1.1 nhid 1
+}
+
+cleanup()
+{
+       ip netns del h1 2>/dev/null
+       ip netns del h2 2>/dev/null
+}
+
+trap cleanup EXIT
+
+################################################################################
+# main
+
+while getopts :pv o
+do
+       case $o in
+               p) PAUSE_ON_FAIL=yes;;
+               v) VERBOSE=1;;
+       esac
+done
+
+cleanup
+setup
+
+run_cmd ip -netns h1 route get 192.168.1.1
+log_test $? 0 "nexthop: get route with nexthop without gw"
+run_cmd ip netns exec h1 ping -c1 192.168.1.1
+log_test $? 0 "nexthop: ping through nexthop without gw"
+
+exit $ret
index 8f48121..57b84e0 100644 (file)
@@ -37,6 +37,7 @@ TEST_PROGS = bridge_igmp.sh \
        ipip_hier_gre_key.sh \
        ipip_hier_gre_keys.sh \
        ipip_hier_gre.sh \
+       local_termination.sh \
        loopback.sh \
        mirror_gre_bound.sh \
        mirror_gre_bridge_1d.sh \
@@ -52,6 +53,7 @@ TEST_PROGS = bridge_igmp.sh \
        mirror_gre_vlan_bridge_1q.sh \
        mirror_gre_vlan.sh \
        mirror_vlan.sh \
+       no_forwarding.sh \
        pedit_dsfield.sh \
        pedit_ip.sh \
        pedit_l4port.sh \
index 37ae49d..3ffb9d6 100755 (executable)
@@ -1240,6 +1240,7 @@ learning_test()
        # FDB entry was installed.
        bridge link set dev $br_port1 flood off
 
+       ip link set $host1_if promisc on
        tc qdisc add dev $host1_if ingress
        tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1250,7 +1251,7 @@ learning_test()
        tc -j -s filter show dev $host1_if ingress \
                | jq -e ".[] | select(.options.handle == 101) \
                | select(.options.actions[0].stats.packets == 1)" &> /dev/null
-       check_fail $? "Packet reached second host when should not"
+       check_fail $? "Packet reached first host when should not"
 
        $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q
        sleep 1
@@ -1289,6 +1290,7 @@ learning_test()
 
        tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host1_if ingress
+       ip link set $host1_if promisc off
 
        bridge link set dev $br_port1 flood on
 
@@ -1306,6 +1308,7 @@ flood_test_do()
 
        # Add an ACL on `host2_if` which will tell us whether the packet
        # was flooded to it or not.
+       ip link set $host2_if promisc on
        tc qdisc add dev $host2_if ingress
        tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \
                flower dst_mac $mac action drop
@@ -1323,6 +1326,7 @@ flood_test_do()
 
        tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower
        tc qdisc del dev $host2_if ingress
+       ip link set $host2_if promisc off
 
        return $err
 }
index f905d53..48a99e1 100644 (file)
@@ -6,7 +6,7 @@ KSFT_KHDR_INSTALL := 1
 CFLAGS =  -Wall -Wl,--no-as-needed -O2 -g -I$(top_srcdir)/usr/include $(KHDR_INCLUDES)
 
 TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
-             simult_flows.sh mptcp_sockopt.sh
+             simult_flows.sh mptcp_sockopt.sh userspace_pm.sh
 
 TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
 
index 6a2f4b9..cb79f07 100644 (file)
@@ -39,7 +39,7 @@ static void syntax(char *argv[])
        fprintf(stderr, "\tdsf lip <local-ip> lport <local-port> rip <remote-ip> rport <remote-port> token <token>\n");
        fprintf(stderr, "\tdel <id> [<ip>]\n");
        fprintf(stderr, "\tget <id>\n");
-       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>]\n");
+       fprintf(stderr, "\tset [<ip>] [id <nr>] flags [no]backup|[no]fullmesh [port <nr>] [token <token>] [rip <ip>] [rport <port>]\n");
        fprintf(stderr, "\tflush\n");
        fprintf(stderr, "\tdump\n");
        fprintf(stderr, "\tlimits [<rcv addr max> <subflow max>]\n");
@@ -1279,7 +1279,10 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
        struct rtattr *rta, *nest;
        struct nlmsghdr *nh;
        u_int32_t flags = 0;
+       u_int32_t token = 0;
+       u_int16_t rport = 0;
        u_int16_t family;
+       void *rip = NULL;
        int nest_start;
        int use_id = 0;
        u_int8_t id;
@@ -1339,7 +1342,13 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                error(1, 0, " missing flags keyword");
 
        for (; arg < argc; arg++) {
-               if (!strcmp(argv[arg], "flags")) {
+               if (!strcmp(argv[arg], "token")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing token value");
+
+                       /* token */
+                       token = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "flags")) {
                        char *tok, *str;
 
                        /* flags */
@@ -1378,12 +1387,72 @@ int set_flags(int fd, int pm_family, int argc, char *argv[])
                        rta->rta_len = RTA_LENGTH(2);
                        memcpy(RTA_DATA(rta), &port, 2);
                        off += NLMSG_ALIGN(rta->rta_len);
+               } else if (!strcmp(argv[arg], "rport")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote port");
+
+                       rport = atoi(argv[arg]);
+               } else if (!strcmp(argv[arg], "rip")) {
+                       if (++arg >= argc)
+                               error(1, 0, " missing remote ip");
+
+                       rip = argv[arg];
                } else {
                        error(1, 0, "unknown keyword %s", argv[arg]);
                }
        }
        nest->rta_len = off - nest_start;
 
+       /* token */
+       if (token) {
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ATTR_TOKEN;
+               rta->rta_len = RTA_LENGTH(4);
+               memcpy(RTA_DATA(rta), &token, 4);
+               off += NLMSG_ALIGN(rta->rta_len);
+       }
+
+       /* remote addr/port */
+       if (rip) {
+               nest_start = off;
+               nest = (void *)(data + off);
+               nest->rta_type = NLA_F_NESTED | MPTCP_PM_ATTR_ADDR_REMOTE;
+               nest->rta_len = RTA_LENGTH(0);
+               off += NLMSG_ALIGN(nest->rta_len);
+
+               /* addr data */
+               rta = (void *)(data + off);
+               if (inet_pton(AF_INET, rip, RTA_DATA(rta))) {
+                       family = AF_INET;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR4;
+                       rta->rta_len = RTA_LENGTH(4);
+               } else if (inet_pton(AF_INET6, rip, RTA_DATA(rta))) {
+                       family = AF_INET6;
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_ADDR6;
+                       rta->rta_len = RTA_LENGTH(16);
+               } else {
+                       error(1, errno, "can't parse ip %s", (char *)rip);
+               }
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               /* family */
+               rta = (void *)(data + off);
+               rta->rta_type = MPTCP_PM_ADDR_ATTR_FAMILY;
+               rta->rta_len = RTA_LENGTH(2);
+               memcpy(RTA_DATA(rta), &family, 2);
+               off += NLMSG_ALIGN(rta->rta_len);
+
+               if (rport) {
+                       rta = (void *)(data + off);
+                       rta->rta_type = MPTCP_PM_ADDR_ATTR_PORT;
+                       rta->rta_len = RTA_LENGTH(2);
+                       memcpy(RTA_DATA(rta), &rport, 2);
+                       off += NLMSG_ALIGN(rta->rta_len);
+               }
+
+               nest->rta_len = off - nest_start;
+       }
+
        do_nl_req(fd, nh, off, 0);
        return 0;
 }
index 78d0bb6..abe3d4e 100755 (executable)
@@ -770,10 +770,42 @@ test_subflows()
        rm -f "$evts"
 }
 
+test_prio()
+{
+       local count
+
+       # Send MP_PRIO signal from client to server machine
+       ip netns exec "$ns2" ./pm_nl_ctl set 10.0.1.2 port "$client4_port" flags backup token "$client4_token" rip 10.0.1.1 rport "$server4_port"
+       sleep 0.5
+
+       # Check TX
+       stdbuf -o0 -e0 printf "MP_PRIO TX                                                 \t"
+       count=$(ip netns exec "$ns2" nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+
+       # Check RX
+       stdbuf -o0 -e0 printf "MP_PRIO RX                                                 \t"
+       count=$(ip netns exec "$ns1" nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
+       [ -z "$count" ] && count=0
+       if [ $count != 1 ]; then
+               stdbuf -o0 -e0 printf "[FAIL]\n"
+               exit 1
+       else
+               stdbuf -o0 -e0 printf "[OK]\n"
+       fi
+}
+
 make_connection
 make_connection "v6"
 test_announce
 test_remove
 test_subflows
+test_prio
 
 exit 0
index f8a19f5..ebbd0b2 100755 (executable)
@@ -34,7 +34,7 @@ cfg_veth() {
        ip -netns "${PEER_NS}" addr add dev veth1 192.168.1.1/24
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
 }
 
 run_one() {
index 820bc50..fad2d1a 100755 (executable)
@@ -34,7 +34,7 @@ run_one() {
        ip -netns "${PEER_NS}" addr add dev veth1 2001:db8::1/64 nodad
        ip -netns "${PEER_NS}" link set dev veth1 up
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx ${rx_args} -r &
        ip netns exec "${PEER_NS}" ./udpgso_bench_rx -t ${rx_args} -r &
 
index 807b74c..832c738 100755 (executable)
@@ -36,7 +36,7 @@ run_one() {
        ip netns exec "${PEER_NS}" ethtool -K veth1 rx-gro-list on
 
 
-       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp_dummy
+       ip -n "${PEER_NS}" link set veth1 xdp object ../bpf/xdp_dummy.o section xdp
        tc -n "${PEER_NS}" qdisc add dev veth1 clsact
        tc -n "${PEER_NS}" filter add dev veth1 ingress prio 4 protocol ipv6 bpf object-file ../bpf/nat6to4.o section schedcls/ingress6/nat_6  direct-action
        tc -n "${PEER_NS}" filter add dev veth1 egress prio 4 protocol ip bpf object-file ../bpf/nat6to4.o section schedcls/egress4/snat4 direct-action
index 6f05e06..1bcd82e 100755 (executable)
@@ -46,7 +46,7 @@ create_ns() {
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V4$ns/24
                ip -n $BASE$ns addr add dev veth$ns $BM_NET_V6$ns/64 nodad
        done
-       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+       ip -n $NS_DST link set veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 }
 
 create_vxlan_endpoint() {
index 19eac3e..430895d 100755 (executable)
@@ -289,14 +289,14 @@ if [ $CPUS -gt 1 ]; then
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 1 tx 2 2>/dev/null
        printf "%-60s" "bad setting: XDP with RX nr less than TX"
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null &&\
+               section xdp 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
 
        # the following tests will run with multiple channels active
        ip netns exec $NS_SRC ethtool -L veth$SRC rx 2
        ip netns exec $NS_DST ethtool -L veth$DST rx 2
        ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o \
-               section xdp_dummy 2>/dev/null
+               section xdp 2>/dev/null
        printf "%-60s" "bad setting: reducing RX nr below peer TX with XDP set"
        ip netns exec $NS_DST ethtool -L veth$DST rx 1 2>/dev/null &&\
                echo "fail - set operation successful ?!?" || echo " ok "
@@ -311,7 +311,7 @@ if [ $CPUS -gt 2 ]; then
        chk_channels "setting invalid channels nr" $DST 2 2
 fi
 
-ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp_dummy 2>/dev/null
+ip -n $NS_DST link set dev veth$DST xdp object ../bpf/xdp_dummy.o section xdp 2>/dev/null
 chk_gro_flag "with xdp attached - gro flag" $DST on
 chk_gro_flag "        - peer gro flag" $SRC off
 chk_tso_flag "        - tso flag" $SRC off
index 7d1b809..9700358 100644 (file)
@@ -19,8 +19,6 @@ endif
 MIRROR := https://download.wireguard.com/qemu-test/distfiles/
 
 KERNEL_BUILD_PATH := $(BUILD_PATH)/kernel$(if $(findstring yes,$(DEBUG_KERNEL)),-debug)
-rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
-WIREGUARD_SOURCES := $(call rwildcard,$(KERNEL_PATH)/drivers/net/wireguard/,*)
 
 default: qemu
 
@@ -109,20 +107,22 @@ CHOST := x86_64-linux-musl
 QEMU_ARCH := x86_64
 KERNEL_ARCH := x86_64
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu max -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),i686)
 CHOST := i686-linux-musl
 QEMU_ARCH := i386
 KERNEL_ARCH := x86
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/arch/x86/boot/bzImage
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(subst x86_64,i686,$(HOST_ARCH)),$(ARCH))
-QEMU_MACHINE := -cpu host -machine q35,accel=kvm
+QEMU_MACHINE := -cpu host -machine microvm,accel=kvm,pit=off,pic=off,rtc=off -no-acpi
 else
-QEMU_MACHINE := -cpu max -machine q35
+QEMU_MACHINE := -cpu coreduo -machine microvm -no-acpi
 endif
 else ifeq ($(ARCH),mips64)
 CHOST := mips64-linux-musl
@@ -208,10 +208,11 @@ QEMU_ARCH := m68k
 KERNEL_ARCH := m68k
 KERNEL_BZIMAGE := $(KERNEL_BUILD_PATH)/vmlinux
 KERNEL_CMDLINE := $(shell sed -n 's/CONFIG_CMDLINE=\(.*\)/\1/p' arch/m68k.config)
+QEMU_VPORT_RESULT := virtio-serial-device
 ifeq ($(HOST_ARCH),$(ARCH))
-QEMU_MACHINE := -cpu host,accel=kvm -machine q800 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -cpu host,accel=kvm -machine virt -append $(KERNEL_CMDLINE)
 else
-QEMU_MACHINE := -machine q800 -smp 1 -append $(KERNEL_CMDLINE)
+QEMU_MACHINE := -machine virt -smp 1 -append $(KERNEL_CMDLINE)
 endif
 else ifeq ($(ARCH),riscv64)
 CHOST := riscv64-linux-musl
@@ -322,8 +323,9 @@ $(KERNEL_BUILD_PATH)/.config: $(TOOLCHAIN_PATH)/.installed kernel.config arch/$(
        cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config $(KERNEL_BUILD_PATH)/minimal.config
        $(if $(findstring yes,$(DEBUG_KERNEL)),cp debug.config $(KERNEL_BUILD_PATH) && cd $(KERNEL_BUILD_PATH) && ARCH=$(KERNEL_ARCH) $(KERNEL_PATH)/scripts/kconfig/merge_config.sh -n $(KERNEL_BUILD_PATH)/.config debug.config,)
 
-$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init ../netns.sh $(WIREGUARD_SOURCES)
+$(KERNEL_BZIMAGE): $(TOOLCHAIN_PATH)/.installed $(KERNEL_BUILD_PATH)/.config $(BUILD_PATH)/init-cpio-spec.txt $(IPERF_PATH)/src/iperf3 $(IPUTILS_PATH)/ping $(BASH_PATH)/bash $(IPROUTE2_PATH)/misc/ss $(IPROUTE2_PATH)/ip/ip $(IPTABLES_PATH)/iptables/xtables-legacy-multi $(NMAP_PATH)/ncat/ncat $(WIREGUARD_TOOLS_PATH)/src/wg $(BUILD_PATH)/init
        $(MAKE) -C $(KERNEL_PATH) O=$(KERNEL_BUILD_PATH) ARCH=$(KERNEL_ARCH) CROSS_COMPILE=$(CROSS_COMPILE)
+.PHONY: $(KERNEL_BZIMAGE)
 
 $(TOOLCHAIN_PATH)/$(CHOST)/include/linux/.installed: | $(KERNEL_BUILD_PATH)/.config $(TOOLCHAIN_PATH)/.installed
        rm -rf $(TOOLCHAIN_PATH)/$(CHOST)/include/linux
index fc7959b..0579c66 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index f3066be..2a3307b 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
 CONFIG_VIRTIO_MENU=y
 CONFIG_VIRTIO_MMIO=y
 CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyAMA0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_CPU_BIG_ENDIAN=y
index 6d90892..35b0650 100644 (file)
@@ -1,6 +1,10 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1024
index 82c925e..39c48cb 100644 (file)
@@ -1,9 +1,7 @@
 CONFIG_MMU=y
+CONFIG_VIRT=y
 CONFIG_M68KCLASSIC=y
-CONFIG_M68040=y
-CONFIG_MAC=y
-CONFIG_SERIAL_PMACZILOG=y
-CONFIG_SERIAL_PMACZILOG_TTYS=y
-CONFIG_SERIAL_PMACZILOG_CONSOLE=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
+CONFIG_CMDLINE="console=ttyGF0 wg.success=vport0p1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index d7ec63c..2a84402 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 18a4982..56146a1 100644 (file)
@@ -7,6 +7,7 @@ CONFIG_POWER_RESET=y
 CONFIG_POWER_RESET_SYSCON=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
 CONFIG_FRAME_WARN=1024
index 5e04882..174a9ff 100644 (file)
@@ -4,6 +4,7 @@ CONFIG_PPC_85xx=y
 CONFIG_PHYS_64BIT=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_COMPAT_32BIT_TIME=y
 CONFIG_MATH_EMULATION=y
 CONFIG_CMDLINE_BOOL=y
 CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
index efa0069..cf2d137 100644 (file)
@@ -1,6 +1,9 @@
-CONFIG_ACPI=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_VIRTIO_MENU=y
+CONFIG_VIRTIO_MMIO=y
+CONFIG_VIRTIO_CONSOLE=y
+CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y
 CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttyS0 wg.success=ttyS1 panic_on_warn=1"
+CONFIG_CMDLINE="console=ttyS0 wg.success=vport0p1 panic_on_warn=1 reboot=t"
 CONFIG_FRAME_WARN=1280
index c9e1284..3e49924 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdlib.h>
 #include <stdbool.h>
 #include <fcntl.h>
+#include <time.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
@@ -70,6 +71,15 @@ static void seed_rng(void)
        close(fd);
 }
 
+static void set_time(void)
+{
+       if (time(NULL))
+               return;
+       pretty_message("[+] Setting fake time...");
+       if (stime(&(time_t){1433512680}) < 0)
+               panic("settimeofday()");
+}
+
 static void mount_filesystems(void)
 {
        pretty_message("[+] Mounting filesystems...");
@@ -259,6 +269,7 @@ int main(int argc, char *argv[])
        print_banner();
        mount_filesystems();
        seed_rng();
+       set_time();
        kmod_selftests();
        enable_logging();
        clear_leaks();