Merge branches 'acpi-apei', 'acpi-pad' and 'acpi-misc'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 26 Jun 2023 15:24:19 +0000 (17:24 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 26 Jun 2023 15:24:19 +0000 (17:24 +0200)
Merge ACPI APEI changes, an ACPI PAD driver update and an ACPI FFH
handling cleanup related to ARM64 for 6.5-rc1:

 - Make ghes_get_devices() return NULL to indicate that there are no
   GHES devices so as to allow vendor-specific EDAC drivers to probe
   then (Li Yang).

 - Mark bert_disable() as __initdata and drop an unused function from
   the APEI GHES code (Miaohe Lin).

 - Make the ACPI PAD (Processor Aggregator Device) driver realize that
   Zhaoxin CPUs support nonstop TSC (Tony W Wang-oc).

 - Drop the certainly unnecessary and likely incorrect inclusion of
   linux/arm-smccc.h from acpi_ffh.c (Sudeep Holla).

* acpi-apei:
  APEI: GHES: correctly return NULL for ghes_get_devices()
  ACPI: APEI: mark bert_disable as __initdata
  ACPI: APEI: GHES: Remove unused ghes_estatus_pool_size_request()

* acpi-pad:
  ACPI: PAD: mark Zhaoxin CPUs NONSTOP TSC correctly

* acpi-misc:
  ACPI: FFH: Drop the inclusion of linux/arm-smccc.h

597 files changed:
.mailmap
Documentation/admin-guide/cgroup-v2.rst
Documentation/devicetree/bindings/ata/ahci-common.yaml
Documentation/devicetree/bindings/cache/qcom,llcc.yaml
Documentation/devicetree/bindings/clock/canaan,k210-clk.yaml
Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
Documentation/devicetree/bindings/mfd/canaan,k210-sysctl.yaml
Documentation/devicetree/bindings/net/realtek-bluetooth.yaml
Documentation/devicetree/bindings/pinctrl/canaan,k210-fpioa.yaml
Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.yaml
Documentation/devicetree/bindings/power/qcom,rpmpd.yaml
Documentation/devicetree/bindings/reset/canaan,k210-rst.yaml
Documentation/devicetree/bindings/riscv/canaan.yaml
Documentation/devicetree/usage-model.rst
Documentation/netlink/specs/ethtool.yaml
Documentation/networking/ip-sysctl.rst
Documentation/riscv/patch-acceptance.rst
Documentation/trace/user_events.rst
Documentation/translations/zh_CN/devicetree/usage-model.rst
MAINTAINERS
Makefile
arch/arm/boot/dts/am57xx-cl-som-am57x.dts
arch/arm/boot/dts/at91-sama7g5ek.dts
arch/arm/boot/dts/at91sam9261ek.dts
arch/arm/boot/dts/imx7d-pico-hobbit.dts
arch/arm/boot/dts/imx7d-sdb.dts
arch/arm/boot/dts/omap3-cm-t3x.dtsi
arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
arch/arm/boot/dts/omap3-lilly-a83x.dtsi
arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
arch/arm/boot/dts/omap3-pandora-common.dtsi
arch/arm/boot/dts/omap5-cm-t54.dts
arch/arm/boot/dts/qcom-apq8026-asus-sparrow.dts
arch/arm/boot/dts/qcom-apq8026-huawei-sturgeon.dts
arch/arm/boot/dts/qcom-apq8026-lg-lenok.dts
arch/arm/boot/dts/qcom-apq8064.dtsi
arch/arm/boot/dts/qcom-apq8084.dtsi
arch/arm/boot/dts/qcom-ipq4019.dtsi
arch/arm/boot/dts/qcom-ipq8064.dtsi
arch/arm/boot/dts/qcom-mdm9615-wp8548-mangoh-green.dts
arch/arm/boot/dts/qcom-msm8660.dtsi
arch/arm/boot/dts/qcom-msm8960.dtsi
arch/arm/boot/dts/qcom-msm8974-lge-nexus5-hammerhead.dts
arch/arm/boot/dts/qcom-msm8974-sony-xperia-rhine.dtsi
arch/arm/boot/dts/qcom-msm8974.dtsi
arch/arm/boot/dts/qcom-msm8974pro-oneplus-bacon.dts
arch/arm/boot/dts/qcom-msm8974pro-samsung-klte.dts
arch/arm/boot/dts/qcom-msm8974pro-sony-xperia-shinano-castor.dts
arch/arm/mach-at91/pm.c
arch/arm64/Kconfig
arch/arm64/boot/dts/freescale/imx8-ss-dma.dtsi
arch/arm64/boot/dts/freescale/imx8mn-beacon-baseboard.dtsi
arch/arm64/boot/dts/freescale/imx8qm-mek.dts
arch/arm64/boot/dts/qcom/ipq5332.dtsi
arch/arm64/boot/dts/qcom/ipq6018.dtsi
arch/arm64/boot/dts/qcom/ipq8074.dtsi
arch/arm64/boot/dts/qcom/ipq9574.dtsi
arch/arm64/boot/dts/qcom/msm8916.dtsi
arch/arm64/boot/dts/qcom/msm8953.dtsi
arch/arm64/boot/dts/qcom/msm8976.dtsi
arch/arm64/boot/dts/qcom/msm8994.dtsi
arch/arm64/boot/dts/qcom/msm8996.dtsi
arch/arm64/boot/dts/qcom/msm8998.dtsi
arch/arm64/boot/dts/qcom/qcm2290.dtsi
arch/arm64/boot/dts/qcom/qcs404.dtsi
arch/arm64/boot/dts/qcom/qdu1000.dtsi
arch/arm64/boot/dts/qcom/sa8155p-adp.dts
arch/arm64/boot/dts/qcom/sa8155p.dtsi [new file with mode: 0644]
arch/arm64/boot/dts/qcom/sa8775p.dtsi
arch/arm64/boot/dts/qcom/sc7180-lite.dtsi
arch/arm64/boot/dts/qcom/sc7180.dtsi
arch/arm64/boot/dts/qcom/sc7280-idp.dtsi
arch/arm64/boot/dts/qcom/sc7280-qcard.dtsi
arch/arm64/boot/dts/qcom/sc7280.dtsi
arch/arm64/boot/dts/qcom/sc8280xp.dtsi
arch/arm64/boot/dts/qcom/sdm630.dtsi
arch/arm64/boot/dts/qcom/sdm670.dtsi
arch/arm64/boot/dts/qcom/sdm845.dtsi
arch/arm64/boot/dts/qcom/sm6115.dtsi
arch/arm64/boot/dts/qcom/sm6125.dtsi
arch/arm64/boot/dts/qcom/sm6350.dtsi
arch/arm64/boot/dts/qcom/sm6375-sony-xperia-murray-pdx225.dts
arch/arm64/boot/dts/qcom/sm6375.dtsi
arch/arm64/boot/dts/qcom/sm8150.dtsi
arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-boe.dts
arch/arm64/boot/dts/qcom/sm8250-xiaomi-elish-csot.dts
arch/arm64/boot/dts/qcom/sm8350.dtsi
arch/arm64/boot/dts/qcom/sm8450.dtsi
arch/arm64/boot/dts/qcom/sm8550.dtsi
arch/arm64/hyperv/mshyperv.c
arch/arm64/mm/fault.c
arch/loongarch/include/asm/loongarch.h
arch/loongarch/include/asm/pgtable-bits.h
arch/loongarch/include/asm/pgtable.h
arch/loongarch/kernel/hw_breakpoint.c
arch/loongarch/kernel/perf_event.c
arch/loongarch/kernel/unaligned.c
arch/nios2/boot/dts/10m50_devboard.dts
arch/nios2/boot/dts/3c120_devboard.dts
arch/parisc/include/asm/assembly.h
arch/powerpc/purgatory/Makefile
arch/riscv/Kconfig
arch/riscv/include/asm/kfence.h
arch/riscv/include/asm/pgtable.h
arch/riscv/mm/init.c
arch/riscv/purgatory/Makefile
arch/s390/purgatory/Makefile
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_vtl.c
arch/x86/kernel/head_64.S
arch/x86/purgatory/Makefile
block/blk-cgroup.c
block/blk-mq.c
crypto/asymmetric_keys/public_key.c
drivers/accel/ivpu/Kconfig
drivers/accel/ivpu/ivpu_hw_mtl.c
drivers/accel/ivpu/ivpu_hw_mtl_reg.h
drivers/accel/ivpu/ivpu_ipc.c
drivers/accel/ivpu/ivpu_job.c
drivers/accel/ivpu/ivpu_mmu.c
drivers/accel/qaic/qaic_drv.c
drivers/acpi/acpi_ffh.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_pad.c
drivers/acpi/acpica/achware.h
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/ec.c
drivers/acpi/nfit/nfit.h
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/sleep.c
drivers/acpi/thermal.c
drivers/acpi/tiny-power-button.c
drivers/acpi/video_detect.c
drivers/acpi/x86/s2idle.c
drivers/acpi/x86/utils.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/base/regmap/regcache.c
drivers/block/null_blk/main.c
drivers/block/rbd.c
drivers/bluetooth/hci_qca.c
drivers/clk/clk-composite.c
drivers/clk/clk-loongson2.c
drivers/clk/mediatek/clk-mt8365.c
drivers/clk/pxa/clk-pxa3xx.c
drivers/edac/qcom_edac.c
drivers/firmware/arm_ffa/driver.c
drivers/firmware/cirrus/cs_dsp.c
drivers/gpio/gpio-sim.c
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.h
drivers/gpu/drm/amd/amdgpu/amdgpu_vm_pt.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c
drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vcn_v4_0.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/link/link_detection.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/ast/ast_dp.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/ast/ast_main.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_post.c
drivers/gpu/drm/bridge/ti-sn65dsi86.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/exynos/exynos_drm_g2d.c
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/i915/display/intel_cdclk.c
drivers/gpu/drm/i915/display/intel_dp_aux.c
drivers/gpu/drm/i915/gem/selftests/i915_gem_context.c
drivers/gpu/drm/i915/gt/selftest_execlists.c
drivers/gpu/drm/lima/lima_sched.c
drivers/gpu/drm/msm/adreno/a6xx_gmu.c
drivers/gpu/drm/msm/adreno/a6xx_gpu.c
drivers/gpu/drm/msm/dp/dp_catalog.c
drivers/gpu/drm/msm/dp/dp_catalog.h
drivers/gpu/drm/msm/dp/dp_display.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/radeon/radeon_fbdev.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/hid/hid-logitech-hidpp.c
drivers/hv/channel_mgmt.c
drivers/hv/hv_common.c
drivers/hv/vmbus_drv.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-slave.c
drivers/i2c/busses/i2c-img-scb.c
drivers/i2c/busses/i2c-mchp-pci1xxxx.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-sprd.c
drivers/infiniband/core/cma.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_main.c
drivers/infiniband/hw/bnxt_re/bnxt_re.h
drivers/infiniband/hw/bnxt_re/ib_verbs.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/mlx5/counters.c
drivers/infiniband/hw/mlx5/fs.c
drivers/infiniband/hw/mlx5/fs.h
drivers/infiniband/hw/mlx5/main.c
drivers/infiniband/hw/mlx5/mlx5_ib.h
drivers/infiniband/hw/mlx5/qp.c
drivers/infiniband/sw/rxe/rxe_cq.c
drivers/infiniband/sw/rxe/rxe_net.c
drivers/infiniband/sw/rxe/rxe_qp.c
drivers/infiniband/sw/rxe/rxe_resp.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/rtrs/rtrs-clt.c
drivers/infiniband/ulp/rtrs/rtrs.c
drivers/input/input.c
drivers/input/joystick/xpad.c
drivers/input/misc/soc_button_array.c
drivers/input/mouse/elantech.c
drivers/input/touchscreen/cyttsp5.c
drivers/md/dm-ioctl.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/media/dvb-core/dvb_frontend.c
drivers/misc/eeprom/Kconfig
drivers/net/dsa/lan9303-core.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/qca/Kconfig
drivers/net/ethernet/amd/pds_core/dev.c
drivers/net/ethernet/broadcom/bcmsysport.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnxt/bnxt.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c
drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/broadcom/genet/bcmgenet.h
drivers/net/ethernet/broadcom/genet/bcmmii.c
drivers/net/ethernet/freescale/enetc/enetc.c
drivers/net/ethernet/freescale/enetc/enetc_qos.c
drivers/net/ethernet/intel/iavf/iavf.h
drivers/net/ethernet/intel/iavf/iavf_main.c
drivers/net/ethernet/intel/iavf/iavf_register.h
drivers/net/ethernet/intel/ice/ice_common.c
drivers/net/ethernet/intel/ice/ice_common.h
drivers/net/ethernet/intel/ice/ice_gnss.c
drivers/net/ethernet/intel/ice/ice_gnss.h
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igc/igc_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/marvell/octeon_ep/octep_main.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc_hash.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/qlogic/qed/qed_l2.c
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/renesas/rswitch.c
drivers/net/ethernet/sfc/efx_channels.c
drivers/net/ethernet/sfc/siena/efx_channels.c
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ipvlan/ipvlan_l3s.c
drivers/net/macsec.c
drivers/net/phy/phylink.c
drivers/net/usb/qmi_wwan.c
drivers/net/virtio_net.c
drivers/net/wan/lapbether.c
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/mediatek/mt76/mt7615/mac.c
drivers/net/wireless/mediatek/mt76/mt7996/mac.c
drivers/net/wireless/realtek/rtw88/mac80211.c
drivers/net/wireless/realtek/rtw88/main.c
drivers/net/wireless/realtek/rtw88/ps.c
drivers/net/wireless/realtek/rtw88/ps.h
drivers/net/wireless/realtek/rtw89/core.c
drivers/net/wireless/realtek/rtw89/mac80211.c
drivers/net/wireless/realtek/rtw89/ps.c
drivers/net/wireless/realtek/rtw89/ps.h
drivers/of/overlay.c
drivers/pci/controller/pci-hyperv.c
drivers/pinctrl/meson/pinctrl-meson-axg.c
drivers/platform/surface/aggregator/controller.c
drivers/platform/surface/surface_aggregator_tabletsw.c
drivers/platform/x86/intel/int3472/clk_and_regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/s390/block/dasd_ioctl.c
drivers/s390/cio/device.c
drivers/s390/net/ism_drv.c
drivers/scsi/aacraid/aacraid.h
drivers/scsi/aacraid/commsup.c
drivers/scsi/aacraid/linit.c
drivers/scsi/aacraid/src.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/storvsc_drv.c
drivers/soc/qcom/Makefile
drivers/soc/qcom/icc-bwmon.c
drivers/soc/qcom/ramp_controller.c
drivers/soc/qcom/rmtfs_mem.c
drivers/soc/qcom/rpmh-rsc.c
drivers/soc/qcom/rpmhpd.c
drivers/soundwire/dmi-quirks.c
drivers/soundwire/qcom.c
drivers/soundwire/stream.c
drivers/spi/spi-cadence-quadspi.c
drivers/spi/spi-dw-mmio.c
drivers/spi/spi-fsl-dspi.c
drivers/spi/spi-fsl-lpspi.c
drivers/spi/spi-mt65xx.c
drivers/spi/spi-qup.c
drivers/staging/octeon/TODO
drivers/target/target_core_transport.c
drivers/tee/amdtee/amdtee_if.h
drivers/tee/amdtee/call.c
drivers/thermal/intel/intel_soc_dts_iosf.c
drivers/thunderbolt/dma_test.c
drivers/thunderbolt/nhi.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tunnel.c
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/lantiq.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/serial/option.c
drivers/usb/typec/pd.c
drivers/usb/typec/ucsi/ucsi.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/vdpa_user/vduse_dev.c
drivers/vhost/net.c
drivers/vhost/vdpa.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
fs/afs/dir.c
fs/afs/vl_probe.c
fs/afs/write.c
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/snap.c
fs/eventpoll.c
fs/ext4/balloc.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/gfs2/file.c
fs/nilfs2/btnode.c
fs/nilfs2/sufile.c
fs/nilfs2/the_nilfs.c
fs/ocfs2/file.c
fs/ocfs2/super.c
fs/smb/client/cifs_debug.c
fs/smb/client/cifsglob.h
fs/smb/client/cifsproto.h
fs/smb/client/connect.c
fs/smb/client/dfs.c
fs/smb/client/file.c
fs/smb/client/smb2ops.c
fs/smb/client/smb2pdu.c
fs/smb/client/transport.c
fs/smb/server/connection.c
fs/smb/server/oplock.c
fs/smb/server/server.c
fs/smb/server/smb2misc.c
fs/smb/server/smb2pdu.c
fs/smb/server/smb_common.c
fs/smb/server/smbacl.c
fs/smb/server/vfs.c
fs/smb/server/vfs.h
fs/smb/server/vfs_cache.c
fs/userfaultfd.c
fs/xfs/libxfs/xfs_ag.c
fs/xfs/libxfs/xfs_alloc.c
fs/xfs/libxfs/xfs_alloc.h
fs/xfs/libxfs/xfs_bmap.c
fs/xfs/libxfs/xfs_bmap_btree.c
fs/xfs/libxfs/xfs_ialloc.c
fs/xfs/libxfs/xfs_log_format.h
fs/xfs/libxfs/xfs_refcount.c
fs/xfs/libxfs/xfs_trans_inode.c
fs/xfs/scrub/bmap.c
fs/xfs/scrub/scrub.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_reflink.c
fs/xfs/xfs_super.c
fs/xfs/xfs_trans.c
include/acpi/acpi_bus.h
include/acpi/acpixf.h
include/dt-bindings/power/qcom-rpmpd.h
include/linux/cpuhotplug.h
include/linux/libata.h
include/linux/mlx5/driver.h
include/linux/netdevice.h
include/linux/notifier.h
include/linux/soc/qcom/llcc-qcom.h
include/linux/surface_aggregator/device.h
include/media/dvb_frontend.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/neighbour.h
include/net/netfilter/nf_flow_table.h
include/net/netfilter/nf_tables.h
include/net/netns/ipv6.h
include/net/ping.h
include/net/pkt_sched.h
include/net/rpl.h
include/net/sch_generic.h
include/net/sock.h
include/rdma/ib_addr.h
include/uapi/linux/bpf.h
include/uapi/linux/ethtool_netlink.h
io_uring/io-wq.c
io_uring/net.c
kernel/bpf/map_in_map.c
kernel/bpf/syscall.c
kernel/cgroup/cgroup-v1.c
kernel/cgroup/cgroup.c
kernel/fork.c
kernel/kexec_file.c
kernel/trace/bpf_trace.c
kernel/trace/trace_events_user.c
kernel/trace/trace_output.c
kernel/vhost_task.c
lib/cpu_rmap.c
lib/radix-tree.c
lib/radix-tree.h [new file with mode: 0644]
lib/test_vmalloc.c
lib/xarray.c
mm/damon/core.c
mm/filemap.c
mm/gup_test.c
mm/mmap.c
mm/zswap.c
net/batman-adv/distributed-arp-table.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sync.c
net/bluetooth/l2cap_core.c
net/can/j1939/main.c
net/can/j1939/socket.c
net/core/dev.c
net/core/skmsg.c
net/dccp/proto.c
net/handshake/handshake.h
net/handshake/request.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_offload.c
net/ipv4/udplite.c
net/ipv6/exthdrs.c
net/ipv6/ping.c
net/ipv6/route.c
net/ipv6/udplite.c
net/mac80211/cfg.c
net/mac80211/he.c
net/mac80211/ieee80211_i.h
net/mac80211/link.c
net/mac80211/mlme.c
net/mac80211/rx.c
net/mac80211/tx.c
net/mac80211/util.c
net/mptcp/pm.c
net/mptcp/pm_netlink.c
net/mptcp/pm_userspace.c
net/mptcp/protocol.h
net/netfilter/ipset/ip_set_core.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_flow_table_core.c
net/netfilter/nf_flow_table_ip.c
net/netfilter/nf_tables_api.c
net/netfilter/nfnetlink.c
net/netfilter/nft_bitwise.c
net/netfilter/nft_set_pipapo.c
net/netlabel/netlabel_kapi.c
net/openvswitch/datapath.c
net/openvswitch/vport.c
net/sched/act_ct.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/cls_api.c
net/sched/cls_u32.c
net/sched/sch_api.c
net/sched/sch_fq_pie.c
net/sched/sch_generic.c
net/sched/sch_mq.c
net/sched/sch_mqprio.c
net/sched/sch_pie.c
net/sched/sch_red.c
net/sched/sch_sfq.c
net/sched/sch_taprio.c
net/sched/sch_teql.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/smc/smc_llc.c
net/tipc/bearer.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/util.c
sound/core/seq/oss/seq_oss_midi.c
sound/isa/gus/gus_pcm.c
sound/pci/cmipci.c
sound/pci/hda/hda_codec.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/ice1712.c
sound/pci/ice1712/ice1724.c
sound/pci/ymfpci/ymfpci_main.c
sound/soc/amd/ps/pci-ps.c
sound/soc/amd/ps/ps-pdm-dma.c
sound/soc/amd/yc/acp6x-mach.c
sound/soc/codecs/cs35l56.c
sound/soc/codecs/max98363.c
sound/soc/codecs/nau8824.c
sound/soc/codecs/wcd938x-sdw.c
sound/soc/codecs/wsa881x.c
sound/soc/codecs/wsa883x.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/generic/simple-card-utils.c
sound/soc/generic/simple-card.c
sound/soc/mediatek/mt8188/mt8188-afe-clk.c
sound/soc/mediatek/mt8188/mt8188-afe-clk.h
sound/soc/mediatek/mt8188/mt8188-afe-pcm.c
sound/soc/mediatek/mt8188/mt8188-audsys-clk.c
sound/soc/mediatek/mt8188/mt8188-audsys-clk.h
sound/soc/mediatek/mt8195/mt8195-afe-clk.c
sound/soc/mediatek/mt8195/mt8195-afe-clk.h
sound/soc/mediatek/mt8195/mt8195-afe-pcm.c
sound/soc/mediatek/mt8195/mt8195-audsys-clk.c
sound/soc/mediatek/mt8195/mt8195-audsys-clk.h
sound/soc/tegra/tegra_pcm.c
sound/usb/pcm.c
sound/usb/quirks.c
tools/include/uapi/linux/bpf.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf_probes.c
tools/testing/radix-tree/Makefile
tools/testing/selftests/alsa/pcm-test.c
tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/sockopt_sk.c
tools/testing/selftests/bpf/progs/inner_array_lookup.c [new file with mode: 0644]
tools/testing/selftests/net/.gitignore
tools/testing/selftests/net/forwarding/hw_stats_l3.sh
tools/testing/selftests/net/mptcp/config
tools/testing/selftests/net/mptcp/diag.sh
tools/testing/selftests/net/mptcp/mptcp_connect.sh
tools/testing/selftests/net/mptcp/mptcp_join.sh
tools/testing/selftests/net/mptcp/mptcp_lib.sh
tools/testing/selftests/net/mptcp/mptcp_sockopt.c
tools/testing/selftests/net/mptcp/mptcp_sockopt.sh
tools/testing/selftests/net/mptcp/pm_netlink.sh
tools/testing/selftests/net/mptcp/userspace_pm.sh
tools/testing/selftests/ptp/testptp.c
tools/testing/selftests/tc-testing/config
tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfb.json
tools/testing/selftests/tc-testing/tdc.sh
tools/testing/selftests/user_events/dyn_test.c
tools/testing/selftests/user_events/ftrace_test.c
tools/testing/selftests/user_events/perf_test.c
tools/virtio/ringtest/.gitignore [new file with mode: 0644]
tools/virtio/ringtest/main.h
tools/virtio/virtio-trace/README
tools/virtio/virtio-trace/trace-agent.c

index bf076bb..650689d 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -233,6 +233,7 @@ Jisheng Zhang <jszhang@kernel.org> <Jisheng.Zhang@synaptics.com>
 Johan Hovold <johan@kernel.org> <jhovold@gmail.com>
 Johan Hovold <johan@kernel.org> <johan@hovoldconsulting.com>
 John Crispin <john@phrozen.org> <blogic@openwrt.org>
+John Keeping <john@keeping.me.uk> <john@metanate.com>
 John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
 John Stultz <johnstul@us.ibm.com>
 <jon.toppins+linux@gmail.com> <jtoppins@cumulusnetworks.com>
index f67c082..e592a93 100644 (file)
@@ -1213,23 +1213,25 @@ PAGE_SIZE multiple when read back.
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
-       Memory usage throttle limit.  This is the main mechanism to
-       control memory usage of a cgroup.  If a cgroup's usage goes
+       Memory usage throttle limit.  If a cgroup's usage goes
        over the high boundary, the processes of the cgroup are
        throttled and put under heavy reclaim pressure.
 
        Going over the high limit never invokes the OOM killer and
-       under extreme conditions the limit may be breached.
+       under extreme conditions the limit may be breached. The high
+       limit should be used in scenarios where an external process
+       monitors the limited cgroup to alleviate heavy reclaim
+       pressure.
 
   memory.max
        A read-write single value file which exists on non-root
        cgroups.  The default is "max".
 
-       Memory usage hard limit.  This is the final protection
-       mechanism.  If a cgroup's memory usage reaches this limit and
-       can't be reduced, the OOM killer is invoked in the cgroup.
-       Under certain circumstances, the usage may go over the limit
-       temporarily.
+       Memory usage hard limit.  This is the main mechanism to limit
+       memory usage of a cgroup.  If a cgroup's memory usage reaches
+       this limit and can't be reduced, the OOM killer is invoked in
+       the cgroup. Under certain circumstances, the usage may go
+       over the limit temporarily.
 
        In default configuration regular 0-order allocations always
        succeed unless OOM killer chooses current task as a victim.
@@ -1238,10 +1240,6 @@ PAGE_SIZE multiple when read back.
        Caller could retry them differently, return into userspace
        as -ENOMEM or silently ignore in cases like disk readahead.
 
-       This is the ultimate protection mechanism.  As long as the
-       high limit is used and monitored properly, this limit's
-       utility is limited to providing the final safety net.
-
   memory.reclaim
        A write-only nested-keyed file which exists for all cgroups.
 
index 7fdf409..38770c4 100644 (file)
@@ -8,7 +8,7 @@ title: Common Properties for Serial ATA AHCI controllers
 
 maintainers:
   - Hans de Goede <hdegoede@redhat.com>
-  - Damien Le Moal <damien.lemoal@opensource.wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description:
   This document defines device tree properties for a common AHCI SATA
index d8b9194..44892aa 100644 (file)
@@ -129,6 +129,7 @@ allOf:
               - qcom,sm8250-llcc
               - qcom,sm8350-llcc
               - qcom,sm8450-llcc
+              - qcom,sm8550-llcc
     then:
       properties:
         reg:
index 998e5cc..380cb6d 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Canaan Kendryte K210 Clock
 
 maintainers:
-  - Damien Le Moal <damien.lemoal@wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description: |
   Canaan Kendryte K210 SoC clocks driver bindings. The clock
index 62f3ca6..32c821f 100644 (file)
@@ -44,7 +44,7 @@ required:
   - clock-names
   - clocks
 
-additionalProperties: true
+unevaluatedProperties: false
 
 examples:
   - |
index 8459d36..3b3beab 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Canaan Kendryte K210 System Controller
 
 maintainers:
-  - Damien Le Moal <damien.lemoal@wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description:
   Canaan Inc. Kendryte K210 SoC system controller which provides a
index 8cc2b99..043e118 100644 (file)
@@ -11,7 +11,7 @@ maintainers:
   - Alistair Francis <alistair@alistair23.me>
 
 description:
-  RTL8723CS/RTL8723CS/RTL8821CS/RTL8822CS is a WiFi + BT chip. WiFi part
+  RTL8723BS/RTL8723CS/RTL8821CS/RTL8822CS is a WiFi + BT chip. WiFi part
   is connected over SDIO, while BT is connected over serial. It speaks
   H5 protocol with few extra commands to upload firmware and change
   module speed.
@@ -27,7 +27,7 @@ properties:
       - items:
           - enum:
               - realtek,rtl8821cs-bt
-          - const: realtek,rtl8822cs-bt
+          - const: realtek,rtl8723bs-bt
 
   device-wake-gpios:
     maxItems: 1
index 7f4f36a..739a08f 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Canaan Kendryte K210 FPIOA
 
 maintainers:
-  - Damien Le Moal <damien.lemoal@wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description:
   The Canaan Kendryte K210 SoC Fully Programmable IO Array (FPIOA)
index c91d3e3..80f9606 100644 (file)
@@ -144,8 +144,9 @@ $defs:
         enum: [0, 1, 2, 3, 4, 5, 6, 7]
 
       qcom,paired:
-        - description:
-            Indicates that the pin should be operating in paired mode.
+        type: boolean
+        description:
+          Indicates that the pin should be operating in paired mode.
 
     required:
       - pins
index afad313..f9c211a 100644 (file)
@@ -29,6 +29,7 @@ properties:
       - qcom,qcm2290-rpmpd
       - qcom,qcs404-rpmpd
       - qcom,qdu1000-rpmhpd
+      - qcom,sa8155p-rpmhpd
       - qcom,sa8540p-rpmhpd
       - qcom,sa8775p-rpmhpd
       - qcom,sdm660-rpmpd
index ee8a2dc..0c01359 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Canaan Kendryte K210 Reset Controller
 
 maintainers:
-  - Damien Le Moal <damien.lemoal@wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description: |
   Canaan Kendryte K210 reset controller driver which supports the SoC
index f8f3f28..41fd11f 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Canaan SoC-based boards
 
 maintainers:
-  - Damien Le Moal <damien.lemoal@wdc.com>
+  - Damien Le Moal <dlemoal@kernel.org>
 
 description:
   Canaan Kendryte K210 SoC-based boards
index b6a2879..0717426 100644 (file)
@@ -415,6 +415,6 @@ When using the DT, this creates problems for of_platform_populate()
 because it must decide whether to register each node as either a
 platform_device or an amba_device.  This unfortunately complicates the
 device creation model a little bit, but the solution turns out not to
-be too invasive.  If a node is compatible with "arm,amba-primecell", then
+be too invasive.  If a node is compatible with "arm,primecell", then
 of_platform_populate() will register it as an amba_device instead of a
 platform_device.
index 3abc576..4846345 100644 (file)
@@ -223,7 +223,7 @@ attribute-sets:
         name: tx-min-frag-size
         type: u32
       -
-        name: tx-min-frag-size
+        name: rx-min-frag-size
         type: u32
       -
         name: verify-enabled
@@ -294,7 +294,7 @@ attribute-sets:
         name: master-slave-state
         type: u8
       -
-        name: master-slave-lanes
+        name: lanes
         type: u32
       -
         name: rate-matching
@@ -322,7 +322,7 @@ attribute-sets:
         name: ext-substate
         type: u8
       -
-        name: down-cnt
+        name: ext-down-cnt
         type: u32
   -
     name: debug
@@ -577,7 +577,7 @@ attribute-sets:
         name: phc-index
         type: u32
   -
-    name: cable-test-nft-nest-result
+    name: cable-test-ntf-nest-result
     attributes:
       -
         name: pair
@@ -586,7 +586,7 @@ attribute-sets:
         name: code
         type: u8
   -
-    name: cable-test-nft-nest-fault-length
+    name: cable-test-ntf-nest-fault-length
     attributes:
       -
         name: pair
@@ -595,16 +595,16 @@ attribute-sets:
         name: cm
         type: u32
   -
-    name: cable-test-nft-nest
+    name: cable-test-ntf-nest
     attributes:
       -
         name: result
         type: nest
-        nested-attributes: cable-test-nft-nest-result
+        nested-attributes: cable-test-ntf-nest-result
       -
         name: fault-length
         type: nest
-        nested-attributes: cable-test-nft-nest-fault-length
+        nested-attributes: cable-test-ntf-nest-fault-length
   -
     name: cable-test
     attributes:
@@ -618,7 +618,7 @@ attribute-sets:
       -
         name: nest
         type: nest
-        nested-attributes: cable-test-nft-nest
+        nested-attributes: cable-test-ntf-nest
   -
     name: cable-test-tdr-cfg
     attributes:
@@ -776,7 +776,7 @@ attribute-sets:
         name: hist-bkt-hi
         type: u32
       -
-        name: hist-bkt-val
+        name: hist-val
         type: u64
   -
     name: stats
@@ -965,7 +965,7 @@ operations:
             - duplex
             - master-slave-cfg
             - master-slave-state
-            - master-slave-lanes
+            - lanes
             - rate-matching
       dump: *linkmodes-get-op
     -
@@ -999,7 +999,7 @@ operations:
             - sqi-max
             - ext-state
             - ext-substate
-            - down-cnt
+            - ext-down-cnt
       dump: *linkstate-get-op
     -
       name: debug-get
@@ -1351,7 +1351,7 @@ operations:
         reply:
           attributes:
             - header
-            - cable-test-nft-nest
+            - cable-test-ntf-nest
     -
       name: cable-test-tdr-act
       doc: Cable test TDR.
@@ -1539,7 +1539,7 @@ operations:
             - hkey
       dump: *rss-get-op
     -
-      name: plca-get
+      name: plca-get-cfg
       doc: Get PLCA params.
 
       attribute-set: plca
@@ -1561,7 +1561,7 @@ operations:
             - burst-tmr
       dump: *plca-get-op
     -
-      name: plca-set
+      name: plca-set-cfg
       doc: Set PLCA params.
 
       attribute-set: plca
@@ -1585,7 +1585,7 @@ operations:
     -
       name: plca-ntf
       doc: Notification for change in PLCA params.
-      notify: plca-get
+      notify: plca-get-cfg
     -
       name: mm-get
       doc: Get MAC Merge configuration and state
index 6ec06a3..80b8f73 100644 (file)
@@ -1352,8 +1352,8 @@ ping_group_range - 2 INTEGERS
        Restrict ICMP_PROTO datagram sockets to users in the group range.
        The default is "1 0", meaning, that nobody (not even root) may
        create ping sockets.  Setting it to "100 100" would grant permissions
-       to the single group. "0 4294967295" would enable it for the world, "100
-       4294967295" would enable it for the users, but not daemons.
+       to the single group. "0 4294967294" would enable it for the world, "100
+       4294967294" would enable it for the users, but not daemons.
 
 tcp_early_demux - BOOLEAN
        Enable early demux for established TCP sockets.
index 07d5a56..634aa22 100644 (file)
@@ -16,6 +16,24 @@ tested code over experimental code.  We wish to extend these same
 principles to the RISC-V-related code that will be accepted for
 inclusion in the kernel.
 
+Patchwork
+---------
+
+RISC-V has a patchwork instance, where the status of patches can be checked:
+
+  https://patchwork.kernel.org/project/linux-riscv/list/
+
+If your patch does not appear in the default view, the RISC-V maintainers have
+likely either requested changes, or expect it to be applied to another tree.
+
+Automation runs against this patchwork instance, building/testing patches as
+they arrive. The automation applies patches against the current HEAD of the
+RISC-V `for-next` and `fixes` branches, depending on whether the patch has been
+detected as a fix. Failing those, it will use the RISC-V `master` branch.
+The exact commit to which a series has been applied will be noted on patchwork.
+Patches for which any of the checks fail are unlikely to be applied and in most
+cases will need to be resubmitted.
+
 Submit Checklist Addendum
 -------------------------
 We'll only accept patches for new modules or extensions if the
index f79987e..e7b0731 100644 (file)
@@ -14,10 +14,6 @@ Programs can view status of the events via
 /sys/kernel/tracing/user_events_status and can both register and write
 data out via /sys/kernel/tracing/user_events_data.
 
-Programs can also use /sys/kernel/tracing/dynamic_events to register and
-delete user based events via the u: prefix. The format of the command to
-dynamic_events is the same as the ioctl with the u: prefix applied.
-
 Typically programs will register a set of events that they wish to expose to
 tools that can read trace_events (such as ftrace and perf). The registration
 process tells the kernel which address and bit to reflect if any tool has
@@ -144,6 +140,9 @@ its name. Delete will only succeed if there are no references left to the
 event (in both user and kernel space). User programs should use a separate file
 to request deletes than the one used for registration due to this.
 
+**NOTE:** By default events will auto-delete when there are no references left
+to the event. Flags in the future may change this logic.
+
 Unregistering
 -------------
 If after registering an event it is no longer wanted to be updated then it can
index c6aee82..19ba4ae 100644 (file)
@@ -325,6 +325,6 @@ Primecell设备。然而,棘手的一点是,AMBA总线上的所有设备并
 
 当使用DT时,这给of_platform_populate()带来了问题,因为它必须决定是否将
 每个节点注册为platform_device或amba_device。不幸的是,这使设备创建模型
-变得有点复杂,但解决方案原来并不是太具有侵略性。如果一个节点与“arm,amba-primecell”
+变得有点复杂,但解决方案原来并不是太具有侵略性。如果一个节点与“arm,primecell”
 兼容,那么of_platform_populate()将把它注册为amba_device而不是
 platform_device。
index 0dab973..ad32db6 100644 (file)
@@ -5728,6 +5728,14 @@ F:       include/linux/tfrc.h
 F:     include/uapi/linux/dccp.h
 F:     net/dccp/
 
+DEBUGOBJECTS:
+M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git core/debugobjects
+F:     lib/debugobjects.c
+F:     include/linux/debugobjects.h
+
 DECSTATION PLATFORM SUPPORT
 M:     "Maciej W. Rozycki" <macro@orcam.me.uk>
 L:     linux-mips@vger.kernel.org
@@ -8791,6 +8799,7 @@ F:        include/linux/gpio/regmap.h
 GPIO SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 M:     Bartosz Golaszewski <brgl@bgdev.pl>
+R:     Andy Shevchenko <andy@kernel.org>
 L:     linux-gpio@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux.git
@@ -9687,8 +9696,9 @@ F:        include/uapi/linux/i2c-*.h
 F:     include/uapi/linux/i2c.h
 
 I2C SUBSYSTEM HOST DRIVERS
+M:     Andi Shyti <andi.shyti@kernel.org>
 L:     linux-i2c@vger.kernel.org
-S:     Odd Fixes
+S:     Maintained
 W:     https://i2c.wiki.kernel.org/
 Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
@@ -17817,7 +17827,7 @@ F:      tools/testing/selftests/rtc/
 Real-time Linux Analysis (RTLA) tools
 M:     Daniel Bristot de Oliveira <bristot@kernel.org>
 M:     Steven Rostedt <rostedt@goodmis.org>
-L:     linux-trace-devel@vger.kernel.org
+L:     linux-trace-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/tools/rtla/
 F:     tools/tracing/rtla/
@@ -18038,6 +18048,14 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/usb/renesas,rzn1-usbf.yaml
 F:     drivers/usb/gadget/udc/renesas_usbf.c
 
+RENESAS RZ/V2M I2C DRIVER
+M:     Fabrizio Castro <fabrizio.castro.jz@renesas.com>
+L:     linux-i2c@vger.kernel.org
+L:     linux-renesas-soc@vger.kernel.org
+S:     Supported
+F:     Documentation/devicetree/bindings/i2c/renesas,rzv2m.yaml
+F:     drivers/i2c/busses/i2c-rzv2m.c
+
 RENESAS USB PHY DRIVER
 M:     Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
 L:     linux-renesas-soc@vger.kernel.org
@@ -18379,7 +18397,7 @@ F:      drivers/infiniband/ulp/rtrs/
 RUNTIME VERIFICATION (RV)
 M:     Daniel Bristot de Oliveira <bristot@kernel.org>
 M:     Steven Rostedt <rostedt@goodmis.org>
-L:     linux-trace-devel@vger.kernel.org
+L:     linux-trace-kernel@vger.kernel.org
 S:     Maintained
 F:     Documentation/trace/rv/
 F:     include/linux/rv.h
@@ -19122,6 +19140,9 @@ SHARED MEMORY COMMUNICATIONS (SMC) SOCKETS
 M:     Karsten Graul <kgraul@linux.ibm.com>
 M:     Wenjia Zhang <wenjia@linux.ibm.com>
 M:     Jan Karcher <jaka@linux.ibm.com>
+R:     D. Wythe <alibuda@linux.alibaba.com>
+R:     Tony Lu <tonylu@linux.alibaba.com>
+R:     Wen Gu <guwen@linux.alibaba.com>
 L:     linux-s390@vger.kernel.org
 S:     Supported
 F:     net/smc/
index 09866a8..b68b43c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc7
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
index 2fc9a5d..625b9b3 100644 (file)
 
                interrupt-parent = <&gpio1>;
                interrupts = <31 0>;
-               pendown-gpio = <&gpio1 31 0>;
+               pendown-gpio = <&gpio1 31 GPIO_ACTIVE_LOW>;
 
 
                ti,x-min = /bits/ 16 <0x0>;
index aa5cc0e..217e9b9 100644 (file)
 };
 
 &shdwc {
-       atmel,shdwc-debouncer = <976>;
+       debounce-delay-us = <976>;
        status = "okay";
 
        input@0 {
index 88869ca..045cb25 100644 (file)
                                        compatible = "ti,ads7843";
                                        interrupts-extended = <&pioC 2 IRQ_TYPE_EDGE_BOTH>;
                                        spi-max-frequency = <3000000>;
-                                       pendown-gpio = <&pioC 2 GPIO_ACTIVE_HIGH>;
+                                       pendown-gpio = <&pioC 2 GPIO_ACTIVE_LOW>;
 
                                        ti,x-min = /bits/ 16 <150>;
                                        ti,x-max = /bits/ 16 <3830>;
index d917dc4..6ad39dc 100644 (file)
@@ -64,7 +64,7 @@
                interrupt-parent = <&gpio2>;
                interrupts = <7 0>;
                spi-max-frequency = <1000000>;
-               pendown-gpio = <&gpio2 7 0>;
+               pendown-gpio = <&gpio2 7 GPIO_ACTIVE_LOW>;
                vcc-supply = <&reg_3p3v>;
                ti,x-min = /bits/ 16 <0>;
                ti,x-max = /bits/ 16 <4095>;
index f483bc0..234e5fc 100644 (file)
                pinctrl-0 = <&pinctrl_tsc2046_pendown>;
                interrupt-parent = <&gpio2>;
                interrupts = <29 0>;
-               pendown-gpio = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio2 29 GPIO_ACTIVE_LOW>;
                touchscreen-max-pressure = <255>;
                wakeup-source;
        };
index e61b8a2..51baedf 100644 (file)
 
                interrupt-parent = <&gpio2>;
                interrupts = <25 0>;            /* gpio_57 */
-               pendown-gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio2 25 GPIO_ACTIVE_LOW>;
 
                ti,x-min = /bits/ 16 <0x0>;
                ti,x-max = /bits/ 16 <0x0fff>;
index 3decc2d..a7f99ae 100644 (file)
@@ -54,7 +54,7 @@
 
                interrupt-parent = <&gpio1>;
                interrupts = <27 0>;            /* gpio_27 */
-               pendown-gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio1 27 GPIO_ACTIVE_LOW>;
 
                ti,x-min = /bits/ 16 <0x0>;
                ti,x-max = /bits/ 16 <0x0fff>;
index c595afe..d310b5c 100644 (file)
                interrupt-parent = <&gpio1>;
                interrupts = <8 0>;   /* boot6 / gpio_8 */
                spi-max-frequency = <1000000>;
-               pendown-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio1 8 GPIO_ACTIVE_LOW>;
                vcc-supply = <&reg_vcc3>;
                pinctrl-names = "default";
                pinctrl-0 = <&tsc2048_pins>;
index 1d6e88f..c3570ac 100644 (file)
 
                interrupt-parent = <&gpio4>;
                interrupts = <18 0>;                    /* gpio_114 */
-               pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
 
                ti,x-min = /bits/ 16 <0x0>;
                ti,x-max = /bits/ 16 <0x0fff>;
index 7e30f9d..d95a0e1 100644 (file)
 
                interrupt-parent = <&gpio4>;
                interrupts = <18 0>;                    /* gpio_114 */
-               pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio4 18 GPIO_ACTIVE_LOW>;
 
                ti,x-min = /bits/ 16 <0x0>;
                ti,x-max = /bits/ 16 <0x0fff>;
index 5598537..4c3b6ba 100644 (file)
                pinctrl-0 = <&penirq_pins>;
                interrupt-parent = <&gpio3>;
                interrupts = <30 IRQ_TYPE_NONE>;        /* GPIO_94 */
-               pendown-gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio3 30 GPIO_ACTIVE_LOW>;
                vcc-supply = <&vaux4>;
 
                ti,x-min = /bits/ 16 <0>;
index 2d87b9f..af288d6 100644 (file)
 
                interrupt-parent = <&gpio1>;
                interrupts = <15 0>;                    /* gpio1_wk15 */
-               pendown-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+               pendown-gpio = <&gpio1 15 GPIO_ACTIVE_LOW>;
 
 
                ti,x-min = /bits/ 16 <0x0>;
index 7a80e1c..aa0e0e8 100644 (file)
                function = "gpio";
                drive-strength = <8>;
                bias-disable;
-               input-enable;
        };
 
        wlan_hostwake_default_state: wlan-hostwake-default-state {
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        wlan_regulator_default_state: wlan-regulator-default-state {
index d640960..5593a3a 100644 (file)
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        wlan_regulator_default_state: wlan-regulator-default-state {
index b823812..b887e53 100644 (file)
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        touch_pins: touch-state {
 
                        drive-strength = <8>;
                        bias-pull-down;
-                       input-enable;
                };
 
                reset-pins {
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        wlan_regulator_default_state: wlan-regulator-default-state {
index 672b246..d228920 100644 (file)
@@ -83,6 +83,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
 
                idle-states {
index b653ea4..83839e1 100644 (file)
@@ -74,6 +74,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                        qcom,saw = <&saw_l2>;
                };
 
index dfcfb33..f0ef86f 100644 (file)
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                        qcom,saw = <&saw_l2>;
                };
        };
index af67647..7581845 100644 (file)
@@ -45,6 +45,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index a830476..b269fdc 100644 (file)
@@ -49,7 +49,6 @@
                gpioext1-pins {
                        pins = "gpio2";
                        function = "gpio";
-                       input-enable;
                        bias-disable;
                };
        };
index f601b40..78023ed 100644 (file)
@@ -36,6 +36,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 2a668cd..616fef2 100644 (file)
@@ -42,6 +42,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index ab35f2d..861695c 100644 (file)
                pins = "gpio73";
                function = "gpio";
                bias-disable;
-               input-enable;
        };
 
        touch_pin: touch-state {
 
                        drive-strength = <2>;
                        bias-disable;
-                       input-enable;
                };
 
                reset-pins {
index d3bec03..68a2f90 100644 (file)
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        sdc1_on: sdc1-on-state {
index 8208012..7ed0d92 100644 (file)
@@ -80,6 +80,7 @@
                L2: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                        qcom,saw = <&saw_l2>;
                };
 
index 8d2a054..8230d0e 100644 (file)
                        function = "gpio";
                        drive-strength = <2>;
                        bias-disable;
-                       input-enable;
                };
 
                reset-pins {
index b9698ff..eb505d6 100644 (file)
                        pins = "gpio75";
                        function = "gpio";
                        drive-strength = <16>;
-                       input-enable;
                };
 
                devwake-pins {
        i2c_touchkey_pins: i2c-touchkey-state {
                pins = "gpio95", "gpio96";
                function = "gpio";
-               input-enable;
                bias-pull-up;
        };
 
        i2c_led_gpioex_pins: i2c-led-gpioex-state {
                pins = "gpio120", "gpio121";
                function = "gpio";
-               input-enable;
                bias-pull-down;
        };
 
        wifi_pin: wifi-state {
                pins = "gpio92";
                function = "gpio";
-               input-enable;
                bias-pull-down;
        };
 
index 04bc58d..0f650ed 100644 (file)
                function = "gpio";
                drive-strength = <2>;
                bias-disable;
-               input-enable;
        };
 
        bt_host_wake_pin: bt-host-wake-state {
index 60dc56d..437dd03 100644 (file)
@@ -334,16 +334,14 @@ static bool at91_pm_eth_quirk_is_valid(struct at91_pm_quirk_eth *eth)
                pdev = of_find_device_by_node(eth->np);
                if (!pdev)
                        return false;
+               /* put_device(eth->dev) is called at the end of suspend. */
                eth->dev = &pdev->dev;
        }
 
        /* No quirks if device isn't a wakeup source. */
-       if (!device_may_wakeup(eth->dev)) {
-               put_device(eth->dev);
+       if (!device_may_wakeup(eth->dev))
                return false;
-       }
 
-       /* put_device(eth->dev) is called at the end of suspend. */
        return true;
 }
 
@@ -439,14 +437,14 @@ clk_unconfigure:
                                pr_err("AT91: PM: failed to enable %s clocks\n",
                                       j == AT91_PM_G_ETH ? "geth" : "eth");
                        }
-               } else {
-                       /*
-                        * Release the reference to eth->dev taken in
-                        * at91_pm_eth_quirk_is_valid().
-                        */
-                       put_device(eth->dev);
-                       eth->dev = NULL;
                }
+
+               /*
+                * Release the reference to eth->dev taken in
+                * at91_pm_eth_quirk_is_valid().
+                */
+               put_device(eth->dev);
+               eth->dev = NULL;
        }
 
        return ret;
index b1201d2..343e1e1 100644 (file)
@@ -1516,7 +1516,7 @@ config XEN
 # 16K |       27          |      14      |       13        |         11         |
 # 64K |       29          |      16      |       13        |         13         |
 config ARCH_FORCE_MAX_ORDER
-       int "Order of maximal physically contiguous allocations" if EXPERT && (ARM64_4K_PAGES || ARM64_16K_PAGES)
+       int
        default "13" if ARM64_64K_PAGES
        default "11" if ARM64_16K_PAGES
        default "10"
index 2dce8f2..adb98a7 100644 (file)
@@ -90,6 +90,8 @@ dma_subsys: bus@5a000000 {
                clocks = <&uart0_lpcg IMX_LPCG_CLK_4>,
                         <&uart0_lpcg IMX_LPCG_CLK_0>;
                clock-names = "ipg", "baud";
+               assigned-clocks = <&clk IMX_SC_R_UART_0 IMX_SC_PM_CLK_PER>;
+               assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_0>;
                status = "disabled";
        };
@@ -100,6 +102,8 @@ dma_subsys: bus@5a000000 {
                clocks = <&uart1_lpcg IMX_LPCG_CLK_4>,
                         <&uart1_lpcg IMX_LPCG_CLK_0>;
                clock-names = "ipg", "baud";
+               assigned-clocks = <&clk IMX_SC_R_UART_1 IMX_SC_PM_CLK_PER>;
+               assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_1>;
                status = "disabled";
        };
@@ -110,6 +114,8 @@ dma_subsys: bus@5a000000 {
                clocks = <&uart2_lpcg IMX_LPCG_CLK_4>,
                         <&uart2_lpcg IMX_LPCG_CLK_0>;
                clock-names = "ipg", "baud";
+               assigned-clocks = <&clk IMX_SC_R_UART_2 IMX_SC_PM_CLK_PER>;
+               assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_2>;
                status = "disabled";
        };
@@ -120,6 +126,8 @@ dma_subsys: bus@5a000000 {
                clocks = <&uart3_lpcg IMX_LPCG_CLK_4>,
                         <&uart3_lpcg IMX_LPCG_CLK_0>;
                clock-names = "ipg", "baud";
+               assigned-clocks = <&clk IMX_SC_R_UART_3 IMX_SC_PM_CLK_PER>;
+               assigned-clock-rates = <80000000>;
                power-domains = <&pd IMX_SC_R_UART_3>;
                status = "disabled";
        };
index 9e82069..5a1f7c3 100644 (file)
@@ -81,7 +81,7 @@
 &ecspi2 {
        pinctrl-names = "default";
        pinctrl-0 = <&pinctrl_espi2>;
-       cs-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
+       cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>;
        status = "okay";
 
        eeprom@0 {
                        MX8MN_IOMUXC_ECSPI2_SCLK_ECSPI2_SCLK            0x82
                        MX8MN_IOMUXC_ECSPI2_MOSI_ECSPI2_MOSI            0x82
                        MX8MN_IOMUXC_ECSPI2_MISO_ECSPI2_MISO            0x82
-                       MX8MN_IOMUXC_ECSPI1_SS0_GPIO5_IO9               0x41
+                       MX8MN_IOMUXC_ECSPI2_SS0_GPIO5_IO13              0x41
                >;
        };
 
index ce9d3f0..607cd6b 100644 (file)
@@ -82,8 +82,8 @@
        pinctrl-0 = <&pinctrl_usdhc2>;
        bus-width = <4>;
        vmmc-supply = <&reg_usdhc2_vmmc>;
-       cd-gpios = <&lsio_gpio4 22 GPIO_ACTIVE_LOW>;
-       wp-gpios = <&lsio_gpio4 21 GPIO_ACTIVE_HIGH>;
+       cd-gpios = <&lsio_gpio5 22 GPIO_ACTIVE_LOW>;
+       wp-gpios = <&lsio_gpio5 21 GPIO_ACTIVE_HIGH>;
        status = "okay";
 };
 
index 12e0e17..af4d971 100644 (file)
@@ -73,6 +73,7 @@
                L2_0: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 9ff4e9d..f531797 100644 (file)
@@ -83,7 +83,8 @@
 
                L2_0: l2-cache {
                        compatible = "cache";
-                       cache-level = <0x2>;
+                       cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 84e715a..5b2c198 100644 (file)
@@ -66,7 +66,8 @@
 
                L2_0: l2-cache {
                        compatible = "cache";
-                       cache-level = <0x2>;
+                       cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 3bb7435..0ed19fb 100644 (file)
@@ -72,6 +72,7 @@
                L2_0: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 7e0fa37..834e0b6 100644 (file)
                L2_0: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
 
                idle-states {
index 602cb18..d44cfa0 100644 (file)
                L2_0: l2-cache-0 {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
 
                L2_1: l2-cache-1 {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 1f0bd24..f47fb8e 100644 (file)
                l2_0: l2-cache0 {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
 
                l2_1: l2-cache1 {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
        };
 
index 2831966..bdc3f2b 100644 (file)
@@ -52,6 +52,7 @@
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
@@ -88,6 +89,7 @@
                        L2_1: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index 2b35cb3..30257c0 100644 (file)
@@ -53,8 +53,9 @@
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                        };
                };
 
@@ -83,8 +84,9 @@
                        #cooling-cells = <2>;
                        next-level-cache = <&L2_1>;
                        L2_1: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index b150437..3ec941f 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
                        L2_1: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index ae5abc7..b29bc4e 100644 (file)
@@ -51,6 +51,7 @@
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index eefed58..972f753 100644 (file)
@@ -95,6 +95,7 @@
                L2_0: l2-cache {
                        compatible = "cache";
                        cache-level = <2>;
+                       cache-unified;
                };
 
                idle-states {
index 7344381..fb553f0 100644 (file)
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -54,6 +58,8 @@
                        next-level-cache = <&L2_100>;
                        L2_100: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -70,6 +76,8 @@
                        next-level-cache = <&L2_200>;
                        L2_200: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -86,6 +94,8 @@
                        next-level-cache = <&L2_300>;
                        L2_300: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 339fea5..15e1ae1 100644 (file)
@@ -7,7 +7,7 @@
 
 #include <dt-bindings/regulator/qcom,rpmh-regulator.h>
 #include <dt-bindings/gpio/gpio.h>
-#include "sm8150.dtsi"
+#include "sa8155p.dtsi"
 #include "pmm8155au_1.dtsi"
 #include "pmm8155au_2.dtsi"
 
diff --git a/arch/arm64/boot/dts/qcom/sa8155p.dtsi b/arch/arm64/boot/dts/qcom/sa8155p.dtsi
new file mode 100644 (file)
index 0000000..ffb7ab6
--- /dev/null
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2023, Linaro Limited
+ *
+ * SA8155P is an automotive variant of SM8150, with some minor changes.
+ * Most notably, the RPMhPD setup differs: MMCX and LCX/LMX rails are gone,
+ * though the cmd-db doesn't reflect that and access attemps result in a bite.
+ */
+
+#include "sm8150.dtsi"
+
+&dispcc {
+       power-domains = <&rpmhpd SA8155P_CX>;
+};
+
+&mdss_dsi0 {
+       power-domains = <&rpmhpd SA8155P_CX>;
+};
+
+&mdss_dsi1 {
+       power-domains = <&rpmhpd SA8155P_CX>;
+};
+
+&mdss_mdp {
+       power-domains = <&rpmhpd SA8155P_CX>;
+};
+
+&remoteproc_slpi {
+       power-domains = <&rpmhpd SA8155P_CX>,
+                       <&rpmhpd SA8155P_MX>;
+};
+
+&rpmhpd {
+       /*
+        * The bindings were crafted such that SA8155P PDs match their
+        * SM8150 counterparts to make it more maintainable and only
+        * necessitate adjusting entries that actually differ
+        */
+       compatible = "qcom,sa8155p-rpmhpd";
+};
index 2343df7..c3310ca 100644 (file)
                        next-level-cache = <&L2_0>;
                        L2_0: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -58,6 +62,8 @@
                        next-level-cache = <&L2_1>;
                        L2_1: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -71,6 +77,8 @@
                        next-level-cache = <&L2_2>;
                        L2_2: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -84,6 +92,8 @@
                        next-level-cache = <&L2_3>;
                        L2_3: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        next-level-cache = <&L2_4>;
                        L2_4: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_1>;
                                L3_1: l3-cache {
                                        compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
 
                        };
                        next-level-cache = <&L2_5>;
                        L2_5: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_1>;
                        };
                };
                        next-level-cache = <&L2_6>;
                        L2_6: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_1>;
                        };
                };
                        next-level-cache = <&L2_7>;
                        L2_7: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_1>;
                        };
                };
index d8ed1d7..4b306a5 100644 (file)
 &cpu6_opp12 {
        opp-peak-kBps = <8532000 23347200>;
 };
+
+&cpu6_opp13 {
+       opp-peak-kBps = <8532000 23347200>;
+};
+
+&cpu6_opp14 {
+       opp-peak-kBps = <8532000 23347200>;
+};
index ea1ffad..f479cab 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
                                        cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index c6dc200..2102704 100644 (file)
        wcd_rx: codec@0,4 {
                compatible = "sdw20217010d00";
                reg = <0 4>;
-               #sound-dai-cells = <1>;
                qcom,rx-port-mapping = <1 2 3 4 5>;
        };
 };
        wcd_tx: codec@0,3 {
                compatible = "sdw20217010d00";
                reg = <0 3>;
-               #sound-dai-cells = <1>;
                qcom,tx-port-mapping = <1 2 3 4>;
        };
 };
index 88b3586..9137db0 100644 (file)
        wcd_rx: codec@0,4 {
                compatible = "sdw20217010d00";
                reg = <0 4>;
-               #sound-dai-cells = <1>;
                qcom,rx-port-mapping = <1 2 3 4 5>;
        };
 };
        wcd_tx: codec@0,3 {
                compatible = "sdw20217010d00";
                reg = <0 3>;
-               #sound-dai-cells = <1>;
                qcom,tx-port-mapping = <1 2 3 4>;
        };
 };
index 31728f4..2fd1d3c 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
                                        cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 8fa9fbf..cc4aef2 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
-                                     cache-level = <3>;
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -83,6 +85,7 @@
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                                        pins = "gpio7";
                                        function = "dmic1_data";
                                        drive-strength = <8>;
+                                       input-enable;
                                };
                        };
 
                                        function = "dmic1_data";
                                        drive-strength = <2>;
                                        bias-pull-down;
+                                       input-enable;
                                };
                        };
 
                                        pins = "gpio9";
                                        function = "dmic2_data";
                                        drive-strength = <8>;
+                                       input-enable;
                                };
                        };
 
                                        function = "dmic2_data";
                                        drive-strength = <2>;
                                        bias-pull-down;
+                                       input-enable;
                                };
                        };
 
                        qcom,tcs-config = <ACTIVE_TCS  2>, <SLEEP_TCS   3>,
                                          <WAKE_TCS    3>, <CONTROL_TCS 1>;
                        label = "apps_rsc";
+                       power-domains = <&CLUSTER_PD>;
 
                        apps_bcm_voter: bcm-voter {
                                compatible = "qcom,bcm-voter";
index 37e72b1..eaead2f 100644 (file)
@@ -63,6 +63,7 @@
                        L2_1: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index c5f839d..b61e13d 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                next-level-cache = <&L3_0>;
+                               cache-level = <2>;
+                               cache-unified;
                                L3_0: l3-cache {
-                                     compatible = "cache";
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -57,6 +61,8 @@
                        next-level-cache = <&L2_100>;
                        L2_100: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -71,6 +77,8 @@
                        next-level-cache = <&L2_200>;
                        L2_200: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
@@ -85,6 +93,8 @@
                        next-level-cache = <&L2_300>;
                        L2_300: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        next-level-cache = <&L2_400>;
                        L2_400: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        next-level-cache = <&L2_500>;
                        L2_500: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        next-level-cache = <&L2_600>;
                        L2_600: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        next-level-cache = <&L2_700>;
                        L2_700: l2-cache {
                                compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 9042444..cdeb05e 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
-                                     cache-level = <3>;
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 631ca32..43f31c1 100644 (file)
@@ -50,6 +50,7 @@
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
                        L2_1: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index 9484752..2aa093d 100644 (file)
@@ -47,6 +47,7 @@
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
@@ -87,6 +88,7 @@
                        L2_1: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                        };
                };
 
index 18c4616..ad34301 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
                                        cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -86,6 +88,7 @@
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 8220e6f..b2f1bb1 100644 (file)
 };
 
 &remoteproc_adsp {
-       firmware-name = "qcom/Sony/murray/adsp.mbn";
+       firmware-name = "qcom/sm6375/Sony/murray/adsp.mbn";
        status = "okay";
 };
 
 &remoteproc_cdsp {
-       firmware-name = "qcom/Sony/murray/cdsp.mbn";
+       firmware-name = "qcom/sm6375/Sony/murray/cdsp.mbn";
        status = "okay";
 };
 
index ae9b6bc..f8d9c34 100644 (file)
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_0: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_100: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_200: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_300: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_400: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_500: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_600: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_700: l2-cache {
-                             compatible = "cache";
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
index 2273fa5..27dcda0 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
-                                     cache-level = <3>;
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
@@ -90,6 +92,7 @@
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
index 8b2ae39..de6101d 100644 (file)
@@ -13,6 +13,6 @@
 };
 
 &display_panel {
-       compatible = "xiaomi,elish-boe-nt36523";
+       compatible = "xiaomi,elish-boe-nt36523", "novatek,nt36523";
        status = "okay";
 };
index a4d5341..4cffe9c 100644 (file)
@@ -13,6 +13,6 @@
 };
 
 &display_panel {
-       compatible = "xiaomi,elish-csot-nt36523";
+       compatible = "xiaomi,elish-csot-nt36523", "novatek,nt36523";
        status = "okay";
 };
index ebcb481..3efdc03 100644 (file)
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_0: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
-                                     cache-level = <3>;
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_100: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_200: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_300: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_400: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_500: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_600: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        power-domain-names = "psci";
                        #cooling-cells = <2>;
                        L2_700: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
index 595533a..d59ea8e 100644 (file)
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 0>;
                        L2_0: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
-                                     compatible = "cache";
-                                     cache-level = <3>;
+                                       compatible = "cache";
+                                       cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 0>;
                        L2_100: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 0>;
                        L2_200: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 0>;
                        L2_300: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 1>;
                        L2_400: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 1>;
                        L2_500: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 1>;
                        L2_600: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
                        #cooling-cells = <2>;
                        clocks = <&cpufreq_hw 2>;
                        L2_700: l2-cache {
-                             compatible = "cache";
-                             cache-level = <2>;
-                             next-level-cache = <&L3_0>;
+                               compatible = "cache";
+                               cache-level = <2>;
+                               cache-unified;
+                               next-level-cache = <&L3_0>;
                        };
                };
 
index 6e9bad8..558cbc4 100644 (file)
                        L2_0: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                                L3_0: l3-cache {
                                        compatible = "cache";
                                        cache-level = <3>;
+                                       cache-unified;
                                };
                        };
                };
                        L2_100: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_200: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_300: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_400: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_500: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_600: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        L2_700: l2-cache {
                                compatible = "cache";
                                cache-level = <2>;
+                               cache-unified;
                                next-level-cache = <&L3_0>;
                        };
                };
                        qcom,din-ports = <4>;
                        qcom,dout-ports = <9>;
 
-                       qcom,ports-sinterval =          <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
+                       qcom,ports-sinterval =          /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
                        qcom,ports-offset1 =            /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>;
                        qcom,ports-offset2 =            /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
                        qcom,ports-hstart =             /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
                        qcom,din-ports = <0>;
                        qcom,dout-ports = <10>;
 
-                       qcom,ports-sinterval =          <0x03 0x3f 0x1f 0x07 0x00 0x18f 0xff 0xff 0xff 0xff>;
+                       qcom,ports-sinterval =          /bits/ 16 <0x03 0x3f 0x1f 0x07 0x00 0x18f 0xff 0xff 0xff 0xff>;
                        qcom,ports-offset1 =            /bits/ 8 <0x00 0x00 0x0b 0x01 0x00 0x00 0xff 0xff 0xff 0xff>;
                        qcom,ports-offset2 =            /bits/ 8 <0x00 0x00 0x0b 0x00 0x00 0x00 0xff 0xff 0xff 0xff>;
                        qcom,ports-hstart =             /bits/ 8 <0xff 0x03 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff>;
                        qcom,din-ports = <4>;
                        qcom,dout-ports = <9>;
 
-                       qcom,ports-sinterval =          <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
+                       qcom,ports-sinterval =          /bits/ 16 <0x07 0x1f 0x3f 0x07 0x1f 0x3f 0x18f 0xff 0xff 0x0f 0x0f 0xff 0x31f>;
                        qcom,ports-offset1 =            /bits/ 8 <0x01 0x03 0x05 0x02 0x04 0x15 0x00 0xff 0xff 0x06 0x0d 0xff 0x00>;
                        qcom,ports-offset2 =            /bits/ 8 <0xff 0x07 0x1f 0xff 0x07 0x1f 0xff 0xff 0xff 0xff 0xff 0xff 0xff>;
                        qcom,ports-hstart =             /bits/ 8 <0xff 0xff 0xff 0xff 0xff 0xff 0x08 0xff 0xff 0xff 0xff 0xff 0x0f>;
 
                system-cache-controller@25000000 {
                        compatible = "qcom,sm8550-llcc";
-                       reg = <0 0x25000000 0 0x800000>,
+                       reg = <0 0x25000000 0 0x200000>,
+                             <0 0x25200000 0 0x200000>,
+                             <0 0x25400000 0 0x200000>,
+                             <0 0x25600000 0 0x200000>,
                              <0 0x25800000 0 0x200000>;
-                       reg-names = "llcc_base", "llcc_broadcast_base";
+                       reg-names = "llcc0_base",
+                                   "llcc1_base",
+                                   "llcc2_base",
+                                   "llcc3_base",
+                                   "llcc_broadcast_base";
                        interrupts = <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>;
                };
 
index a406454..f1b8a04 100644 (file)
@@ -67,7 +67,7 @@ static int __init hyperv_init(void)
        if (ret)
                return ret;
 
-       ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "arm64/hyperv_init:online",
+       ret = cpuhp_setup_state(CPUHP_AP_HYPERV_ONLINE, "arm64/hyperv_init:online",
                                hv_common_cpu_init, hv_common_cpu_die);
        if (ret < 0) {
                hv_common_free();
index cb21ccd..6045a51 100644 (file)
@@ -600,8 +600,7 @@ static int __kprobes do_page_fault(unsigned long far, unsigned long esr,
                vma_end_read(vma);
                goto lock_mmap;
        }
-       fault = handle_mm_fault(vma, addr & PAGE_MASK,
-                               mm_flags | FAULT_FLAG_VMA_LOCK, regs);
+       fault = handle_mm_fault(vma, addr, mm_flags | FAULT_FLAG_VMA_LOCK, regs);
        vma_end_read(vma);
 
        if (!(fault & VM_FAULT_RETRY)) {
index b3323ab..35e8a52 100644 (file)
@@ -1496,7 +1496,7 @@ __BUILD_CSR_OP(tlbidx)
 #define write_fcsr(dest, val) \
 do {   \
        __asm__ __volatile__(   \
-       "       movgr2fcsr      %0, "__stringify(dest)" \n"     \
+       "       movgr2fcsr      "__stringify(dest)", %0 \n"     \
        : : "r" (val)); \
 } while (0)
 
index 8b98d22..de46a6b 100644 (file)
 #define        _PAGE_PFN_SHIFT         12
 #define        _PAGE_SWP_EXCLUSIVE_SHIFT 23
 #define        _PAGE_PFN_END_SHIFT     48
+#define        _PAGE_PRESENT_INVALID_SHIFT 60
 #define        _PAGE_NO_READ_SHIFT     61
 #define        _PAGE_NO_EXEC_SHIFT     62
 #define        _PAGE_RPLV_SHIFT        63
 
 /* Used by software */
 #define _PAGE_PRESENT          (_ULCAST_(1) << _PAGE_PRESENT_SHIFT)
+#define _PAGE_PRESENT_INVALID  (_ULCAST_(1) << _PAGE_PRESENT_INVALID_SHIFT)
 #define _PAGE_WRITE            (_ULCAST_(1) << _PAGE_WRITE_SHIFT)
 #define _PAGE_ACCESSED         (_ULCAST_(1) << _PAGE_ACCESSED_SHIFT)
 #define _PAGE_MODIFIED         (_ULCAST_(1) << _PAGE_MODIFIED_SHIFT)
index d28fb9d..9a9f9ff 100644 (file)
@@ -213,7 +213,7 @@ static inline int pmd_bad(pmd_t pmd)
 static inline int pmd_present(pmd_t pmd)
 {
        if (unlikely(pmd_val(pmd) & _PAGE_HUGE))
-               return !!(pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE));
+               return !!(pmd_val(pmd) & (_PAGE_PRESENT | _PAGE_PROTNONE | _PAGE_PRESENT_INVALID));
 
        return pmd_val(pmd) != (unsigned long)invalid_pte_table;
 }
@@ -558,6 +558,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
 
 static inline pmd_t pmd_mkinvalid(pmd_t pmd)
 {
+       pmd_val(pmd) |= _PAGE_PRESENT_INVALID;
        pmd_val(pmd) &= ~(_PAGE_PRESENT | _PAGE_VALID | _PAGE_DIRTY | _PAGE_PROTNONE);
 
        return pmd;
index 2406c95..021b59c 100644 (file)
@@ -396,6 +396,8 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
 
        if (hw->ctrl.type != LOONGARCH_BREAKPOINT_EXECUTE)
                alignment_mask = 0x7;
+       else
+               alignment_mask = 0x3;
        offset = hw->address & alignment_mask;
 
        hw->address &= ~alignment_mask;
index ff28f99..0491bf4 100644 (file)
@@ -271,7 +271,7 @@ static void loongarch_pmu_enable_event(struct hw_perf_event *evt, int idx)
        WARN_ON(idx < 0 || idx >= loongarch_pmu.num_counters);
 
        /* Make sure interrupt enabled. */
-       cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) |
+       cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base) |
                (evt->config_base & M_PERFCTL_CONFIG_MASK) | CSR_PERFCTRL_IE;
 
        cpu = (event->cpu >= 0) ? event->cpu : smp_processor_id();
@@ -594,7 +594,7 @@ static struct pmu pmu = {
 
 static unsigned int loongarch_pmu_perf_event_encode(const struct loongarch_perf_event *pev)
 {
-       return (pev->event_id & 0xff);
+       return M_PERFCTL_EVENT(pev->event_id);
 }
 
 static const struct loongarch_perf_event *loongarch_pmu_map_general_event(int idx)
@@ -849,7 +849,7 @@ static void resume_local_counters(void)
 
 static const struct loongarch_perf_event *loongarch_pmu_map_raw_event(u64 config)
 {
-       raw_event.event_id = config & 0xff;
+       raw_event.event_id = M_PERFCTL_EVENT(config);
 
        return &raw_event;
 }
index bdff825..85fae3d 100644 (file)
@@ -485,7 +485,7 @@ static int __init debugfs_unaligned(void)
        struct dentry *d;
 
        d = debugfs_create_dir("loongarch", NULL);
-       if (!d)
+       if (IS_ERR_OR_NULL(d))
                return -ENOMEM;
 
        debugfs_create_u32("unaligned_instructions_user",
index 56339be..0e7e5b0 100644 (file)
@@ -97,7 +97,7 @@
                        rx-fifo-depth = <8192>;
                        tx-fifo-depth = <8192>;
                        address-bits = <48>;
-                       max-frame-size = <1518>;
+                       max-frame-size = <1500>;
                        local-mac-address = [00 00 00 00 00 00];
                        altr,has-supplementary-unicast;
                        altr,enable-sup-addr = <1>;
index d10fb81..3ee3169 100644 (file)
                                interrupt-names = "rx_irq", "tx_irq";
                                rx-fifo-depth = <8192>;
                                tx-fifo-depth = <8192>;
-                               max-frame-size = <1518>;
+                               max-frame-size = <1500>;
                                local-mac-address = [ 00 00 00 00 00 00 ];
                                phy-mode = "rgmii-id";
                                phy-handle = <&phy0>;
index 0f0d4a4..75677b5 100644 (file)
 #include <asm/asmregs.h>
 #include <asm/psw.h>
 
-       sp      =       30
-       gp      =       27
-       ipsw    =       22
-
        /*
         * We provide two versions of each macro to convert from physical
         * to virtual and vice versa. The "_r1" versions take one argument
index 6f5e272..78473d6 100644 (file)
@@ -5,6 +5,11 @@ KCSAN_SANITIZE := n
 
 targets += trampoline_$(BITS).o purgatory.ro
 
+# When profile-guided optimization is enabled, llvm emits two different
+# overlapping text sections, which is not supported by kexec. Remove profile
+# optimization flags.
+KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
+
 LDFLAGS_purgatory.ro := -e purgatory_start -r --no-undefined
 
 $(obj)/purgatory.ro: $(obj)/trampoline_$(BITS).o FORCE
index 2bb0c38..5966ad9 100644 (file)
@@ -26,6 +26,7 @@ config RISCV
        select ARCH_HAS_GIGANTIC_PAGE
        select ARCH_HAS_KCOV
        select ARCH_HAS_MMIOWB
+       select ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
        select ARCH_HAS_PMEM_API
        select ARCH_HAS_PTE_SPECIAL
        select ARCH_HAS_SET_DIRECT_MAP if MMU
index d887a54..0bbffd5 100644 (file)
@@ -8,41 +8,8 @@
 #include <asm-generic/pgalloc.h>
 #include <asm/pgtable.h>
 
-static inline int split_pmd_page(unsigned long addr)
-{
-       int i;
-       unsigned long pfn = PFN_DOWN(__pa((addr & PMD_MASK)));
-       pmd_t *pmd = pmd_off_k(addr);
-       pte_t *pte = pte_alloc_one_kernel(&init_mm);
-
-       if (!pte)
-               return -ENOMEM;
-
-       for (i = 0; i < PTRS_PER_PTE; i++)
-               set_pte(pte + i, pfn_pte(pfn + i, PAGE_KERNEL));
-       set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa(pte)), PAGE_TABLE));
-
-       flush_tlb_kernel_range(addr, addr + PMD_SIZE);
-       return 0;
-}
-
 static inline bool arch_kfence_init_pool(void)
 {
-       int ret;
-       unsigned long addr;
-       pmd_t *pmd;
-
-       for (addr = (unsigned long)__kfence_pool; is_kfence_address((void *)addr);
-            addr += PAGE_SIZE) {
-               pmd = pmd_off_k(addr);
-
-               if (pmd_leaf(*pmd)) {
-                       ret = split_pmd_page(addr);
-                       if (ret)
-                               return false;
-               }
-       }
-
        return true;
 }
 
index 2258b27..75970ee 100644 (file)
@@ -165,8 +165,7 @@ extern struct pt_alloc_ops pt_ops __initdata;
                                         _PAGE_EXEC | _PAGE_WRITE)
 
 #define PAGE_COPY              PAGE_READ
-#define PAGE_COPY_EXEC         PAGE_EXEC
-#define PAGE_COPY_READ_EXEC    PAGE_READ_EXEC
+#define PAGE_COPY_EXEC         PAGE_READ_EXEC
 #define PAGE_SHARED            PAGE_WRITE
 #define PAGE_SHARED_EXEC       PAGE_WRITE_EXEC
 
index c6bb966..4fa420f 100644 (file)
@@ -23,6 +23,7 @@
 #ifdef CONFIG_RELOCATABLE
 #include <linux/elf.h>
 #endif
+#include <linux/kfence.h>
 
 #include <asm/fixmap.h>
 #include <asm/tlbflush.h>
@@ -293,7 +294,7 @@ static const pgprot_t protection_map[16] = {
        [VM_EXEC]                                       = PAGE_EXEC,
        [VM_EXEC | VM_READ]                             = PAGE_READ_EXEC,
        [VM_EXEC | VM_WRITE]                            = PAGE_COPY_EXEC,
-       [VM_EXEC | VM_WRITE | VM_READ]                  = PAGE_COPY_READ_EXEC,
+       [VM_EXEC | VM_WRITE | VM_READ]                  = PAGE_COPY_EXEC,
        [VM_SHARED]                                     = PAGE_NONE,
        [VM_SHARED | VM_READ]                           = PAGE_READ,
        [VM_SHARED | VM_WRITE]                          = PAGE_SHARED,
@@ -659,18 +660,19 @@ void __init create_pgd_mapping(pgd_t *pgdp,
        create_pgd_next_mapping(nextp, va, pa, sz, prot);
 }
 
-static uintptr_t __init best_map_size(phys_addr_t base, phys_addr_t size)
+static uintptr_t __init best_map_size(phys_addr_t pa, uintptr_t va,
+                                     phys_addr_t size)
 {
-       if (!(base & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE)
+       if (!(pa & (PGDIR_SIZE - 1)) && !(va & (PGDIR_SIZE - 1)) && size >= PGDIR_SIZE)
                return PGDIR_SIZE;
 
-       if (!(base & (P4D_SIZE - 1)) && size >= P4D_SIZE)
+       if (!(pa & (P4D_SIZE - 1)) && !(va & (P4D_SIZE - 1)) && size >= P4D_SIZE)
                return P4D_SIZE;
 
-       if (!(base & (PUD_SIZE - 1)) && size >= PUD_SIZE)
+       if (!(pa & (PUD_SIZE - 1)) && !(va & (PUD_SIZE - 1)) && size >= PUD_SIZE)
                return PUD_SIZE;
 
-       if (!(base & (PMD_SIZE - 1)) && size >= PMD_SIZE)
+       if (!(pa & (PMD_SIZE - 1)) && !(va & (PMD_SIZE - 1)) && size >= PMD_SIZE)
                return PMD_SIZE;
 
        return PAGE_SIZE;
@@ -1167,14 +1169,16 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
 }
 
 static void __init create_linear_mapping_range(phys_addr_t start,
-                                              phys_addr_t end)
+                                              phys_addr_t end,
+                                              uintptr_t fixed_map_size)
 {
        phys_addr_t pa;
        uintptr_t va, map_size;
 
        for (pa = start; pa < end; pa += map_size) {
                va = (uintptr_t)__va(pa);
-               map_size = best_map_size(pa, end - pa);
+               map_size = fixed_map_size ? fixed_map_size :
+                                           best_map_size(pa, va, end - pa);
 
                create_pgd_mapping(swapper_pg_dir, va, pa, map_size,
                                   pgprot_from_va(va));
@@ -1184,6 +1188,7 @@ static void __init create_linear_mapping_range(phys_addr_t start,
 static void __init create_linear_mapping_page_table(void)
 {
        phys_addr_t start, end;
+       phys_addr_t kfence_pool __maybe_unused;
        u64 i;
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
@@ -1197,6 +1202,19 @@ static void __init create_linear_mapping_page_table(void)
        memblock_mark_nomap(krodata_start, krodata_size);
 #endif
 
+#ifdef CONFIG_KFENCE
+       /*
+        *  kfence pool must be backed by PAGE_SIZE mappings, so allocate it
+        *  before we setup the linear mapping so that we avoid using hugepages
+        *  for this region.
+        */
+       kfence_pool = memblock_phys_alloc(KFENCE_POOL_SIZE, PAGE_SIZE);
+       BUG_ON(!kfence_pool);
+
+       memblock_mark_nomap(kfence_pool, KFENCE_POOL_SIZE);
+       __kfence_pool = __va(kfence_pool);
+#endif
+
        /* Map all memory banks in the linear mapping */
        for_each_mem_range(i, &start, &end) {
                if (start >= end)
@@ -1207,17 +1225,25 @@ static void __init create_linear_mapping_page_table(void)
                if (end >= __pa(PAGE_OFFSET) + memory_limit)
                        end = __pa(PAGE_OFFSET) + memory_limit;
 
-               create_linear_mapping_range(start, end);
+               create_linear_mapping_range(start, end, 0);
        }
 
 #ifdef CONFIG_STRICT_KERNEL_RWX
-       create_linear_mapping_range(ktext_start, ktext_start + ktext_size);
+       create_linear_mapping_range(ktext_start, ktext_start + ktext_size, 0);
        create_linear_mapping_range(krodata_start,
-                                   krodata_start + krodata_size);
+                                   krodata_start + krodata_size, 0);
 
        memblock_clear_nomap(ktext_start,  ktext_size);
        memblock_clear_nomap(krodata_start, krodata_size);
 #endif
+
+#ifdef CONFIG_KFENCE
+       create_linear_mapping_range(kfence_pool,
+                                   kfence_pool + KFENCE_POOL_SIZE,
+                                   PAGE_SIZE);
+
+       memblock_clear_nomap(kfence_pool, KFENCE_POOL_SIZE);
+#endif
 }
 
 static void __init setup_vm_final(void)
index 5730797..bd2e27f 100644 (file)
@@ -35,6 +35,11 @@ CFLAGS_sha256.o := -D__DISABLE_EXPORTS
 CFLAGS_string.o := -D__DISABLE_EXPORTS
 CFLAGS_ctype.o := -D__DISABLE_EXPORTS
 
+# When profile-guided optimization is enabled, llvm emits two different
+# overlapping text sections, which is not supported by kexec. Remove profile
+# optimization flags.
+KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
+
 # When linking purgatory.ro with -r unresolved symbols are not checked,
 # also link a purgatory.chk binary without -r to check for unresolved symbols.
 PURGATORY_LDFLAGS := -e purgatory_start -z nodefaultlib
index 32573b4..cc8cf5a 100644 (file)
@@ -26,6 +26,7 @@ KBUILD_CFLAGS += -Wno-pointer-sign -Wno-sign-compare
 KBUILD_CFLAGS += -fno-zero-initialized-in-bss -fno-builtin -ffreestanding
 KBUILD_CFLAGS += -Os -m64 -msoft-float -fno-common
 KBUILD_CFLAGS += -fno-stack-protector
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
 KBUILD_CFLAGS += $(CLANG_FLAGS)
 KBUILD_CFLAGS += $(call cc-option,-fno-PIE)
 KBUILD_AFLAGS := $(filter-out -DCC_USING_EXPOLINE,$(KBUILD_AFLAGS))
index a5f9474..6c04b52 100644 (file)
@@ -416,7 +416,7 @@ void __init hyperv_init(void)
                        goto free_vp_assist_page;
        }
 
-       cpuhp = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/hyperv_init:online",
+       cpuhp = cpuhp_setup_state(CPUHP_AP_HYPERV_ONLINE, "x86/hyperv_init:online",
                                  hv_cpu_init, hv_cpu_die);
        if (cpuhp < 0)
                goto free_ghcb_page;
index 1ba5d3b..85d38b9 100644 (file)
@@ -20,6 +20,8 @@ void __init hv_vtl_init_platform(void)
 {
        pr_info("Linux runs in Hyper-V Virtual Trust Level\n");
 
+       x86_platform.realmode_reserve = x86_init_noop;
+       x86_platform.realmode_init = x86_init_noop;
        x86_init.irqs.pre_vector_init = x86_init_noop;
        x86_init.timers.timer_init = x86_init_noop;
 
index a5df3e9..113c133 100644 (file)
@@ -77,6 +77,15 @@ SYM_CODE_START_NOALIGN(startup_64)
        call    startup_64_setup_env
        popq    %rsi
 
+       /* Now switch to __KERNEL_CS so IRET works reliably */
+       pushq   $__KERNEL_CS
+       leaq    .Lon_kernel_cs(%rip), %rax
+       pushq   %rax
+       lretq
+
+.Lon_kernel_cs:
+       UNWIND_HINT_END_OF_STACK
+
 #ifdef CONFIG_AMD_MEM_ENCRYPT
        /*
         * Activate SEV/SME memory encryption if supported/enabled. This needs to
@@ -90,15 +99,6 @@ SYM_CODE_START_NOALIGN(startup_64)
        popq    %rsi
 #endif
 
-       /* Now switch to __KERNEL_CS so IRET works reliably */
-       pushq   $__KERNEL_CS
-       leaq    .Lon_kernel_cs(%rip), %rax
-       pushq   %rax
-       lretq
-
-.Lon_kernel_cs:
-       UNWIND_HINT_END_OF_STACK
-
        /* Sanitize CPU configuration */
        call verify_cpu
 
index 82fec66..42abd6a 100644 (file)
@@ -14,6 +14,11 @@ $(obj)/sha256.o: $(srctree)/lib/crypto/sha256.c FORCE
 
 CFLAGS_sha256.o := -D__DISABLE_EXPORTS
 
+# When profile-guided optimization is enabled, llvm emits two different
+# overlapping text sections, which is not supported by kexec. Remove profile
+# optimization flags.
+KBUILD_CFLAGS := $(filter-out -fprofile-sample-use=% -fprofile-use=%,$(KBUILD_CFLAGS))
+
 # When linking purgatory.ro with -r unresolved symbols are not checked,
 # also link a purgatory.chk binary without -r to check for unresolved symbols.
 PURGATORY_LDFLAGS := -e purgatory_start -z nodefaultlib
index 0ce64dd..f0b5c9c 100644 (file)
@@ -34,6 +34,8 @@
 #include "blk-ioprio.h"
 #include "blk-throttle.h"
 
+static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu);
+
 /*
  * blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation.
  * blkcg_pol_register_mutex nests outside of it and synchronizes entire
@@ -56,6 +58,8 @@ static LIST_HEAD(all_blkcgs);         /* protected by blkcg_pol_mutex */
 
 bool blkcg_debug_stats = false;
 
+static DEFINE_RAW_SPINLOCK(blkg_stat_lock);
+
 #define BLKG_DESTROY_BATCH_SIZE  64
 
 /*
@@ -163,10 +167,20 @@ static void blkg_free(struct blkcg_gq *blkg)
 static void __blkg_release(struct rcu_head *rcu)
 {
        struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head);
+       struct blkcg *blkcg = blkg->blkcg;
+       int cpu;
 
 #ifdef CONFIG_BLK_CGROUP_PUNT_BIO
        WARN_ON(!bio_list_empty(&blkg->async_bios));
 #endif
+       /*
+        * Flush all the non-empty percpu lockless lists before releasing
+        * us, given these stat belongs to us.
+        *
+        * blkg_stat_lock is for serializing blkg stat update
+        */
+       for_each_possible_cpu(cpu)
+               __blkcg_rstat_flush(blkcg, cpu);
 
        /* release the blkcg and parent blkg refs this blkg has been holding */
        css_put(&blkg->blkcg->css);
@@ -951,17 +965,12 @@ static void blkcg_iostat_update(struct blkcg_gq *blkg, struct blkg_iostat *cur,
        u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags);
 }
 
-static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
+static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu)
 {
-       struct blkcg *blkcg = css_to_blkcg(css);
        struct llist_head *lhead = per_cpu_ptr(blkcg->lhead, cpu);
        struct llist_node *lnode;
        struct blkg_iostat_set *bisc, *next_bisc;
 
-       /* Root-level stats are sourced from system-wide IO stats */
-       if (!cgroup_parent(css->cgroup))
-               return;
-
        rcu_read_lock();
 
        lnode = llist_del_all(lhead);
@@ -969,6 +978,14 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
                goto out;
 
        /*
+        * For covering concurrent parent blkg update from blkg_release().
+        *
+        * When flushing from cgroup, cgroup_rstat_lock is always held, so
+        * this lock won't cause contention most of time.
+        */
+       raw_spin_lock(&blkg_stat_lock);
+
+       /*
         * Iterate only the iostat_cpu's queued in the lockless list.
         */
        llist_for_each_entry_safe(bisc, next_bisc, lnode, lnode) {
@@ -991,13 +1008,19 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
                if (parent && parent->parent)
                        blkcg_iostat_update(parent, &blkg->iostat.cur,
                                            &blkg->iostat.last);
-               percpu_ref_put(&blkg->refcnt);
        }
-
+       raw_spin_unlock(&blkg_stat_lock);
 out:
        rcu_read_unlock();
 }
 
+static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
+{
+       /* Root-level stats are sourced from system-wide IO stats */
+       if (cgroup_parent(css->cgroup))
+               __blkcg_rstat_flush(css_to_blkcg(css), cpu);
+}
+
 /*
  * We source root cgroup stats from the system-wide stats to avoid
  * tracking the same information twice and incurring overhead when no
@@ -2075,7 +2098,6 @@ void blk_cgroup_bio_start(struct bio *bio)
 
                llist_add(&bis->lnode, lhead);
                WRITE_ONCE(bis->lqueued, true);
-               percpu_ref_get(&bis->blkg->refcnt);
        }
 
        u64_stats_update_end_irqrestore(&bis->sync, flags);
index f6dad08..850bfb8 100644 (file)
@@ -683,6 +683,10 @@ static void __blk_mq_free_request(struct request *rq)
        blk_crypto_free_request(rq);
        blk_pm_mark_last_busy(rq);
        rq->mq_hctx = NULL;
+
+       if (rq->rq_flags & RQF_MQ_INFLIGHT)
+               __blk_mq_dec_active_requests(hctx);
+
        if (rq->tag != BLK_MQ_NO_TAG)
                blk_mq_put_tag(hctx->tags, ctx, rq->tag);
        if (sched_tag != BLK_MQ_NO_TAG)
@@ -694,15 +698,11 @@ static void __blk_mq_free_request(struct request *rq)
 void blk_mq_free_request(struct request *rq)
 {
        struct request_queue *q = rq->q;
-       struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
 
        if ((rq->rq_flags & RQF_ELVPRIV) &&
            q->elevator->type->ops.finish_request)
                q->elevator->type->ops.finish_request(rq);
 
-       if (rq->rq_flags & RQF_MQ_INFLIGHT)
-               __blk_mq_dec_active_requests(hctx);
-
        if (unlikely(laptop_mode && !blk_rq_is_passthrough(rq)))
                laptop_io_completion(q->disk->bdi);
 
index eca5671..50c933f 100644 (file)
@@ -380,9 +380,10 @@ int public_key_verify_signature(const struct public_key *pkey,
        struct crypto_wait cwait;
        struct crypto_akcipher *tfm;
        struct akcipher_request *req;
-       struct scatterlist src_sg[2];
+       struct scatterlist src_sg;
        char alg_name[CRYPTO_MAX_ALG_NAME];
-       char *key, *ptr;
+       char *buf, *ptr;
+       size_t buf_len;
        int ret;
 
        pr_devel("==>%s()\n", __func__);
@@ -420,34 +421,37 @@ int public_key_verify_signature(const struct public_key *pkey,
        if (!req)
                goto error_free_tfm;
 
-       key = kmalloc(pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
-                     GFP_KERNEL);
-       if (!key)
+       buf_len = max_t(size_t, pkey->keylen + sizeof(u32) * 2 + pkey->paramlen,
+                       sig->s_size + sig->digest_size);
+
+       buf = kmalloc(buf_len, GFP_KERNEL);
+       if (!buf)
                goto error_free_req;
 
-       memcpy(key, pkey->key, pkey->keylen);
-       ptr = key + pkey->keylen;
+       memcpy(buf, pkey->key, pkey->keylen);
+       ptr = buf + pkey->keylen;
        ptr = pkey_pack_u32(ptr, pkey->algo);
        ptr = pkey_pack_u32(ptr, pkey->paramlen);
        memcpy(ptr, pkey->params, pkey->paramlen);
 
        if (pkey->key_is_private)
-               ret = crypto_akcipher_set_priv_key(tfm, key, pkey->keylen);
+               ret = crypto_akcipher_set_priv_key(tfm, buf, pkey->keylen);
        else
-               ret = crypto_akcipher_set_pub_key(tfm, key, pkey->keylen);
+               ret = crypto_akcipher_set_pub_key(tfm, buf, pkey->keylen);
        if (ret)
-               goto error_free_key;
+               goto error_free_buf;
 
        if (strcmp(pkey->pkey_algo, "sm2") == 0 && sig->data_size) {
                ret = cert_sig_digest_update(sig, tfm);
                if (ret)
-                       goto error_free_key;
+                       goto error_free_buf;
        }
 
-       sg_init_table(src_sg, 2);
-       sg_set_buf(&src_sg[0], sig->s, sig->s_size);
-       sg_set_buf(&src_sg[1], sig->digest, sig->digest_size);
-       akcipher_request_set_crypt(req, src_sg, NULL, sig->s_size,
+       memcpy(buf, sig->s, sig->s_size);
+       memcpy(buf + sig->s_size, sig->digest, sig->digest_size);
+
+       sg_init_one(&src_sg, buf, sig->s_size + sig->digest_size);
+       akcipher_request_set_crypt(req, &src_sg, NULL, sig->s_size,
                                   sig->digest_size);
        crypto_init_wait(&cwait);
        akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
@@ -455,8 +459,8 @@ int public_key_verify_signature(const struct public_key *pkey,
                                      crypto_req_done, &cwait);
        ret = crypto_wait_req(crypto_akcipher_verify(req), &cwait);
 
-error_free_key:
-       kfree(key);
+error_free_buf:
+       kfree(buf);
 error_free_req:
        akcipher_request_free(req);
 error_free_tfm:
index 9bdf168..1a4c4ed 100644 (file)
@@ -7,6 +7,7 @@ config DRM_ACCEL_IVPU
        depends on PCI && PCI_MSI
        select FW_LOADER
        select SHMEM
+       select GENERIC_ALLOCATOR
        help
          Choose this option if you have a system that has an 14th generation Intel CPU
          or newer. VPU stands for Versatile Processing Unit and it's a CPU-integrated
index 382ec12..fef3542 100644 (file)
@@ -197,6 +197,11 @@ static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev)
        hw->pll.pn_ratio = clamp_t(u8, fuse_pn_ratio, hw->pll.min_ratio, hw->pll.max_ratio);
 }
 
+static int ivpu_hw_mtl_wait_for_vpuip_bar(struct ivpu_device *vdev)
+{
+       return REGV_POLL_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, AON, 0, 100);
+}
+
 static int ivpu_pll_drive(struct ivpu_device *vdev, bool enable)
 {
        struct ivpu_hw_info *hw = vdev->hw;
@@ -239,6 +244,12 @@ static int ivpu_pll_drive(struct ivpu_device *vdev, bool enable)
                        ivpu_err(vdev, "Timed out waiting for PLL ready status\n");
                        return ret;
                }
+
+               ret = ivpu_hw_mtl_wait_for_vpuip_bar(vdev);
+               if (ret) {
+                       ivpu_err(vdev, "Timed out waiting for VPUIP bar\n");
+                       return ret;
+               }
        }
 
        return 0;
@@ -256,7 +267,7 @@ static int ivpu_pll_disable(struct ivpu_device *vdev)
 
 static void ivpu_boot_host_ss_rst_clr_assert(struct ivpu_device *vdev)
 {
-       u32 val = REGV_RD32(MTL_VPU_HOST_SS_CPR_RST_CLR);
+       u32 val = 0;
 
        val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, TOP_NOC, val);
        val = REG_SET_FLD(MTL_VPU_HOST_SS_CPR_RST_CLR, DSS_MAS, val);
@@ -754,9 +765,8 @@ static int ivpu_hw_mtl_power_down(struct ivpu_device *vdev)
 {
        int ret = 0;
 
-       if (ivpu_hw_mtl_reset(vdev)) {
+       if (!ivpu_hw_mtl_is_idle(vdev) && ivpu_hw_mtl_reset(vdev)) {
                ivpu_err(vdev, "Failed to reset the VPU\n");
-               ret = -EIO;
        }
 
        if (ivpu_pll_disable(vdev)) {
@@ -764,8 +774,10 @@ static int ivpu_hw_mtl_power_down(struct ivpu_device *vdev)
                ret = -EIO;
        }
 
-       if (ivpu_hw_mtl_d0i3_enable(vdev))
-               ivpu_warn(vdev, "Failed to enable D0I3\n");
+       if (ivpu_hw_mtl_d0i3_enable(vdev)) {
+               ivpu_err(vdev, "Failed to enter D0I3\n");
+               ret = -EIO;
+       }
 
        return ret;
 }
index d83ccfd..593b8ff 100644 (file)
@@ -91,6 +91,7 @@
 #define MTL_VPU_HOST_SS_CPR_RST_SET_MSS_MAS_MASK                       BIT_MASK(11)
 
 #define MTL_VPU_HOST_SS_CPR_RST_CLR                                    0x00000098u
+#define MTL_VPU_HOST_SS_CPR_RST_CLR_AON_MASK                           BIT_MASK(0)
 #define MTL_VPU_HOST_SS_CPR_RST_CLR_TOP_NOC_MASK                       BIT_MASK(1)
 #define MTL_VPU_HOST_SS_CPR_RST_CLR_DSS_MAS_MASK                       BIT_MASK(10)
 #define MTL_VPU_HOST_SS_CPR_RST_CLR_MSS_MAS_MASK                       BIT_MASK(11)
index 3adcfa8..fa0af59 100644 (file)
@@ -183,9 +183,7 @@ ivpu_ipc_send(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct v
        struct ivpu_ipc_info *ipc = vdev->ipc;
        int ret;
 
-       ret = mutex_lock_interruptible(&ipc->lock);
-       if (ret)
-               return ret;
+       mutex_lock(&ipc->lock);
 
        if (!ipc->on) {
                ret = -EAGAIN;
index 3c6f1e1..d45be06 100644 (file)
@@ -431,6 +431,7 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
        struct ivpu_file_priv *file_priv = file->driver_priv;
        struct ivpu_device *vdev = file_priv->vdev;
        struct ww_acquire_ctx acquire_ctx;
+       enum dma_resv_usage usage;
        struct ivpu_bo *bo;
        int ret;
        u32 i;
@@ -461,22 +462,28 @@ ivpu_job_prepare_bos_for_submit(struct drm_file *file, struct ivpu_job *job, u32
 
        job->cmd_buf_vpu_addr = bo->vpu_addr + commands_offset;
 
-       ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx);
+       ret = drm_gem_lock_reservations((struct drm_gem_object **)job->bos, buf_count,
+                                       &acquire_ctx);
        if (ret) {
                ivpu_warn(vdev, "Failed to lock reservations: %d\n", ret);
                return ret;
        }
 
-       ret = dma_resv_reserve_fences(bo->base.resv, 1);
-       if (ret) {
-               ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
-               goto unlock_reservations;
+       for (i = 0; i < buf_count; i++) {
+               ret = dma_resv_reserve_fences(job->bos[i]->base.resv, 1);
+               if (ret) {
+                       ivpu_warn(vdev, "Failed to reserve fences: %d\n", ret);
+                       goto unlock_reservations;
+               }
        }
 
-       dma_resv_add_fence(bo->base.resv, job->done_fence, DMA_RESV_USAGE_WRITE);
+       for (i = 0; i < buf_count; i++) {
+               usage = (i == CMD_BUF_IDX) ? DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_BOOKKEEP;
+               dma_resv_add_fence(job->bos[i]->base.resv, job->done_fence, usage);
+       }
 
 unlock_reservations:
-       drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, 1, &acquire_ctx);
+       drm_gem_unlock_reservations((struct drm_gem_object **)job->bos, buf_count, &acquire_ctx);
 
        wmb(); /* Flush write combining buffers */
 
index 694e978..b8b259b 100644 (file)
@@ -587,16 +587,11 @@ static int ivpu_mmu_strtab_init(struct ivpu_device *vdev)
 int ivpu_mmu_invalidate_tlb(struct ivpu_device *vdev, u16 ssid)
 {
        struct ivpu_mmu_info *mmu = vdev->mmu;
-       int ret;
-
-       ret = mutex_lock_interruptible(&mmu->lock);
-       if (ret)
-               return ret;
+       int ret = 0;
 
-       if (!mmu->on) {
-               ret = 0;
+       mutex_lock(&mmu->lock);
+       if (!mmu->on)
                goto unlock;
-       }
 
        ret = ivpu_mmu_cmdq_write_tlbi_nh_asid(vdev, ssid);
        if (ret)
@@ -614,7 +609,7 @@ static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma)
        struct ivpu_mmu_cdtab *cdtab = &mmu->cdtab;
        u64 *entry;
        u64 cd[4];
-       int ret;
+       int ret = 0;
 
        if (ssid > IVPU_MMU_CDTAB_ENT_COUNT)
                return -EINVAL;
@@ -655,14 +650,9 @@ static int ivpu_mmu_cd_add(struct ivpu_device *vdev, u32 ssid, u64 cd_dma)
        ivpu_dbg(vdev, MMU, "CDTAB %s entry (SSID=%u, dma=%pad): 0x%llx, 0x%llx, 0x%llx, 0x%llx\n",
                 cd_dma ? "write" : "clear", ssid, &cd_dma, cd[0], cd[1], cd[2], cd[3]);
 
-       ret = mutex_lock_interruptible(&mmu->lock);
-       if (ret)
-               return ret;
-
-       if (!mmu->on) {
-               ret = 0;
+       mutex_lock(&mmu->lock);
+       if (!mmu->on)
                goto unlock;
-       }
 
        ret = ivpu_mmu_cmdq_write_cfgi_all(vdev);
        if (ret)
index 2d0828d..b5ba550 100644 (file)
@@ -97,6 +97,7 @@ static int qaic_open(struct drm_device *dev, struct drm_file *file)
 
 cleanup_usr:
        cleanup_srcu_struct(&usr->qddev_lock);
+       ida_free(&qaic_usrs, usr->handle);
 free_usr:
        kfree(usr);
 dev_unlock:
@@ -224,6 +225,9 @@ static void qaic_destroy_drm_device(struct qaic_device *qdev, s32 partition_id)
        struct qaic_user *usr;
 
        qddev = qdev->qddev;
+       qdev->qddev = NULL;
+       if (!qddev)
+               return;
 
        /*
         * Existing users get unresolvable errors till they close FDs.
index 19aff80..8d51269 100644 (file)
@@ -9,8 +9,6 @@
 #include <linux/idr.h>
 #include <linux/io.h>
 
-#include <linux/arm-smccc.h>
-
 static struct acpi_ffh_info ffh_ctx;
 
 int __weak acpi_ffh_address_space_arch_setup(void *handler_ctxt,
index 77186f0..539e700 100644 (file)
@@ -201,11 +201,19 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
        writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
 }
 
-/* BSW PWM used for backlight control by the i915 driver */
+/*
+ * BSW PWM1 is used for backlight control by the i915 driver
+ * BSW PWM2 is used for backlight control for fixed (etched into the glass)
+ * touch controls on some models. These touch-controls have specialized
+ * drivers which know they need the "pwm_soc_lpss_2" con-id.
+ */
 static struct pwm_lookup bsw_pwm_lookup[] = {
        PWM_LOOKUP_WITH_MODULE("80862288:00", 0, "0000:00:02.0",
                               "pwm_soc_backlight", 0, PWM_POLARITY_NORMAL,
                               "pwm-lpss-platform"),
+       PWM_LOOKUP_WITH_MODULE("80862289:00", 0, NULL,
+                              "pwm_soc_lpss_2", 0, PWM_POLARITY_NORMAL,
+                              "pwm-lpss-platform"),
 };
 
 static void bsw_pwm_setup(struct lpss_private_data *pdata)
index 02f1a1b..7a453c5 100644 (file)
@@ -66,6 +66,7 @@ static void power_saving_mwait_init(void)
        case X86_VENDOR_AMD:
        case X86_VENDOR_INTEL:
        case X86_VENDOR_ZHAOXIN:
+       case X86_VENDOR_CENTAUR:
                /*
                 * AMD Fam10h TSC will tick in all
                 * C/P/S0/S1 states when this bit is set.
index ebf8fd3..79bbfe0 100644 (file)
@@ -101,8 +101,6 @@ acpi_status
 acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info,
                       acpi_event_status *event_status);
 
-acpi_status acpi_hw_disable_all_gpes(void);
-
 acpi_status acpi_hw_enable_all_runtime_gpes(void);
 
 acpi_status acpi_hw_enable_all_wakeup_gpes(void);
index d161ff7..b6ab360 100644 (file)
@@ -530,65 +530,30 @@ static void acpi_notify_device(acpi_handle handle, u32 event, void *data)
        acpi_drv->ops.notify(device, event);
 }
 
-static void acpi_notify_device_fixed(void *data)
-{
-       struct acpi_device *device = data;
-
-       /* Fixed hardware devices have no handles */
-       acpi_notify_device(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
-}
-
-static u32 acpi_device_fixed_event(void *data)
-{
-       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_notify_device_fixed, data);
-       return ACPI_INTERRUPT_HANDLED;
-}
-
 static int acpi_device_install_notify_handler(struct acpi_device *device,
                                              struct acpi_driver *acpi_drv)
 {
-       acpi_status status;
-
-       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
-               status =
-                   acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                                    acpi_device_fixed_event,
-                                                    device);
-       } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
-               status =
-                   acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                                    acpi_device_fixed_event,
-                                                    device);
-       } else {
-               u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
+       u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
                                ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
+       acpi_status status;
 
-               status = acpi_install_notify_handler(device->handle, type,
-                                                    acpi_notify_device,
-                                                    device);
-       }
-
+       status = acpi_install_notify_handler(device->handle, type,
+                                            acpi_notify_device, device);
        if (ACPI_FAILURE(status))
                return -EINVAL;
+
        return 0;
 }
 
 static void acpi_device_remove_notify_handler(struct acpi_device *device,
                                              struct acpi_driver *acpi_drv)
 {
-       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
-               acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                               acpi_device_fixed_event);
-       } else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) {
-               acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                               acpi_device_fixed_event);
-       } else {
-               u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
+       u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ?
                                ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY;
 
-               acpi_remove_notify_handler(device->handle, type,
-                                          acpi_notify_device);
-       }
+       acpi_remove_notify_handler(device->handle, type,
+                                  acpi_notify_device);
+
        acpi_os_wait_events_complete();
 }
 
index 475e1ed..1e76a64 100644 (file)
@@ -78,6 +78,15 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
                .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
        },
        {
+               /* Nextbook Ares 8A tablet, _LID device always reports lid closed */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "M882"),
+               },
+               .driver_data = (void *)(long)ACPI_BUTTON_LID_INIT_DISABLED,
+       },
+       {
                /*
                 * Lenovo Yoga 9 14ITL5, initial notification of the LID device
                 * never happens.
@@ -126,7 +135,6 @@ static const struct dmi_system_id dmi_lid_quirks[] = {
 
 static int acpi_button_add(struct acpi_device *device);
 static void acpi_button_remove(struct acpi_device *device);
-static void acpi_button_notify(struct acpi_device *device, u32 event);
 
 #ifdef CONFIG_PM_SLEEP
 static int acpi_button_suspend(struct device *dev);
@@ -144,7 +152,6 @@ static struct acpi_driver acpi_button_driver = {
        .ops = {
                .add = acpi_button_add,
                .remove = acpi_button_remove,
-               .notify = acpi_button_notify,
        },
        .drv.pm = &acpi_button_pm,
 };
@@ -400,45 +407,65 @@ static void acpi_lid_initialize_state(struct acpi_device *device)
        button->lid_state_initialized = true;
 }
 
-static void acpi_button_notify(struct acpi_device *device, u32 event)
+static void acpi_lid_notify(acpi_handle handle, u32 event, void *data)
 {
-       struct acpi_button *button = acpi_driver_data(device);
+       struct acpi_device *device = data;
+       struct acpi_button *button;
+
+       if (event != ACPI_BUTTON_NOTIFY_STATUS) {
+               acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
+                                 event);
+               return;
+       }
+
+       button = acpi_driver_data(device);
+       if (!button->lid_state_initialized)
+               return;
+
+       acpi_lid_update_state(device, true);
+}
+
+static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct acpi_device *device = data;
+       struct acpi_button *button;
        struct input_dev *input;
+       int keycode;
 
-       switch (event) {
-       case ACPI_FIXED_HARDWARE_EVENT:
-               event = ACPI_BUTTON_NOTIFY_STATUS;
-               fallthrough;
-       case ACPI_BUTTON_NOTIFY_STATUS:
-               input = button->input;
-               if (button->type == ACPI_BUTTON_TYPE_LID) {
-                       if (button->lid_state_initialized)
-                               acpi_lid_update_state(device, true);
-               } else {
-                       int keycode;
-
-                       acpi_pm_wakeup_event(&device->dev);
-                       if (button->suspended)
-                               break;
-
-                       keycode = test_bit(KEY_SLEEP, input->keybit) ?
-                                               KEY_SLEEP : KEY_POWER;
-                       input_report_key(input, keycode, 1);
-                       input_sync(input);
-                       input_report_key(input, keycode, 0);
-                       input_sync(input);
-
-                       acpi_bus_generate_netlink_event(
-                                       device->pnp.device_class,
-                                       dev_name(&device->dev),
-                                       event, ++button->pushed);
-               }
-               break;
-       default:
+       if (event != ACPI_BUTTON_NOTIFY_STATUS) {
                acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n",
                                  event);
-               break;
+               return;
        }
+
+       acpi_pm_wakeup_event(&device->dev);
+
+       button = acpi_driver_data(device);
+       if (button->suspended)
+               return;
+
+       input = button->input;
+       keycode = test_bit(KEY_SLEEP, input->keybit) ? KEY_SLEEP : KEY_POWER;
+
+       input_report_key(input, keycode, 1);
+       input_sync(input);
+       input_report_key(input, keycode, 0);
+       input_sync(input);
+
+       acpi_bus_generate_netlink_event(device->pnp.device_class,
+                                       dev_name(&device->dev),
+                                       event, ++button->pushed);
+}
+
+static void acpi_button_notify_run(void *data)
+{
+       acpi_button_notify(NULL, ACPI_BUTTON_NOTIFY_STATUS, data);
+}
+
+static u32 acpi_button_event(void *data)
+{
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_button_notify_run, data);
+       return ACPI_INTERRUPT_HANDLED;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -480,11 +507,13 @@ static int acpi_lid_input_open(struct input_dev *input)
 
 static int acpi_button_add(struct acpi_device *device)
 {
+       acpi_notify_handler handler;
        struct acpi_button *button;
        struct input_dev *input;
        const char *hid = acpi_device_hid(device);
+       acpi_status status;
        char *name, *class;
-       int error;
+       int error = 0;
 
        if (!strcmp(hid, ACPI_BUTTON_HID_LID) &&
             lid_init_state == ACPI_BUTTON_LID_INIT_DISABLED)
@@ -508,17 +537,20 @@ static int acpi_button_add(struct acpi_device *device)
        if (!strcmp(hid, ACPI_BUTTON_HID_POWER) ||
            !strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
                button->type = ACPI_BUTTON_TYPE_POWER;
+               handler = acpi_button_notify;
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_POWER);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
        } else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
                   !strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
                button->type = ACPI_BUTTON_TYPE_SLEEP;
+               handler = acpi_button_notify;
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
        } else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
                button->type = ACPI_BUTTON_TYPE_LID;
+               handler = acpi_lid_notify;
                strcpy(name, ACPI_BUTTON_DEVICE_NAME_LID);
                sprintf(class, "%s/%s",
                        ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
@@ -526,12 +558,15 @@ static int acpi_button_add(struct acpi_device *device)
        } else {
                pr_info("Unsupported hid [%s]\n", hid);
                error = -ENODEV;
-               goto err_free_input;
        }
 
-       error = acpi_button_add_fs(device);
-       if (error)
-               goto err_free_input;
+       if (!error)
+               error = acpi_button_add_fs(device);
+
+       if (error) {
+               input_free_device(input);
+               goto err_free_button;
+       }
 
        snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid);
 
@@ -559,6 +594,29 @@ static int acpi_button_add(struct acpi_device *device)
        error = input_register_device(input);
        if (error)
                goto err_remove_fs;
+
+       switch (device->device_type) {
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                                         acpi_button_event,
+                                                         device);
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               status = acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                                         acpi_button_event,
+                                                         device);
+               break;
+       default:
+               status = acpi_install_notify_handler(device->handle,
+                                                    ACPI_DEVICE_NOTIFY, handler,
+                                                    device);
+               break;
+       }
+       if (ACPI_FAILURE(status)) {
+               error = -ENODEV;
+               goto err_input_unregister;
+       }
+
        if (button->type == ACPI_BUTTON_TYPE_LID) {
                /*
                 * This assumes there's only one lid device, or if there are
@@ -571,11 +629,11 @@ static int acpi_button_add(struct acpi_device *device)
        pr_info("%s [%s]\n", name, acpi_device_bid(device));
        return 0;
 
- err_remove_fs:
+err_input_unregister:
+       input_unregister_device(input);
+err_remove_fs:
        acpi_button_remove_fs(device);
- err_free_input:
-       input_free_device(input);
- err_free_button:
+err_free_button:
        kfree(button);
        return error;
 }
@@ -584,6 +642,24 @@ static void acpi_button_remove(struct acpi_device *device)
 {
        struct acpi_button *button = acpi_driver_data(device);
 
+       switch (device->device_type) {
+       case ACPI_BUS_TYPE_POWER_BUTTON:
+               acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                               acpi_button_event);
+               break;
+       case ACPI_BUS_TYPE_SLEEP_BUTTON:
+               acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
+                                               acpi_button_event);
+               break;
+       default:
+               acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                          button->type == ACPI_BUTTON_TYPE_LID ?
+                                               acpi_lid_notify :
+                                               acpi_button_notify);
+               break;
+       }
+       acpi_os_wait_events_complete();
+
        acpi_button_remove_fs(device);
        input_unregister_device(button->input);
        kfree(button);
index 928899a..8569f55 100644 (file)
@@ -662,21 +662,6 @@ static void advance_transaction(struct acpi_ec *ec, bool interrupt)
 
        ec_dbg_stm("%s (%d)", interrupt ? "IRQ" : "TASK", smp_processor_id());
 
-       /*
-        * Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
-        * changes to always trigger a GPE interrupt.
-        *
-        * GPE STS is a W1C register, which means:
-        *
-        * 1. Software can clear it without worrying about clearing the other
-        *    GPEs' STS bits when the hardware sets them in parallel.
-        *
-        * 2. As long as software can ensure only clearing it when it is set,
-        *    hardware won't set it in parallel.
-        */
-       if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
-               acpi_clear_gpe(NULL, ec->gpe);
-
        status = acpi_ec_read_status(ec);
 
        /*
@@ -1287,6 +1272,22 @@ static void acpi_ec_handle_interrupt(struct acpi_ec *ec)
        unsigned long flags;
 
        spin_lock_irqsave(&ec->lock, flags);
+
+       /*
+        * Clear GPE_STS upfront to allow subsequent hardware GPE_STS 0->1
+        * changes to always trigger a GPE interrupt.
+        *
+        * GPE STS is a W1C register, which means:
+        *
+        * 1. Software can clear it without worrying about clearing the other
+        *    GPEs' STS bits when the hardware sets them in parallel.
+        *
+        * 2. As long as software can ensure only clearing it when it is set,
+        *    hardware won't set it in parallel.
+        */
+       if (ec->gpe >= 0 && acpi_ec_gpe_status_set(ec))
+               acpi_clear_gpe(NULL, ec->gpe);
+
        advance_transaction(ec, true);
        spin_unlock_irqrestore(&ec->lock, flags);
 }
index 6023ad6..573bc0d 100644 (file)
@@ -347,4 +347,6 @@ int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm,
 void acpi_nfit_desc_init(struct acpi_nfit_desc *acpi_desc, struct device *dev);
 bool intel_fwa_supported(struct nvdimm_bus *nvdimm_bus);
 extern struct device_attribute dev_attr_firmware_activate_noidle;
+void nfit_intel_shutdown_status(struct nfit_mem *nfit_mem);
+
 #endif /* __NFIT_H__ */
index 0800a9d..1dd8d5a 100644 (file)
@@ -470,52 +470,6 @@ static const struct dmi_system_id asus_laptop[] = {
        { }
 };
 
-static const struct dmi_system_id lenovo_laptop[] = {
-       {
-               .ident = "LENOVO IdeaPad Flex 5 14ALC7",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "82R9"),
-               },
-       },
-       {
-               .ident = "LENOVO IdeaPad Flex 5 16ALC7",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "82RA"),
-               },
-       },
-       { }
-};
-
-static const struct dmi_system_id tongfang_gm_rg[] = {
-       {
-               .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD",
-               .matches = {
-                       DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
-               },
-       },
-       { }
-};
-
-static const struct dmi_system_id maingear_laptop[] = {
-       {
-               .ident = "MAINGEAR Vector Pro 2 15",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"),
-               }
-       },
-       {
-               .ident = "MAINGEAR Vector Pro 2 17",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"),
-               },
-       },
-       { }
-};
-
 static const struct dmi_system_id lg_laptop[] = {
        {
                .ident = "LG Electronics 17U70P",
@@ -539,10 +493,6 @@ struct irq_override_cmp {
 static const struct irq_override_cmp override_table[] = {
        { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
        { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
-       { lenovo_laptop, 6, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true },
-       { lenovo_laptop, 10, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, true },
-       { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true },
-       { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true },
        { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
 };
 
@@ -562,16 +512,6 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
                        return entry->override;
        }
 
-#ifdef CONFIG_X86
-       /*
-        * IRQ override isn't needed on modern AMD Zen systems and
-        * this override breaks active low IRQs on AMD Ryzen 6000 and
-        * newer systems. Skip it.
-        */
-       if (boot_cpu_has(X86_FEATURE_ZEN))
-               return false;
-#endif
-
        return true;
 }
 
index 0c6f06a..1c3e1e2 100644 (file)
@@ -2029,8 +2029,6 @@ static u32 acpi_scan_check_dep(acpi_handle handle, bool check_dep)
        return count;
 }
 
-static bool acpi_bus_scan_second_pass;
-
 static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
                                      struct acpi_device **adev_p)
 {
@@ -2050,10 +2048,8 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, bool check_dep,
                        return AE_OK;
 
                /* Bail out if there are dependencies. */
-               if (acpi_scan_check_dep(handle, check_dep) > 0) {
-                       acpi_bus_scan_second_pass = true;
+               if (acpi_scan_check_dep(handle, check_dep) > 0)
                        return AE_CTRL_DEPTH;
-               }
 
                fallthrough;
        case ACPI_TYPE_ANY:     /* for ACPI_ROOT_OBJECT */
@@ -2301,6 +2297,12 @@ static bool acpi_scan_clear_dep_queue(struct acpi_device *adev)
        return true;
 }
 
+static void acpi_scan_delete_dep_data(struct acpi_dep_data *dep)
+{
+       list_del(&dep->node);
+       kfree(dep);
+}
+
 static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
 {
        struct acpi_device *adev = acpi_get_acpi_dev(dep->consumer);
@@ -2311,8 +2313,10 @@ static int acpi_scan_clear_dep(struct acpi_dep_data *dep, void *data)
                        acpi_dev_put(adev);
        }
 
-       list_del(&dep->node);
-       kfree(dep);
+       if (dep->free_when_met)
+               acpi_scan_delete_dep_data(dep);
+       else
+               dep->met = true;
 
        return 0;
 }
@@ -2406,6 +2410,55 @@ struct acpi_device *acpi_dev_get_next_consumer_dev(struct acpi_device *supplier,
 }
 EXPORT_SYMBOL_GPL(acpi_dev_get_next_consumer_dev);
 
+static void acpi_scan_postponed_branch(acpi_handle handle)
+{
+       struct acpi_device *adev = NULL;
+
+       if (ACPI_FAILURE(acpi_bus_check_add(handle, false, &adev)))
+               return;
+
+       acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
+                           acpi_bus_check_add_2, NULL, NULL, (void **)&adev);
+       acpi_bus_attach(adev, NULL);
+}
+
+static void acpi_scan_postponed(void)
+{
+       struct acpi_dep_data *dep, *tmp;
+
+       mutex_lock(&acpi_dep_list_lock);
+
+       list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+               acpi_handle handle = dep->consumer;
+
+               /*
+                * In case there are multiple acpi_dep_list entries with the
+                * same consumer, skip the current entry if the consumer device
+                * object corresponding to it is present already.
+                */
+               if (!acpi_fetch_acpi_dev(handle)) {
+                       /*
+                        * Even though the lock is released here, tmp is
+                        * guaranteed to be valid, because none of the list
+                        * entries following dep is marked as "free when met"
+                        * and so they cannot be deleted.
+                        */
+                       mutex_unlock(&acpi_dep_list_lock);
+
+                       acpi_scan_postponed_branch(handle);
+
+                       mutex_lock(&acpi_dep_list_lock);
+               }
+
+               if (dep->met)
+                       acpi_scan_delete_dep_data(dep);
+               else
+                       dep->free_when_met = true;
+       }
+
+       mutex_unlock(&acpi_dep_list_lock);
+}
+
 /**
  * acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
  * @handle: Root of the namespace scope to scan.
@@ -2424,8 +2477,6 @@ int acpi_bus_scan(acpi_handle handle)
 {
        struct acpi_device *device = NULL;
 
-       acpi_bus_scan_second_pass = false;
-
        /* Pass 1: Avoid enumerating devices with missing dependencies. */
 
        if (ACPI_SUCCESS(acpi_bus_check_add(handle, true, &device)))
@@ -2438,19 +2489,9 @@ int acpi_bus_scan(acpi_handle handle)
 
        acpi_bus_attach(device, (void *)true);
 
-       if (!acpi_bus_scan_second_pass)
-               return 0;
-
        /* Pass 2: Enumerate all of the remaining devices. */
 
-       device = NULL;
-
-       if (ACPI_SUCCESS(acpi_bus_check_add(handle, false, &device)))
-               acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
-                                   acpi_bus_check_add_2, NULL, NULL,
-                                   (void **)&device);
-
-       acpi_bus_attach(device, NULL);
+       acpi_scan_postponed();
 
        return 0;
 }
index 72470b9..808484d 100644 (file)
@@ -636,11 +636,19 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        }
 
        /*
-        * Disable and clear GPE status before interrupt is enabled. Some GPEs
-        * (like wakeup GPE) haven't handler, this can avoid such GPE misfire.
-        * acpi_leave_sleep_state will reenable specific GPEs later
+        * Disable all GPE and clear their status bits before interrupts are
+        * enabled. Some GPEs (like wakeup GPEs) have no handlers and this can
+        * prevent them from producing spurious interrups.
+        *
+        * acpi_leave_sleep_state() will reenable specific GPEs later.
+        *
+        * Because this code runs on one CPU with disabled interrupts (all of
+        * the other CPUs are offline at this time), it need not acquire any
+        * sleeping locks which may trigger an implicit preemption point even
+        * if there is no contention, so avoid doing that by using a low-level
+        * library routine here.
         */
-       acpi_disable_all_gpes();
+       acpi_hw_disable_all_gpes();
        /* Allow EC transactions to happen. */
        acpi_ec_unblock_transactions();
 
@@ -840,7 +848,7 @@ void __weak acpi_s2idle_setup(void)
        s2idle_set_ops(&acpi_s2idle_ops);
 }
 
-static void acpi_sleep_suspend_setup(void)
+static void __init acpi_sleep_suspend_setup(void)
 {
        bool suspend_ops_needed = false;
        int i;
index 4720a36..f9f6ebb 100644 (file)
 #define ACPI_THERMAL_NOTIFY_HOT                0xF1
 #define ACPI_THERMAL_MODE_ACTIVE       0x00
 
-#define ACPI_THERMAL_MAX_ACTIVE        10
-#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
+#define ACPI_THERMAL_MAX_ACTIVE                10
+#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
 
-MODULE_AUTHOR("Paul Diefenbaugh");
-MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
-MODULE_LICENSE("GPL");
+#define ACPI_TRIPS_CRITICAL    BIT(0)
+#define ACPI_TRIPS_HOT         BIT(1)
+#define ACPI_TRIPS_PASSIVE     BIT(2)
+#define ACPI_TRIPS_ACTIVE      BIT(3)
+#define ACPI_TRIPS_DEVICES     BIT(4)
+
+#define ACPI_TRIPS_THRESHOLDS  (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
+
+#define ACPI_TRIPS_INIT                (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
+                                ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
+                                ACPI_TRIPS_DEVICES)
+
+/*
+ * This exception is thrown out in two cases:
+ * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
+ *   when re-evaluating the AML code.
+ * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
+ *   We need to re-bind the cooling devices of a thermal zone when this occurs.
+ */
+#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, tz, str) \
+do { \
+       if (flags != ACPI_TRIPS_INIT) \
+               acpi_handle_info(tz->device->handle, \
+                       "ACPI thermal trip point %s changed\n" \
+                       "Please report to linux-acpi@vger.kernel.org\n", str); \
+} while (0)
 
 static int act;
 module_param(act, int, 0644);
@@ -73,75 +96,30 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
 
 static struct workqueue_struct *acpi_thermal_pm_queue;
 
-static int acpi_thermal_add(struct acpi_device *device);
-static void acpi_thermal_remove(struct acpi_device *device);
-static void acpi_thermal_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id  thermal_device_ids[] = {
-       {ACPI_THERMAL_HID, 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
-
-#ifdef CONFIG_PM_SLEEP
-static int acpi_thermal_suspend(struct device *dev);
-static int acpi_thermal_resume(struct device *dev);
-#else
-#define acpi_thermal_suspend NULL
-#define acpi_thermal_resume NULL
-#endif
-static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
-
-static struct acpi_driver acpi_thermal_driver = {
-       .name = "thermal",
-       .class = ACPI_THERMAL_CLASS,
-       .ids = thermal_device_ids,
-       .ops = {
-               .add = acpi_thermal_add,
-               .remove = acpi_thermal_remove,
-               .notify = acpi_thermal_notify,
-               },
-       .drv.pm = &acpi_thermal_pm,
-};
-
-struct acpi_thermal_state {
-       u8 critical:1;
-       u8 hot:1;
-       u8 passive:1;
-       u8 active:1;
-       u8 reserved:4;
-       int active_index;
-};
-
-struct acpi_thermal_state_flags {
-       u8 valid:1;
-       u8 enabled:1;
-       u8 reserved:6;
-};
-
 struct acpi_thermal_critical {
-       struct acpi_thermal_state_flags flags;
        unsigned long temperature;
+       bool valid;
 };
 
 struct acpi_thermal_hot {
-       struct acpi_thermal_state_flags flags;
        unsigned long temperature;
+       bool valid;
 };
 
 struct acpi_thermal_passive {
-       struct acpi_thermal_state_flags flags;
+       struct acpi_handle_list devices;
        unsigned long temperature;
        unsigned long tc1;
        unsigned long tc2;
        unsigned long tsp;
-       struct acpi_handle_list devices;
+       bool valid;
 };
 
 struct acpi_thermal_active {
-       struct acpi_thermal_state_flags flags;
-       unsigned long temperature;
        struct acpi_handle_list devices;
+       unsigned long temperature;
+       bool valid;
+       bool enabled;
 };
 
 struct acpi_thermal_trips {
@@ -151,12 +129,6 @@ struct acpi_thermal_trips {
        struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
 };
 
-struct acpi_thermal_flags {
-       u8 cooling_mode:1;      /* _SCP */
-       u8 devices:1;           /* _TZD */
-       u8 reserved:6;
-};
-
 struct acpi_thermal {
        struct acpi_device *device;
        acpi_bus_id name;
@@ -164,8 +136,6 @@ struct acpi_thermal {
        unsigned long last_temperature;
        unsigned long polling_frequency;
        volatile u8 zombie;
-       struct acpi_thermal_flags flags;
-       struct acpi_thermal_state state;
        struct acpi_thermal_trips trips;
        struct acpi_handle_list devices;
        struct thermal_zone_device *thermal_zone;
@@ -220,52 +190,12 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
        return 0;
 }
 
-static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
-{
-       if (!tz)
-               return -EINVAL;
-
-       if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
-                                                   "_SCP", mode)))
-               return -ENODEV;
-
-       return 0;
-}
-
-#define ACPI_TRIPS_CRITICAL    0x01
-#define ACPI_TRIPS_HOT         0x02
-#define ACPI_TRIPS_PASSIVE     0x04
-#define ACPI_TRIPS_ACTIVE      0x08
-#define ACPI_TRIPS_DEVICES     0x10
-
-#define ACPI_TRIPS_REFRESH_THRESHOLDS  (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
-#define ACPI_TRIPS_REFRESH_DEVICES     ACPI_TRIPS_DEVICES
-
-#define ACPI_TRIPS_INIT      (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT |   \
-                             ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE |  \
-                             ACPI_TRIPS_DEVICES)
-
-/*
- * This exception is thrown out in two cases:
- * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
- *   when re-evaluating the AML code.
- * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
- *   We need to re-bind the cooling devices of a thermal zone when this occurs.
- */
-#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, tz, str)   \
-do {   \
-       if (flags != ACPI_TRIPS_INIT)   \
-               acpi_handle_info(tz->device->handle,    \
-               "ACPI thermal trip point %s changed\n"  \
-               "Please report to linux-acpi@vger.kernel.org\n", str); \
-} while (0)
-
 static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 {
        acpi_status status;
        unsigned long long tmp;
        struct acpi_handle_list devices;
-       int valid = 0;
+       bool valid = false;
        int i;
 
        /* Critical Shutdown */
@@ -279,21 +209,21 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                 * ... so lets discard those as invalid.
                 */
                if (ACPI_FAILURE(status)) {
-                       tz->trips.critical.flags.valid = 0;
+                       tz->trips.critical.valid = false;
                        acpi_handle_debug(tz->device->handle,
                                          "No critical threshold\n");
                } else if (tmp <= 2732) {
                        pr_info(FW_BUG "Invalid critical threshold (%llu)\n", tmp);
-                       tz->trips.critical.flags.valid = 0;
+                       tz->trips.critical.valid = false;
                } else {
-                       tz->trips.critical.flags.valid = 1;
+                       tz->trips.critical.valid = true;
                        acpi_handle_debug(tz->device->handle,
                                          "Found critical threshold [%lu]\n",
                                          tz->trips.critical.temperature);
                }
-               if (tz->trips.critical.flags.valid) {
+               if (tz->trips.critical.valid) {
                        if (crt == -1) {
-                               tz->trips.critical.flags.valid = 0;
+                               tz->trips.critical.valid = false;
                        } else if (crt > 0) {
                                unsigned long crt_k = celsius_to_deci_kelvin(crt);
 
@@ -312,12 +242,12 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        if (flag & ACPI_TRIPS_HOT) {
                status = acpi_evaluate_integer(tz->device->handle, "_HOT", NULL, &tmp);
                if (ACPI_FAILURE(status)) {
-                       tz->trips.hot.flags.valid = 0;
+                       tz->trips.hot.valid = false;
                        acpi_handle_debug(tz->device->handle,
                                          "No hot threshold\n");
                } else {
                        tz->trips.hot.temperature = tmp;
-                       tz->trips.hot.flags.valid = 1;
+                       tz->trips.hot.valid = true;
                        acpi_handle_debug(tz->device->handle,
                                          "Found hot threshold [%lu]\n",
                                          tz->trips.hot.temperature);
@@ -325,9 +255,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
        }
 
        /* Passive (optional) */
-       if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
+       if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.valid) ||
            flag == ACPI_TRIPS_INIT) {
-               valid = tz->trips.passive.flags.valid;
+               valid = tz->trips.passive.valid;
                if (psv == -1) {
                        status = AE_SUPPORT;
                } else if (psv > 0) {
@@ -339,44 +269,44 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                }
 
                if (ACPI_FAILURE(status)) {
-                       tz->trips.passive.flags.valid = 0;
+                       tz->trips.passive.valid = false;
                } else {
                        tz->trips.passive.temperature = tmp;
-                       tz->trips.passive.flags.valid = 1;
+                       tz->trips.passive.valid = true;
                        if (flag == ACPI_TRIPS_INIT) {
                                status = acpi_evaluate_integer(tz->device->handle,
                                                               "_TC1", NULL, &tmp);
                                if (ACPI_FAILURE(status))
-                                       tz->trips.passive.flags.valid = 0;
+                                       tz->trips.passive.valid = false;
                                else
                                        tz->trips.passive.tc1 = tmp;
 
                                status = acpi_evaluate_integer(tz->device->handle,
                                                               "_TC2", NULL, &tmp);
                                if (ACPI_FAILURE(status))
-                                       tz->trips.passive.flags.valid = 0;
+                                       tz->trips.passive.valid = false;
                                else
                                        tz->trips.passive.tc2 = tmp;
 
                                status = acpi_evaluate_integer(tz->device->handle,
                                                               "_TSP", NULL, &tmp);
                                if (ACPI_FAILURE(status))
-                                       tz->trips.passive.flags.valid = 0;
+                                       tz->trips.passive.valid = false;
                                else
                                        tz->trips.passive.tsp = tmp;
                        }
                }
        }
-       if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
+       if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.valid) {
                memset(&devices, 0, sizeof(struct acpi_handle_list));
                status = acpi_evaluate_reference(tz->device->handle, "_PSL",
                                                 NULL, &devices);
                if (ACPI_FAILURE(status)) {
                        acpi_handle_info(tz->device->handle,
                                         "Invalid passive threshold\n");
-                       tz->trips.passive.flags.valid = 0;
+                       tz->trips.passive.valid = false;
                } else {
-                       tz->trips.passive.flags.valid = 1;
+                       tz->trips.passive.valid = true;
                }
 
                if (memcmp(&tz->trips.passive.devices, &devices,
@@ -387,24 +317,24 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                }
        }
        if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
-               if (valid != tz->trips.passive.flags.valid)
+               if (valid != tz->trips.passive.valid)
                        ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
        }
 
        /* Active (optional) */
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
                char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
-               valid = tz->trips.active[i].flags.valid;
+               valid = tz->trips.active[i].valid;
 
                if (act == -1)
                        break; /* disable all active trip points */
 
                if (flag == ACPI_TRIPS_INIT || ((flag & ACPI_TRIPS_ACTIVE) &&
-                   tz->trips.active[i].flags.valid)) {
+                   tz->trips.active[i].valid)) {
                        status = acpi_evaluate_integer(tz->device->handle,
                                                       name, NULL, &tmp);
                        if (ACPI_FAILURE(status)) {
-                               tz->trips.active[i].flags.valid = 0;
+                               tz->trips.active[i].valid = false;
                                if (i == 0)
                                        break;
 
@@ -426,21 +356,21 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                                break;
                        } else {
                                tz->trips.active[i].temperature = tmp;
-                               tz->trips.active[i].flags.valid = 1;
+                               tz->trips.active[i].valid = true;
                        }
                }
 
                name[2] = 'L';
-               if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid) {
+               if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].valid) {
                        memset(&devices, 0, sizeof(struct acpi_handle_list));
                        status = acpi_evaluate_reference(tz->device->handle,
                                                         name, NULL, &devices);
                        if (ACPI_FAILURE(status)) {
                                acpi_handle_info(tz->device->handle,
                                                 "Invalid active%d threshold\n", i);
-                               tz->trips.active[i].flags.valid = 0;
+                               tz->trips.active[i].valid = false;
                        } else {
-                               tz->trips.active[i].flags.valid = 1;
+                               tz->trips.active[i].valid = true;
                        }
 
                        if (memcmp(&tz->trips.active[i].devices, &devices,
@@ -451,10 +381,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
                        }
                }
                if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
-                       if (valid != tz->trips.active[i].flags.valid)
+                       if (valid != tz->trips.active[i].valid)
                                ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state");
 
-               if (!tz->trips.active[i].flags.valid)
+               if (!tz->trips.active[i].valid)
                        break;
        }
 
@@ -474,17 +404,18 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
 
 static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
 {
-       int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
+       int i, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
+       bool valid;
 
        if (ret)
                return ret;
 
-       valid = tz->trips.critical.flags.valid |
-               tz->trips.hot.flags.valid |
-               tz->trips.passive.flags.valid;
+       valid = tz->trips.critical.valid |
+               tz->trips.hot.valid |
+               tz->trips.passive.valid;
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
-               valid |= tz->trips.active[i].flags.valid;
+               valid = valid || tz->trips.active[i].valid;
 
        if (!valid) {
                pr_warn(FW_BUG "No valid trip found\n");
@@ -521,7 +452,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
        if (!tz || trip < 0)
                return -EINVAL;
 
-       if (tz->trips.critical.flags.valid) {
+       if (tz->trips.critical.valid) {
                if (!trip) {
                        *type = THERMAL_TRIP_CRITICAL;
                        return 0;
@@ -529,7 +460,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       if (tz->trips.hot.flags.valid) {
+       if (tz->trips.hot.valid) {
                if (!trip) {
                        *type = THERMAL_TRIP_HOT;
                        return 0;
@@ -537,7 +468,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       if (tz->trips.passive.flags.valid) {
+       if (tz->trips.passive.valid) {
                if (!trip) {
                        *type = THERMAL_TRIP_PASSIVE;
                        return 0;
@@ -545,7 +476,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].flags.valid; i++) {
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) {
                if (!trip) {
                        *type = THERMAL_TRIP_ACTIVE;
                        return 0;
@@ -565,7 +496,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
        if (!tz || trip < 0)
                return -EINVAL;
 
-       if (tz->trips.critical.flags.valid) {
+       if (tz->trips.critical.valid) {
                if (!trip) {
                        *temp = deci_kelvin_to_millicelsius_with_offset(
                                        tz->trips.critical.temperature,
@@ -575,7 +506,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       if (tz->trips.hot.flags.valid) {
+       if (tz->trips.hot.valid) {
                if (!trip) {
                        *temp = deci_kelvin_to_millicelsius_with_offset(
                                        tz->trips.hot.temperature,
@@ -585,7 +516,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       if (tz->trips.passive.flags.valid) {
+       if (tz->trips.passive.valid) {
                if (!trip) {
                        *temp = deci_kelvin_to_millicelsius_with_offset(
                                        tz->trips.passive.temperature,
@@ -596,7 +527,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
        }
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
-               tz->trips.active[i].flags.valid; i++) {
+               tz->trips.active[i].valid; i++) {
                if (!trip) {
                        *temp = deci_kelvin_to_millicelsius_with_offset(
                                        tz->trips.active[i].temperature,
@@ -614,7 +545,7 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
 {
        struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
 
-       if (tz->trips.critical.flags.valid) {
+       if (tz->trips.critical.valid) {
                *temperature = deci_kelvin_to_millicelsius_with_offset(
                                        tz->trips.critical.temperature,
                                        tz->kelvin_offset);
@@ -700,13 +631,13 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
        int trip = -1;
        int result = 0;
 
-       if (tz->trips.critical.flags.valid)
+       if (tz->trips.critical.valid)
                trip++;
 
-       if (tz->trips.hot.flags.valid)
+       if (tz->trips.hot.valid)
                trip++;
 
-       if (tz->trips.passive.flags.valid) {
+       if (tz->trips.passive.valid) {
                trip++;
                for (i = 0; i < tz->trips.passive.devices.count; i++) {
                        handle = tz->trips.passive.devices.handles[i];
@@ -731,7 +662,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
        }
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-               if (!tz->trips.active[i].flags.valid)
+               if (!tz->trips.active[i].valid)
                        break;
 
                trip++;
@@ -819,19 +750,19 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
        acpi_status status;
        int i;
 
-       if (tz->trips.critical.flags.valid)
+       if (tz->trips.critical.valid)
                trips++;
 
-       if (tz->trips.hot.flags.valid)
+       if (tz->trips.hot.valid)
                trips++;
 
-       if (tz->trips.passive.flags.valid)
+       if (tz->trips.passive.valid)
                trips++;
 
-       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].flags.valid;
+       for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid;
             i++, trips++);
 
-       if (tz->trips.passive.flags.valid)
+       if (tz->trips.passive.valid)
                tz->thermal_zone = thermal_zone_device_register("acpitz", trips, 0, tz,
                                                                &acpi_thermal_zone_ops, NULL,
                                                                tz->trips.passive.tsp * 100,
@@ -906,13 +837,13 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event)
                acpi_queue_thermal_check(tz);
                break;
        case ACPI_THERMAL_NOTIFY_THRESHOLDS:
-               acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
+               acpi_thermal_trips_update(tz, ACPI_TRIPS_THRESHOLDS);
                acpi_queue_thermal_check(tz);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                dev_name(&device->dev), event, 0);
                break;
        case ACPI_THERMAL_NOTIFY_DEVICES:
-               acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
+               acpi_thermal_trips_update(tz, ACPI_TRIPS_DEVICES);
                acpi_queue_thermal_check(tz);
                acpi_bus_generate_netlink_event(device->pnp.device_class,
                                                dev_name(&device->dev), event, 0);
@@ -976,9 +907,8 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
                return result;
 
        /* Set the cooling mode [_SCP] to active cooling (default) */
-       result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
-       if (!result)
-               tz->flags.cooling_mode = 1;
+       acpi_execute_simple_method(tz->device->handle, "_SCP",
+                                  ACPI_THERMAL_MODE_ACTIVE);
 
        /* Get default polling frequency [_TZP] (optional) */
        if (tzp)
@@ -1001,7 +931,7 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
  */
 static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
 {
-       if (tz->trips.critical.flags.valid &&
+       if (tz->trips.critical.valid &&
            (tz->trips.critical.temperature % 5) == 1)
                tz->kelvin_offset = 273100;
        else
@@ -1110,27 +1040,48 @@ static int acpi_thermal_resume(struct device *dev)
                return -EINVAL;
 
        for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
-               if (!tz->trips.active[i].flags.valid)
+               if (!tz->trips.active[i].valid)
                        break;
 
-               tz->trips.active[i].flags.enabled = 1;
+               tz->trips.active[i].enabled = true;
                for (j = 0; j < tz->trips.active[i].devices.count; j++) {
                        result = acpi_bus_update_power(
                                        tz->trips.active[i].devices.handles[j],
                                        &power_state);
                        if (result || (power_state != ACPI_STATE_D0)) {
-                               tz->trips.active[i].flags.enabled = 0;
+                               tz->trips.active[i].enabled = false;
                                break;
                        }
                }
-               tz->state.active |= tz->trips.active[i].flags.enabled;
        }
 
        acpi_queue_thermal_check(tz);
 
        return AE_OK;
 }
+#else
+#define acpi_thermal_suspend   NULL
+#define acpi_thermal_resume    NULL
 #endif
+static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
+
+static const struct acpi_device_id  thermal_device_ids[] = {
+       {ACPI_THERMAL_HID, 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
+
+static struct acpi_driver acpi_thermal_driver = {
+       .name = "thermal",
+       .class = ACPI_THERMAL_CLASS,
+       .ids = thermal_device_ids,
+       .ops = {
+               .add = acpi_thermal_add,
+               .remove = acpi_thermal_remove,
+               .notify = acpi_thermal_notify,
+               },
+       .drv.pm = &acpi_thermal_pm,
+};
 
 static int thermal_act(const struct dmi_system_id *d) {
        if (act == 0) {
@@ -1236,3 +1187,7 @@ static void __exit acpi_thermal_exit(void)
 
 module_init(acpi_thermal_init);
 module_exit(acpi_thermal_exit);
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
+MODULE_LICENSE("GPL");
index 598f548..6353be6 100644 (file)
@@ -19,18 +19,52 @@ static const struct acpi_device_id tiny_power_button_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, tiny_power_button_device_ids);
 
-static int acpi_noop_add(struct acpi_device *device)
+static void acpi_tiny_power_button_notify(acpi_handle handle, u32 event, void *data)
 {
-       return 0;
+       kill_cad_pid(power_signal, 1);
 }
 
-static void acpi_noop_remove(struct acpi_device *device)
+static void acpi_tiny_power_button_notify_run(void *not_used)
 {
+       acpi_tiny_power_button_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, NULL);
 }
 
-static void acpi_tiny_power_button_notify(struct acpi_device *device, u32 event)
+static u32 acpi_tiny_power_button_event(void *not_used)
 {
-       kill_cad_pid(power_signal, 1);
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_tiny_power_button_notify_run, NULL);
+       return ACPI_INTERRUPT_HANDLED;
+}
+
+static int acpi_tiny_power_button_add(struct acpi_device *device)
+{
+       acpi_status status;
+
+       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
+               status = acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                                         acpi_tiny_power_button_event,
+                                                         NULL);
+       } else {
+               status = acpi_install_notify_handler(device->handle,
+                                                    ACPI_DEVICE_NOTIFY,
+                                                    acpi_tiny_power_button_notify,
+                                                    NULL);
+       }
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return 0;
+}
+
+static void acpi_tiny_power_button_remove(struct acpi_device *device)
+{
+       if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) {
+               acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
+                                               acpi_tiny_power_button_event);
+       } else {
+               acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+                                          acpi_tiny_power_button_notify);
+       }
+       acpi_os_wait_events_complete();
 }
 
 static struct acpi_driver acpi_tiny_power_button_driver = {
@@ -38,9 +72,8 @@ static struct acpi_driver acpi_tiny_power_button_driver = {
        .class = "tiny-power-button",
        .ids = tiny_power_button_device_ids,
        .ops = {
-               .add = acpi_noop_add,
-               .remove = acpi_noop_remove,
-               .notify = acpi_tiny_power_button_notify,
+               .add = acpi_tiny_power_button_add,
+               .remove = acpi_tiny_power_button_remove,
        },
 };
 
index bcc25d4..18cc08c 100644 (file)
@@ -471,6 +471,22 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
                },
        },
        {
+        .callback = video_detect_force_native,
+        /* Lenovo ThinkPad X131e (3371 AMD version) */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "3371"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
+        /* Apple iMac11,3 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "iMac11,3"),
+               },
+       },
+       {
         /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
         .callback = video_detect_force_native,
         /* Apple MacBook Pro 12,1 */
@@ -514,6 +530,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
        },
        {
         .callback = video_detect_force_native,
+        /* Dell Studio 1569 */
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Studio 1569"),
+               },
+       },
+       {
+        .callback = video_detect_force_native,
         /* Acer Aspire 3830TG */
         .matches = {
                DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -828,6 +852,27 @@ enum acpi_backlight_type __acpi_video_get_backlight_type(bool native, bool *auto
        if (native_available)
                return acpi_backlight_native;
 
+       /*
+        * The vendor specific BIOS interfaces are only necessary for
+        * laptops from before ~2008.
+        *
+        * For laptops from ~2008 till ~2023 this point is never reached
+        * because on those (video_caps & ACPI_VIDEO_BACKLIGHT) above is true.
+        *
+        * Laptops from after ~2023 no longer support ACPI_VIDEO_BACKLIGHT,
+        * if this point is reached on those, this likely means that
+        * the GPU kms driver which sets native_available has not loaded yet.
+        *
+        * Returning acpi_backlight_vendor in this case is known to sometimes
+        * cause a non working vendor specific /sys/class/backlight device to
+        * get registered.
+        *
+        * Return acpi_backlight_none on laptops with ACPI tables written
+        * for Windows 8 (laptops from after ~2012) to avoid this problem.
+        */
+       if (acpi_osi_is_win8())
+               return acpi_backlight_none;
+
        /* No ACPI video/native (old hw), use vendor specific fw methods. */
        return acpi_backlight_vendor;
 }
index e499c60..7214197 100644 (file)
@@ -485,11 +485,11 @@ int acpi_s2idle_prepare_late(void)
                                        ACPI_LPS0_ENTRY,
                                        lps0_dsm_func_mask, lps0_dsm_guid);
        if (lps0_dsm_func_mask_microsoft > 0) {
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
-                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
                /* modern standby entry */
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY,
                                lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+               acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY,
+                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
        }
 
        list_for_each_entry(handler, &lps0_s2idle_devops_head, list_node) {
@@ -524,11 +524,6 @@ void acpi_s2idle_restore_early(void)
                if (handler->restore)
                        handler->restore();
 
-       /* Modern standby exit */
-       if (lps0_dsm_func_mask_microsoft > 0)
-               acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
-                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
-
        /* LPS0 exit */
        if (lps0_dsm_func_mask > 0)
                acpi_sleep_run_lps0_dsm(acpi_s2idle_vendor_amd() ?
@@ -539,6 +534,11 @@ void acpi_s2idle_restore_early(void)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT,
                                lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
 
+       /* Modern standby exit */
+       if (lps0_dsm_func_mask_microsoft > 0)
+               acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT,
+                               lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft);
+
        /* Screen on */
        if (lps0_dsm_func_mask_microsoft > 0)
                acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON,
index 9c2d6f3..c2b925f 100644 (file)
@@ -259,10 +259,11 @@ bool force_storage_d3(void)
  * drivers/platform/x86/x86-android-tablets.c kernel module.
  */
 #define ACPI_QUIRK_SKIP_I2C_CLIENTS                            BIT(0)
-#define ACPI_QUIRK_UART1_TTY_UART2_SKIP                                BIT(1)
-#define ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY                    BIT(2)
-#define ACPI_QUIRK_USE_ACPI_AC_AND_BATTERY                     BIT(3)
-#define ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS                    BIT(4)
+#define ACPI_QUIRK_UART1_SKIP                                  BIT(1)
+#define ACPI_QUIRK_UART1_TTY_UART2_SKIP                                BIT(2)
+#define ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY                    BIT(3)
+#define ACPI_QUIRK_USE_ACPI_AC_AND_BATTERY                     BIT(4)
+#define ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS                    BIT(5)
 
 static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
        /*
@@ -319,6 +320,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
                        DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
                },
                .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
+                                       ACPI_QUIRK_UART1_SKIP |
                                        ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY |
                                        ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
        },
@@ -365,7 +367,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
                                        ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
        },
        {
-               /* Nextbook Ares 8 */
+               /* Nextbook Ares 8 (BYT version)*/
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "M890BAP"),
@@ -375,6 +377,16 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
                                        ACPI_QUIRK_SKIP_GPIO_EVENT_HANDLERS),
        },
        {
+               /* Nextbook Ares 8A (CHT version)*/
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
+                       DMI_MATCH(DMI_BIOS_VERSION, "M882"),
+               },
+               .driver_data = (void *)(ACPI_QUIRK_SKIP_I2C_CLIENTS |
+                                       ACPI_QUIRK_SKIP_ACPI_AC_AND_BATTERY),
+       },
+       {
                /* Whitelabel (sold as various brands) TM800A550L */
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
@@ -392,6 +404,7 @@ static const struct dmi_system_id acpi_quirk_skip_dmi_ids[] = {
 #if IS_ENABLED(CONFIG_X86_ANDROID_TABLETS)
 static const struct acpi_device_id i2c_acpi_known_good_ids[] = {
        { "10EC5640", 0 }, /* RealTek ALC5640 audio codec */
+       { "10EC5651", 0 }, /* RealTek ALC5651 audio codec */
        { "INT33F4", 0 },  /* X-Powers AXP288 PMIC */
        { "INT33FD", 0 },  /* Intel Crystal Cove PMIC */
        { "INT34D3", 0 },  /* Intel Whiskey Cove PMIC */
@@ -438,6 +451,9 @@ int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *s
        if (dmi_id)
                quirks = (unsigned long)dmi_id->driver_data;
 
+       if ((quirks & ACPI_QUIRK_UART1_SKIP) && uid == 1)
+               *skip = true;
+
        if (quirks & ACPI_QUIRK_UART1_TTY_UART2_SKIP) {
                if (uid == 1)
                        return -ENODEV; /* Create tty cdev instead of serdev */
index 8bf612b..b4f246f 100644 (file)
@@ -5348,7 +5348,7 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 
        mutex_init(&ap->scsi_scan_mutex);
        INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
-       INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
+       INIT_DELAYED_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
        INIT_LIST_HEAD(&ap->eh_done_q);
        init_waitqueue_head(&ap->eh_wait_q);
        init_completion(&ap->park_req_pending);
@@ -5954,6 +5954,7 @@ static void ata_port_detach(struct ata_port *ap)
        WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED));
 
        cancel_delayed_work_sync(&ap->hotplug_task);
+       cancel_delayed_work_sync(&ap->scsi_rescan_task);
 
  skip_eh:
        /* clean up zpodd on port removal */
index a6c9018..6f8d141 100644 (file)
@@ -2984,7 +2984,7 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link,
                        ehc->i.flags |= ATA_EHI_SETMODE;
 
                        /* schedule the scsi_rescan_device() here */
-                       schedule_work(&(ap->scsi_rescan_task));
+                       schedule_delayed_work(&ap->scsi_rescan_task, 0);
                } else if (dev->class == ATA_DEV_UNKNOWN &&
                           ehc->tries[dev->devno] &&
                           ata_class_enabled(ehc->classes[dev->devno])) {
index 8ce9028..551077c 100644 (file)
@@ -4597,10 +4597,11 @@ int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
 void ata_scsi_dev_rescan(struct work_struct *work)
 {
        struct ata_port *ap =
-               container_of(work, struct ata_port, scsi_rescan_task);
+               container_of(work, struct ata_port, scsi_rescan_task.work);
        struct ata_link *link;
        struct ata_device *dev;
        unsigned long flags;
+       bool delay_rescan = false;
 
        mutex_lock(&ap->scsi_scan_mutex);
        spin_lock_irqsave(ap->lock, flags);
@@ -4614,6 +4615,21 @@ void ata_scsi_dev_rescan(struct work_struct *work)
                        if (scsi_device_get(sdev))
                                continue;
 
+                       /*
+                        * If the rescan work was scheduled because of a resume
+                        * event, the port is already fully resumed, but the
+                        * SCSI device may not yet be fully resumed. In such
+                        * case, executing scsi_rescan_device() may cause a
+                        * deadlock with the PM code on device_lock(). Prevent
+                        * this by giving up and retrying rescan after a short
+                        * delay.
+                        */
+                       delay_rescan = sdev->sdev_gendev.power.is_suspended;
+                       if (delay_rescan) {
+                               scsi_device_put(sdev);
+                               break;
+                       }
+
                        spin_unlock_irqrestore(ap->lock, flags);
                        scsi_rescan_device(&(sdev->sdev_gendev));
                        scsi_device_put(sdev);
@@ -4623,4 +4639,8 @@ void ata_scsi_dev_rescan(struct work_struct *work)
 
        spin_unlock_irqrestore(ap->lock, flags);
        mutex_unlock(&ap->scsi_scan_mutex);
+
+       if (delay_rescan)
+               schedule_delayed_work(&ap->scsi_rescan_task,
+                                     msecs_to_jiffies(5));
 }
index 0295646..97c681f 100644 (file)
@@ -284,6 +284,9 @@ static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg,
 {
        int ret;
 
+       if (!regmap_writeable(map, reg))
+               return false;
+
        /* If we don't know the chip just got reset, then sync everything. */
        if (!map->no_sync_defaults)
                return true;
index b3fedaf..8640130 100644 (file)
@@ -2244,6 +2244,7 @@ static void null_destroy_dev(struct nullb *nullb)
        struct nullb_device *dev = nullb->dev;
 
        null_del_dev(nullb);
+       null_free_device_storage(dev, false);
        null_free_dev(dev);
 }
 
index 84ad3b1..632751d 100644 (file)
@@ -1334,14 +1334,30 @@ static bool rbd_obj_is_tail(struct rbd_obj_request *obj_req)
 /*
  * Must be called after rbd_obj_calc_img_extents().
  */
-static bool rbd_obj_copyup_enabled(struct rbd_obj_request *obj_req)
+static void rbd_obj_set_copyup_enabled(struct rbd_obj_request *obj_req)
 {
-       if (!obj_req->num_img_extents ||
-           (rbd_obj_is_entire(obj_req) &&
-            !obj_req->img_request->snapc->num_snaps))
-               return false;
+       rbd_assert(obj_req->img_request->snapc);
 
-       return true;
+       if (obj_req->img_request->op_type == OBJ_OP_DISCARD) {
+               dout("%s %p objno %llu discard\n", __func__, obj_req,
+                    obj_req->ex.oe_objno);
+               return;
+       }
+
+       if (!obj_req->num_img_extents) {
+               dout("%s %p objno %llu not overlapping\n", __func__, obj_req,
+                    obj_req->ex.oe_objno);
+               return;
+       }
+
+       if (rbd_obj_is_entire(obj_req) &&
+           !obj_req->img_request->snapc->num_snaps) {
+               dout("%s %p objno %llu entire\n", __func__, obj_req,
+                    obj_req->ex.oe_objno);
+               return;
+       }
+
+       obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
 }
 
 static u64 rbd_obj_img_extents_bytes(struct rbd_obj_request *obj_req)
@@ -1442,6 +1458,7 @@ __rbd_obj_add_osd_request(struct rbd_obj_request *obj_req,
 static struct ceph_osd_request *
 rbd_obj_add_osd_request(struct rbd_obj_request *obj_req, int num_ops)
 {
+       rbd_assert(obj_req->img_request->snapc);
        return __rbd_obj_add_osd_request(obj_req, obj_req->img_request->snapc,
                                         num_ops);
 }
@@ -1578,15 +1595,18 @@ static void rbd_img_request_init(struct rbd_img_request *img_request,
        mutex_init(&img_request->state_mutex);
 }
 
+/*
+ * Only snap_id is captured here, for reads.  For writes, snapshot
+ * context is captured in rbd_img_object_requests() after exclusive
+ * lock is ensured to be held.
+ */
 static void rbd_img_capture_header(struct rbd_img_request *img_req)
 {
        struct rbd_device *rbd_dev = img_req->rbd_dev;
 
        lockdep_assert_held(&rbd_dev->header_rwsem);
 
-       if (rbd_img_is_write(img_req))
-               img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
-       else
+       if (!rbd_img_is_write(img_req))
                img_req->snap_id = rbd_dev->spec->snap_id;
 
        if (rbd_dev_parent_get(rbd_dev))
@@ -2233,9 +2253,6 @@ static int rbd_obj_init_write(struct rbd_obj_request *obj_req)
        if (ret)
                return ret;
 
-       if (rbd_obj_copyup_enabled(obj_req))
-               obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
-
        obj_req->write_state = RBD_OBJ_WRITE_START;
        return 0;
 }
@@ -2341,8 +2358,6 @@ static int rbd_obj_init_zeroout(struct rbd_obj_request *obj_req)
        if (ret)
                return ret;
 
-       if (rbd_obj_copyup_enabled(obj_req))
-               obj_req->flags |= RBD_OBJ_FLAG_COPYUP_ENABLED;
        if (!obj_req->num_img_extents) {
                obj_req->flags |= RBD_OBJ_FLAG_NOOP_FOR_NONEXISTENT;
                if (rbd_obj_is_entire(obj_req))
@@ -3286,6 +3301,7 @@ again:
        case RBD_OBJ_WRITE_START:
                rbd_assert(!*result);
 
+               rbd_obj_set_copyup_enabled(obj_req);
                if (rbd_obj_write_is_noop(obj_req))
                        return true;
 
@@ -3472,9 +3488,19 @@ static int rbd_img_exclusive_lock(struct rbd_img_request *img_req)
 
 static void rbd_img_object_requests(struct rbd_img_request *img_req)
 {
+       struct rbd_device *rbd_dev = img_req->rbd_dev;
        struct rbd_obj_request *obj_req;
 
        rbd_assert(!img_req->pending.result && !img_req->pending.num_pending);
+       rbd_assert(!need_exclusive_lock(img_req) ||
+                  __rbd_is_lock_owner(rbd_dev));
+
+       if (rbd_img_is_write(img_req)) {
+               rbd_assert(!img_req->snapc);
+               down_read(&rbd_dev->header_rwsem);
+               img_req->snapc = ceph_get_snap_context(rbd_dev->header.snapc);
+               up_read(&rbd_dev->header_rwsem);
+       }
 
        for_each_obj_request(img_req, obj_req) {
                int result = 0;
@@ -3492,7 +3518,6 @@ static void rbd_img_object_requests(struct rbd_img_request *img_req)
 
 static bool rbd_img_advance(struct rbd_img_request *img_req, int *result)
 {
-       struct rbd_device *rbd_dev = img_req->rbd_dev;
        int ret;
 
 again:
@@ -3513,9 +3538,6 @@ again:
                if (*result)
                        return true;
 
-               rbd_assert(!need_exclusive_lock(img_req) ||
-                          __rbd_is_lock_owner(rbd_dev));
-
                rbd_img_object_requests(img_req);
                if (!img_req->pending.num_pending) {
                        *result = img_req->pending.result;
@@ -3977,6 +3999,10 @@ static int rbd_post_acquire_action(struct rbd_device *rbd_dev)
 {
        int ret;
 
+       ret = rbd_dev_refresh(rbd_dev);
+       if (ret)
+               return ret;
+
        if (rbd_dev->header.features & RBD_FEATURE_OBJECT_MAP) {
                ret = rbd_object_map_open(rbd_dev);
                if (ret)
index 1b06450..e30c979 100644 (file)
@@ -78,7 +78,8 @@ enum qca_flags {
        QCA_HW_ERROR_EVENT,
        QCA_SSR_TRIGGERED,
        QCA_BT_OFF,
-       QCA_ROM_FW
+       QCA_ROM_FW,
+       QCA_DEBUGFS_CREATED,
 };
 
 enum qca_capabilities {
@@ -635,6 +636,9 @@ static void qca_debugfs_init(struct hci_dev *hdev)
        if (!hdev->debugfs)
                return;
 
+       if (test_and_set_bit(QCA_DEBUGFS_CREATED, &qca->flags))
+               return;
+
        ibs_dir = debugfs_create_dir("ibs", hdev->debugfs);
 
        /* read only */
index edfa946..66759fe 100644 (file)
@@ -119,7 +119,10 @@ static int clk_composite_determine_rate(struct clk_hw *hw,
                        if (ret)
                                continue;
 
-                       rate_diff = abs(req->rate - tmp_req.rate);
+                       if (req->rate >= tmp_req.rate)
+                               rate_diff = req->rate - tmp_req.rate;
+                       else
+                               rate_diff = tmp_req.rate - req->rate;
 
                        if (!rate_diff || !req->best_parent_hw
                                       || best_rate_diff > rate_diff) {
index 70ae1dd..bacdcbb 100644 (file)
@@ -40,7 +40,7 @@ static struct clk_hw *loongson2_clk_register(struct device *dev,
 {
        int ret;
        struct clk_hw *hw;
-       struct clk_init_data init;
+       struct clk_init_data init = { };
 
        hw = devm_kzalloc(dev, sizeof(*hw), GFP_KERNEL);
        if (!hw)
index 6b4e193..c87a6c4 100644 (file)
@@ -23,6 +23,7 @@
 static DEFINE_SPINLOCK(mt8365_clk_lock);
 
 static const struct mtk_fixed_clk top_fixed_clks[] = {
+       FIXED_CLK(CLK_TOP_CLK_NULL, "clk_null", NULL, 0),
        FIXED_CLK(CLK_TOP_I2S0_BCK, "i2s0_bck", NULL, 26000000),
        FIXED_CLK(CLK_TOP_DSI0_LNTC_DSICK, "dsi0_lntc_dsick", "clk26m",
                  75000000),
@@ -559,6 +560,14 @@ static const struct mtk_clk_divider top_adj_divs[] = {
                  0x324, 16, 8, CLK_DIVIDER_ROUND_CLOSEST),
        DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV3, "apll12_ck_div3", "apll_i2s3_sel",
                  0x324, 24, 8, CLK_DIVIDER_ROUND_CLOSEST),
+       DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV4, "apll12_ck_div4", "apll_tdmout_sel",
+                 0x328, 0, 8, CLK_DIVIDER_ROUND_CLOSEST),
+       DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV4B, "apll12_ck_div4b", "apll_tdmout_sel",
+                 0x328, 8, 8, CLK_DIVIDER_ROUND_CLOSEST),
+       DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV5, "apll12_ck_div5", "apll_tdmin_sel",
+                 0x328, 16, 8, CLK_DIVIDER_ROUND_CLOSEST),
+       DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV5B, "apll12_ck_div5b", "apll_tdmin_sel",
+                 0x328, 24, 8, CLK_DIVIDER_ROUND_CLOSEST),
        DIV_ADJ_F(CLK_TOP_APLL12_CK_DIV6, "apll12_ck_div6", "apll_spdif_sel",
                  0x32c, 0, 8, CLK_DIVIDER_ROUND_CLOSEST),
 };
@@ -583,15 +592,15 @@ static const struct mtk_gate_regs top2_cg_regs = {
 
 #define GATE_TOP0(_id, _name, _parent, _shift)                 \
        GATE_MTK(_id, _name, _parent, &top0_cg_regs,            \
-                _shift, &mtk_clk_gate_ops_no_setclr_inv)
+                _shift, &mtk_clk_gate_ops_no_setclr)
 
 #define GATE_TOP1(_id, _name, _parent, _shift)                 \
        GATE_MTK(_id, _name, _parent, &top1_cg_regs,            \
-                _shift, &mtk_clk_gate_ops_no_setclr)
+                _shift, &mtk_clk_gate_ops_no_setclr_inv)
 
 #define GATE_TOP2(_id, _name, _parent, _shift)                 \
        GATE_MTK(_id, _name, _parent, &top2_cg_regs,            \
-                _shift, &mtk_clk_gate_ops_no_setclr)
+                _shift, &mtk_clk_gate_ops_no_setclr_inv)
 
 static const struct mtk_gate top_clk_gates[] = {
        GATE_TOP0(CLK_TOP_CONN_32K, "conn_32k", "clk32k", 10),
@@ -696,6 +705,7 @@ static const struct mtk_gate ifr_clks[] = {
        GATE_IFR3(CLK_IFR_GCPU, "ifr_gcpu", "axi_sel", 8),
        GATE_IFR3(CLK_IFR_TRNG, "ifr_trng", "axi_sel", 9),
        GATE_IFR3(CLK_IFR_AUXADC, "ifr_auxadc", "clk26m", 10),
+       GATE_IFR3(CLK_IFR_CPUM, "ifr_cpum", "clk26m", 11),
        GATE_IFR3(CLK_IFR_AUXADC_MD, "ifr_auxadc_md", "clk26m", 14),
        GATE_IFR3(CLK_IFR_AP_DMA, "ifr_ap_dma", "axi_sel", 18),
        GATE_IFR3(CLK_IFR_DEBUGSYS, "ifr_debugsys", "axi_sel", 24),
@@ -717,6 +727,8 @@ static const struct mtk_gate ifr_clks[] = {
        GATE_IFR5(CLK_IFR_PWRAP_TMR, "ifr_pwrap_tmr", "clk26m", 12),
        GATE_IFR5(CLK_IFR_PWRAP_SPI, "ifr_pwrap_spi", "clk26m", 13),
        GATE_IFR5(CLK_IFR_PWRAP_SYS, "ifr_pwrap_sys", "clk26m", 14),
+       GATE_MTK_FLAGS(CLK_IFR_MCU_PM_BK, "ifr_mcu_pm_bk", NULL, &ifr5_cg_regs,
+                       17, &mtk_clk_gate_ops_setclr, CLK_IGNORE_UNUSED),
        GATE_IFR5(CLK_IFR_IRRX_26M, "ifr_irrx_26m", "clk26m", 22),
        GATE_IFR5(CLK_IFR_IRRX_32K, "ifr_irrx_32k", "clk32k", 23),
        GATE_IFR5(CLK_IFR_I2C0_AXI, "ifr_i2c0_axi", "i2c_sel", 24),
index 42958a5..621e298 100644 (file)
@@ -164,7 +164,7 @@ void pxa3xx_clk_update_accr(u32 disable, u32 enable, u32 xclkcfg, u32 mask)
        accr &= ~disable;
        accr |= enable;
 
-       writel(accr, ACCR);
+       writel(accr, clk_regs + ACCR);
        if (xclkcfg)
                __asm__("mcr p14, 0, %0, c6, c0, 0\n" : : "r"(xclkcfg));
 
index 265e0fb..b2db545 100644 (file)
 #define TRP_SYN_REG_CNT                 6
 #define DRP_SYN_REG_CNT                 8
 
-#define LLCC_COMMON_STATUS0             0x0003000c
 #define LLCC_LB_CNT_MASK                GENMASK(31, 28)
 #define LLCC_LB_CNT_SHIFT               28
 
-/* Single & double bit syndrome register offsets */
-#define TRP_ECC_SB_ERR_SYN0             0x0002304c
-#define TRP_ECC_DB_ERR_SYN0             0x00020370
-#define DRP_ECC_SB_ERR_SYN0             0x0004204c
-#define DRP_ECC_DB_ERR_SYN0             0x00042070
-
-/* Error register offsets */
-#define TRP_ECC_ERROR_STATUS1           0x00020348
-#define TRP_ECC_ERROR_STATUS0           0x00020344
-#define DRP_ECC_ERROR_STATUS1           0x00042048
-#define DRP_ECC_ERROR_STATUS0           0x00042044
-
-/* TRP, DRP interrupt register offsets */
-#define DRP_INTERRUPT_STATUS            0x00041000
-#define TRP_INTERRUPT_0_STATUS          0x00020480
-#define DRP_INTERRUPT_CLEAR             0x00041008
-#define DRP_ECC_ERROR_CNTR_CLEAR        0x00040004
-#define TRP_INTERRUPT_0_CLEAR           0x00020484
-#define TRP_ECC_ERROR_CNTR_CLEAR        0x00020440
-
 /* Mask and shift macros */
 #define ECC_DB_ERR_COUNT_MASK           GENMASK(4, 0)
 #define ECC_DB_ERR_WAYS_MASK            GENMASK(31, 16)
 #define DRP_TRP_INT_CLEAR               GENMASK(1, 0)
 #define DRP_TRP_CNT_CLEAR               GENMASK(1, 0)
 
-/* Config registers offsets*/
-#define DRP_ECC_ERROR_CFG               0x00040000
-
-/* Tag RAM, Data RAM interrupt register offsets */
-#define CMN_INTERRUPT_0_ENABLE          0x0003001c
-#define CMN_INTERRUPT_2_ENABLE          0x0003003c
-#define TRP_INTERRUPT_0_ENABLE          0x00020488
-#define DRP_INTERRUPT_ENABLE            0x0004100c
-
 #define SB_ERROR_THRESHOLD              0x1
 #define SB_ERROR_THRESHOLD_SHIFT        24
 #define SB_DB_TRP_INTERRUPT_ENABLE      0x3
@@ -88,9 +58,6 @@ enum {
 static const struct llcc_edac_reg_data edac_reg_data[] = {
        [LLCC_DRAM_CE] = {
                .name = "DRAM Single-bit",
-               .synd_reg = DRP_ECC_SB_ERR_SYN0,
-               .count_status_reg = DRP_ECC_ERROR_STATUS1,
-               .ways_status_reg = DRP_ECC_ERROR_STATUS0,
                .reg_cnt = DRP_SYN_REG_CNT,
                .count_mask = ECC_SB_ERR_COUNT_MASK,
                .ways_mask = ECC_SB_ERR_WAYS_MASK,
@@ -98,9 +65,6 @@ static const struct llcc_edac_reg_data edac_reg_data[] = {
        },
        [LLCC_DRAM_UE] = {
                .name = "DRAM Double-bit",
-               .synd_reg = DRP_ECC_DB_ERR_SYN0,
-               .count_status_reg = DRP_ECC_ERROR_STATUS1,
-               .ways_status_reg = DRP_ECC_ERROR_STATUS0,
                .reg_cnt = DRP_SYN_REG_CNT,
                .count_mask = ECC_DB_ERR_COUNT_MASK,
                .ways_mask = ECC_DB_ERR_WAYS_MASK,
@@ -108,9 +72,6 @@ static const struct llcc_edac_reg_data edac_reg_data[] = {
        },
        [LLCC_TRAM_CE] = {
                .name = "TRAM Single-bit",
-               .synd_reg = TRP_ECC_SB_ERR_SYN0,
-               .count_status_reg = TRP_ECC_ERROR_STATUS1,
-               .ways_status_reg = TRP_ECC_ERROR_STATUS0,
                .reg_cnt = TRP_SYN_REG_CNT,
                .count_mask = ECC_SB_ERR_COUNT_MASK,
                .ways_mask = ECC_SB_ERR_WAYS_MASK,
@@ -118,9 +79,6 @@ static const struct llcc_edac_reg_data edac_reg_data[] = {
        },
        [LLCC_TRAM_UE] = {
                .name = "TRAM Double-bit",
-               .synd_reg = TRP_ECC_DB_ERR_SYN0,
-               .count_status_reg = TRP_ECC_ERROR_STATUS1,
-               .ways_status_reg = TRP_ECC_ERROR_STATUS0,
                .reg_cnt = TRP_SYN_REG_CNT,
                .count_mask = ECC_DB_ERR_COUNT_MASK,
                .ways_mask = ECC_DB_ERR_WAYS_MASK,
@@ -128,7 +86,7 @@ static const struct llcc_edac_reg_data edac_reg_data[] = {
        },
 };
 
-static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap)
+static int qcom_llcc_core_setup(struct llcc_drv_data *drv, struct regmap *llcc_bcast_regmap)
 {
        u32 sb_err_threshold;
        int ret;
@@ -137,31 +95,31 @@ static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap)
         * Configure interrupt enable registers such that Tag, Data RAM related
         * interrupts are propagated to interrupt controller for servicing
         */
-       ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
+       ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable,
                                 TRP0_INTERRUPT_ENABLE,
                                 TRP0_INTERRUPT_ENABLE);
        if (ret)
                return ret;
 
-       ret = regmap_update_bits(llcc_bcast_regmap, TRP_INTERRUPT_0_ENABLE,
+       ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->trp_interrupt_0_enable,
                                 SB_DB_TRP_INTERRUPT_ENABLE,
                                 SB_DB_TRP_INTERRUPT_ENABLE);
        if (ret)
                return ret;
 
        sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT);
-       ret = regmap_write(llcc_bcast_regmap, DRP_ECC_ERROR_CFG,
+       ret = regmap_write(llcc_bcast_regmap, drv->edac_reg_offset->drp_ecc_error_cfg,
                           sb_err_threshold);
        if (ret)
                return ret;
 
-       ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
+       ret = regmap_update_bits(llcc_bcast_regmap, drv->edac_reg_offset->cmn_interrupt_2_enable,
                                 DRP0_INTERRUPT_ENABLE,
                                 DRP0_INTERRUPT_ENABLE);
        if (ret)
                return ret;
 
-       ret = regmap_write(llcc_bcast_regmap, DRP_INTERRUPT_ENABLE,
+       ret = regmap_write(llcc_bcast_regmap, drv->edac_reg_offset->drp_interrupt_enable,
                           SB_DB_DRP_INTERRUPT_ENABLE);
        return ret;
 }
@@ -170,29 +128,33 @@ static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap)
 static int
 qcom_llcc_clear_error_status(int err_type, struct llcc_drv_data *drv)
 {
-       int ret = 0;
+       int ret;
 
        switch (err_type) {
        case LLCC_DRAM_CE:
        case LLCC_DRAM_UE:
-               ret = regmap_write(drv->bcast_regmap, DRP_INTERRUPT_CLEAR,
+               ret = regmap_write(drv->bcast_regmap,
+                                  drv->edac_reg_offset->drp_interrupt_clear,
                                   DRP_TRP_INT_CLEAR);
                if (ret)
                        return ret;
 
-               ret = regmap_write(drv->bcast_regmap, DRP_ECC_ERROR_CNTR_CLEAR,
+               ret = regmap_write(drv->bcast_regmap,
+                                  drv->edac_reg_offset->drp_ecc_error_cntr_clear,
                                   DRP_TRP_CNT_CLEAR);
                if (ret)
                        return ret;
                break;
        case LLCC_TRAM_CE:
        case LLCC_TRAM_UE:
-               ret = regmap_write(drv->bcast_regmap, TRP_INTERRUPT_0_CLEAR,
+               ret = regmap_write(drv->bcast_regmap,
+                                  drv->edac_reg_offset->trp_interrupt_0_clear,
                                   DRP_TRP_INT_CLEAR);
                if (ret)
                        return ret;
 
-               ret = regmap_write(drv->bcast_regmap, TRP_ECC_ERROR_CNTR_CLEAR,
+               ret = regmap_write(drv->bcast_regmap,
+                                  drv->edac_reg_offset->trp_ecc_error_cntr_clear,
                                   DRP_TRP_CNT_CLEAR);
                if (ret)
                        return ret;
@@ -205,16 +167,54 @@ qcom_llcc_clear_error_status(int err_type, struct llcc_drv_data *drv)
        return ret;
 }
 
+struct qcom_llcc_syn_regs {
+       u32 synd_reg;
+       u32 count_status_reg;
+       u32 ways_status_reg;
+};
+
+static void get_reg_offsets(struct llcc_drv_data *drv, int err_type,
+                           struct qcom_llcc_syn_regs *syn_regs)
+{
+       const struct llcc_edac_reg_offset *edac_reg_offset = drv->edac_reg_offset;
+
+       switch (err_type) {
+       case LLCC_DRAM_CE:
+               syn_regs->synd_reg = edac_reg_offset->drp_ecc_sb_err_syn0;
+               syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1;
+               syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0;
+               break;
+       case LLCC_DRAM_UE:
+               syn_regs->synd_reg = edac_reg_offset->drp_ecc_db_err_syn0;
+               syn_regs->count_status_reg = edac_reg_offset->drp_ecc_error_status1;
+               syn_regs->ways_status_reg = edac_reg_offset->drp_ecc_error_status0;
+               break;
+       case LLCC_TRAM_CE:
+               syn_regs->synd_reg = edac_reg_offset->trp_ecc_sb_err_syn0;
+               syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1;
+               syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0;
+               break;
+       case LLCC_TRAM_UE:
+               syn_regs->synd_reg = edac_reg_offset->trp_ecc_db_err_syn0;
+               syn_regs->count_status_reg = edac_reg_offset->trp_ecc_error_status1;
+               syn_regs->ways_status_reg = edac_reg_offset->trp_ecc_error_status0;
+               break;
+       }
+}
+
 /* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/
 static int
 dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
 {
        struct llcc_edac_reg_data reg_data = edac_reg_data[err_type];
+       struct qcom_llcc_syn_regs regs = { };
        int err_cnt, err_ways, ret, i;
        u32 synd_reg, synd_val;
 
+       get_reg_offsets(drv, err_type, &regs);
+
        for (i = 0; i < reg_data.reg_cnt; i++) {
-               synd_reg = reg_data.synd_reg + (i * 4);
+               synd_reg = regs.synd_reg + (i * 4);
                ret = regmap_read(drv->regmaps[bank], synd_reg,
                                  &synd_val);
                if (ret)
@@ -224,7 +224,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
                            reg_data.name, i, synd_val);
        }
 
-       ret = regmap_read(drv->regmaps[bank], reg_data.count_status_reg,
+       ret = regmap_read(drv->regmaps[bank], regs.count_status_reg,
                          &err_cnt);
        if (ret)
                goto clear;
@@ -234,7 +234,7 @@ dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
        edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n",
                    reg_data.name, err_cnt);
 
-       ret = regmap_read(drv->regmaps[bank], reg_data.ways_status_reg,
+       ret = regmap_read(drv->regmaps[bank], regs.ways_status_reg,
                          &err_ways);
        if (ret)
                goto clear;
@@ -295,7 +295,7 @@ static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl)
 
        /* Iterate over the banks and look for Tag RAM or Data RAM errors */
        for (i = 0; i < drv->num_banks; i++) {
-               ret = regmap_read(drv->regmaps[i], DRP_INTERRUPT_STATUS,
+               ret = regmap_read(drv->regmaps[i], drv->edac_reg_offset->drp_interrupt_status,
                                  &drp_error);
 
                if (!ret && (drp_error & SB_ECC_ERROR)) {
@@ -310,7 +310,7 @@ static irqreturn_t llcc_ecc_irq_handler(int irq, void *edev_ctl)
                if (!ret)
                        irq_rc = IRQ_HANDLED;
 
-               ret = regmap_read(drv->regmaps[i], TRP_INTERRUPT_0_STATUS,
+               ret = regmap_read(drv->regmaps[i], drv->edac_reg_offset->trp_interrupt_0_status,
                                  &trp_error);
 
                if (!ret && (trp_error & SB_ECC_ERROR)) {
@@ -342,7 +342,7 @@ static int qcom_llcc_edac_probe(struct platform_device *pdev)
        int ecc_irq;
        int rc;
 
-       rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap);
+       rc = qcom_llcc_core_setup(llcc_driv_data, llcc_driv_data->bcast_regmap);
        if (rc)
                return rc;
 
index e234091..2109cd1 100644 (file)
@@ -424,6 +424,7 @@ ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize,
                ep_mem_access->flag = 0;
                ep_mem_access->reserved = 0;
        }
+       mem_region->handle = 0;
        mem_region->reserved_0 = 0;
        mem_region->reserved_1 = 0;
        mem_region->ep_count = args->nattrs;
index e4ccfb6..ec056f6 100644 (file)
@@ -2124,6 +2124,7 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
                                   file, blocks, le32_to_cpu(blk->len),
                                   type, le32_to_cpu(blk->id));
 
+                       region_name = cs_dsp_mem_region_name(type);
                        mem = cs_dsp_find_region(dsp, type);
                        if (!mem) {
                                cs_dsp_err(dsp, "No base for region %x\n", type);
@@ -2147,8 +2148,8 @@ static int cs_dsp_load_coeff(struct cs_dsp *dsp, const struct firmware *firmware
                                reg = dsp->ops->region_to_reg(mem, reg);
                                reg += offset;
                        } else {
-                               cs_dsp_err(dsp, "No %x for algorithm %x\n",
-                                          type, le32_to_cpu(blk->id));
+                               cs_dsp_err(dsp, "No %s for algorithm %x\n",
+                                          region_name, le32_to_cpu(blk->id));
                        }
                        break;
 
index a1c8702..8b49b0a 100644 (file)
@@ -696,6 +696,9 @@ static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank,
        char **line_names;
 
        list_for_each_entry(line, &bank->line_list, siblings) {
+               if (line->offset >= bank->num_lines)
+                       continue;
+
                if (line->name) {
                        if (line->offset > max_offset)
                                max_offset = line->offset;
@@ -721,8 +724,13 @@ static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank,
        if (!line_names)
                return ERR_PTR(-ENOMEM);
 
-       list_for_each_entry(line, &bank->line_list, siblings)
-               line_names[line->offset] = line->name;
+       list_for_each_entry(line, &bank->line_list, siblings) {
+               if (line->offset >= bank->num_lines)
+                       continue;
+
+               if (line->name && (line->offset <= max_offset))
+                       line_names[line->offset] = line->name;
+       }
 
        return line_names;
 }
@@ -754,6 +762,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
 
        list_for_each_entry(bank, &dev->bank_list, siblings) {
                list_for_each_entry(line, &bank->line_list, siblings) {
+                       if (line->offset >= bank->num_lines)
+                               continue;
+
                        if (line->hog)
                                num_hogs++;
                }
@@ -769,6 +780,9 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev)
 
        list_for_each_entry(bank, &dev->bank_list, siblings) {
                list_for_each_entry(line, &bank->line_list, siblings) {
+                       if (line->offset >= bank->num_lines)
+                               continue;
+
                        if (!line->hog)
                                continue;
 
index aeeec21..fd6e837 100644 (file)
@@ -1092,16 +1092,20 @@ bool amdgpu_acpi_is_s0ix_active(struct amdgpu_device *adev)
         * S0ix even though the system is suspending to idle, so return false
         * in that case.
         */
-       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
-               dev_warn_once(adev->dev,
+       if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) {
+               dev_err_once(adev->dev,
                              "Power consumption will be higher as BIOS has not been configured for suspend-to-idle.\n"
                              "To use suspend-to-idle change the sleep mode in BIOS setup.\n");
+               return false;
+       }
 
 #if !IS_ENABLED(CONFIG_AMD_PMC)
-       dev_warn_once(adev->dev,
+       dev_err_once(adev->dev,
                      "Power consumption will be higher as the kernel has not been compiled with CONFIG_AMD_PMC.\n");
-#endif /* CONFIG_AMD_PMC */
+       return false;
+#else
        return true;
+#endif /* CONFIG_AMD_PMC */
 }
 
 #endif /* CONFIG_SUSPEND */
index b1ca1ab..393b6fb 100644 (file)
@@ -1615,6 +1615,7 @@ static const u16 amdgpu_unsupported_pciidlist[] = {
        0x5874,
        0x5940,
        0x5941,
+       0x5b70,
        0x5b72,
        0x5b73,
        0x5b74,
index 2bd1a54..a70103a 100644 (file)
@@ -79,9 +79,10 @@ static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo)
 static void amdgpu_bo_vm_destroy(struct ttm_buffer_object *tbo)
 {
        struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
-       struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
+       struct amdgpu_bo *shadow_bo = ttm_to_amdgpu_bo(tbo), *bo;
        struct amdgpu_bo_vm *vmbo;
 
+       bo = shadow_bo->parent;
        vmbo = to_amdgpu_bo_vm(bo);
        /* in case amdgpu_device_recover_vram got NULL of bo->parent */
        if (!list_empty(&vmbo->shadow_list)) {
@@ -139,7 +140,7 @@ void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
 
                if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
                        places[c].lpfn = visible_pfn;
-               else if (adev->gmc.real_vram_size != adev->gmc.visible_vram_size)
+               else
                        places[c].flags |= TTM_PL_FLAG_TOPDOWN;
 
                if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
@@ -694,11 +695,6 @@ int amdgpu_bo_create_vm(struct amdgpu_device *adev,
                return r;
 
        *vmbo_ptr = to_amdgpu_bo_vm(bo_ptr);
-       INIT_LIST_HEAD(&(*vmbo_ptr)->shadow_list);
-       /* Set destroy callback to amdgpu_bo_vm_destroy after vmbo->shadow_list
-        * is initialized.
-        */
-       bo_ptr->tbo.destroy = &amdgpu_bo_vm_destroy;
        return r;
 }
 
@@ -715,6 +711,8 @@ void amdgpu_bo_add_to_shadow_list(struct amdgpu_bo_vm *vmbo)
 
        mutex_lock(&adev->shadow_list_lock);
        list_add_tail(&vmbo->shadow_list, &adev->shadow_list);
+       vmbo->shadow->parent = amdgpu_bo_ref(&vmbo->bo);
+       vmbo->shadow->tbo.destroy = &amdgpu_bo_vm_destroy;
        mutex_unlock(&adev->shadow_list_lock);
 }
 
index 9d7e6e0..a150b7a 100644 (file)
@@ -3548,6 +3548,9 @@ static ssize_t amdgpu_psp_vbflash_read(struct file *filp, struct kobject *kobj,
        void *fw_pri_cpu_addr;
        int ret;
 
+       if (adev->psp.vbflash_image_size == 0)
+               return -EINVAL;
+
        dev_info(adev->dev, "VBIOS flash to PSP started");
 
        ret = amdgpu_bo_create_kernel(adev, adev->psp.vbflash_image_size,
@@ -3599,13 +3602,13 @@ static ssize_t amdgpu_psp_vbflash_status(struct device *dev,
 }
 
 static const struct bin_attribute psp_vbflash_bin_attr = {
-       .attr = {.name = "psp_vbflash", .mode = 0664},
+       .attr = {.name = "psp_vbflash", .mode = 0660},
        .size = 0,
        .write = amdgpu_psp_vbflash_write,
        .read = amdgpu_psp_vbflash_read,
 };
 
-static DEVICE_ATTR(psp_vbflash_status, 0444, amdgpu_psp_vbflash_status, NULL);
+static DEVICE_ATTR(psp_vbflash_status, 0440, amdgpu_psp_vbflash_status, NULL);
 
 int amdgpu_psp_sysfs_init(struct amdgpu_device *adev)
 {
index dc474b8..49de3a3 100644 (file)
@@ -581,3 +581,21 @@ void amdgpu_ring_ib_end(struct amdgpu_ring *ring)
        if (ring->is_sw_ring)
                amdgpu_sw_ring_ib_end(ring);
 }
+
+void amdgpu_ring_ib_on_emit_cntl(struct amdgpu_ring *ring)
+{
+       if (ring->is_sw_ring)
+               amdgpu_sw_ring_ib_mark_offset(ring, AMDGPU_MUX_OFFSET_TYPE_CONTROL);
+}
+
+void amdgpu_ring_ib_on_emit_ce(struct amdgpu_ring *ring)
+{
+       if (ring->is_sw_ring)
+               amdgpu_sw_ring_ib_mark_offset(ring, AMDGPU_MUX_OFFSET_TYPE_CE);
+}
+
+void amdgpu_ring_ib_on_emit_de(struct amdgpu_ring *ring)
+{
+       if (ring->is_sw_ring)
+               amdgpu_sw_ring_ib_mark_offset(ring, AMDGPU_MUX_OFFSET_TYPE_DE);
+}
index d874944..2474cb7 100644 (file)
@@ -227,6 +227,9 @@ struct amdgpu_ring_funcs {
        int (*preempt_ib)(struct amdgpu_ring *ring);
        void (*emit_mem_sync)(struct amdgpu_ring *ring);
        void (*emit_wave_limit)(struct amdgpu_ring *ring, bool enable);
+       void (*patch_cntl)(struct amdgpu_ring *ring, unsigned offset);
+       void (*patch_ce)(struct amdgpu_ring *ring, unsigned offset);
+       void (*patch_de)(struct amdgpu_ring *ring, unsigned offset);
 };
 
 struct amdgpu_ring {
@@ -318,10 +321,16 @@ struct amdgpu_ring {
 #define amdgpu_ring_init_cond_exec(r) (r)->funcs->init_cond_exec((r))
 #define amdgpu_ring_patch_cond_exec(r,o) (r)->funcs->patch_cond_exec((r),(o))
 #define amdgpu_ring_preempt_ib(r) (r)->funcs->preempt_ib(r)
+#define amdgpu_ring_patch_cntl(r, o) ((r)->funcs->patch_cntl((r), (o)))
+#define amdgpu_ring_patch_ce(r, o) ((r)->funcs->patch_ce((r), (o)))
+#define amdgpu_ring_patch_de(r, o) ((r)->funcs->patch_de((r), (o)))
 
 int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw);
 void amdgpu_ring_ib_begin(struct amdgpu_ring *ring);
 void amdgpu_ring_ib_end(struct amdgpu_ring *ring);
+void amdgpu_ring_ib_on_emit_cntl(struct amdgpu_ring *ring);
+void amdgpu_ring_ib_on_emit_ce(struct amdgpu_ring *ring);
+void amdgpu_ring_ib_on_emit_de(struct amdgpu_ring *ring);
 
 void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);
 void amdgpu_ring_generic_pad_ib(struct amdgpu_ring *ring, struct amdgpu_ib *ib);
index 62079f0..73516ab 100644 (file)
@@ -105,6 +105,16 @@ static void amdgpu_mux_resubmit_chunks(struct amdgpu_ring_mux *mux)
                                amdgpu_fence_update_start_timestamp(e->ring,
                                                                    chunk->sync_seq,
                                                                    ktime_get());
+                               if (chunk->sync_seq ==
+                                       le32_to_cpu(*(e->ring->fence_drv.cpu_addr + 2))) {
+                                       if (chunk->cntl_offset <= e->ring->buf_mask)
+                                               amdgpu_ring_patch_cntl(e->ring,
+                                                                      chunk->cntl_offset);
+                                       if (chunk->ce_offset <= e->ring->buf_mask)
+                                               amdgpu_ring_patch_ce(e->ring, chunk->ce_offset);
+                                       if (chunk->de_offset <= e->ring->buf_mask)
+                                               amdgpu_ring_patch_de(e->ring, chunk->de_offset);
+                               }
                                amdgpu_ring_mux_copy_pkt_from_sw_ring(mux, e->ring,
                                                                      chunk->start,
                                                                      chunk->end);
@@ -407,6 +417,17 @@ void amdgpu_sw_ring_ib_end(struct amdgpu_ring *ring)
        amdgpu_ring_mux_end_ib(mux, ring);
 }
 
+void amdgpu_sw_ring_ib_mark_offset(struct amdgpu_ring *ring, enum amdgpu_ring_mux_offset_type type)
+{
+       struct amdgpu_device *adev = ring->adev;
+       struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
+       unsigned offset;
+
+       offset = ring->wptr & ring->buf_mask;
+
+       amdgpu_ring_mux_ib_mark_offset(mux, ring, offset, type);
+}
+
 void amdgpu_ring_mux_start_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
 {
        struct amdgpu_mux_entry *e;
@@ -429,6 +450,10 @@ void amdgpu_ring_mux_start_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *r
        }
 
        chunk->start = ring->wptr;
+       /* the initialized value used to check if they are set by the ib submission*/
+       chunk->cntl_offset = ring->buf_mask + 1;
+       chunk->de_offset = ring->buf_mask + 1;
+       chunk->ce_offset = ring->buf_mask + 1;
        list_add_tail(&chunk->entry, &e->list);
 }
 
@@ -454,6 +479,41 @@ static void scan_and_remove_signaled_chunk(struct amdgpu_ring_mux *mux, struct a
        }
 }
 
+void amdgpu_ring_mux_ib_mark_offset(struct amdgpu_ring_mux *mux,
+                                   struct amdgpu_ring *ring, u64 offset,
+                                   enum amdgpu_ring_mux_offset_type type)
+{
+       struct amdgpu_mux_entry *e;
+       struct amdgpu_mux_chunk *chunk;
+
+       e = amdgpu_ring_mux_sw_entry(mux, ring);
+       if (!e) {
+               DRM_ERROR("cannot find entry!\n");
+               return;
+       }
+
+       chunk = list_last_entry(&e->list, struct amdgpu_mux_chunk, entry);
+       if (!chunk) {
+               DRM_ERROR("cannot find chunk!\n");
+               return;
+       }
+
+       switch (type) {
+       case AMDGPU_MUX_OFFSET_TYPE_CONTROL:
+               chunk->cntl_offset = offset;
+               break;
+       case AMDGPU_MUX_OFFSET_TYPE_DE:
+               chunk->de_offset = offset;
+               break;
+       case AMDGPU_MUX_OFFSET_TYPE_CE:
+               chunk->ce_offset = offset;
+               break;
+       default:
+               DRM_ERROR("invalid type (%d)\n", type);
+               break;
+       }
+}
+
 void amdgpu_ring_mux_end_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring)
 {
        struct amdgpu_mux_entry *e;
index 4be45fc..b22d4fb 100644 (file)
@@ -50,6 +50,12 @@ struct amdgpu_mux_entry {
        struct list_head        list;
 };
 
+enum amdgpu_ring_mux_offset_type {
+       AMDGPU_MUX_OFFSET_TYPE_CONTROL,
+       AMDGPU_MUX_OFFSET_TYPE_DE,
+       AMDGPU_MUX_OFFSET_TYPE_CE,
+};
+
 struct amdgpu_ring_mux {
        struct amdgpu_ring      *real_ring;
 
@@ -72,12 +78,18 @@ struct amdgpu_ring_mux {
  * @sync_seq: the fence seqno related with the saved IB.
  * @start:- start location on the software ring.
  * @end:- end location on the software ring.
+ * @control_offset:- the PRE_RESUME bit position used for resubmission.
+ * @de_offset:- the anchor in write_data for de meta of resubmission.
+ * @ce_offset:- the anchor in write_data for ce meta of resubmission.
  */
 struct amdgpu_mux_chunk {
        struct list_head        entry;
        uint32_t                sync_seq;
        u64                     start;
        u64                     end;
+       u64                     cntl_offset;
+       u64                     de_offset;
+       u64                     ce_offset;
 };
 
 int amdgpu_ring_mux_init(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring,
@@ -89,6 +101,8 @@ u64 amdgpu_ring_mux_get_wptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ri
 u64 amdgpu_ring_mux_get_rptr(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
 void amdgpu_ring_mux_start_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
 void amdgpu_ring_mux_end_ib(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring);
+void amdgpu_ring_mux_ib_mark_offset(struct amdgpu_ring_mux *mux, struct amdgpu_ring *ring,
+                                   u64 offset, enum amdgpu_ring_mux_offset_type type);
 bool amdgpu_mcbp_handle_trailing_fence_irq(struct amdgpu_ring_mux *mux);
 
 u64 amdgpu_sw_ring_get_rptr_gfx(struct amdgpu_ring *ring);
@@ -97,6 +111,7 @@ void amdgpu_sw_ring_set_wptr_gfx(struct amdgpu_ring *ring);
 void amdgpu_sw_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count);
 void amdgpu_sw_ring_ib_begin(struct amdgpu_ring *ring);
 void amdgpu_sw_ring_ib_end(struct amdgpu_ring *ring);
+void amdgpu_sw_ring_ib_mark_offset(struct amdgpu_ring *ring, enum amdgpu_ring_mux_offset_type type);
 const char *amdgpu_sw_ring_name(int idx);
 unsigned int amdgpu_sw_ring_priority(int idx);
 
index df63dc3..051c719 100644 (file)
@@ -564,7 +564,6 @@ int amdgpu_vm_pt_create(struct amdgpu_device *adev, struct amdgpu_vm *vm,
                return r;
        }
 
-       (*vmbo)->shadow->parent = amdgpu_bo_ref(bo);
        amdgpu_bo_add_to_shadow_list(*vmbo);
 
        return 0;
index 43d6a9d..afacfb9 100644 (file)
@@ -800,7 +800,7 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
 {
        struct amdgpu_vram_mgr *mgr = to_vram_mgr(man);
        struct drm_buddy *mm = &mgr->mm;
-       struct drm_buddy_block *block;
+       struct amdgpu_vram_reservation *rsv;
 
        drm_printf(printer, "  vis usage:%llu\n",
                   amdgpu_vram_mgr_vis_usage(mgr));
@@ -812,8 +812,9 @@ static void amdgpu_vram_mgr_debug(struct ttm_resource_manager *man,
        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);
+       list_for_each_entry(rsv, &mgr->reserved_pages, blocks)
+               drm_printf(printer, "%#018llx-%#018llx: %llu\n",
+                       rsv->start, rsv->start + rsv->size, rsv->size);
        mutex_unlock(&mgr->lock);
 }
 
index ce22f7b..a674c8a 100644 (file)
@@ -149,16 +149,6 @@ MODULE_FIRMWARE("amdgpu/aldebaran_sjt_mec2.bin");
 #define mmGOLDEN_TSC_COUNT_LOWER_Renoir                0x0026
 #define mmGOLDEN_TSC_COUNT_LOWER_Renoir_BASE_IDX       1
 
-#define mmGOLDEN_TSC_COUNT_UPPER_Raven   0x007a
-#define mmGOLDEN_TSC_COUNT_UPPER_Raven_BASE_IDX 0
-#define mmGOLDEN_TSC_COUNT_LOWER_Raven   0x007b
-#define mmGOLDEN_TSC_COUNT_LOWER_Raven_BASE_IDX 0
-
-#define mmGOLDEN_TSC_COUNT_UPPER_Raven2   0x0068
-#define mmGOLDEN_TSC_COUNT_UPPER_Raven2_BASE_IDX 0
-#define mmGOLDEN_TSC_COUNT_LOWER_Raven2   0x0069
-#define mmGOLDEN_TSC_COUNT_LOWER_Raven2_BASE_IDX 0
-
 enum ta_ras_gfx_subblock {
        /*CPC*/
        TA_RAS_BLOCK__GFX_CPC_INDEX_START = 0,
@@ -765,7 +755,7 @@ static void gfx_v9_0_set_rlc_funcs(struct amdgpu_device *adev);
 static int gfx_v9_0_get_cu_info(struct amdgpu_device *adev,
                                struct amdgpu_cu_info *cu_info);
 static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev);
-static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume);
+static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume, bool usegds);
 static u64 gfx_v9_0_ring_get_rptr_compute(struct amdgpu_ring *ring);
 static void gfx_v9_0_query_ras_error_count(struct amdgpu_device *adev,
                                          void *ras_error_status);
@@ -4004,31 +3994,6 @@ static uint64_t gfx_v9_0_get_gpu_clock_counter(struct amdgpu_device *adev)
                preempt_enable();
                clock = clock_lo | (clock_hi << 32ULL);
                break;
-       case IP_VERSION(9, 1, 0):
-       case IP_VERSION(9, 2, 2):
-               preempt_disable();
-               if (adev->rev_id >= 0x8) {
-                       clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2);
-                       clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2);
-                       hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven2);
-               } else {
-                       clock_hi = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven);
-                       clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven);
-                       hi_check = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_UPPER_Raven);
-               }
-               /* The PWR TSC clock frequency is 100MHz, which sets 32-bit carry over
-               * roughly every 42 seconds.
-               */
-               if (hi_check != clock_hi) {
-                       if (adev->rev_id >= 0x8)
-                               clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven2);
-                       else
-                               clock_lo = RREG32_SOC15_NO_KIQ(PWR, 0, mmGOLDEN_TSC_COUNT_LOWER_Raven);
-                       clock_hi = hi_check;
-               }
-               preempt_enable();
-               clock = clock_lo | (clock_hi << 32ULL);
-               break;
        default:
                amdgpu_gfx_off_ctrl(adev, false);
                mutex_lock(&adev->gfx.gpu_clock_mutex);
@@ -5162,7 +5127,8 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
                        gfx_v9_0_ring_emit_de_meta(ring,
                                                   (!amdgpu_sriov_vf(ring->adev) &&
                                                   flags & AMDGPU_IB_PREEMPTED) ?
-                                                  true : false);
+                                                  true : false,
+                                                  job->gds_size > 0 && job->gds_base != 0);
        }
 
        amdgpu_ring_write(ring, header);
@@ -5173,9 +5139,83 @@ static void gfx_v9_0_ring_emit_ib_gfx(struct amdgpu_ring *ring,
 #endif
                lower_32_bits(ib->gpu_addr));
        amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr));
+       amdgpu_ring_ib_on_emit_cntl(ring);
        amdgpu_ring_write(ring, control);
 }
 
+static void gfx_v9_0_ring_patch_cntl(struct amdgpu_ring *ring,
+                                    unsigned offset)
+{
+       u32 control = ring->ring[offset];
+
+       control |= INDIRECT_BUFFER_PRE_RESUME(1);
+       ring->ring[offset] = control;
+}
+
+static void gfx_v9_0_ring_patch_ce_meta(struct amdgpu_ring *ring,
+                                       unsigned offset)
+{
+       struct amdgpu_device *adev = ring->adev;
+       void *ce_payload_cpu_addr;
+       uint64_t payload_offset, payload_size;
+
+       payload_size = sizeof(struct v9_ce_ib_state);
+
+       if (ring->is_mes_queue) {
+               payload_offset = offsetof(struct amdgpu_mes_ctx_meta_data,
+                                         gfx[0].gfx_meta_data) +
+                       offsetof(struct v9_gfx_meta_data, ce_payload);
+               ce_payload_cpu_addr =
+                       amdgpu_mes_ctx_get_offs_cpu_addr(ring, payload_offset);
+       } else {
+               payload_offset = offsetof(struct v9_gfx_meta_data, ce_payload);
+               ce_payload_cpu_addr = adev->virt.csa_cpu_addr + payload_offset;
+       }
+
+       if (offset + (payload_size >> 2) <= ring->buf_mask + 1) {
+               memcpy((void *)&ring->ring[offset], ce_payload_cpu_addr, payload_size);
+       } else {
+               memcpy((void *)&ring->ring[offset], ce_payload_cpu_addr,
+                      (ring->buf_mask + 1 - offset) << 2);
+               payload_size -= (ring->buf_mask + 1 - offset) << 2;
+               memcpy((void *)&ring->ring[0],
+                      ce_payload_cpu_addr + ((ring->buf_mask + 1 - offset) << 2),
+                      payload_size);
+       }
+}
+
+static void gfx_v9_0_ring_patch_de_meta(struct amdgpu_ring *ring,
+                                       unsigned offset)
+{
+       struct amdgpu_device *adev = ring->adev;
+       void *de_payload_cpu_addr;
+       uint64_t payload_offset, payload_size;
+
+       payload_size = sizeof(struct v9_de_ib_state);
+
+       if (ring->is_mes_queue) {
+               payload_offset = offsetof(struct amdgpu_mes_ctx_meta_data,
+                                         gfx[0].gfx_meta_data) +
+                       offsetof(struct v9_gfx_meta_data, de_payload);
+               de_payload_cpu_addr =
+                       amdgpu_mes_ctx_get_offs_cpu_addr(ring, payload_offset);
+       } else {
+               payload_offset = offsetof(struct v9_gfx_meta_data, de_payload);
+               de_payload_cpu_addr = adev->virt.csa_cpu_addr + payload_offset;
+       }
+
+       if (offset + (payload_size >> 2) <= ring->buf_mask + 1) {
+               memcpy((void *)&ring->ring[offset], de_payload_cpu_addr, payload_size);
+       } else {
+               memcpy((void *)&ring->ring[offset], de_payload_cpu_addr,
+                      (ring->buf_mask + 1 - offset) << 2);
+               payload_size -= (ring->buf_mask + 1 - offset) << 2;
+               memcpy((void *)&ring->ring[0],
+                      de_payload_cpu_addr + ((ring->buf_mask + 1 - offset) << 2),
+                      payload_size);
+       }
+}
+
 static void gfx_v9_0_ring_emit_ib_compute(struct amdgpu_ring *ring,
                                          struct amdgpu_job *job,
                                          struct amdgpu_ib *ib,
@@ -5371,6 +5411,8 @@ static void gfx_v9_0_ring_emit_ce_meta(struct amdgpu_ring *ring, bool resume)
        amdgpu_ring_write(ring, lower_32_bits(ce_payload_gpu_addr));
        amdgpu_ring_write(ring, upper_32_bits(ce_payload_gpu_addr));
 
+       amdgpu_ring_ib_on_emit_ce(ring);
+
        if (resume)
                amdgpu_ring_write_multiple(ring, ce_payload_cpu_addr,
                                           sizeof(ce_payload) >> 2);
@@ -5404,10 +5446,6 @@ static int gfx_v9_0_ring_preempt_ib(struct amdgpu_ring *ring)
        amdgpu_ring_alloc(ring, 13);
        gfx_v9_0_ring_emit_fence(ring, ring->trail_fence_gpu_addr,
                                 ring->trail_seq, AMDGPU_FENCE_FLAG_EXEC | AMDGPU_FENCE_FLAG_INT);
-       /*reset the CP_VMID_PREEMPT after trailing fence*/
-       amdgpu_ring_emit_wreg(ring,
-                             SOC15_REG_OFFSET(GC, 0, mmCP_VMID_PREEMPT),
-                             0x0);
 
        /* assert IB preemption, emit the trailing fence */
        kiq->pmf->kiq_unmap_queues(kiq_ring, ring, PREEMPT_QUEUES_NO_UNMAP,
@@ -5430,6 +5468,10 @@ static int gfx_v9_0_ring_preempt_ib(struct amdgpu_ring *ring)
                DRM_WARN("ring %d timeout to preempt ib\n", ring->idx);
        }
 
+       /*reset the CP_VMID_PREEMPT after trailing fence*/
+       amdgpu_ring_emit_wreg(ring,
+                             SOC15_REG_OFFSET(GC, 0, mmCP_VMID_PREEMPT),
+                             0x0);
        amdgpu_ring_commit(ring);
 
        /* deassert preemption condition */
@@ -5437,7 +5479,7 @@ static int gfx_v9_0_ring_preempt_ib(struct amdgpu_ring *ring)
        return r;
 }
 
-static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume)
+static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume, bool usegds)
 {
        struct amdgpu_device *adev = ring->adev;
        struct v9_de_ib_state de_payload = {0};
@@ -5468,8 +5510,10 @@ static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume)
                                 PAGE_SIZE);
        }
 
-       de_payload.gds_backup_addrlo = lower_32_bits(gds_addr);
-       de_payload.gds_backup_addrhi = upper_32_bits(gds_addr);
+       if (usegds) {
+               de_payload.gds_backup_addrlo = lower_32_bits(gds_addr);
+               de_payload.gds_backup_addrhi = upper_32_bits(gds_addr);
+       }
 
        cnt = (sizeof(de_payload) >> 2) + 4 - 2;
        amdgpu_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, cnt));
@@ -5480,6 +5524,7 @@ static void gfx_v9_0_ring_emit_de_meta(struct amdgpu_ring *ring, bool resume)
        amdgpu_ring_write(ring, lower_32_bits(de_payload_gpu_addr));
        amdgpu_ring_write(ring, upper_32_bits(de_payload_gpu_addr));
 
+       amdgpu_ring_ib_on_emit_de(ring);
        if (resume)
                amdgpu_ring_write_multiple(ring, de_payload_cpu_addr,
                                           sizeof(de_payload) >> 2);
@@ -6890,6 +6935,9 @@ static const struct amdgpu_ring_funcs gfx_v9_0_sw_ring_funcs_gfx = {
        .emit_reg_write_reg_wait = gfx_v9_0_ring_emit_reg_write_reg_wait,
        .soft_recovery = gfx_v9_0_ring_soft_recovery,
        .emit_mem_sync = gfx_v9_0_emit_mem_sync,
+       .patch_cntl = gfx_v9_0_ring_patch_cntl,
+       .patch_de = gfx_v9_0_ring_patch_de_meta,
+       .patch_ce = gfx_v9_0_ring_patch_ce_meta,
 };
 
 static const struct amdgpu_ring_funcs gfx_v9_0_ring_funcs_compute = {
index 6d15d5c..a2fd1ff 100644 (file)
@@ -301,10 +301,11 @@ static u32 soc15_get_xclk(struct amdgpu_device *adev)
        u32 reference_clock = adev->clock.spll.reference_freq;
 
        if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 0) ||
-           adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1) ||
-           adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 0) ||
-           adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 1))
+           adev->ip_versions[MP1_HWIP][0] == IP_VERSION(12, 0, 1))
                return 10000;
+       if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 0) ||
+           adev->ip_versions[MP1_HWIP][0] == IP_VERSION(10, 0, 1))
+               return reference_clock / 4;
 
        return reference_clock;
 }
index e5fd1e0..da126ff 100644 (file)
@@ -129,7 +129,11 @@ static int vcn_v4_0_sw_init(void *handle)
                if (adev->vcn.harvest_config & (1 << i))
                        continue;
 
-               atomic_set(&adev->vcn.inst[i].sched_score, 0);
+               /* Init instance 0 sched_score to 1, so it's scheduled after other instances */
+               if (i == 0)
+                       atomic_set(&adev->vcn.inst[i].sched_score, 1);
+               else
+                       atomic_set(&adev->vcn.inst[i].sched_score, 0);
 
                /* VCN UNIFIED TRAP */
                r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
index 531f173..c0360db 100644 (file)
@@ -542,8 +542,15 @@ static u32 vi_get_xclk(struct amdgpu_device *adev)
        u32 reference_clock = adev->clock.spll.reference_freq;
        u32 tmp;
 
-       if (adev->flags & AMD_IS_APU)
-               return reference_clock;
+       if (adev->flags & AMD_IS_APU) {
+               switch (adev->asic_type) {
+               case CHIP_STONEY:
+                       /* vbios says 48Mhz, but the actual freq is 100Mhz */
+                       return 10000;
+               default:
+                       return reference_clock;
+               }
+       }
 
        tmp = RREG32_SMC(ixCG_CLKPIN_CNTL_2);
        if (REG_GET_FIELD(tmp, CG_CLKPIN_CNTL_2, MUX_TCLK_TO_XCLK))
index d5cec03..7acd73e 100644 (file)
@@ -7196,7 +7196,13 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
                                drm_add_modes_noedid(connector, 1920, 1080);
        } else {
                amdgpu_dm_connector_ddc_get_modes(connector, edid);
-               amdgpu_dm_connector_add_common_modes(encoder, connector);
+               /* most eDP supports only timings from its edid,
+                * usually only detailed timings are available
+                * from eDP edid. timings which are not from edid
+                * may damage eDP
+                */
+               if (connector->connector_type != DRM_MODE_CONNECTOR_eDP)
+                       amdgpu_dm_connector_add_common_modes(encoder, connector);
                amdgpu_dm_connector_add_freesync_modes(connector, edid);
        }
        amdgpu_dm_fbc_init(connector);
@@ -8198,6 +8204,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
                        bundle->stream_update.abm_level = &acrtc_state->abm_level;
 
+               mutex_lock(&dm->dc_lock);
+               if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
+                               acrtc_state->stream->link->psr_settings.psr_allow_active)
+                       amdgpu_dm_psr_disable(acrtc_state->stream);
+               mutex_unlock(&dm->dc_lock);
+
                /*
                 * If FreeSync state on the stream has changed then we need to
                 * re-adjust the min/max bounds now that DC doesn't handle this
@@ -8211,10 +8223,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                        spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
                }
                mutex_lock(&dm->dc_lock);
-               if ((acrtc_state->update_type > UPDATE_TYPE_FAST) &&
-                               acrtc_state->stream->link->psr_settings.psr_allow_active)
-                       amdgpu_dm_psr_disable(acrtc_state->stream);
-
                update_planes_and_stream_adapter(dm->dc,
                                         acrtc_state->update_type,
                                         planes_count,
index 52564b9..7cde67b 100644 (file)
@@ -1981,6 +1981,9 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
        return result;
 }
 
+static bool commit_minimal_transition_state(struct dc *dc,
+               struct dc_state *transition_base_context);
+
 /**
  * dc_commit_streams - Commit current stream state
  *
@@ -2002,6 +2005,8 @@ enum dc_status dc_commit_streams(struct dc *dc,
        struct dc_state *context;
        enum dc_status res = DC_OK;
        struct dc_validation_set set[MAX_STREAMS] = {0};
+       struct pipe_ctx *pipe;
+       bool handle_exit_odm2to1 = false;
 
        if (dc->ctx->dce_environment == DCE_ENV_VIRTUAL_HW)
                return res;
@@ -2026,6 +2031,22 @@ enum dc_status dc_commit_streams(struct dc *dc,
                }
        }
 
+       /* Check for case where we are going from odm 2:1 to max
+        *  pipe scenario.  For these cases, we will call
+        *  commit_minimal_transition_state() to exit out of odm 2:1
+        *  first before processing new streams
+        */
+       if (stream_count == dc->res_pool->pipe_count) {
+               for (i = 0; i < dc->res_pool->pipe_count; i++) {
+                       pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+                       if (pipe->next_odm_pipe)
+                               handle_exit_odm2to1 = true;
+               }
+       }
+
+       if (handle_exit_odm2to1)
+               res = commit_minimal_transition_state(dc, dc->current_state);
+
        context = dc_create_state(dc);
        if (!context)
                goto context_alloc_fail;
@@ -3872,6 +3893,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
        unsigned int i, j;
        unsigned int pipe_in_use = 0;
        bool subvp_in_use = false;
+       bool odm_in_use = false;
 
        if (!transition_context)
                return false;
@@ -3900,6 +3922,18 @@ static bool commit_minimal_transition_state(struct dc *dc,
                }
        }
 
+       /* If ODM is enabled and we are adding or removing planes from any ODM
+        * pipe, we must use the minimal transition.
+        */
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream && pipe->next_odm_pipe) {
+                       odm_in_use = true;
+                       break;
+               }
+       }
+
        /* When the OS add a new surface if we have been used all of pipes with odm combine
         * and mpc split feature, it need use commit_minimal_transition_state to transition safely.
         * After OS exit MPO, it will back to use odm and mpc split with all of pipes, we need
@@ -3908,7 +3942,7 @@ static bool commit_minimal_transition_state(struct dc *dc,
         * Reduce the scenarios to use dc_commit_state_no_check in the stage of flip. Especially
         * enter/exit MPO when DCN still have enough resources.
         */
-       if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use) {
+       if (pipe_in_use != dc->res_pool->pipe_count && !subvp_in_use && !odm_in_use) {
                dc_release_state(transition_context);
                return true;
        }
index 117d80c..fe15513 100644 (file)
@@ -1446,6 +1446,26 @@ static int acquire_first_split_pipe(
 
                        split_pipe->stream = stream;
                        return i;
+               } else if (split_pipe->prev_odm_pipe &&
+                               split_pipe->prev_odm_pipe->plane_state == split_pipe->plane_state) {
+                       split_pipe->prev_odm_pipe->next_odm_pipe = split_pipe->next_odm_pipe;
+                       if (split_pipe->next_odm_pipe)
+                               split_pipe->next_odm_pipe->prev_odm_pipe = split_pipe->prev_odm_pipe;
+
+                       if (split_pipe->prev_odm_pipe->plane_state)
+                               resource_build_scaling_params(split_pipe->prev_odm_pipe);
+
+                       memset(split_pipe, 0, sizeof(*split_pipe));
+                       split_pipe->stream_res.tg = pool->timing_generators[i];
+                       split_pipe->plane_res.hubp = pool->hubps[i];
+                       split_pipe->plane_res.ipp = pool->ipps[i];
+                       split_pipe->plane_res.dpp = pool->dpps[i];
+                       split_pipe->stream_res.opp = pool->opps[i];
+                       split_pipe->plane_res.mpcc_inst = pool->dpps[i]->inst;
+                       split_pipe->pipe_idx = i;
+
+                       split_pipe->stream = stream;
+                       return i;
                }
        }
        return -1;
index 47beb4e..0c4c320 100644 (file)
@@ -138,7 +138,7 @@ struct _vcs_dpi_soc_bounding_box_st dcn3_2_soc = {
        .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
        .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
        .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
-       .pct_ideal_sdp_bw_after_urgent = 100.0,
+       .pct_ideal_sdp_bw_after_urgent = 90.0,
        .pct_ideal_fabric_bw_after_urgent = 67.0,
        .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 20.0,
        .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0, // N/A, for now keep as is until DML implemented
index a131e30..d471d58 100644 (file)
@@ -980,6 +980,11 @@ static bool detect_link_and_local_sink(struct dc_link *link,
                                        (link->dpcd_caps.dongle_type !=
                                                        DISPLAY_DONGLE_DP_HDMI_CONVERTER))
                                converter_disable_audio = true;
+
+                       /* limited link rate to HBR3 for DPIA until we implement USB4 V2 */
+                       if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+                                       link->reported_link_cap.link_rate > LINK_RATE_HIGH3)
+                               link->reported_link_cap.link_rate = LINK_RATE_HIGH3;
                        break;
                }
 
index 75f1868..85d5359 100644 (file)
@@ -2067,33 +2067,94 @@ static int sienna_cichlid_display_disable_memory_clock_switch(struct smu_context
        return ret;
 }
 
+static void sienna_cichlid_get_override_pcie_settings(struct smu_context *smu,
+                                                     uint32_t *gen_speed_override,
+                                                     uint32_t *lane_width_override)
+{
+       struct amdgpu_device *adev = smu->adev;
+
+       *gen_speed_override = 0xff;
+       *lane_width_override = 0xff;
+
+       switch (adev->pdev->device) {
+       case 0x73A0:
+       case 0x73A1:
+       case 0x73A2:
+       case 0x73A3:
+       case 0x73AB:
+       case 0x73AE:
+               /* Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32 */
+               *lane_width_override = 6;
+               break;
+       case 0x73E0:
+       case 0x73E1:
+       case 0x73E3:
+               *lane_width_override = 4;
+               break;
+       case 0x7420:
+       case 0x7421:
+       case 0x7422:
+       case 0x7423:
+       case 0x7424:
+               *lane_width_override = 3;
+               break;
+       default:
+               break;
+       }
+}
+
+#define MAX(a, b)      ((a) > (b) ? (a) : (b))
+
 static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
                                         uint32_t pcie_gen_cap,
                                         uint32_t pcie_width_cap)
 {
        struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
-
-       uint32_t smu_pcie_arg;
+       struct smu_11_0_pcie_table *pcie_table = &dpm_context->dpm_tables.pcie_table;
+       uint32_t gen_speed_override, lane_width_override;
        uint8_t *table_member1, *table_member2;
+       uint32_t min_gen_speed, max_gen_speed;
+       uint32_t min_lane_width, max_lane_width;
+       uint32_t smu_pcie_arg;
        int ret, i;
 
        GET_PPTABLE_MEMBER(PcieGenSpeed, &table_member1);
        GET_PPTABLE_MEMBER(PcieLaneCount, &table_member2);
 
-       /* lclk dpm table setup */
-       for (i = 0; i < MAX_PCIE_CONF; i++) {
-               dpm_context->dpm_tables.pcie_table.pcie_gen[i] = table_member1[i];
-               dpm_context->dpm_tables.pcie_table.pcie_lane[i] = table_member2[i];
+       sienna_cichlid_get_override_pcie_settings(smu,
+                                                 &gen_speed_override,
+                                                 &lane_width_override);
+
+       /* PCIE gen speed override */
+       if (gen_speed_override != 0xff) {
+               min_gen_speed = MIN(pcie_gen_cap, gen_speed_override);
+               max_gen_speed = MIN(pcie_gen_cap, gen_speed_override);
+       } else {
+               min_gen_speed = MAX(0, table_member1[0]);
+               max_gen_speed = MIN(pcie_gen_cap, table_member1[1]);
+               min_gen_speed = min_gen_speed > max_gen_speed ?
+                               max_gen_speed : min_gen_speed;
        }
+       pcie_table->pcie_gen[0] = min_gen_speed;
+       pcie_table->pcie_gen[1] = max_gen_speed;
+
+       /* PCIE lane width override */
+       if (lane_width_override != 0xff) {
+               min_lane_width = MIN(pcie_width_cap, lane_width_override);
+               max_lane_width = MIN(pcie_width_cap, lane_width_override);
+       } else {
+               min_lane_width = MAX(1, table_member2[0]);
+               max_lane_width = MIN(pcie_width_cap, table_member2[1]);
+               min_lane_width = min_lane_width > max_lane_width ?
+                                max_lane_width : min_lane_width;
+       }
+       pcie_table->pcie_lane[0] = min_lane_width;
+       pcie_table->pcie_lane[1] = max_lane_width;
 
        for (i = 0; i < NUM_LINK_LEVELS; i++) {
-               smu_pcie_arg = (i << 16) |
-                       ((table_member1[i] <= pcie_gen_cap) ?
-                        (table_member1[i] << 8) :
-                        (pcie_gen_cap << 8)) |
-                       ((table_member2[i] <= pcie_width_cap) ?
-                        table_member2[i] :
-                        pcie_width_cap);
+               smu_pcie_arg = (i << 16 |
+                               pcie_table->pcie_gen[i] << 8 |
+                               pcie_table->pcie_lane[i]);
 
                ret = smu_cmn_send_smc_msg_with_param(smu,
                                SMU_MSG_OverridePcieParameters,
@@ -2101,11 +2162,6 @@ static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
                                NULL);
                if (ret)
                        return ret;
-
-               if (table_member1[i] > pcie_gen_cap)
-                       dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap;
-               if (table_member2[i] > pcie_width_cap)
-                       dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap;
        }
 
        return 0;
index 393c6a7..ca37918 100644 (file)
@@ -573,11 +573,11 @@ int smu_v13_0_init_power(struct smu_context *smu)
        if (smu_power->power_context || smu_power->power_context_size != 0)
                return -EINVAL;
 
-       smu_power->power_context = kzalloc(sizeof(struct smu_13_0_dpm_context),
+       smu_power->power_context = kzalloc(sizeof(struct smu_13_0_power_context),
                                           GFP_KERNEL);
        if (!smu_power->power_context)
                return -ENOMEM;
-       smu_power->power_context_size = sizeof(struct smu_13_0_dpm_context);
+       smu_power->power_context_size = sizeof(struct smu_13_0_power_context);
 
        return 0;
 }
index 09405ef..08577d1 100644 (file)
@@ -1696,10 +1696,39 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
                }
        }
 
-       /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
-       workload_type = smu_cmn_to_asic_specific_index(smu,
+       if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE &&
+               (((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xC8)) ||
+               ((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xCC)))) {
+               ret = smu_cmn_update_table(smu,
+                                          SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+                                          WORKLOAD_PPLIB_COMPUTE_BIT,
+                                          (void *)(&activity_monitor_external),
+                                          false);
+               if (ret) {
+                       dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
+                       return ret;
+               }
+
+               ret = smu_cmn_update_table(smu,
+                                          SMU_TABLE_ACTIVITY_MONITOR_COEFF,
+                                          WORKLOAD_PPLIB_CUSTOM_BIT,
+                                          (void *)(&activity_monitor_external),
+                                          true);
+               if (ret) {
+                       dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
+                       return ret;
+               }
+
+               workload_type = smu_cmn_to_asic_specific_index(smu,
+                                                      CMN2ASIC_MAPPING_WORKLOAD,
+                                                      PP_SMC_POWER_PROFILE_CUSTOM);
+       } else {
+               /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+               workload_type = smu_cmn_to_asic_specific_index(smu,
                                                       CMN2ASIC_MAPPING_WORKLOAD,
                                                       smu->power_profile_mode);
+       }
+
        if (workload_type < 0)
                return -EINVAL;
 
index fbb070f..6dc1a09 100644 (file)
@@ -119,53 +119,32 @@ err_astdp_edid_not_ready:
 /*
  * Launch Aspeed DP
  */
-void ast_dp_launch(struct drm_device *dev, u8 bPower)
+void ast_dp_launch(struct drm_device *dev)
 {
-       u32 i = 0, j = 0, WaitCount = 1;
-       u8 bDPTX = 0;
+       u32 i = 0;
        u8 bDPExecute = 1;
-
        struct ast_device *ast = to_ast_device(dev);
-       // S3 come back, need more time to wait BMC ready.
-       if (bPower)
-               WaitCount = 300;
-
-
-       // Wait total count by different condition.
-       for (j = 0; j < WaitCount; j++) {
-               bDPTX = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, TX_TYPE_MASK);
-
-               if (bDPTX)
-                       break;
 
+       // Wait one second then timeout.
+       while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, ASTDP_MCU_FW_EXECUTING) !=
+               ASTDP_MCU_FW_EXECUTING) {
+               i++;
+               // wait 100 ms
                msleep(100);
-       }
 
-       // 0xE : ASTDP with DPMCU FW handling
-       if (bDPTX == ASTDP_DPMCU_TX) {
-               // Wait one second then timeout.
-               i = 0;
-
-               while (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, COPROCESSOR_LAUNCH) !=
-                       COPROCESSOR_LAUNCH) {
-                       i++;
-                       // wait 100 ms
-                       msleep(100);
-
-                       if (i >= 10) {
-                               // DP would not be ready.
-                               bDPExecute = 0;
-                               break;
-                       }
+               if (i >= 10) {
+                       // DP would not be ready.
+                       bDPExecute = 0;
+                       break;
                }
+       }
 
-               if (bDPExecute)
-                       ast->tx_chip_types |= BIT(AST_TX_ASTDP);
+       if (!bDPExecute)
+               drm_err(dev, "Wait DPMCU executing timeout\n");
 
-               ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
-                                                       (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
-                                                       ASTDP_HOST_EDID_READ_DONE);
-       }
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xE5,
+                              (u8) ~ASTDP_HOST_EDID_READ_DONE_MASK,
+                              ASTDP_HOST_EDID_READ_DONE);
 }
 
 
index a501169..5498a66 100644 (file)
@@ -350,9 +350,6 @@ int ast_mode_config_init(struct ast_device *ast);
 #define AST_DP501_LINKRATE     0xf014
 #define AST_DP501_EDID_DATA    0xf020
 
-/* Define for Soc scratched reg */
-#define COPROCESSOR_LAUNCH                     BIT(5)
-
 /*
  * Display Transmitter Type:
  */
@@ -480,7 +477,7 @@ struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
 
 /* aspeed DP */
 int ast_astdp_read_edid(struct drm_device *dev, u8 *ediddata);
-void ast_dp_launch(struct drm_device *dev, u8 bPower);
+void ast_dp_launch(struct drm_device *dev);
 void ast_dp_power_on_off(struct drm_device *dev, bool no);
 void ast_dp_set_on_off(struct drm_device *dev, bool no);
 void ast_dp_set_mode(struct drm_crtc *crtc, struct ast_vbios_mode_info *vbios_mode);
index f32ce29..1f35438 100644 (file)
@@ -254,8 +254,13 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
                case 0x0c:
                        ast->tx_chip_types = AST_TX_DP501_BIT;
                }
-       } else if (ast->chip == AST2600)
-               ast_dp_launch(&ast->base, 0);
+       } else if (ast->chip == AST2600) {
+               if (ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xD1, TX_TYPE_MASK) ==
+                   ASTDP_DPMCU_TX) {
+                       ast->tx_chip_types = AST_TX_ASTDP_BIT;
+                       ast_dp_launch(&ast->base);
+               }
+       }
 
        /* Print stuff for diagnostic purposes */
        if (ast->tx_chip_types & AST_TX_NONE_BIT)
@@ -264,6 +269,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post)
                drm_info(dev, "Using Sil164 TMDS transmitter\n");
        if (ast->tx_chip_types & AST_TX_DP501_BIT)
                drm_info(dev, "Using DP501 DisplayPort transmitter\n");
+       if (ast->tx_chip_types & AST_TX_ASTDP_BIT)
+               drm_info(dev, "Using ASPEED DisplayPort transmitter\n");
 
        return 0;
 }
index 3637482..b3c670a 100644 (file)
@@ -1647,6 +1647,8 @@ static int ast_dp501_output_init(struct ast_device *ast)
 static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector)
 {
        void *edid;
+       struct drm_device *dev = connector->dev;
+       struct ast_device *ast = to_ast_device(dev);
 
        int succ;
        int count;
@@ -1655,9 +1657,17 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector)
        if (!edid)
                goto err_drm_connector_update_edid_property;
 
+       /*
+        * Protect access to I/O registers from concurrent modesetting
+        * by acquiring the I/O-register lock.
+        */
+       mutex_lock(&ast->ioregs_lock);
+
        succ = ast_astdp_read_edid(connector->dev, edid);
        if (succ < 0)
-               goto err_kfree;
+               goto err_mutex_unlock;
+
+       mutex_unlock(&ast->ioregs_lock);
 
        drm_connector_update_edid_property(connector, edid);
        count = drm_add_edid_modes(connector, edid);
@@ -1665,7 +1675,8 @@ static int ast_astdp_connector_helper_get_modes(struct drm_connector *connector)
 
        return count;
 
-err_kfree:
+err_mutex_unlock:
+       mutex_unlock(&ast->ioregs_lock);
        kfree(edid);
 err_drm_connector_update_edid_property:
        drm_connector_update_edid_property(connector, NULL);
index 71bb36b..a005aec 100644 (file)
@@ -380,7 +380,8 @@ void ast_post_gpu(struct drm_device *dev)
        ast_set_def_ext_reg(dev);
 
        if (ast->chip == AST2600) {
-               ast_dp_launch(dev, 1);
+               if (ast->tx_chip_types & AST_TX_ASTDP_BIT)
+                       ast_dp_launch(dev);
        } else if (ast->config_mode == ast_use_p2a) {
                if (ast->chip == AST2500)
                        ast_post_chip_2500(dev);
index 7a74878..4676cf2 100644 (file)
@@ -298,6 +298,10 @@ static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata)
                if (refclk_lut[i] == refclk_rate)
                        break;
 
+       /* avoid buffer overflow and "1" is the default rate in the datasheet. */
+       if (i >= refclk_lut_size)
+               i = 1;
+
        regmap_update_bits(pdata->regmap, SN_DPPLL_SRC_REG, REFCLK_FREQ_MASK,
                           REFCLK_FREQ(i));
 
index 6bb1b8b..fd27f19 100644 (file)
@@ -1545,17 +1545,19 @@ static void drm_fb_helper_fill_pixel_fmt(struct fb_var_screeninfo *var,
        }
 }
 
-static void __fill_var(struct fb_var_screeninfo *var,
+static void __fill_var(struct fb_var_screeninfo *var, struct fb_info *info,
                       struct drm_framebuffer *fb)
 {
        int i;
 
        var->xres_virtual = fb->width;
        var->yres_virtual = fb->height;
-       var->accel_flags = FB_ACCELF_TEXT;
+       var->accel_flags = 0;
        var->bits_per_pixel = drm_format_info_bpp(fb->format, 0);
 
-       var->height = var->width = 0;
+       var->height = info->var.height;
+       var->width = info->var.width;
+
        var->left_margin = var->right_margin = 0;
        var->upper_margin = var->lower_margin = 0;
        var->hsync_len = var->vsync_len = 0;
@@ -1618,7 +1620,7 @@ int drm_fb_helper_check_var(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
-       __fill_var(var, fb);
+       __fill_var(var, info, fb);
 
        /*
         * fb_pan_display() validates this, but fb_set_par() doesn't and just
@@ -2074,7 +2076,7 @@ static void drm_fb_helper_fill_var(struct fb_info *info,
        info->pseudo_palette = fb_helper->pseudo_palette;
        info->var.xoffset = 0;
        info->var.yoffset = 0;
-       __fill_var(&info->var, fb);
+       __fill_var(&info->var, info, fb);
        info->var.activate = FB_ACTIVATE_NOW;
 
        drm_fb_helper_fill_pixel_fmt(&info->var, format);
index ec784e5..414e585 100644 (file)
@@ -1335,7 +1335,7 @@ int exynos_g2d_exec_ioctl(struct drm_device *drm_dev, void *data,
        /* Let the runqueue know that there is work to do. */
        queue_work(g2d->g2d_workq, &g2d->runqueue_work);
 
-       if (runqueue_node->async)
+       if (req->async)
                goto out;
 
        wait_for_completion(&runqueue_node->complete);
index 4d56c8c..f5e1adf 100644 (file)
@@ -469,8 +469,6 @@ static int vidi_remove(struct platform_device *pdev)
        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
                kfree(ctx->raw_edid);
                ctx->raw_edid = NULL;
-
-               return -EINVAL;
        }
 
        component_del(&pdev->dev, &vidi_component_ops);
index 084a483..2aaaba0 100644 (file)
@@ -1453,6 +1453,18 @@ static u8 tgl_calc_voltage_level(int cdclk)
                return 0;
 }
 
+static u8 rplu_calc_voltage_level(int cdclk)
+{
+       if (cdclk > 556800)
+               return 3;
+       else if (cdclk > 480000)
+               return 2;
+       else if (cdclk > 312000)
+               return 1;
+       else
+               return 0;
+}
+
 static void icl_readout_refclk(struct drm_i915_private *dev_priv,
                               struct intel_cdclk_config *cdclk_config)
 {
@@ -3242,6 +3254,13 @@ static const struct intel_cdclk_funcs mtl_cdclk_funcs = {
        .calc_voltage_level = tgl_calc_voltage_level,
 };
 
+static const struct intel_cdclk_funcs rplu_cdclk_funcs = {
+       .get_cdclk = bxt_get_cdclk,
+       .set_cdclk = bxt_set_cdclk,
+       .modeset_calc_cdclk = bxt_modeset_calc_cdclk,
+       .calc_voltage_level = rplu_calc_voltage_level,
+};
+
 static const struct intel_cdclk_funcs tgl_cdclk_funcs = {
        .get_cdclk = bxt_get_cdclk,
        .set_cdclk = bxt_set_cdclk,
@@ -3384,14 +3403,17 @@ void intel_init_cdclk_hooks(struct drm_i915_private *dev_priv)
                dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
                dev_priv->display.cdclk.table = dg2_cdclk_table;
        } else if (IS_ALDERLAKE_P(dev_priv)) {
-               dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
                /* Wa_22011320316:adl-p[a0] */
-               if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0))
+               if (IS_ADLP_DISPLAY_STEP(dev_priv, STEP_A0, STEP_B0)) {
                        dev_priv->display.cdclk.table = adlp_a_step_cdclk_table;
-               else if (IS_ADLP_RPLU(dev_priv))
+                       dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
+               } else if (IS_ADLP_RPLU(dev_priv)) {
                        dev_priv->display.cdclk.table = rplu_cdclk_table;
-               else
+                       dev_priv->display.funcs.cdclk = &rplu_cdclk_funcs;
+               } else {
                        dev_priv->display.cdclk.table = adlp_cdclk_table;
+                       dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
+               }
        } else if (IS_ROCKETLAKE(dev_priv)) {
                dev_priv->display.funcs.cdclk = &tgl_cdclk_funcs;
                dev_priv->display.cdclk.table = rkl_cdclk_table;
index 705915d..524bd6d 100644 (file)
@@ -129,7 +129,7 @@ static int intel_dp_aux_sync_len(void)
 
 static int intel_dp_aux_fw_sync_len(void)
 {
-       int precharge = 16; /* 10-16 */
+       int precharge = 10; /* 10-16 */
        int preamble = 8;
 
        return precharge + preamble;
index a81fa6a..7b516b1 100644 (file)
@@ -346,8 +346,10 @@ static int live_parallel_switch(void *arg)
                                continue;
 
                        ce = intel_context_create(data[m].ce[0]->engine);
-                       if (IS_ERR(ce))
+                       if (IS_ERR(ce)) {
+                               err = PTR_ERR(ce);
                                goto out;
+                       }
 
                        err = intel_context_pin(ce);
                        if (err) {
@@ -367,8 +369,10 @@ static int live_parallel_switch(void *arg)
 
                worker = kthread_create_worker(0, "igt/parallel:%s",
                                               data[n].ce[0]->engine->name);
-               if (IS_ERR(worker))
+               if (IS_ERR(worker)) {
+                       err = PTR_ERR(worker);
                        goto out;
+               }
 
                data[n].worker = worker;
        }
@@ -397,8 +401,10 @@ static int live_parallel_switch(void *arg)
                        }
                }
 
-               if (igt_live_test_end(&t))
-                       err = -EIO;
+               if (igt_live_test_end(&t)) {
+                       err = err ?: -EIO;
+                       break;
+               }
        }
 
 out:
index 736b89a..4202df5 100644 (file)
@@ -1530,8 +1530,8 @@ static int live_busywait_preempt(void *arg)
        struct drm_i915_gem_object *obj;
        struct i915_vma *vma;
        enum intel_engine_id id;
-       int err = -ENOMEM;
        u32 *map;
+       int err;
 
        /*
         * Verify that even without HAS_LOGICAL_RING_PREEMPTION, we can
@@ -1539,13 +1539,17 @@ static int live_busywait_preempt(void *arg)
         */
 
        ctx_hi = kernel_context(gt->i915, NULL);
-       if (!ctx_hi)
-               return -ENOMEM;
+       if (IS_ERR(ctx_hi))
+               return PTR_ERR(ctx_hi);
+
        ctx_hi->sched.priority = I915_CONTEXT_MAX_USER_PRIORITY;
 
        ctx_lo = kernel_context(gt->i915, NULL);
-       if (!ctx_lo)
+       if (IS_ERR(ctx_lo)) {
+               err = PTR_ERR(ctx_lo);
                goto err_ctx_hi;
+       }
+
        ctx_lo->sched.priority = I915_CONTEXT_MIN_USER_PRIORITY;
 
        obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE);
index ff00340..ffd91a5 100644 (file)
@@ -165,7 +165,7 @@ int lima_sched_context_init(struct lima_sched_pipe *pipe,
 void lima_sched_context_fini(struct lima_sched_pipe *pipe,
                             struct lima_sched_context *context)
 {
-       drm_sched_entity_fini(&context->base);
+       drm_sched_entity_destroy(&context->base);
 }
 
 struct dma_fence *lima_sched_context_queue_task(struct lima_sched_task *task)
index e16b4b3..8914992 100644 (file)
@@ -1526,8 +1526,6 @@ int a6xx_gmu_init(struct a6xx_gpu *a6xx_gpu, struct device_node *node)
        if (!pdev)
                return -ENODEV;
 
-       mutex_init(&gmu->lock);
-
        gmu->dev = &pdev->dev;
 
        of_dma_configure(gmu->dev, node, true);
index 9fb214f..52da379 100644 (file)
@@ -1981,6 +1981,8 @@ struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
        adreno_gpu = &a6xx_gpu->base;
        gpu = &adreno_gpu->base;
 
+       mutex_init(&a6xx_gpu->gmu.lock);
+
        adreno_gpu->registers = NULL;
 
        /*
index 7a8cf1c..5142aeb 100644 (file)
@@ -620,7 +620,7 @@ void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
                                config & DP_DP_HPD_INT_MASK);
 }
 
-void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
+void dp_catalog_ctrl_hpd_enable(struct dp_catalog *dp_catalog)
 {
        struct dp_catalog_private *catalog = container_of(dp_catalog,
                                struct dp_catalog_private, dp_catalog);
@@ -635,6 +635,19 @@ void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog)
        dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, DP_DP_HPD_CTRL_HPD_EN);
 }
 
+void dp_catalog_ctrl_hpd_disable(struct dp_catalog *dp_catalog)
+{
+       struct dp_catalog_private *catalog = container_of(dp_catalog,
+                               struct dp_catalog_private, dp_catalog);
+
+       u32 reftimer = dp_read_aux(catalog, REG_DP_DP_HPD_REFTIMER);
+
+       reftimer &= ~DP_DP_HPD_REFTIMER_ENABLE;
+       dp_write_aux(catalog, REG_DP_DP_HPD_REFTIMER, reftimer);
+
+       dp_write_aux(catalog, REG_DP_DP_HPD_CTRL, 0);
+}
+
 static void dp_catalog_enable_sdp(struct dp_catalog_private *catalog)
 {
        /* trigger sdp */
index 82376a2..38786e8 100644 (file)
@@ -104,7 +104,8 @@ bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
 void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
                        u32 intr_mask, bool en);
-void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_hpd_enable(struct dp_catalog *dp_catalog);
+void dp_catalog_ctrl_hpd_disable(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog);
 void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter);
 u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
index 99a38db..03b0eda 100644 (file)
 #include "dp_audio.h"
 #include "dp_debug.h"
 
+static bool psr_enabled = false;
+module_param(psr_enabled, bool, 0);
+MODULE_PARM_DESC(psr_enabled, "enable PSR for eDP and DP displays");
+
 #define HPD_STRING_SIZE 30
 
 enum {
@@ -407,7 +411,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
 
        edid = dp->panel->edid;
 
-       dp->dp_display.psr_supported = dp->panel->psr_cap.version;
+       dp->dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled;
 
        dp->audio_supported = drm_detect_monitor_audio(edid);
        dp_panel_handle_sink_request(dp->panel);
@@ -616,12 +620,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
                dp->hpd_state = ST_MAINLINK_READY;
        }
 
-       /* enable HDP irq_hpd/replug interrupt */
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog,
-                                          DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
-                                          true);
-
        drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
                        dp->dp_display.connector_type, state);
        mutex_unlock(&dp->event_mutex);
@@ -659,12 +657,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
        drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
                        dp->dp_display.connector_type, state);
 
-       /* disable irq_hpd/replug interrupts */
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog,
-                                          DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
-                                          false);
-
        /* unplugged, no more irq_hpd handle */
        dp_del_event(dp, EV_IRQ_HPD_INT);
 
@@ -688,10 +680,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
                return 0;
        }
 
-       /* disable HPD plug interrupts */
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
-
        /*
         * We don't need separate work for disconnect as
         * connect/attention interrupts are disabled
@@ -707,10 +695,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
        /* signal the disconnect event early to ensure proper teardown */
        dp_display_handle_plugged_change(&dp->dp_display, false);
 
-       /* enable HDP plug interrupt to prepare for next plugin */
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
-
        drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
                        dp->dp_display.connector_type, state);
 
@@ -1083,26 +1067,6 @@ void msm_dp_snapshot(struct msm_disp_state *disp_state, struct msm_dp *dp)
        mutex_unlock(&dp_display->event_mutex);
 }
 
-static void dp_display_config_hpd(struct dp_display_private *dp)
-{
-
-       dp_display_host_init(dp);
-       dp_catalog_ctrl_hpd_config(dp->catalog);
-
-       /* Enable plug and unplug interrupts only if requested */
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog,
-                               DP_DP_HPD_PLUG_INT_MASK |
-                               DP_DP_HPD_UNPLUG_INT_MASK,
-                               true);
-
-       /* Enable interrupt first time
-        * we are leaving dp clocks on during disconnect
-        * and never disable interrupt
-        */
-       enable_irq(dp->irq);
-}
-
 void dp_display_set_psr(struct msm_dp *dp_display, bool enter)
 {
        struct dp_display_private *dp;
@@ -1177,7 +1141,7 @@ static int hpd_event_thread(void *data)
 
                switch (todo->event_id) {
                case EV_HPD_INIT_SETUP:
-                       dp_display_config_hpd(dp_priv);
+                       dp_display_host_init(dp_priv);
                        break;
                case EV_HPD_PLUG_INT:
                        dp_hpd_plug_handle(dp_priv, todo->data);
@@ -1283,7 +1247,6 @@ int dp_display_request_irq(struct msm_dp *dp_display)
                                dp->irq, rc);
                return rc;
        }
-       disable_irq(dp->irq);
 
        return 0;
 }
@@ -1395,13 +1358,8 @@ static int dp_pm_resume(struct device *dev)
        /* turn on dp ctrl/phy */
        dp_display_host_init(dp);
 
-       dp_catalog_ctrl_hpd_config(dp->catalog);
-
-       if (dp->dp_display.internal_hpd)
-               dp_catalog_hpd_config_intr(dp->catalog,
-                               DP_DP_HPD_PLUG_INT_MASK |
-                               DP_DP_HPD_UNPLUG_INT_MASK,
-                               true);
+       if (dp_display->is_edp)
+               dp_catalog_ctrl_hpd_enable(dp->catalog);
 
        if (dp_catalog_link_is_connected(dp->catalog)) {
                /*
@@ -1569,9 +1527,8 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 
        if (aux_bus && dp->is_edp) {
                dp_display_host_init(dp_priv);
-               dp_catalog_ctrl_hpd_config(dp_priv->catalog);
+               dp_catalog_ctrl_hpd_enable(dp_priv->catalog);
                dp_display_host_phy_init(dp_priv);
-               enable_irq(dp_priv->irq);
 
                /*
                 * The code below assumes that the panel will finish probing
@@ -1613,7 +1570,6 @@ static int dp_display_get_next_bridge(struct msm_dp *dp)
 
 error:
        if (dp->is_edp) {
-               disable_irq(dp_priv->irq);
                dp_display_host_phy_exit(dp_priv);
                dp_display_host_deinit(dp_priv);
        }
@@ -1802,16 +1758,31 @@ void dp_bridge_hpd_enable(struct drm_bridge *bridge)
 {
        struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
        struct msm_dp *dp_display = dp_bridge->dp_display;
+       struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+       mutex_lock(&dp->event_mutex);
+       dp_catalog_ctrl_hpd_enable(dp->catalog);
+
+       /* enable HDP interrupts */
+       dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, true);
 
        dp_display->internal_hpd = true;
+       mutex_unlock(&dp->event_mutex);
 }
 
 void dp_bridge_hpd_disable(struct drm_bridge *bridge)
 {
        struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
        struct msm_dp *dp_display = dp_bridge->dp_display;
+       struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+       mutex_lock(&dp->event_mutex);
+       /* disable HDP interrupts */
+       dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_INT_MASK, false);
+       dp_catalog_ctrl_hpd_disable(dp->catalog);
 
        dp_display->internal_hpd = false;
+       mutex_unlock(&dp->event_mutex);
 }
 
 void dp_bridge_hpd_notify(struct drm_bridge *bridge,
index b4cfa44..463ca41 100644 (file)
@@ -449,6 +449,8 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        if (ret)
                goto err_cleanup_mode_config;
 
+       dma_set_max_seg_size(dev, UINT_MAX);
+
        /* Bind all our sub-components: */
        ret = component_bind_all(dev, ddev);
        if (ret)
@@ -459,8 +461,6 @@ static int msm_drm_init(struct device *dev, const struct drm_driver *drv)
        if (ret)
                goto err_msm_uninit;
 
-       dma_set_max_seg_size(dev, UINT_MAX);
-
        msm_gem_shrinker_init(ddev);
 
        if (priv->kms_init) {
index 8cf096f..a2ae8c2 100644 (file)
@@ -220,6 +220,9 @@ static void nouveau_dsm_pci_probe(struct pci_dev *pdev, acpi_handle *dhandle_out
        int optimus_funcs;
        struct pci_dev *parent_pdev;
 
+       if (pdev->vendor != PCI_VENDOR_ID_NVIDIA)
+               return;
+
        *has_pr3 = false;
        parent_pdev = pci_upstream_bridge(pdev);
        if (parent_pdev) {
index 086b66b..f75c6f0 100644 (file)
@@ -730,7 +730,8 @@ out:
 #endif
 
        nouveau_connector_set_edid(nv_connector, edid);
-       nouveau_connector_set_encoder(connector, nv_encoder);
+       if (nv_encoder)
+               nouveau_connector_set_encoder(connector, nv_encoder);
        return status;
 }
 
@@ -966,7 +967,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
        /* Determine display colour depth for everything except LVDS now,
         * DP requires this before mode_valid() is called.
         */
-       if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
+       if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
                nouveau_connector_detect_depth(connector);
 
        /* Find the native mode if this is a digital panel, if we didn't
@@ -987,7 +988,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
         * "native" mode as some VBIOS tables require us to use the
         * pixel clock as part of the lookup...
         */
-       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode)
                nouveau_connector_detect_depth(connector);
 
        if (nv_encoder->dcb->type == DCB_OUTPUT_TV)
index cc7c5b4..7aac938 100644 (file)
@@ -137,10 +137,16 @@ nouveau_name(struct drm_device *dev)
 static inline bool
 nouveau_cli_work_ready(struct dma_fence *fence)
 {
-       if (!dma_fence_is_signaled(fence))
-               return false;
-       dma_fence_put(fence);
-       return true;
+       bool ret = true;
+
+       spin_lock_irq(fence->lock);
+       if (!dma_fence_is_signaled_locked(fence))
+               ret = false;
+       spin_unlock_irq(fence->lock);
+
+       if (ret == true)
+               dma_fence_put(fence);
+       return ret;
 }
 
 static void
index fe76e29..8f6c3ae 100644 (file)
@@ -307,6 +307,7 @@ static void radeon_fbdev_client_unregister(struct drm_client_dev *client)
 
        if (fb_helper->info) {
                vga_switcheroo_client_fb_set(rdev->pdev, NULL);
+               drm_helper_force_disable_all(dev);
                drm_fb_helper_unregister_info(fb_helper);
        } else {
                drm_client_release(&fb_helper->client);
index bdc5af2..d3f5ddb 100644 (file)
@@ -459,7 +459,6 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
        struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_gem_set_domain *args = data;
        struct drm_gem_object *gobj;
-       struct radeon_bo *robj;
        int r;
 
        /* for now if someone requests domain CPU -
@@ -472,13 +471,12 @@ int radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                up_read(&rdev->exclusive_lock);
                return -ENOENT;
        }
-       robj = gem_to_radeon_bo(gobj);
 
        r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain);
 
        drm_gem_object_put(gobj);
        up_read(&rdev->exclusive_lock);
-       r = radeon_gem_handle_lockup(robj->rdev, r);
+       r = radeon_gem_handle_lockup(rdev, r);
        return r;
 }
 
index 2246044..5e1a412 100644 (file)
@@ -286,7 +286,7 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
        struct hidpp_report *message,
        struct hidpp_report *response)
 {
-       int ret;
+       int ret = -1;
        int max_retries = 3;
 
        mutex_lock(&hidpp->send_mutex);
@@ -300,13 +300,13 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
         */
        *response = *message;
 
-       for (; max_retries != 0; max_retries--) {
+       for (; max_retries != 0 && ret; max_retries--) {
                ret = __hidpp_send_report(hidpp->hid_dev, message);
 
                if (ret) {
                        dbg_hid("__hidpp_send_report returned err: %d\n", ret);
                        memset(response, 0, sizeof(struct hidpp_report));
-                       goto exit;
+                       break;
                }
 
                if (!wait_event_timeout(hidpp->wait, hidpp->answer_available,
@@ -314,14 +314,14 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
                        dbg_hid("%s:timeout waiting for response\n", __func__);
                        memset(response, 0, sizeof(struct hidpp_report));
                        ret = -ETIMEDOUT;
-                       goto exit;
+                       break;
                }
 
                if (response->report_id == REPORT_ID_HIDPP_SHORT &&
                    response->rap.sub_id == HIDPP_ERROR) {
                        ret = response->rap.params[1];
                        dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
-                       goto exit;
+                       break;
                }
 
                if ((response->report_id == REPORT_ID_HIDPP_LONG ||
@@ -330,13 +330,12 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
                        ret = response->fap.params[1];
                        if (ret != HIDPP20_ERROR_BUSY) {
                                dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
-                               goto exit;
+                               break;
                        }
                        dbg_hid("%s:got busy hidpp 2.0 error %02X, retrying\n", __func__, ret);
                }
        }
 
-exit:
        mutex_unlock(&hidpp->send_mutex);
        return ret;
 
index 007f26d..2f4d09c 100644 (file)
@@ -829,11 +829,22 @@ static void vmbus_wait_for_unload(void)
                if (completion_done(&vmbus_connection.unload_event))
                        goto completed;
 
-               for_each_online_cpu(cpu) {
+               for_each_present_cpu(cpu) {
                        struct hv_per_cpu_context *hv_cpu
                                = per_cpu_ptr(hv_context.cpu_context, cpu);
 
+                       /*
+                        * In a CoCo VM the synic_message_page is not allocated
+                        * in hv_synic_alloc(). Instead it is set/cleared in
+                        * hv_synic_enable_regs() and hv_synic_disable_regs()
+                        * such that it is set only when the CPU is online. If
+                        * not all present CPUs are online, the message page
+                        * might be NULL, so skip such CPUs.
+                        */
                        page_addr = hv_cpu->synic_message_page;
+                       if (!page_addr)
+                               continue;
+
                        msg = (struct hv_message *)page_addr
                                + VMBUS_MESSAGE_SINT;
 
@@ -867,11 +878,14 @@ completed:
         * maybe-pending messages on all CPUs to be able to receive new
         * messages after we reconnect.
         */
-       for_each_online_cpu(cpu) {
+       for_each_present_cpu(cpu) {
                struct hv_per_cpu_context *hv_cpu
                        = per_cpu_ptr(hv_context.cpu_context, cpu);
 
                page_addr = hv_cpu->synic_message_page;
+               if (!page_addr)
+                       continue;
+
                msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
                msg->header.message_type = HVMSG_NONE;
        }
index 64f9cec..542a1d5 100644 (file)
@@ -364,13 +364,20 @@ int hv_common_cpu_init(unsigned int cpu)
        flags = irqs_disabled() ? GFP_ATOMIC : GFP_KERNEL;
 
        inputarg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
-       *inputarg = kmalloc(pgcount * HV_HYP_PAGE_SIZE, flags);
-       if (!(*inputarg))
-               return -ENOMEM;
 
-       if (hv_root_partition) {
-               outputarg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
-               *outputarg = (char *)(*inputarg) + HV_HYP_PAGE_SIZE;
+       /*
+        * hyperv_pcpu_input_arg and hyperv_pcpu_output_arg memory is already
+        * allocated if this CPU was previously online and then taken offline
+        */
+       if (!*inputarg) {
+               *inputarg = kmalloc(pgcount * HV_HYP_PAGE_SIZE, flags);
+               if (!(*inputarg))
+                       return -ENOMEM;
+
+               if (hv_root_partition) {
+                       outputarg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
+                       *outputarg = (char *)(*inputarg) + HV_HYP_PAGE_SIZE;
+               }
        }
 
        msr_vp_index = hv_get_register(HV_REGISTER_VP_INDEX);
@@ -385,24 +392,17 @@ int hv_common_cpu_init(unsigned int cpu)
 
 int hv_common_cpu_die(unsigned int cpu)
 {
-       unsigned long flags;
-       void **inputarg, **outputarg;
-       void *mem;
-
-       local_irq_save(flags);
-
-       inputarg = (void **)this_cpu_ptr(hyperv_pcpu_input_arg);
-       mem = *inputarg;
-       *inputarg = NULL;
-
-       if (hv_root_partition) {
-               outputarg = (void **)this_cpu_ptr(hyperv_pcpu_output_arg);
-               *outputarg = NULL;
-       }
-
-       local_irq_restore(flags);
-
-       kfree(mem);
+       /*
+        * The hyperv_pcpu_input_arg and hyperv_pcpu_output_arg memory
+        * is not freed when the CPU goes offline as the hyperv_pcpu_input_arg
+        * may be used by the Hyper-V vPCI driver in reassigning interrupts
+        * as part of the offlining process.  The interrupt reassignment
+        * happens *after* the CPUHP_AP_HYPERV_ONLINE state has run and
+        * called this function.
+        *
+        * If a previously offlined CPU is brought back online again, the
+        * originally allocated memory is reused in hv_common_cpu_init().
+        */
 
        return 0;
 }
index 1c65a6d..67f95a2 100644 (file)
@@ -1372,7 +1372,7 @@ static int vmbus_bus_init(void)
        ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online",
                                hv_synic_init, hv_synic_cleanup);
        if (ret < 0)
-               goto err_cpuhp;
+               goto err_alloc;
        hyperv_cpuhp_online = ret;
 
        ret = vmbus_connect();
@@ -1392,9 +1392,8 @@ static int vmbus_bus_init(void)
 
 err_connect:
        cpuhp_remove_state(hyperv_cpuhp_online);
-err_cpuhp:
-       hv_synic_free();
 err_alloc:
+       hv_synic_free();
        if (vmbus_irq == -1) {
                hv_remove_vmbus_handler();
        } else {
index c5d87aa..bf23bfb 100644 (file)
@@ -40,6 +40,7 @@
 #define DW_IC_CON_BUS_CLEAR_CTRL               BIT(11)
 
 #define DW_IC_DATA_CMD_DAT                     GENMASK(7, 0)
+#define DW_IC_DATA_CMD_FIRST_DATA_BYTE         BIT(11)
 
 /*
  * Registers offset
index cec2505..2e079cf 100644 (file)
@@ -176,6 +176,10 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
 
                do {
                        regmap_read(dev->map, DW_IC_DATA_CMD, &tmp);
+                       if (tmp & DW_IC_DATA_CMD_FIRST_DATA_BYTE)
+                               i2c_slave_event(dev->slave,
+                                               I2C_SLAVE_WRITE_REQUESTED,
+                                               &val);
                        val = tmp;
                        i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
                                        &val);
index 8e98794..39c479f 100644 (file)
 #define IMG_I2C_TIMEOUT                        (msecs_to_jiffies(1000))
 
 /*
- * Worst incs are 1 (innacurate) and 16*256 (irregular).
+ * Worst incs are 1 (inaccurate) and 16*256 (irregular).
  * So a sensible inc is the logarithmic mean: 64 (2^6), which is
  * in the middle of the valid range (0-127).
  */
index b21ffd6..5ef136c 100644 (file)
@@ -1118,8 +1118,10 @@ static int pci1xxxx_i2c_resume(struct device *dev)
 static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_i2c_pm_ops, pci1xxxx_i2c_suspend,
                         pci1xxxx_i2c_resume);
 
-static void pci1xxxx_i2c_shutdown(struct pci1xxxx_i2c *i2c)
+static void pci1xxxx_i2c_shutdown(void *data)
 {
+       struct pci1xxxx_i2c *i2c = data;
+
        pci1xxxx_i2c_config_padctrl(i2c, false);
        pci1xxxx_i2c_configure_core_reg(i2c, false);
 }
@@ -1156,7 +1158,7 @@ static int pci1xxxx_i2c_probe_pci(struct pci_dev *pdev,
        init_completion(&i2c->i2c_xfer_done);
        pci1xxxx_i2c_init(i2c);
 
-       ret = devm_add_action(dev, (void (*)(void *))pci1xxxx_i2c_shutdown, i2c);
+       ret = devm_add_action(dev, pci1xxxx_i2c_shutdown, i2c);
        if (ret)
                return ret;
 
index 047dfef..878c076 100644 (file)
@@ -520,6 +520,17 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
 
        while (readl(drv_data->reg_base + drv_data->reg_offsets.control) &
                                                MV64XXX_I2C_REG_CONTROL_IFLG) {
+               /*
+                * It seems that sometime the controller updates the status
+                * register only after it asserts IFLG in control register.
+                * This may result in weird bugs when in atomic mode. A delay
+                * of 100 ns before reading the status register solves this
+                * issue. This bug does not seem to appear when using
+                * interrupts.
+                */
+               if (drv_data->atomic)
+                       ndelay(100);
+
                status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
                mv64xxx_i2c_fsm(drv_data, status);
                mv64xxx_i2c_do_action(drv_data);
index 4fe15cd..ffc54fb 100644 (file)
@@ -576,12 +576,14 @@ static int sprd_i2c_remove(struct platform_device *pdev)
        struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev);
        int ret;
 
-       ret = pm_runtime_resume_and_get(i2c_dev->dev);
+       ret = pm_runtime_get_sync(i2c_dev->dev);
        if (ret < 0)
-               return ret;
+               dev_err(&pdev->dev, "Failed to resume device (%pe)\n", ERR_PTR(ret));
 
        i2c_del_adapter(&i2c_dev->adap);
-       clk_disable_unprepare(i2c_dev->clk);
+
+       if (ret >= 0)
+               clk_disable_unprepare(i2c_dev->clk);
 
        pm_runtime_put_noidle(i2c_dev->dev);
        pm_runtime_disable(i2c_dev->dev);
index 93a1c48..6b3f438 100644 (file)
@@ -3295,7 +3295,7 @@ static int cma_resolve_iboe_route(struct rdma_id_private *id_priv)
        route->path_rec->traffic_class = tos;
        route->path_rec->mtu = iboe_get_mtu(ndev->mtu);
        route->path_rec->rate_selector = IB_SA_EQ;
-       route->path_rec->rate = iboe_get_rate(ndev);
+       route->path_rec->rate = IB_RATE_PORT_CURRENT;
        dev_put(ndev);
        route->path_rec->packet_life_time_selector = IB_SA_EQ;
        /* In case ACK timeout is set, use this value to calculate
@@ -4964,7 +4964,7 @@ static int cma_iboe_join_multicast(struct rdma_id_private *id_priv,
        if (!ndev)
                return -ENODEV;
 
-       ib.rec.rate = iboe_get_rate(ndev);
+       ib.rec.rate = IB_RATE_PORT_CURRENT;
        ib.rec.hop_limit = 1;
        ib.rec.mtu = iboe_get_mtu(ndev->mtu);
 
index 4796f6a..e836c9c 100644 (file)
@@ -1850,8 +1850,13 @@ static int modify_qp(struct uverbs_attr_bundle *attrs,
                attr->path_mtu = cmd->base.path_mtu;
        if (cmd->base.attr_mask & IB_QP_PATH_MIG_STATE)
                attr->path_mig_state = cmd->base.path_mig_state;
-       if (cmd->base.attr_mask & IB_QP_QKEY)
+       if (cmd->base.attr_mask & IB_QP_QKEY) {
+               if (cmd->base.qkey & IB_QP_SET_QKEY && !capable(CAP_NET_RAW)) {
+                       ret = -EPERM;
+                       goto release_qp;
+               }
                attr->qkey = cmd->base.qkey;
+       }
        if (cmd->base.attr_mask & IB_QP_RQ_PSN)
                attr->rq_psn = cmd->base.rq_psn;
        if (cmd->base.attr_mask & IB_QP_SQ_PSN)
index fbace69..7c9c79c 100644 (file)
@@ -222,8 +222,12 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
        spin_lock_irq(&ev_queue->lock);
 
        while (list_empty(&ev_queue->event_list)) {
-               spin_unlock_irq(&ev_queue->lock);
+               if (ev_queue->is_closed) {
+                       spin_unlock_irq(&ev_queue->lock);
+                       return -EIO;
+               }
 
+               spin_unlock_irq(&ev_queue->lock);
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
 
@@ -233,12 +237,6 @@ static ssize_t ib_uverbs_event_read(struct ib_uverbs_event_queue *ev_queue,
                        return -ERESTARTSYS;
 
                spin_lock_irq(&ev_queue->lock);
-
-               /* If device was disassociated and no event exists set an error */
-               if (list_empty(&ev_queue->event_list) && ev_queue->is_closed) {
-                       spin_unlock_irq(&ev_queue->lock);
-                       return -EIO;
-               }
        }
 
        event = list_entry(ev_queue->event_list.next, struct ib_uverbs_event, list);
index 5a2baf4..2c95e6f 100644 (file)
@@ -135,8 +135,6 @@ struct bnxt_re_dev {
 
        struct delayed_work             worker;
        u8                              cur_prio_map;
-       u16                             active_speed;
-       u8                              active_width;
 
        /* FP Notification Queue (CQ & SRQ) */
        struct tasklet_struct           nq_task;
index b1c3641..952811c 100644 (file)
@@ -199,6 +199,7 @@ int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num,
 {
        struct bnxt_re_dev *rdev = to_bnxt_re_dev(ibdev, ibdev);
        struct bnxt_qplib_dev_attr *dev_attr = &rdev->dev_attr;
+       int rc;
 
        memset(port_attr, 0, sizeof(*port_attr));
 
@@ -228,10 +229,10 @@ int bnxt_re_query_port(struct ib_device *ibdev, u32 port_num,
        port_attr->sm_sl = 0;
        port_attr->subnet_timeout = 0;
        port_attr->init_type_reply = 0;
-       port_attr->active_speed = rdev->active_speed;
-       port_attr->active_width = rdev->active_width;
+       rc = ib_get_eth_speed(&rdev->ibdev, port_num, &port_attr->active_speed,
+                             &port_attr->active_width);
 
-       return 0;
+       return rc;
 }
 
 int bnxt_re_get_port_immutable(struct ib_device *ibdev, u32 port_num,
index e34eccd..3073398 100644 (file)
@@ -1077,8 +1077,6 @@ static int bnxt_re_ib_init(struct bnxt_re_dev *rdev)
                return rc;
        }
        dev_info(rdev_to_dev(rdev), "Device registered with IB successfully");
-       ib_get_eth_speed(&rdev->ibdev, 1, &rdev->active_speed,
-                        &rdev->active_width);
        set_bit(BNXT_RE_FLAG_ISSUE_ROCE_STATS, &rdev->flags);
 
        event = netif_running(rdev->netdev) && netif_carrier_ok(rdev->netdev) ?
index 1c06920..93257fa 100644 (file)
@@ -209,7 +209,8 @@ static const struct mlx5_ib_counters *get_counters(struct mlx5_ib_dev *dev,
             !vport_qcounters_supported(dev)) || !port_num)
                return &dev->port[0].cnts;
 
-       return &dev->port[port_num - 1].cnts;
+       return is_mdev_switchdev_mode(dev->mdev) ?
+              &dev->port[1].cnts : &dev->port[port_num - 1].cnts;
 }
 
 /**
@@ -262,7 +263,7 @@ static struct rdma_hw_stats *
 mlx5_ib_alloc_hw_port_stats(struct ib_device *ibdev, u32 port_num)
 {
        struct mlx5_ib_dev *dev = to_mdev(ibdev);
-       const struct mlx5_ib_counters *cnts = &dev->port[port_num - 1].cnts;
+       const struct mlx5_ib_counters *cnts = get_counters(dev, port_num);
 
        return do_alloc_stats(cnts);
 }
@@ -329,6 +330,7 @@ static int mlx5_ib_query_q_counters_vport(struct mlx5_ib_dev *dev,
 {
        u32 out[MLX5_ST_SZ_DW(query_q_counter_out)] = {};
        u32 in[MLX5_ST_SZ_DW(query_q_counter_in)] = {};
+       struct mlx5_core_dev *mdev;
        __be32 val;
        int ret, i;
 
@@ -336,12 +338,16 @@ static int mlx5_ib_query_q_counters_vport(struct mlx5_ib_dev *dev,
            dev->port[port_num].rep->vport == MLX5_VPORT_UPLINK)
                return 0;
 
+       mdev = mlx5_eswitch_get_core_dev(dev->port[port_num].rep->esw);
+       if (!mdev)
+               return -EOPNOTSUPP;
+
        MLX5_SET(query_q_counter_in, in, opcode, MLX5_CMD_OP_QUERY_Q_COUNTER);
        MLX5_SET(query_q_counter_in, in, other_vport, 1);
        MLX5_SET(query_q_counter_in, in, vport_number,
                 dev->port[port_num].rep->vport);
        MLX5_SET(query_q_counter_in, in, aggregate, 1);
-       ret = mlx5_cmd_exec_inout(dev->mdev, query_q_counter, in, out);
+       ret = mlx5_cmd_exec_inout(mdev, query_q_counter, in, out);
        if (ret)
                return ret;
 
@@ -575,43 +581,53 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev,
        bool is_vport = is_mdev_switchdev_mode(dev->mdev) &&
                        port_num != MLX5_VPORT_PF;
        const struct mlx5_ib_counter *names;
-       int j = 0, i;
+       int j = 0, i, size;
 
        names = is_vport ? vport_basic_q_cnts : basic_q_cnts;
-       for (i = 0; i < ARRAY_SIZE(basic_q_cnts); i++, j++) {
+       size = is_vport ? ARRAY_SIZE(vport_basic_q_cnts) :
+                         ARRAY_SIZE(basic_q_cnts);
+       for (i = 0; i < size; i++, j++) {
                descs[j].name = names[i].name;
-               offsets[j] = basic_q_cnts[i].offset;
+               offsets[j] = names[i].offset;
        }
 
        names = is_vport ? vport_out_of_seq_q_cnts : out_of_seq_q_cnts;
+       size = is_vport ? ARRAY_SIZE(vport_out_of_seq_q_cnts) :
+                         ARRAY_SIZE(out_of_seq_q_cnts);
        if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt)) {
-               for (i = 0; i < ARRAY_SIZE(out_of_seq_q_cnts); i++, j++) {
+               for (i = 0; i < size; i++, j++) {
                        descs[j].name = names[i].name;
-                       offsets[j] = out_of_seq_q_cnts[i].offset;
+                       offsets[j] = names[i].offset;
                }
        }
 
        names = is_vport ? vport_retrans_q_cnts : retrans_q_cnts;
+       size = is_vport ? ARRAY_SIZE(vport_retrans_q_cnts) :
+                         ARRAY_SIZE(retrans_q_cnts);
        if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters)) {
-               for (i = 0; i < ARRAY_SIZE(retrans_q_cnts); i++, j++) {
+               for (i = 0; i < size; i++, j++) {
                        descs[j].name = names[i].name;
-                       offsets[j] = retrans_q_cnts[i].offset;
+                       offsets[j] = names[i].offset;
                }
        }
 
        names = is_vport ? vport_extended_err_cnts : extended_err_cnts;
+       size = is_vport ? ARRAY_SIZE(vport_extended_err_cnts) :
+                         ARRAY_SIZE(extended_err_cnts);
        if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters)) {
-               for (i = 0; i < ARRAY_SIZE(extended_err_cnts); i++, j++) {
+               for (i = 0; i < size; i++, j++) {
                        descs[j].name = names[i].name;
-                       offsets[j] = extended_err_cnts[i].offset;
+                       offsets[j] = names[i].offset;
                }
        }
 
        names = is_vport ? vport_roce_accl_cnts : roce_accl_cnts;
+       size = is_vport ? ARRAY_SIZE(vport_roce_accl_cnts) :
+                         ARRAY_SIZE(roce_accl_cnts);
        if (MLX5_CAP_GEN(dev->mdev, roce_accl)) {
-               for (i = 0; i < ARRAY_SIZE(roce_accl_cnts); i++, j++) {
+               for (i = 0; i < size; i++, j++) {
                        descs[j].name = names[i].name;
-                       offsets[j] = roce_accl_cnts[i].offset;
+                       offsets[j] = names[i].offset;
                }
        }
 
@@ -661,25 +677,37 @@ static void mlx5_ib_fill_counters(struct mlx5_ib_dev *dev,
 static int __mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev,
                                    struct mlx5_ib_counters *cnts, u32 port_num)
 {
-       u32 num_counters, num_op_counters = 0;
+       bool is_vport = is_mdev_switchdev_mode(dev->mdev) &&
+                       port_num != MLX5_VPORT_PF;
+       u32 num_counters, num_op_counters = 0, size;
 
-       num_counters = ARRAY_SIZE(basic_q_cnts);
+       size = is_vport ? ARRAY_SIZE(vport_basic_q_cnts) :
+                         ARRAY_SIZE(basic_q_cnts);
+       num_counters = size;
 
+       size = is_vport ? ARRAY_SIZE(vport_out_of_seq_q_cnts) :
+                         ARRAY_SIZE(out_of_seq_q_cnts);
        if (MLX5_CAP_GEN(dev->mdev, out_of_seq_cnt))
-               num_counters += ARRAY_SIZE(out_of_seq_q_cnts);
+               num_counters += size;
 
+       size = is_vport ? ARRAY_SIZE(vport_retrans_q_cnts) :
+                         ARRAY_SIZE(retrans_q_cnts);
        if (MLX5_CAP_GEN(dev->mdev, retransmission_q_counters))
-               num_counters += ARRAY_SIZE(retrans_q_cnts);
+               num_counters += size;
 
+       size = is_vport ? ARRAY_SIZE(vport_extended_err_cnts) :
+                         ARRAY_SIZE(extended_err_cnts);
        if (MLX5_CAP_GEN(dev->mdev, enhanced_error_q_counters))
-               num_counters += ARRAY_SIZE(extended_err_cnts);
+               num_counters += size;
 
+       size = is_vport ? ARRAY_SIZE(vport_roce_accl_cnts) :
+                         ARRAY_SIZE(roce_accl_cnts);
        if (MLX5_CAP_GEN(dev->mdev, roce_accl))
-               num_counters += ARRAY_SIZE(roce_accl_cnts);
+               num_counters += size;
 
        cnts->num_q_counters = num_counters;
 
-       if (is_mdev_switchdev_mode(dev->mdev) && port_num != MLX5_VPORT_PF)
+       if (is_vport)
                goto skip_non_qcounters;
 
        if (MLX5_CAP_GEN(dev->mdev, cc_query_allowed)) {
@@ -725,11 +753,11 @@ err:
 static void mlx5_ib_dealloc_counters(struct mlx5_ib_dev *dev)
 {
        u32 in[MLX5_ST_SZ_DW(dealloc_q_counter_in)] = {};
-       int num_cnt_ports;
+       int num_cnt_ports = dev->num_ports;
        int i, j;
 
-       num_cnt_ports = (!is_mdev_switchdev_mode(dev->mdev) ||
-                        vport_qcounters_supported(dev)) ? dev->num_ports : 1;
+       if (is_mdev_switchdev_mode(dev->mdev))
+               num_cnt_ports = min(2, num_cnt_ports);
 
        MLX5_SET(dealloc_q_counter_in, in, opcode,
                 MLX5_CMD_OP_DEALLOC_Q_COUNTER);
@@ -761,15 +789,22 @@ static int mlx5_ib_alloc_counters(struct mlx5_ib_dev *dev)
 {
        u32 out[MLX5_ST_SZ_DW(alloc_q_counter_out)] = {};
        u32 in[MLX5_ST_SZ_DW(alloc_q_counter_in)] = {};
-       int num_cnt_ports;
+       int num_cnt_ports = dev->num_ports;
        int err = 0;
        int i;
        bool is_shared;
 
        MLX5_SET(alloc_q_counter_in, in, opcode, MLX5_CMD_OP_ALLOC_Q_COUNTER);
        is_shared = MLX5_CAP_GEN(dev->mdev, log_max_uctx) != 0;
-       num_cnt_ports = (!is_mdev_switchdev_mode(dev->mdev) ||
-                        vport_qcounters_supported(dev)) ? dev->num_ports : 1;
+
+       /*
+        * In switchdev we need to allocate two ports, one that is used for
+        * the device Q_counters and it is essentially the real Q_counters of
+        * this device, while the other is used as a helper for PF to be able to
+        * query all other vports.
+        */
+       if (is_mdev_switchdev_mode(dev->mdev))
+               num_cnt_ports = min(2, num_cnt_ports);
 
        for (i = 0; i < num_cnt_ports; i++) {
                err = __mlx5_ib_alloc_counters(dev, &dev->port[i].cnts, i);
index 3008632..1e419e0 100644 (file)
@@ -695,8 +695,6 @@ static struct mlx5_ib_flow_prio *_get_prio(struct mlx5_ib_dev *dev,
        struct mlx5_flow_table_attr ft_attr = {};
        struct mlx5_flow_table *ft;
 
-       if (mlx5_ib_shared_ft_allowed(&dev->ib_dev))
-               ft_attr.uid = MLX5_SHARED_RESOURCE_UID;
        ft_attr.prio = priority;
        ft_attr.max_fte = num_entries;
        ft_attr.flags = flags;
@@ -2025,6 +2023,237 @@ static int flow_matcher_cleanup(struct ib_uobject *uobject,
        return 0;
 }
 
+static int steering_anchor_create_ft(struct mlx5_ib_dev *dev,
+                                    struct mlx5_ib_flow_prio *ft_prio,
+                                    enum mlx5_flow_namespace_type ns_type)
+{
+       struct mlx5_flow_table_attr ft_attr = {};
+       struct mlx5_flow_namespace *ns;
+       struct mlx5_flow_table *ft;
+
+       if (ft_prio->anchor.ft)
+               return 0;
+
+       ns = mlx5_get_flow_namespace(dev->mdev, ns_type);
+       if (!ns)
+               return -EOPNOTSUPP;
+
+       ft_attr.flags = MLX5_FLOW_TABLE_UNMANAGED;
+       ft_attr.uid = MLX5_SHARED_RESOURCE_UID;
+       ft_attr.prio = 0;
+       ft_attr.max_fte = 2;
+       ft_attr.level = 1;
+
+       ft = mlx5_create_flow_table(ns, &ft_attr);
+       if (IS_ERR(ft))
+               return PTR_ERR(ft);
+
+       ft_prio->anchor.ft = ft;
+
+       return 0;
+}
+
+static void steering_anchor_destroy_ft(struct mlx5_ib_flow_prio *ft_prio)
+{
+       if (ft_prio->anchor.ft) {
+               mlx5_destroy_flow_table(ft_prio->anchor.ft);
+               ft_prio->anchor.ft = NULL;
+       }
+}
+
+static int
+steering_anchor_create_fg_drop(struct mlx5_ib_flow_prio *ft_prio)
+{
+       int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+       struct mlx5_flow_group *fg;
+       void *flow_group_in;
+       int err = 0;
+
+       if (ft_prio->anchor.fg_drop)
+               return 0;
+
+       flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+       if (!flow_group_in)
+               return -ENOMEM;
+
+       MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
+       MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
+
+       fg = mlx5_create_flow_group(ft_prio->anchor.ft, flow_group_in);
+       if (IS_ERR(fg)) {
+               err = PTR_ERR(fg);
+               goto out;
+       }
+
+       ft_prio->anchor.fg_drop = fg;
+
+out:
+       kvfree(flow_group_in);
+
+       return err;
+}
+
+static void
+steering_anchor_destroy_fg_drop(struct mlx5_ib_flow_prio *ft_prio)
+{
+       if (ft_prio->anchor.fg_drop) {
+               mlx5_destroy_flow_group(ft_prio->anchor.fg_drop);
+               ft_prio->anchor.fg_drop = NULL;
+       }
+}
+
+static int
+steering_anchor_create_fg_goto_table(struct mlx5_ib_flow_prio *ft_prio)
+{
+       int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
+       struct mlx5_flow_group *fg;
+       void *flow_group_in;
+       int err = 0;
+
+       if (ft_prio->anchor.fg_goto_table)
+               return 0;
+
+       flow_group_in = kvzalloc(inlen, GFP_KERNEL);
+       if (!flow_group_in)
+               return -ENOMEM;
+
+       fg = mlx5_create_flow_group(ft_prio->anchor.ft, flow_group_in);
+       if (IS_ERR(fg)) {
+               err = PTR_ERR(fg);
+               goto out;
+       }
+       ft_prio->anchor.fg_goto_table = fg;
+
+out:
+       kvfree(flow_group_in);
+
+       return err;
+}
+
+static void
+steering_anchor_destroy_fg_goto_table(struct mlx5_ib_flow_prio *ft_prio)
+{
+       if (ft_prio->anchor.fg_goto_table) {
+               mlx5_destroy_flow_group(ft_prio->anchor.fg_goto_table);
+               ft_prio->anchor.fg_goto_table = NULL;
+       }
+}
+
+static int
+steering_anchor_create_rule_drop(struct mlx5_ib_flow_prio *ft_prio)
+{
+       struct mlx5_flow_act flow_act = {};
+       struct mlx5_flow_handle *handle;
+
+       if (ft_prio->anchor.rule_drop)
+               return 0;
+
+       flow_act.fg = ft_prio->anchor.fg_drop;
+       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
+
+       handle = mlx5_add_flow_rules(ft_prio->anchor.ft, NULL, &flow_act,
+                                    NULL, 0);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       ft_prio->anchor.rule_drop = handle;
+
+       return 0;
+}
+
+static void steering_anchor_destroy_rule_drop(struct mlx5_ib_flow_prio *ft_prio)
+{
+       if (ft_prio->anchor.rule_drop) {
+               mlx5_del_flow_rules(ft_prio->anchor.rule_drop);
+               ft_prio->anchor.rule_drop = NULL;
+       }
+}
+
+static int
+steering_anchor_create_rule_goto_table(struct mlx5_ib_flow_prio *ft_prio)
+{
+       struct mlx5_flow_destination dest = {};
+       struct mlx5_flow_act flow_act = {};
+       struct mlx5_flow_handle *handle;
+
+       if (ft_prio->anchor.rule_goto_table)
+               return 0;
+
+       flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
+       flow_act.flags |= FLOW_ACT_IGNORE_FLOW_LEVEL;
+       flow_act.fg = ft_prio->anchor.fg_goto_table;
+
+       dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
+       dest.ft = ft_prio->flow_table;
+
+       handle = mlx5_add_flow_rules(ft_prio->anchor.ft, NULL, &flow_act,
+                                    &dest, 1);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       ft_prio->anchor.rule_goto_table = handle;
+
+       return 0;
+}
+
+static void
+steering_anchor_destroy_rule_goto_table(struct mlx5_ib_flow_prio *ft_prio)
+{
+       if (ft_prio->anchor.rule_goto_table) {
+               mlx5_del_flow_rules(ft_prio->anchor.rule_goto_table);
+               ft_prio->anchor.rule_goto_table = NULL;
+       }
+}
+
+static int steering_anchor_create_res(struct mlx5_ib_dev *dev,
+                                     struct mlx5_ib_flow_prio *ft_prio,
+                                     enum mlx5_flow_namespace_type ns_type)
+{
+       int err;
+
+       err = steering_anchor_create_ft(dev, ft_prio, ns_type);
+       if (err)
+               return err;
+
+       err = steering_anchor_create_fg_drop(ft_prio);
+       if (err)
+               goto destroy_ft;
+
+       err = steering_anchor_create_fg_goto_table(ft_prio);
+       if (err)
+               goto destroy_fg_drop;
+
+       err = steering_anchor_create_rule_drop(ft_prio);
+       if (err)
+               goto destroy_fg_goto_table;
+
+       err = steering_anchor_create_rule_goto_table(ft_prio);
+       if (err)
+               goto destroy_rule_drop;
+
+       return 0;
+
+destroy_rule_drop:
+       steering_anchor_destroy_rule_drop(ft_prio);
+destroy_fg_goto_table:
+       steering_anchor_destroy_fg_goto_table(ft_prio);
+destroy_fg_drop:
+       steering_anchor_destroy_fg_drop(ft_prio);
+destroy_ft:
+       steering_anchor_destroy_ft(ft_prio);
+
+       return err;
+}
+
+static void mlx5_steering_anchor_destroy_res(struct mlx5_ib_flow_prio *ft_prio)
+{
+       steering_anchor_destroy_rule_goto_table(ft_prio);
+       steering_anchor_destroy_rule_drop(ft_prio);
+       steering_anchor_destroy_fg_goto_table(ft_prio);
+       steering_anchor_destroy_fg_drop(ft_prio);
+       steering_anchor_destroy_ft(ft_prio);
+}
+
 static int steering_anchor_cleanup(struct ib_uobject *uobject,
                                   enum rdma_remove_reason why,
                                   struct uverbs_attr_bundle *attrs)
@@ -2035,6 +2264,9 @@ static int steering_anchor_cleanup(struct ib_uobject *uobject,
                return -EBUSY;
 
        mutex_lock(&obj->dev->flow_db->lock);
+       if (!--obj->ft_prio->anchor.rule_goto_table_ref)
+               steering_anchor_destroy_rule_goto_table(obj->ft_prio);
+
        put_flow_table(obj->dev, obj->ft_prio, true);
        mutex_unlock(&obj->dev->flow_db->lock);
 
@@ -2042,6 +2274,24 @@ static int steering_anchor_cleanup(struct ib_uobject *uobject,
        return 0;
 }
 
+static void fs_cleanup_anchor(struct mlx5_ib_flow_prio *prio,
+                             int count)
+{
+       while (count--)
+               mlx5_steering_anchor_destroy_res(&prio[count]);
+}
+
+void mlx5_ib_fs_cleanup_anchor(struct mlx5_ib_dev *dev)
+{
+       fs_cleanup_anchor(dev->flow_db->prios, MLX5_IB_NUM_FLOW_FT);
+       fs_cleanup_anchor(dev->flow_db->egress_prios, MLX5_IB_NUM_FLOW_FT);
+       fs_cleanup_anchor(dev->flow_db->sniffer, MLX5_IB_NUM_SNIFFER_FTS);
+       fs_cleanup_anchor(dev->flow_db->egress, MLX5_IB_NUM_EGRESS_FTS);
+       fs_cleanup_anchor(dev->flow_db->fdb, MLX5_IB_NUM_FDB_FTS);
+       fs_cleanup_anchor(dev->flow_db->rdma_rx, MLX5_IB_NUM_FLOW_FT);
+       fs_cleanup_anchor(dev->flow_db->rdma_tx, MLX5_IB_NUM_FLOW_FT);
+}
+
 static int mlx5_ib_matcher_ns(struct uverbs_attr_bundle *attrs,
                              struct mlx5_ib_flow_matcher *obj)
 {
@@ -2182,21 +2432,31 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_STEERING_ANCHOR_CREATE)(
                return -ENOMEM;
 
        mutex_lock(&dev->flow_db->lock);
+
        ft_prio = _get_flow_table(dev, priority, ns_type, 0);
        if (IS_ERR(ft_prio)) {
-               mutex_unlock(&dev->flow_db->lock);
                err = PTR_ERR(ft_prio);
                goto free_obj;
        }
 
        ft_prio->refcount++;
-       ft_id = mlx5_flow_table_id(ft_prio->flow_table);
-       mutex_unlock(&dev->flow_db->lock);
+
+       if (!ft_prio->anchor.rule_goto_table_ref) {
+               err = steering_anchor_create_res(dev, ft_prio, ns_type);
+               if (err)
+                       goto put_flow_table;
+       }
+
+       ft_prio->anchor.rule_goto_table_ref++;
+
+       ft_id = mlx5_flow_table_id(ft_prio->anchor.ft);
 
        err = uverbs_copy_to(attrs, MLX5_IB_ATTR_STEERING_ANCHOR_FT_ID,
                             &ft_id, sizeof(ft_id));
        if (err)
-               goto put_flow_table;
+               goto destroy_res;
+
+       mutex_unlock(&dev->flow_db->lock);
 
        uobj->object = obj;
        obj->dev = dev;
@@ -2205,8 +2465,10 @@ static int UVERBS_HANDLER(MLX5_IB_METHOD_STEERING_ANCHOR_CREATE)(
 
        return 0;
 
+destroy_res:
+       --ft_prio->anchor.rule_goto_table_ref;
+       mlx5_steering_anchor_destroy_res(ft_prio);
 put_flow_table:
-       mutex_lock(&dev->flow_db->lock);
        put_flow_table(dev, ft_prio, true);
        mutex_unlock(&dev->flow_db->lock);
 free_obj:
index ad320ad..b973490 100644 (file)
@@ -10,6 +10,7 @@
 
 #if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
 int mlx5_ib_fs_init(struct mlx5_ib_dev *dev);
+void mlx5_ib_fs_cleanup_anchor(struct mlx5_ib_dev *dev);
 #else
 static inline int mlx5_ib_fs_init(struct mlx5_ib_dev *dev)
 {
@@ -21,9 +22,24 @@ static inline int mlx5_ib_fs_init(struct mlx5_ib_dev *dev)
        mutex_init(&dev->flow_db->lock);
        return 0;
 }
+
+inline void mlx5_ib_fs_cleanup_anchor(struct mlx5_ib_dev *dev) {}
 #endif
+
 static inline void mlx5_ib_fs_cleanup(struct mlx5_ib_dev *dev)
 {
+       /* When a steering anchor is created, a special flow table is also
+        * created for the user to reference. Since the user can reference it,
+        * the kernel cannot trust that when the user destroys the steering
+        * anchor, they no longer reference the flow table.
+        *
+        * To address this issue, when a user destroys a steering anchor, only
+        * the flow steering rule in the table is destroyed, but the table
+        * itself is kept to deal with the above scenario. The remaining
+        * resources are only removed when the RDMA device is destroyed, which
+        * is a safe assumption that all references are gone.
+        */
+       mlx5_ib_fs_cleanup_anchor(dev);
        kfree(dev->flow_db);
 }
 #endif /* _MLX5_IB_FS_H */
index 5d45de2..f0b394e 100644 (file)
@@ -4275,6 +4275,9 @@ const struct mlx5_ib_profile raw_eth_profile = {
        STAGE_CREATE(MLX5_IB_STAGE_POST_IB_REG_UMR,
                     mlx5_ib_stage_post_ib_reg_umr_init,
                     NULL),
+       STAGE_CREATE(MLX5_IB_STAGE_DELAY_DROP,
+                    mlx5_ib_stage_delay_drop_init,
+                    mlx5_ib_stage_delay_drop_cleanup),
        STAGE_CREATE(MLX5_IB_STAGE_RESTRACK,
                     mlx5_ib_restrack_init,
                     NULL),
index efa4dc6..2dfa6f4 100644 (file)
@@ -237,8 +237,19 @@ enum {
 #define MLX5_IB_NUM_SNIFFER_FTS                2
 #define MLX5_IB_NUM_EGRESS_FTS         1
 #define MLX5_IB_NUM_FDB_FTS            MLX5_BY_PASS_NUM_REGULAR_PRIOS
+
+struct mlx5_ib_anchor {
+       struct mlx5_flow_table *ft;
+       struct mlx5_flow_group *fg_goto_table;
+       struct mlx5_flow_group *fg_drop;
+       struct mlx5_flow_handle *rule_goto_table;
+       struct mlx5_flow_handle *rule_drop;
+       unsigned int rule_goto_table_ref;
+};
+
 struct mlx5_ib_flow_prio {
        struct mlx5_flow_table          *flow_table;
+       struct mlx5_ib_anchor           anchor;
        unsigned int                    refcount;
 };
 
@@ -1587,6 +1598,9 @@ static inline bool mlx5_ib_lag_should_assign_affinity(struct mlx5_ib_dev *dev)
            MLX5_CAP_PORT_SELECTION(dev->mdev, port_select_flow_table_bypass))
                return 0;
 
+       if (mlx5_lag_is_lacp_owner(dev->mdev) && !dev->lag_active)
+               return 0;
+
        return dev->lag_active ||
                (MLX5_CAP_GEN(dev->mdev, num_lag_ports) > 1 &&
                 MLX5_CAP_GEN(dev->mdev, lag_tx_port_affinity));
index 70ca8ff..78b96bf 100644 (file)
@@ -1237,6 +1237,9 @@ static int create_raw_packet_qp_tis(struct mlx5_ib_dev *dev,
 
        MLX5_SET(create_tis_in, in, uid, to_mpd(pd)->uid);
        MLX5_SET(tisc, tisc, transport_domain, tdn);
+       if (!mlx5_ib_lag_should_assign_affinity(dev) &&
+           mlx5_lag_is_lacp_owner(dev->mdev))
+               MLX5_SET(tisc, tisc, strict_lag_tx_port_affinity, 1);
        if (qp->flags & IB_QP_CREATE_SOURCE_QPN)
                MLX5_SET(tisc, tisc, underlay_qpn, qp->underlay_qpn);
 
index 20ff0c0..6ca2a05 100644 (file)
@@ -113,8 +113,6 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
 
        queue_advance_producer(cq->queue, QUEUE_TYPE_TO_CLIENT);
 
-       spin_unlock_irqrestore(&cq->cq_lock, flags);
-
        if ((cq->notify == IB_CQ_NEXT_COMP) ||
            (cq->notify == IB_CQ_SOLICITED && solicited)) {
                cq->notify = 0;
@@ -122,6 +120,8 @@ int rxe_cq_post(struct rxe_cq *cq, struct rxe_cqe *cqe, int solicited)
                cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context);
        }
 
+       spin_unlock_irqrestore(&cq->cq_lock, flags);
+
        return 0;
 }
 
index a38fab1..cd59666 100644 (file)
@@ -159,6 +159,9 @@ static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
        pkt->mask = RXE_GRH_MASK;
        pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph);
 
+       /* remove udp header */
+       skb_pull(skb, sizeof(struct udphdr));
+
        rxe_rcv(skb);
 
        return 0;
@@ -401,6 +404,9 @@ static int rxe_loopback(struct sk_buff *skb, struct rxe_pkt_info *pkt)
                return -EIO;
        }
 
+       /* remove udp header */
+       skb_pull(skb, sizeof(struct udphdr));
+
        rxe_rcv(skb);
 
        return 0;
index 61a2eb7..a0f2064 100644 (file)
@@ -176,6 +176,9 @@ static void rxe_qp_init_misc(struct rxe_dev *rxe, struct rxe_qp *qp,
        spin_lock_init(&qp->rq.producer_lock);
        spin_lock_init(&qp->rq.consumer_lock);
 
+       skb_queue_head_init(&qp->req_pkts);
+       skb_queue_head_init(&qp->resp_pkts);
+
        atomic_set(&qp->ssn, 0);
        atomic_set(&qp->skb_out, 0);
 }
@@ -234,8 +237,6 @@ static int rxe_qp_init_req(struct rxe_dev *rxe, struct rxe_qp *qp,
        qp->req.opcode          = -1;
        qp->comp.opcode         = -1;
 
-       skb_queue_head_init(&qp->req_pkts);
-
        rxe_init_task(&qp->req.task, qp, rxe_requester);
        rxe_init_task(&qp->comp.task, qp, rxe_completer);
 
@@ -279,8 +280,6 @@ static int rxe_qp_init_resp(struct rxe_dev *rxe, struct rxe_qp *qp,
                }
        }
 
-       skb_queue_head_init(&qp->resp_pkts);
-
        rxe_init_task(&qp->resp.task, qp, rxe_responder);
 
        qp->resp.opcode         = OPCODE_NONE;
index 1da044f..ee68306 100644 (file)
@@ -489,8 +489,9 @@ static enum resp_states check_rkey(struct rxe_qp *qp,
                if (mw->access & IB_ZERO_BASED)
                        qp->resp.offset = mw->addr;
 
-               rxe_put(mw);
                rxe_get(mr);
+               rxe_put(mw);
+               mw = NULL;
        } else {
                mr = lookup_mr(qp->pd, access, rkey, RXE_LOOKUP_REMOTE);
                if (!mr) {
index f290cd4..92e1e75 100644 (file)
@@ -657,9 +657,13 @@ static int
 isert_connect_error(struct rdma_cm_id *cma_id)
 {
        struct isert_conn *isert_conn = cma_id->qp->qp_context;
+       struct isert_np *isert_np = cma_id->context;
 
        ib_drain_qp(isert_conn->qp);
+
+       mutex_lock(&isert_np->mutex);
        list_del_init(&isert_conn->node);
+       mutex_unlock(&isert_np->mutex);
        isert_conn->cm_id = NULL;
        isert_put_conn(isert_conn);
 
@@ -2431,6 +2435,7 @@ isert_free_np(struct iscsi_np *np)
 {
        struct isert_np *isert_np = np->np_context;
        struct isert_conn *isert_conn, *n;
+       LIST_HEAD(drop_conn_list);
 
        if (isert_np->cm_id)
                rdma_destroy_id(isert_np->cm_id);
@@ -2450,7 +2455,7 @@ isert_free_np(struct iscsi_np *np)
                                         node) {
                        isert_info("cleaning isert_conn %p state (%d)\n",
                                   isert_conn, isert_conn->state);
-                       isert_connect_release(isert_conn);
+                       list_move_tail(&isert_conn->node, &drop_conn_list);
                }
        }
 
@@ -2461,11 +2466,16 @@ isert_free_np(struct iscsi_np *np)
                                         node) {
                        isert_info("cleaning isert_conn %p state (%d)\n",
                                   isert_conn, isert_conn->state);
-                       isert_connect_release(isert_conn);
+                       list_move_tail(&isert_conn->node, &drop_conn_list);
                }
        }
        mutex_unlock(&isert_np->mutex);
 
+       list_for_each_entry_safe(isert_conn, n, &drop_conn_list, node) {
+               list_del_init(&isert_conn->node);
+               isert_connect_release(isert_conn);
+       }
+
        np->np_context = NULL;
        kfree(isert_np);
 }
@@ -2560,8 +2570,6 @@ static void isert_wait_conn(struct iscsit_conn *conn)
        isert_put_unsol_pending_cmds(conn);
        isert_wait4cmds(conn);
        isert_wait4logout(isert_conn);
-
-       queue_work(isert_release_wq, &isert_conn->release_work);
 }
 
 static void isert_free_conn(struct iscsit_conn *conn)
index edb2e3a..cfb50bf 100644 (file)
@@ -2040,6 +2040,7 @@ static int rtrs_clt_rdma_cm_handler(struct rdma_cm_id *cm_id,
        return 0;
 }
 
+/* The caller should do the cleanup in case of error */
 static int create_cm(struct rtrs_clt_con *con)
 {
        struct rtrs_path *s = con->c.path;
@@ -2062,14 +2063,14 @@ static int create_cm(struct rtrs_clt_con *con)
        err = rdma_set_reuseaddr(cm_id, 1);
        if (err != 0) {
                rtrs_err(s, "Set address reuse failed, err: %d\n", err);
-               goto destroy_cm;
+               return err;
        }
        err = rdma_resolve_addr(cm_id, (struct sockaddr *)&clt_path->s.src_addr,
                                (struct sockaddr *)&clt_path->s.dst_addr,
                                RTRS_CONNECT_TIMEOUT_MS);
        if (err) {
                rtrs_err(s, "Failed to resolve address, err: %d\n", err);
-               goto destroy_cm;
+               return err;
        }
        /*
         * Combine connection status and session events. This is needed
@@ -2084,29 +2085,15 @@ static int create_cm(struct rtrs_clt_con *con)
                if (err == 0)
                        err = -ETIMEDOUT;
                /* Timedout or interrupted */
-               goto errr;
-       }
-       if (con->cm_err < 0) {
-               err = con->cm_err;
-               goto errr;
+               return err;
        }
-       if (READ_ONCE(clt_path->state) != RTRS_CLT_CONNECTING) {
+       if (con->cm_err < 0)
+               return con->cm_err;
+       if (READ_ONCE(clt_path->state) != RTRS_CLT_CONNECTING)
                /* Device removal */
-               err = -ECONNABORTED;
-               goto errr;
-       }
+               return -ECONNABORTED;
 
        return 0;
-
-errr:
-       stop_cm(con);
-       mutex_lock(&con->con_mutex);
-       destroy_con_cq_qp(con);
-       mutex_unlock(&con->con_mutex);
-destroy_cm:
-       destroy_cm(con);
-
-       return err;
 }
 
 static void rtrs_clt_path_up(struct rtrs_clt_path *clt_path)
@@ -2334,7 +2321,7 @@ static void rtrs_clt_close_work(struct work_struct *work)
 static int init_conns(struct rtrs_clt_path *clt_path)
 {
        unsigned int cid;
-       int err;
+       int err, i;
 
        /*
         * On every new session connections increase reconnect counter
@@ -2350,10 +2337,8 @@ static int init_conns(struct rtrs_clt_path *clt_path)
                        goto destroy;
 
                err = create_cm(to_clt_con(clt_path->s.con[cid]));
-               if (err) {
-                       destroy_con(to_clt_con(clt_path->s.con[cid]));
+               if (err)
                        goto destroy;
-               }
        }
        err = alloc_path_reqs(clt_path);
        if (err)
@@ -2364,15 +2349,21 @@ static int init_conns(struct rtrs_clt_path *clt_path)
        return 0;
 
 destroy:
-       while (cid--) {
-               struct rtrs_clt_con *con = to_clt_con(clt_path->s.con[cid]);
+       /* Make sure we do the cleanup in the order they are created */
+       for (i = 0; i <= cid; i++) {
+               struct rtrs_clt_con *con;
 
-               stop_cm(con);
+               if (!clt_path->s.con[i])
+                       break;
 
-               mutex_lock(&con->con_mutex);
-               destroy_con_cq_qp(con);
-               mutex_unlock(&con->con_mutex);
-               destroy_cm(con);
+               con = to_clt_con(clt_path->s.con[i]);
+               if (con->c.cm_id) {
+                       stop_cm(con);
+                       mutex_lock(&con->con_mutex);
+                       destroy_con_cq_qp(con);
+                       mutex_unlock(&con->con_mutex);
+                       destroy_cm(con);
+               }
                destroy_con(con);
        }
        /*
index 4bf9d86..3696f36 100644 (file)
@@ -37,8 +37,10 @@ struct rtrs_iu *rtrs_iu_alloc(u32 iu_num, size_t size, gfp_t gfp_mask,
                        goto err;
 
                iu->dma_addr = ib_dma_map_single(dma_dev, iu->buf, size, dir);
-               if (ib_dma_mapping_error(dma_dev, iu->dma_addr))
+               if (ib_dma_mapping_error(dma_dev, iu->dma_addr)) {
+                       kfree(iu->buf);
                        goto err;
+               }
 
                iu->cqe.done  = done;
                iu->size      = size;
index 37e876d..641eb86 100644 (file)
@@ -703,7 +703,7 @@ void input_close_device(struct input_handle *handle)
 
        __input_release_device(handle);
 
-       if (!dev->inhibited && !--dev->users) {
+       if (!--dev->users && !dev->inhibited) {
                if (dev->poller)
                        input_dev_poller_stop(dev->poller);
                if (dev->close)
index 28be88e..f33622f 100644 (file)
@@ -281,7 +281,6 @@ static const struct xpad_device {
        { 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
        { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
        { 0x146b, 0x0604, "Bigben Interactive DAIJA Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
-       { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
        { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
        { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
        { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
index 0948938..e79f549 100644 (file)
@@ -109,6 +109,27 @@ static const struct dmi_system_id dmi_use_low_level_irq[] = {
 };
 
 /*
+ * Some devices have a wrong entry which points to a GPIO which is
+ * required in another driver, so this driver must not claim it.
+ */
+static const struct dmi_system_id dmi_invalid_acpi_index[] = {
+       {
+               /*
+                * Lenovo Yoga Book X90F / X90L, the PNP0C40 home button entry
+                * points to a GPIO which is not a home button and which is
+                * required by the lenovo-yogabook driver.
+                */
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+                       DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
+               },
+               .driver_data = (void *)1l,
+       },
+       {} /* Terminating entry */
+};
+
+/*
  * Get the Nth GPIO number from the ACPI object.
  */
 static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
@@ -137,6 +158,8 @@ soc_button_device_create(struct platform_device *pdev,
        struct platform_device *pd;
        struct gpio_keys_button *gpio_keys;
        struct gpio_keys_platform_data *gpio_keys_pdata;
+       const struct dmi_system_id *dmi_id;
+       int invalid_acpi_index = -1;
        int error, gpio, irq;
        int n_buttons = 0;
 
@@ -154,10 +177,17 @@ soc_button_device_create(struct platform_device *pdev,
        gpio_keys = (void *)(gpio_keys_pdata + 1);
        n_buttons = 0;
 
+       dmi_id = dmi_first_match(dmi_invalid_acpi_index);
+       if (dmi_id)
+               invalid_acpi_index = (long)dmi_id->driver_data;
+
        for (info = button_info; info->name; info++) {
                if (info->autorepeat != autorepeat)
                        continue;
 
+               if (info->acpi_index == invalid_acpi_index)
+                       continue;
+
                error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
                if (error || irq < 0) {
                        /*
index ece97f8..2118b20 100644 (file)
@@ -674,10 +674,11 @@ static void process_packet_head_v4(struct psmouse *psmouse)
        struct input_dev *dev = psmouse->dev;
        struct elantech_data *etd = psmouse->private;
        unsigned char *packet = psmouse->packet;
-       int id = ((packet[3] & 0xe0) >> 5) - 1;
+       int id;
        int pres, traces;
 
-       if (id < 0)
+       id = ((packet[3] & 0xe0) >> 5) - 1;
+       if (id < 0 || id >= ETP_MAX_FINGERS)
                return;
 
        etd->mt[id].x = ((packet[1] & 0x0f) << 8) | packet[2];
@@ -707,7 +708,7 @@ static void process_packet_motion_v4(struct psmouse *psmouse)
        int id, sid;
 
        id = ((packet[0] & 0xe0) >> 5) - 1;
-       if (id < 0)
+       if (id < 0 || id >= ETP_MAX_FINGERS)
                return;
 
        sid = ((packet[3] & 0xe0) >> 5) - 1;
@@ -728,7 +729,7 @@ static void process_packet_motion_v4(struct psmouse *psmouse)
        input_report_abs(dev, ABS_MT_POSITION_X, etd->mt[id].x);
        input_report_abs(dev, ABS_MT_POSITION_Y, etd->mt[id].y);
 
-       if (sid >= 0) {
+       if (sid >= 0 && sid < ETP_MAX_FINGERS) {
                etd->mt[sid].x += delta_x2 * weight;
                etd->mt[sid].y -= delta_y2 * weight;
                input_mt_slot(dev, sid);
index 30102cb..3c9d072 100644 (file)
@@ -560,7 +560,7 @@ static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts)
 static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts)
 {
        int rc;
-       u8 cmd[HID_OUTPUT_BL_LAUNCH_APP];
+       u8 cmd[HID_OUTPUT_BL_LAUNCH_APP_SIZE];
        u16 crc;
 
        put_unaligned_le16(HID_OUTPUT_BL_LAUNCH_APP_SIZE, cmd);
index cc77cf3..7d5c9c5 100644 (file)
@@ -1168,13 +1168,10 @@ static int do_resume(struct dm_ioctl *param)
        /* Do we need to load a new map ? */
        if (new_map) {
                sector_t old_size, new_size;
-               int srcu_idx;
 
                /* Suspend if it isn't already suspended */
-               old_map = dm_get_live_table(md, &srcu_idx);
-               if ((param->flags & DM_SKIP_LOCKFS_FLAG) || !old_map)
+               if (param->flags & DM_SKIP_LOCKFS_FLAG)
                        suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
-               dm_put_live_table(md, srcu_idx);
                if (param->flags & DM_NOFLUSH_FLAG)
                        suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
                if (!dm_suspended_md(md))
index 9f5cb52..b9461fa 100644 (file)
@@ -1756,13 +1756,15 @@ int dm_thin_remove_range(struct dm_thin_device *td,
 
 int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *result)
 {
-       int r;
+       int r = -EINVAL;
        uint32_t ref_count;
 
        down_read(&pmd->root_lock);
-       r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
-       if (!r)
-               *result = (ref_count > 1);
+       if (!pmd->fail_io) {
+               r = dm_sm_get_count(pmd->data_sm, b, &ref_count);
+               if (!r)
+                       *result = (ref_count > 1);
+       }
        up_read(&pmd->root_lock);
 
        return r;
@@ -1770,10 +1772,11 @@ int dm_pool_block_is_shared(struct dm_pool_metadata *pmd, dm_block_t b, bool *re
 
 int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e)
 {
-       int r = 0;
+       int r = -EINVAL;
 
        pmd_write_lock(pmd);
-       r = dm_sm_inc_blocks(pmd->data_sm, b, e);
+       if (!pmd->fail_io)
+               r = dm_sm_inc_blocks(pmd->data_sm, b, e);
        pmd_write_unlock(pmd);
 
        return r;
@@ -1781,10 +1784,11 @@ int dm_pool_inc_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_
 
 int dm_pool_dec_data_range(struct dm_pool_metadata *pmd, dm_block_t b, dm_block_t e)
 {
-       int r = 0;
+       int r = -EINVAL;
 
        pmd_write_lock(pmd);
-       r = dm_sm_dec_blocks(pmd->data_sm, b, e);
+       if (!pmd->fail_io)
+               r = dm_sm_dec_blocks(pmd->data_sm, b, e);
        pmd_write_unlock(pmd);
 
        return r;
index 2b13c94..39410bf 100644 (file)
@@ -401,8 +401,7 @@ static int issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t da
        sector_t s = block_to_sectors(tc->pool, data_b);
        sector_t len = block_to_sectors(tc->pool, data_e - data_b);
 
-       return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOWAIT,
-                                     &op->bio);
+       return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOIO, &op->bio);
 }
 
 static void end_discard(struct discard_op *op, int r)
index 3b694ba..fffb0cb 100644 (file)
@@ -1172,7 +1172,8 @@ static inline sector_t max_io_len_target_boundary(struct dm_target *ti,
 }
 
 static sector_t __max_io_len(struct dm_target *ti, sector_t sector,
-                            unsigned int max_granularity)
+                            unsigned int max_granularity,
+                            unsigned int max_sectors)
 {
        sector_t target_offset = dm_target_offset(ti, sector);
        sector_t len = max_io_len_target_boundary(ti, target_offset);
@@ -1186,13 +1187,13 @@ static sector_t __max_io_len(struct dm_target *ti, sector_t sector,
        if (!max_granularity)
                return len;
        return min_t(sector_t, len,
-               min(queue_max_sectors(ti->table->md->queue),
+               min(max_sectors ? : queue_max_sectors(ti->table->md->queue),
                    blk_chunk_sectors_left(target_offset, max_granularity)));
 }
 
 static inline sector_t max_io_len(struct dm_target *ti, sector_t sector)
 {
-       return __max_io_len(ti, sector, ti->max_io_len);
+       return __max_io_len(ti, sector, ti->max_io_len, 0);
 }
 
 int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
@@ -1581,12 +1582,13 @@ static void __send_empty_flush(struct clone_info *ci)
 
 static void __send_changing_extent_only(struct clone_info *ci, struct dm_target *ti,
                                        unsigned int num_bios,
-                                       unsigned int max_granularity)
+                                       unsigned int max_granularity,
+                                       unsigned int max_sectors)
 {
        unsigned int len, bios;
 
        len = min_t(sector_t, ci->sector_count,
-                   __max_io_len(ti, ci->sector, max_granularity));
+                   __max_io_len(ti, ci->sector, max_granularity, max_sectors));
 
        atomic_add(num_bios, &ci->io->io_count);
        bios = __send_duplicate_bios(ci, ti, num_bios, &len);
@@ -1623,23 +1625,27 @@ static blk_status_t __process_abnormal_io(struct clone_info *ci,
 {
        unsigned int num_bios = 0;
        unsigned int max_granularity = 0;
+       unsigned int max_sectors = 0;
        struct queue_limits *limits = dm_get_queue_limits(ti->table->md);
 
        switch (bio_op(ci->bio)) {
        case REQ_OP_DISCARD:
                num_bios = ti->num_discard_bios;
+               max_sectors = limits->max_discard_sectors;
                if (ti->max_discard_granularity)
-                       max_granularity = limits->max_discard_sectors;
+                       max_granularity = max_sectors;
                break;
        case REQ_OP_SECURE_ERASE:
                num_bios = ti->num_secure_erase_bios;
+               max_sectors = limits->max_secure_erase_sectors;
                if (ti->max_secure_erase_granularity)
-                       max_granularity = limits->max_secure_erase_sectors;
+                       max_granularity = max_sectors;
                break;
        case REQ_OP_WRITE_ZEROES:
                num_bios = ti->num_write_zeroes_bios;
+               max_sectors = limits->max_write_zeroes_sectors;
                if (ti->max_write_zeroes_granularity)
-                       max_granularity = limits->max_write_zeroes_sectors;
+                       max_granularity = max_sectors;
                break;
        default:
                break;
@@ -1654,7 +1660,8 @@ static blk_status_t __process_abnormal_io(struct clone_info *ci,
        if (unlikely(!num_bios))
                return BLK_STS_NOTSUPP;
 
-       __send_changing_extent_only(ci, ti, num_bios, max_granularity);
+       __send_changing_extent_only(ci, ti, num_bios,
+                                   max_granularity, max_sectors);
        return BLK_STS_OK;
 }
 
@@ -2808,6 +2815,10 @@ retry:
        }
 
        map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
+       if (!map) {
+               /* avoid deadlock with fs/namespace.c:do_mount() */
+               suspend_flags &= ~DM_SUSPEND_LOCKFS_FLAG;
+       }
 
        r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE, DMF_SUSPENDED);
        if (r)
index bc6950a..9293b05 100644 (file)
@@ -817,26 +817,15 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
 
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
-       mutex_lock(&fe->remove_mutex);
-
        if (fe->exit != DVB_FE_DEVICE_REMOVED)
                fe->exit = DVB_FE_NORMAL_EXIT;
        mb();
 
-       if (!fepriv->thread) {
-               mutex_unlock(&fe->remove_mutex);
+       if (!fepriv->thread)
                return;
-       }
 
        kthread_stop(fepriv->thread);
 
-       mutex_unlock(&fe->remove_mutex);
-
-       if (fepriv->dvbdev->users < -1) {
-               wait_event(fepriv->dvbdev->wait_queue,
-                          fepriv->dvbdev->users == -1);
-       }
-
        sema_init(&fepriv->sem, 1);
        fepriv->state = FESTATE_IDLE;
 
@@ -2780,13 +2769,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
        struct dvb_adapter *adapter = fe->dvb;
        int ret;
 
-       mutex_lock(&fe->remove_mutex);
-
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
-       if (fe->exit == DVB_FE_DEVICE_REMOVED) {
-               ret = -ENODEV;
-               goto err_remove_mutex;
-       }
+       if (fe->exit == DVB_FE_DEVICE_REMOVED)
+               return -ENODEV;
 
        if (adapter->mfe_shared == 2) {
                mutex_lock(&adapter->mfe_lock);
@@ -2794,8 +2779,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                        if (adapter->mfe_dvbdev &&
                            !adapter->mfe_dvbdev->writers) {
                                mutex_unlock(&adapter->mfe_lock);
-                               ret = -EBUSY;
-                               goto err_remove_mutex;
+                               return -EBUSY;
                        }
                        adapter->mfe_dvbdev = dvbdev;
                }
@@ -2818,10 +2802,8 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                        while (mferetry-- && (mfedev->users != -1 ||
                                              mfepriv->thread)) {
                                if (msleep_interruptible(500)) {
-                                       if (signal_pending(current)) {
-                                               ret = -EINTR;
-                                               goto err_remove_mutex;
-                                       }
+                                       if (signal_pending(current))
+                                               return -EINTR;
                                }
                        }
 
@@ -2833,8 +2815,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
                                if (mfedev->users != -1 ||
                                    mfepriv->thread) {
                                        mutex_unlock(&adapter->mfe_lock);
-                                       ret = -EBUSY;
-                                       goto err_remove_mutex;
+                                       return -EBUSY;
                                }
                                adapter->mfe_dvbdev = dvbdev;
                        }
@@ -2893,8 +2874,6 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
 
        if (adapter->mfe_shared)
                mutex_unlock(&adapter->mfe_lock);
-
-       mutex_unlock(&fe->remove_mutex);
        return ret;
 
 err3:
@@ -2916,9 +2895,6 @@ err1:
 err0:
        if (adapter->mfe_shared)
                mutex_unlock(&adapter->mfe_lock);
-
-err_remove_mutex:
-       mutex_unlock(&fe->remove_mutex);
        return ret;
 }
 
@@ -2929,8 +2905,6 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
        struct dvb_frontend_private *fepriv = fe->frontend_priv;
        int ret;
 
-       mutex_lock(&fe->remove_mutex);
-
        dev_dbg(fe->dvb->device, "%s:\n", __func__);
 
        if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -2952,18 +2926,10 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
                }
                mutex_unlock(&fe->dvb->mdev_lock);
 #endif
+               if (fe->exit != DVB_FE_NO_EXIT)
+                       wake_up(&dvbdev->wait_queue);
                if (fe->ops.ts_bus_ctrl)
                        fe->ops.ts_bus_ctrl(fe, 0);
-
-               if (fe->exit != DVB_FE_NO_EXIT) {
-                       mutex_unlock(&fe->remove_mutex);
-                       wake_up(&dvbdev->wait_queue);
-               } else {
-                       mutex_unlock(&fe->remove_mutex);
-               }
-
-       } else {
-               mutex_unlock(&fe->remove_mutex);
        }
 
        dvb_frontend_put(fe);
@@ -3064,7 +3030,6 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
        fepriv = fe->frontend_priv;
 
        kref_init(&fe->refcount);
-       mutex_init(&fe->remove_mutex);
 
        /*
         * After initialization, there need to be two references: one
index f0a7531..2d240bf 100644 (file)
@@ -6,6 +6,7 @@ config EEPROM_AT24
        depends on I2C && SYSFS
        select NVMEM
        select NVMEM_SYSFS
+       select REGMAP
        select REGMAP_I2C
        help
          Enable this driver to get read/write support to most I2C EEPROMs
index cbe8318..c0215a8 100644 (file)
@@ -1188,8 +1188,6 @@ static int lan9303_port_fdb_add(struct dsa_switch *ds, int port,
        struct lan9303 *chip = ds->priv;
 
        dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
-       if (vid)
-               return -EOPNOTSUPP;
 
        return lan9303_alr_add_port(chip, addr, port, false);
 }
@@ -1201,8 +1199,6 @@ static int lan9303_port_fdb_del(struct dsa_switch *ds, int port,
        struct lan9303 *chip = ds->priv;
 
        dev_dbg(chip->dev, "%s(%d, %pM, %d)\n", __func__, port, addr, vid);
-       if (vid)
-               return -EOPNOTSUPP;
        lan9303_alr_del_port(chip, addr, port);
 
        return 0;
index cfb3fae..d172a3e 100644 (file)
@@ -1263,7 +1263,7 @@ static void vsc9959_tas_guard_bands_update(struct ocelot *ocelot, int port)
        /* Consider the standard Ethernet overhead of 8 octets preamble+SFD,
         * 4 octets FCS, 12 octets IFG.
         */
-       needed_bit_time_ps = (maxlen + 24) * picos_per_byte;
+       needed_bit_time_ps = (u64)(maxlen + 24) * picos_per_byte;
 
        dev_dbg(ocelot->dev,
                "port %d: max frame size %d needs %llu ps at speed %d\n",
index 4347b42..de9da46 100644 (file)
@@ -20,6 +20,7 @@ config NET_DSA_QCA8K_LEDS_SUPPORT
        bool "Qualcomm Atheros QCA8K Ethernet switch family LEDs support"
        depends on NET_DSA_QCA8K
        depends on LEDS_CLASS=y || LEDS_CLASS=NET_DSA_QCA8K
+       depends on LEDS_TRIGGERS
        help
          This enabled support for LEDs present on the Qualcomm Atheros
          QCA8K Ethernet switch chips.
index f7c597e..debe521 100644 (file)
@@ -68,9 +68,15 @@ bool pdsc_is_fw_running(struct pdsc *pdsc)
 
 bool pdsc_is_fw_good(struct pdsc *pdsc)
 {
-       u8 gen = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION;
+       bool fw_running = pdsc_is_fw_running(pdsc);
+       u8 gen;
 
-       return pdsc_is_fw_running(pdsc) && gen == pdsc->fw_generation;
+       /* Make sure to update the cached fw_status by calling
+        * pdsc_is_fw_running() before getting the generation
+        */
+       gen = pdsc->fw_status & PDS_CORE_FW_STS_F_GENERATION;
+
+       return fw_running && gen == pdsc->fw_generation;
 }
 
 static u8 pdsc_devcmd_status(struct pdsc *pdsc)
index 38d0cda..bf1611c 100644 (file)
@@ -2531,9 +2531,9 @@ static int bcm_sysport_probe(struct platform_device *pdev)
        priv->irq0 = platform_get_irq(pdev, 0);
        if (!priv->is_lite) {
                priv->irq1 = platform_get_irq(pdev, 1);
-               priv->wol_irq = platform_get_irq(pdev, 2);
+               priv->wol_irq = platform_get_irq_optional(pdev, 2);
        } else {
-               priv->wol_irq = platform_get_irq(pdev, 1);
+               priv->wol_irq = platform_get_irq_optional(pdev, 1);
        }
        if (priv->irq0 <= 0 || (priv->irq1 <= 0 && !priv->is_lite)) {
                ret = -EINVAL;
index 637d162..1e7a6f1 100644 (file)
@@ -14294,11 +14294,16 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
        bp->fw_seq = SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) &
                                                        DRV_MSG_SEQ_NUMBER_MASK;
 
-       if (netif_running(dev))
-               bnx2x_nic_load(bp, LOAD_NORMAL);
+       if (netif_running(dev)) {
+               if (bnx2x_nic_load(bp, LOAD_NORMAL)) {
+                       netdev_err(bp->dev, "Error during driver initialization, try unloading/reloading the driver\n");
+                       goto done;
+               }
+       }
 
        netif_device_attach(dev);
 
+done:
        rtnl_unlock();
 }
 
index dcd9367..b499bc9 100644 (file)
@@ -692,7 +692,7 @@ next_tx_int:
 
        __netif_txq_completed_wake(txq, nr_pkts, tx_bytes,
                                   bnxt_tx_avail(bp, txr), bp->tx_wake_thresh,
-                                  READ_ONCE(txr->dev_state) != BNXT_DEV_STATE_CLOSING);
+                                  READ_ONCE(txr->dev_state) == BNXT_DEV_STATE_CLOSING);
 }
 
 static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping,
@@ -2365,6 +2365,9 @@ static int bnxt_async_event_process(struct bnxt *bp,
                                struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
                                u64 ns;
 
+                               if (!ptp)
+                                       goto async_event_process_exit;
+
                                spin_lock_bh(&ptp->ptp_lock);
                                bnxt_ptp_update_current_time(bp);
                                ns = (((u64)BNXT_EVENT_PHC_RTC_UPDATE(data1) <<
@@ -4763,6 +4766,9 @@ int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size,
                if (event_id == ASYNC_EVENT_CMPL_EVENT_ID_ERROR_RECOVERY &&
                    !(bp->fw_cap & BNXT_FW_CAP_ERROR_RECOVERY))
                        continue;
+               if (event_id == ASYNC_EVENT_CMPL_EVENT_ID_PHC_UPDATE &&
+                   !bp->ptp_cfg)
+                       continue;
                __set_bit(bnxt_async_events_arr[i], async_events_bmap);
        }
        if (bmap && bmap_size) {
@@ -5350,6 +5356,7 @@ static void bnxt_hwrm_update_rss_hash_cfg(struct bnxt *bp)
        if (hwrm_req_init(bp, req, HWRM_VNIC_RSS_QCFG))
                return;
 
+       req->vnic_id = cpu_to_le16(vnic->fw_vnic_id);
        /* all contexts configured to same hash_type, zero always exists */
        req->rss_ctx_idx = cpu_to_le16(vnic->fw_rss_cos_lb_ctx[0]);
        resp = hwrm_req_hold(bp, req);
@@ -8812,6 +8819,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
                goto err_out;
        }
 
+       if (BNXT_VF(bp))
+               bnxt_hwrm_func_qcfg(bp);
+
        rc = bnxt_setup_vnic(bp, 0);
        if (rc)
                goto err_out;
@@ -11598,6 +11608,7 @@ static void bnxt_tx_timeout(struct net_device *dev, unsigned int txqueue)
 static void bnxt_fw_health_check(struct bnxt *bp)
 {
        struct bnxt_fw_health *fw_health = bp->fw_health;
+       struct pci_dev *pdev = bp->pdev;
        u32 val;
 
        if (!fw_health->enabled || test_bit(BNXT_STATE_IN_FW_RESET, &bp->state))
@@ -11611,7 +11622,7 @@ static void bnxt_fw_health_check(struct bnxt *bp)
        }
 
        val = bnxt_fw_health_readl(bp, BNXT_FW_HEARTBEAT_REG);
-       if (val == fw_health->last_fw_heartbeat) {
+       if (val == fw_health->last_fw_heartbeat && pci_device_is_present(pdev)) {
                fw_health->arrests++;
                goto fw_reset;
        }
@@ -11619,7 +11630,7 @@ static void bnxt_fw_health_check(struct bnxt *bp)
        fw_health->last_fw_heartbeat = val;
 
        val = bnxt_fw_health_readl(bp, BNXT_FW_RESET_CNT_REG);
-       if (val != fw_health->last_fw_reset_cnt) {
+       if (val != fw_health->last_fw_reset_cnt && pci_device_is_present(pdev)) {
                fw_health->discoveries++;
                goto fw_reset;
        }
@@ -13025,26 +13036,37 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp)
 
 #endif /* CONFIG_RFS_ACCEL */
 
-static int bnxt_udp_tunnel_sync(struct net_device *netdev, unsigned int table)
+static int bnxt_udp_tunnel_set_port(struct net_device *netdev, unsigned int table,
+                                   unsigned int entry, struct udp_tunnel_info *ti)
 {
        struct bnxt *bp = netdev_priv(netdev);
-       struct udp_tunnel_info ti;
        unsigned int cmd;
 
-       udp_tunnel_nic_get_port(netdev, table, 0, &ti);
-       if (ti.type == UDP_TUNNEL_TYPE_VXLAN)
+       if (ti->type == UDP_TUNNEL_TYPE_VXLAN)
                cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN;
        else
                cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE;
 
-       if (ti.port)
-               return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti.port, cmd);
+       return bnxt_hwrm_tunnel_dst_port_alloc(bp, ti->port, cmd);
+}
+
+static int bnxt_udp_tunnel_unset_port(struct net_device *netdev, unsigned int table,
+                                     unsigned int entry, struct udp_tunnel_info *ti)
+{
+       struct bnxt *bp = netdev_priv(netdev);
+       unsigned int cmd;
+
+       if (ti->type == UDP_TUNNEL_TYPE_VXLAN)
+               cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN;
+       else
+               cmd = TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE;
 
        return bnxt_hwrm_tunnel_dst_port_free(bp, cmd);
 }
 
 static const struct udp_tunnel_nic_info bnxt_udp_tunnels = {
-       .sync_table     = bnxt_udp_tunnel_sync,
+       .set_port       = bnxt_udp_tunnel_set_port,
+       .unset_port     = bnxt_udp_tunnel_unset_port,
        .flags          = UDP_TUNNEL_NIC_INFO_MAY_SLEEP |
                          UDP_TUNNEL_NIC_INFO_OPEN_ONLY,
        .tables         = {
index 2dd8ee4..8fd5071 100644 (file)
@@ -3831,7 +3831,7 @@ static int bnxt_reset(struct net_device *dev, u32 *flags)
                }
        }
 
-       if (req & BNXT_FW_RESET_AP) {
+       if (!BNXT_CHIP_P4_PLUS(bp) && (req & BNXT_FW_RESET_AP)) {
                /* This feature is not supported in older firmware versions */
                if (bp->hwrm_spec_code >= 0x10803) {
                        if (!bnxt_firmware_reset_ap(dev)) {
index e466891..f388671 100644 (file)
@@ -952,6 +952,7 @@ int bnxt_ptp_init(struct bnxt *bp, bool phc_cfg)
                bnxt_ptp_timecounter_init(bp, true);
                bnxt_ptp_adjfine_rtc(bp, 0);
        }
+       bnxt_hwrm_func_drv_rgtr(bp, NULL, 0, true);
 
        ptp->ptp_info = bnxt_ptp_caps;
        if ((bp->fw_cap & BNXT_FW_CAP_PTP_PPS)) {
index eca0c92..2b5761a 100644 (file)
@@ -1272,7 +1272,8 @@ static void bcmgenet_get_ethtool_stats(struct net_device *dev,
        }
 }
 
-static void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
+                            bool tx_lpi_enabled)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        u32 off = priv->hw_params->tbuf_offset + TBUF_ENERGY_CTRL;
@@ -1292,7 +1293,7 @@ static void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
 
        /* Enable EEE and switch to a 27Mhz clock automatically */
        reg = bcmgenet_readl(priv->base + off);
-       if (enable)
+       if (tx_lpi_enabled)
                reg |= TBUF_EEE_EN | TBUF_PM_EN;
        else
                reg &= ~(TBUF_EEE_EN | TBUF_PM_EN);
@@ -1313,6 +1314,7 @@ static void bcmgenet_eee_enable_set(struct net_device *dev, bool enable)
 
        priv->eee.eee_enabled = enable;
        priv->eee.eee_active = enable;
+       priv->eee.tx_lpi_enabled = tx_lpi_enabled;
 }
 
 static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e)
@@ -1328,6 +1330,7 @@ static int bcmgenet_get_eee(struct net_device *dev, struct ethtool_eee *e)
 
        e->eee_enabled = p->eee_enabled;
        e->eee_active = p->eee_active;
+       e->tx_lpi_enabled = p->tx_lpi_enabled;
        e->tx_lpi_timer = bcmgenet_umac_readl(priv, UMAC_EEE_LPI_TIMER);
 
        return phy_ethtool_get_eee(dev->phydev, e);
@@ -1337,7 +1340,6 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e)
 {
        struct bcmgenet_priv *priv = netdev_priv(dev);
        struct ethtool_eee *p = &priv->eee;
-       int ret = 0;
 
        if (GENET_IS_V1(priv))
                return -EOPNOTSUPP;
@@ -1348,16 +1350,11 @@ static int bcmgenet_set_eee(struct net_device *dev, struct ethtool_eee *e)
        p->eee_enabled = e->eee_enabled;
 
        if (!p->eee_enabled) {
-               bcmgenet_eee_enable_set(dev, false);
+               bcmgenet_eee_enable_set(dev, false, false);
        } else {
-               ret = phy_init_eee(dev->phydev, false);
-               if (ret) {
-                       netif_err(priv, hw, dev, "EEE initialization failed\n");
-                       return ret;
-               }
-
+               p->eee_active = phy_init_eee(dev->phydev, false) >= 0;
                bcmgenet_umac_writel(priv, e->tx_lpi_timer, UMAC_EEE_LPI_TIMER);
-               bcmgenet_eee_enable_set(dev, true);
+               bcmgenet_eee_enable_set(dev, p->eee_active, e->tx_lpi_enabled);
        }
 
        return phy_ethtool_set_eee(dev->phydev, e);
@@ -4279,9 +4276,6 @@ static int bcmgenet_resume(struct device *d)
        if (!device_may_wakeup(d))
                phy_resume(dev->phydev);
 
-       if (priv->eee.eee_enabled)
-               bcmgenet_eee_enable_set(dev, true);
-
        bcmgenet_netif_start(dev);
 
        netif_device_attach(dev);
index 946f6e2..1985c0e 100644 (file)
@@ -703,4 +703,7 @@ int bcmgenet_wol_power_down_cfg(struct bcmgenet_priv *priv,
 void bcmgenet_wol_power_up_cfg(struct bcmgenet_priv *priv,
                               enum bcmgenet_power_mode mode);
 
+void bcmgenet_eee_enable_set(struct net_device *dev, bool enable,
+                            bool tx_lpi_enabled);
+
 #endif /* __BCMGENET_H__ */
index be04290..c15ed0a 100644 (file)
@@ -87,6 +87,11 @@ static void bcmgenet_mac_config(struct net_device *dev)
                reg |= CMD_TX_EN | CMD_RX_EN;
        }
        bcmgenet_umac_writel(priv, reg, UMAC_CMD);
+
+       priv->eee.eee_active = phy_init_eee(phydev, 0) >= 0;
+       bcmgenet_eee_enable_set(dev,
+                               priv->eee.eee_enabled && priv->eee.eee_active,
+                               priv->eee.tx_lpi_enabled);
 }
 
 /* setup netdev link state when PHY link status change and
index 3c4fa26..9e1b253 100644 (file)
@@ -1229,7 +1229,13 @@ static int enetc_clean_rx_ring(struct enetc_bdr *rx_ring,
                if (!skb)
                        break;
 
-               rx_byte_cnt += skb->len;
+               /* When set, the outer VLAN header is extracted and reported
+                * in the receive buffer descriptor. So rx_byte_cnt should
+                * add the length of the extracted VLAN header.
+                */
+               if (bd_status & ENETC_RXBD_FLAG_VLAN)
+                       rx_byte_cnt += VLAN_HLEN;
+               rx_byte_cnt += skb->len + ETH_HLEN;
                rx_frm_cnt++;
 
                napi_gro_receive(napi, skb);
@@ -1565,6 +1571,14 @@ static int enetc_clean_rx_ring_xdp(struct enetc_bdr *rx_ring,
                enetc_build_xdp_buff(rx_ring, bd_status, &rxbd, &i,
                                     &cleaned_cnt, &xdp_buff);
 
+               /* When set, the outer VLAN header is extracted and reported
+                * in the receive buffer descriptor. So rx_byte_cnt should
+                * add the length of the extracted VLAN header.
+                */
+               if (bd_status & ENETC_RXBD_FLAG_VLAN)
+                       rx_byte_cnt += VLAN_HLEN;
+               rx_byte_cnt += xdp_get_buff_len(&xdp_buff);
+
                xdp_act = bpf_prog_run_xdp(prog, &xdp_buff);
 
                switch (xdp_act) {
index 83c27bb..126007a 100644 (file)
@@ -181,8 +181,8 @@ int enetc_setup_tc_cbs(struct net_device *ndev, void *type_data)
        int bw_sum = 0;
        u8 bw;
 
-       prio_top = netdev_get_prio_tc_map(ndev, tc_nums - 1);
-       prio_next = netdev_get_prio_tc_map(ndev, tc_nums - 2);
+       prio_top = tc_nums - 1;
+       prio_next = tc_nums - 2;
 
        /* Support highest prio and second prio tc in cbs mode */
        if (tc != prio_top && tc != prio_next)
index 9abaff1..39d0fe7 100644 (file)
@@ -525,7 +525,7 @@ void iavf_set_ethtool_ops(struct net_device *netdev);
 void iavf_update_stats(struct iavf_adapter *adapter);
 void iavf_reset_interrupt_capability(struct iavf_adapter *adapter);
 int iavf_init_interrupt_scheme(struct iavf_adapter *adapter);
-void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask);
+void iavf_irq_enable_queues(struct iavf_adapter *adapter);
 void iavf_free_all_tx_resources(struct iavf_adapter *adapter);
 void iavf_free_all_rx_resources(struct iavf_adapter *adapter);
 
index 2de4baf..4a66873 100644 (file)
@@ -359,21 +359,18 @@ static void iavf_irq_disable(struct iavf_adapter *adapter)
 }
 
 /**
- * iavf_irq_enable_queues - Enable interrupt for specified queues
+ * iavf_irq_enable_queues - Enable interrupt for all queues
  * @adapter: board private structure
- * @mask: bitmap of queues to enable
  **/
-void iavf_irq_enable_queues(struct iavf_adapter *adapter, u32 mask)
+void iavf_irq_enable_queues(struct iavf_adapter *adapter)
 {
        struct iavf_hw *hw = &adapter->hw;
        int i;
 
        for (i = 1; i < adapter->num_msix_vectors; i++) {
-               if (mask & BIT(i - 1)) {
-                       wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
-                            IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
-                            IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
-               }
+               wr32(hw, IAVF_VFINT_DYN_CTLN1(i - 1),
+                    IAVF_VFINT_DYN_CTLN1_INTENA_MASK |
+                    IAVF_VFINT_DYN_CTLN1_ITR_INDX_MASK);
        }
 }
 
@@ -387,7 +384,7 @@ void iavf_irq_enable(struct iavf_adapter *adapter, bool flush)
        struct iavf_hw *hw = &adapter->hw;
 
        iavf_misc_irq_enable(adapter);
-       iavf_irq_enable_queues(adapter, ~0);
+       iavf_irq_enable_queues(adapter);
 
        if (flush)
                iavf_flush(hw);
index bf79333..a19e888 100644 (file)
@@ -40,7 +40,7 @@
 #define IAVF_VFINT_DYN_CTL01_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTL01_INTENA_SHIFT)
 #define IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
 #define IAVF_VFINT_DYN_CTL01_ITR_INDX_MASK IAVF_MASK(0x3, IAVF_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
-#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...15 */ /* Reset: VFR */
+#define IAVF_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4)) /* _i=0...63 */ /* Reset: VFR */
 #define IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT 0
 #define IAVF_VFINT_DYN_CTLN1_INTENA_MASK IAVF_MASK(0x1, IAVF_VFINT_DYN_CTLN1_INTENA_SHIFT)
 #define IAVF_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
index 0157f6e..eb2dc09 100644 (file)
@@ -5160,7 +5160,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
  */
 int
 ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
-                u16 bus_addr, __le16 addr, u8 params, u8 *data,
+                u16 bus_addr, __le16 addr, u8 params, const u8 *data,
                 struct ice_sq_cd *cd)
 {
        struct ice_aq_desc desc = { 0 };
index 8ba5f93..81961a7 100644 (file)
@@ -229,7 +229,7 @@ ice_aq_read_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
                struct ice_sq_cd *cd);
 int
 ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
-                u16 bus_addr, __le16 addr, u8 params, u8 *data,
+                u16 bus_addr, __le16 addr, u8 params, const u8 *data,
                 struct ice_sq_cd *cd);
 bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw);
 #endif /* _ICE_COMMON_H_ */
index 2ea8a2b..75c9de6 100644 (file)
@@ -16,8 +16,8 @@
  * * number of bytes written - success
  * * negative - error code
  */
-static unsigned int
-ice_gnss_do_write(struct ice_pf *pf, unsigned char *buf, unsigned int size)
+static int
+ice_gnss_do_write(struct ice_pf *pf, const unsigned char *buf, unsigned int size)
 {
        struct ice_aqc_link_topo_addr link_topo;
        struct ice_hw *hw = &pf->hw;
@@ -72,39 +72,7 @@ err_out:
        dev_err(ice_pf_to_dev(pf), "GNSS failed to write, offset=%u, size=%u, err=%d\n",
                offset, size, err);
 
-       return offset;
-}
-
-/**
- * ice_gnss_write_pending - Write all pending data to internal GNSS
- * @work: GNSS write work structure
- */
-static void ice_gnss_write_pending(struct kthread_work *work)
-{
-       struct gnss_serial *gnss = container_of(work, struct gnss_serial,
-                                               write_work);
-       struct ice_pf *pf = gnss->back;
-
-       if (!pf)
-               return;
-
-       if (!test_bit(ICE_FLAG_GNSS, pf->flags))
-               return;
-
-       if (!list_empty(&gnss->queue)) {
-               struct gnss_write_buf *write_buf = NULL;
-               unsigned int bytes;
-
-               write_buf = list_first_entry(&gnss->queue,
-                                            struct gnss_write_buf, queue);
-
-               bytes = ice_gnss_do_write(pf, write_buf->buf, write_buf->size);
-               dev_dbg(ice_pf_to_dev(pf), "%u bytes written to GNSS\n", bytes);
-
-               list_del(&write_buf->queue);
-               kfree(write_buf->buf);
-               kfree(write_buf);
-       }
+       return err;
 }
 
 /**
@@ -128,12 +96,7 @@ static void ice_gnss_read(struct kthread_work *work)
        int err = 0;
 
        pf = gnss->back;
-       if (!pf) {
-               err = -EFAULT;
-               goto exit;
-       }
-
-       if (!test_bit(ICE_FLAG_GNSS, pf->flags))
+       if (!pf || !test_bit(ICE_FLAG_GNSS, pf->flags))
                return;
 
        hw = &pf->hw;
@@ -191,7 +154,6 @@ free_buf:
        free_page((unsigned long)buf);
 requeue:
        kthread_queue_delayed_work(gnss->kworker, &gnss->read_work, delay);
-exit:
        if (err)
                dev_dbg(ice_pf_to_dev(pf), "GNSS failed to read err=%d\n", err);
 }
@@ -220,8 +182,6 @@ static struct gnss_serial *ice_gnss_struct_init(struct ice_pf *pf)
        pf->gnss_serial = gnss;
 
        kthread_init_delayed_work(&gnss->read_work, ice_gnss_read);
-       INIT_LIST_HEAD(&gnss->queue);
-       kthread_init_work(&gnss->write_work, ice_gnss_write_pending);
        kworker = kthread_create_worker(0, "ice-gnss-%s", dev_name(dev));
        if (IS_ERR(kworker)) {
                kfree(gnss);
@@ -281,7 +241,6 @@ static void ice_gnss_close(struct gnss_device *gdev)
        if (!gnss)
                return;
 
-       kthread_cancel_work_sync(&gnss->write_work);
        kthread_cancel_delayed_work_sync(&gnss->read_work);
 }
 
@@ -300,10 +259,7 @@ ice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,
               size_t count)
 {
        struct ice_pf *pf = gnss_get_drvdata(gdev);
-       struct gnss_write_buf *write_buf;
        struct gnss_serial *gnss;
-       unsigned char *cmd_buf;
-       int err = count;
 
        /* We cannot write a single byte using our I2C implementation. */
        if (count <= 1 || count > ICE_GNSS_TTY_WRITE_BUF)
@@ -319,24 +275,7 @@ ice_gnss_write(struct gnss_device *gdev, const unsigned char *buf,
        if (!gnss)
                return -ENODEV;
 
-       cmd_buf = kcalloc(count, sizeof(*buf), GFP_KERNEL);
-       if (!cmd_buf)
-               return -ENOMEM;
-
-       memcpy(cmd_buf, buf, count);
-       write_buf = kzalloc(sizeof(*write_buf), GFP_KERNEL);
-       if (!write_buf) {
-               kfree(cmd_buf);
-               return -ENOMEM;
-       }
-
-       write_buf->buf = cmd_buf;
-       write_buf->size = count;
-       INIT_LIST_HEAD(&write_buf->queue);
-       list_add_tail(&write_buf->queue, &gnss->queue);
-       kthread_queue_work(gnss->kworker, &gnss->write_work);
-
-       return err;
+       return ice_gnss_do_write(pf, buf, count);
 }
 
 static const struct gnss_operations ice_gnss_ops = {
@@ -432,7 +371,6 @@ void ice_gnss_exit(struct ice_pf *pf)
        if (pf->gnss_serial) {
                struct gnss_serial *gnss = pf->gnss_serial;
 
-               kthread_cancel_work_sync(&gnss->write_work);
                kthread_cancel_delayed_work_sync(&gnss->read_work);
                kthread_destroy_worker(gnss->kworker);
                gnss->kworker = NULL;
index b8bb8b6..75e567a 100644 (file)
  */
 #define ICE_GNSS_UBX_WRITE_BYTES       (ICE_MAX_I2C_WRITE_BYTES + 1)
 
-struct gnss_write_buf {
-       struct list_head queue;
-       unsigned int size;
-       unsigned char *buf;
-};
-
 /**
  * struct gnss_serial - data used to initialize GNSS TTY port
  * @back: back pointer to PF
  * @kworker: kwork thread for handling periodic work
  * @read_work: read_work function for handling GNSS reads
- * @write_work: write_work function for handling GNSS writes
- * @queue: write buffers queue
  */
 struct gnss_serial {
        struct ice_pf *back;
        struct kthread_worker *kworker;
        struct kthread_delayed_work read_work;
-       struct kthread_work write_work;
-       struct list_head queue;
 };
 
 #if IS_ENABLED(CONFIG_GNSS)
index a1f7c8e..42c318c 100644 (file)
@@ -4802,9 +4802,13 @@ err_init_pf:
 static void ice_deinit_dev(struct ice_pf *pf)
 {
        ice_free_irq_msix_misc(pf);
-       ice_clear_interrupt_scheme(pf);
        ice_deinit_pf(pf);
        ice_deinit_hw(&pf->hw);
+
+       /* Service task is already stopped, so call reset directly. */
+       ice_reset(&pf->hw, ICE_RESET_PFR);
+       pci_wait_for_pending_transaction(pf->pdev);
+       ice_clear_interrupt_scheme(pf);
 }
 
 static void ice_init_features(struct ice_pf *pf)
@@ -5094,10 +5098,6 @@ int ice_load(struct ice_pf *pf)
        struct ice_vsi *vsi;
        int err;
 
-       err = ice_reset(&pf->hw, ICE_RESET_PFR);
-       if (err)
-               return err;
-
        err = ice_init_dev(pf);
        if (err)
                return err;
@@ -5354,12 +5354,6 @@ static void ice_remove(struct pci_dev *pdev)
        ice_setup_mc_magic_wake(pf);
        ice_set_wake(pf);
 
-       /* Issue a PFR as part of the prescribed driver unload flow.  Do not
-        * do it via ice_schedule_reset() since there is no need to rebuild
-        * and the service task is already stopped.
-        */
-       ice_reset(&pf->hw, ICE_RESET_PFR);
-       pci_wait_for_pending_transaction(pdev);
        pci_disable_device(pdev);
 }
 
@@ -7056,6 +7050,10 @@ int ice_down(struct ice_vsi *vsi)
        ice_for_each_txq(vsi, i)
                ice_clean_tx_ring(vsi->tx_rings[i]);
 
+       if (ice_is_xdp_ena_vsi(vsi))
+               ice_for_each_xdp_txq(vsi, i)
+                       ice_clean_tx_ring(vsi->xdp_rings[i]);
+
        ice_for_each_rxq(vsi, i)
                ice_clean_rx_ring(vsi->rx_rings[i]);
 
index 7d60da1..319ed60 100644 (file)
@@ -822,6 +822,8 @@ static int igb_set_eeprom(struct net_device *netdev,
                 */
                ret_val = hw->nvm.ops.read(hw, last_word, 1,
                                   &eeprom_buff[last_word - first_word]);
+               if (ret_val)
+                       goto out;
        }
 
        /* Device's eeprom is always little-endian, word addressable */
@@ -841,6 +843,7 @@ static int igb_set_eeprom(struct net_device *netdev,
                hw->nvm.ops.update(hw);
 
        igb_set_fw_version(adapter);
+out:
        kfree(eeprom_buff);
        return ret_val;
 }
index 58872a4..bb3db38 100644 (file)
@@ -6947,6 +6947,7 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt)
        struct e1000_hw *hw = &adapter->hw;
        struct ptp_clock_event event;
        struct timespec64 ts;
+       unsigned long flags;
 
        if (pin < 0 || pin >= IGB_N_SDP)
                return;
@@ -6954,9 +6955,12 @@ static void igb_extts(struct igb_adapter *adapter, int tsintr_tt)
        if (hw->mac.type == e1000_82580 ||
            hw->mac.type == e1000_i354 ||
            hw->mac.type == e1000_i350) {
-               s64 ns = rd32(auxstmpl);
+               u64 ns = rd32(auxstmpl);
 
-               ns += ((s64)(rd32(auxstmph) & 0xFF)) << 32;
+               ns += ((u64)(rd32(auxstmph) & 0xFF)) << 32;
+               spin_lock_irqsave(&adapter->tmreg_lock, flags);
+               ns = timecounter_cyc2time(&adapter->tc, ns);
+               spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
                ts = ns_to_timespec64(ns);
        } else {
                ts.tv_nsec = rd32(auxstmpl);
index 1c46768..fa76419 100644 (file)
@@ -254,6 +254,13 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
        /* reset BQL for queue */
        netdev_tx_reset_queue(txring_txq(tx_ring));
 
+       /* Zero out the buffer ring */
+       memset(tx_ring->tx_buffer_info, 0,
+              sizeof(*tx_ring->tx_buffer_info) * tx_ring->count);
+
+       /* Zero out the descriptor ring */
+       memset(tx_ring->desc, 0, tx_ring->size);
+
        /* reset next_to_use and next_to_clean */
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
@@ -267,7 +274,7 @@ static void igc_clean_tx_ring(struct igc_ring *tx_ring)
  */
 void igc_free_tx_resources(struct igc_ring *tx_ring)
 {
-       igc_clean_tx_ring(tx_ring);
+       igc_disable_tx_ring(tx_ring);
 
        vfree(tx_ring->tx_buffer_info);
        tx_ring->tx_buffer_info = NULL;
@@ -6723,6 +6730,9 @@ static void igc_remove(struct pci_dev *pdev)
 
        igc_ptp_stop(adapter);
 
+       pci_disable_ptm(pdev);
+       pci_clear_master(pdev);
+
        set_bit(__IGC_DOWN, &adapter->state);
 
        del_timer_sync(&adapter->watchdog_timer);
index 5d83c88..1726297 100644 (file)
@@ -1256,7 +1256,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
        if (!__netif_txq_completed_wake(txq, total_packets, total_bytes,
                                        ixgbe_desc_unused(tx_ring),
                                        TX_WAKE_THRESHOLD,
-                                       netif_carrier_ok(tx_ring->netdev) &&
+                                       !netif_carrier_ok(tx_ring->netdev) ||
                                        test_bit(__IXGBE_DOWN, &adapter->state)))
                ++tx_ring->tx_stats.restart_queue;
 
index e1853da..43eb6e8 100644 (file)
@@ -981,6 +981,9 @@ int octep_device_setup(struct octep_device *oct)
                oct->mmio[i].hw_addr =
                        ioremap(pci_resource_start(oct->pdev, i * 2),
                                pci_resource_len(oct->pdev, i * 2));
+               if (!oct->mmio[i].hw_addr)
+                       goto unmap_prev;
+
                oct->mmio[i].mapped = 1;
        }
 
@@ -1015,7 +1018,9 @@ int octep_device_setup(struct octep_device *oct)
        return 0;
 
 unsupported_dev:
-       for (i = 0; i < OCTEP_MMIO_REGIONS; i++)
+       i = OCTEP_MMIO_REGIONS;
+unmap_prev:
+       while (i--)
                iounmap(oct->mmio[i].hw_addr);
 
        kfree(oct->conf);
index 4ad707e..f01d057 100644 (file)
@@ -1878,7 +1878,8 @@ static int nix_check_txschq_alloc_req(struct rvu *rvu, int lvl, u16 pcifunc,
                free_cnt = rvu_rsrc_free_count(&txsch->schq);
        }
 
-       if (free_cnt < req_schq || req_schq > MAX_TXSCHQ_PER_FUNC)
+       if (free_cnt < req_schq || req->schq[lvl] > MAX_TXSCHQ_PER_FUNC ||
+           req->schq_contig[lvl] > MAX_TXSCHQ_PER_FUNC)
                return NIX_AF_ERR_TLX_ALLOC_FAIL;
 
        /* If contiguous queues are needed, check for availability */
@@ -4080,10 +4081,6 @@ int rvu_mbox_handler_nix_set_rx_cfg(struct rvu *rvu, struct nix_rx_cfg *req,
 
 static u64 rvu_get_lbk_link_credits(struct rvu *rvu, u16 lbk_max_frs)
 {
-       /* CN10k supports 72KB FIFO size and max packet size of 64k */
-       if (rvu->hw->lbk_bufsize == 0x12000)
-               return (rvu->hw->lbk_bufsize - lbk_max_frs) / 16;
-
        return 1600; /* 16 * max LBK datarate = 16 * 100Gbps */
 }
 
index 5120911..9f11c1e 100644 (file)
@@ -1164,10 +1164,8 @@ static u16 __rvu_npc_exact_cmd_rules_cnt_update(struct rvu *rvu, int drop_mcam_i
 {
        struct npc_exact_table *table;
        u16 *cnt, old_cnt;
-       bool promisc;
 
        table = rvu->hw->table;
-       promisc = table->promisc_mode[drop_mcam_idx];
 
        cnt = &table->cnt_cmd_rules[drop_mcam_idx];
        old_cnt = *cnt;
@@ -1179,16 +1177,13 @@ static u16 __rvu_npc_exact_cmd_rules_cnt_update(struct rvu *rvu, int drop_mcam_i
 
        *enable_or_disable_cam = false;
 
-       if (promisc)
-               goto done;
-
-       /* If all rules are deleted and not already in promisc mode; disable cam */
+       /* If all rules are deleted, disable cam */
        if (!*cnt && val < 0) {
                *enable_or_disable_cam = true;
                goto done;
        }
 
-       /* If rule got added and not already in promisc mode; enable cam */
+       /* If rule got added, enable cam */
        if (!old_cnt && val > 0) {
                *enable_or_disable_cam = true;
                goto done;
@@ -1443,7 +1438,6 @@ int rvu_npc_exact_promisc_disable(struct rvu *rvu, u16 pcifunc)
        u32 drop_mcam_idx;
        bool *promisc;
        bool rc;
-       u32 cnt;
 
        table = rvu->hw->table;
 
@@ -1466,17 +1460,8 @@ int rvu_npc_exact_promisc_disable(struct rvu *rvu, u16 pcifunc)
                return LMAC_AF_ERR_INVALID_PARAM;
        }
        *promisc = false;
-       cnt = __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, 0, NULL);
        mutex_unlock(&table->lock);
 
-       /* If no dmac filter entries configured, disable drop rule */
-       if (!cnt)
-               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, false);
-       else
-               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, !*promisc);
-
-       dev_dbg(rvu->dev, "%s: disabled  promisc mode (cgx=%d lmac=%d, cnt=%d)\n",
-               __func__, cgx_id, lmac_id, cnt);
        return 0;
 }
 
@@ -1494,7 +1479,6 @@ int rvu_npc_exact_promisc_enable(struct rvu *rvu, u16 pcifunc)
        u32 drop_mcam_idx;
        bool *promisc;
        bool rc;
-       u32 cnt;
 
        table = rvu->hw->table;
 
@@ -1517,17 +1501,8 @@ int rvu_npc_exact_promisc_enable(struct rvu *rvu, u16 pcifunc)
                return LMAC_AF_ERR_INVALID_PARAM;
        }
        *promisc = true;
-       cnt = __rvu_npc_exact_cmd_rules_cnt_update(rvu, drop_mcam_idx, 0, NULL);
        mutex_unlock(&table->lock);
 
-       /* If no dmac filter entries configured, disable drop rule */
-       if (!cnt)
-               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, false);
-       else
-               rvu_npc_enable_mcam_by_entry_index(rvu, drop_mcam_idx, NIX_INTF_RX, !*promisc);
-
-       dev_dbg(rvu->dev, "%s: Enabled promisc mode (cgx=%d lmac=%d cnt=%d)\n",
-               __func__, cgx_id, lmac_id, cnt);
        return 0;
 }
 
index 1d87937..2295204 100644 (file)
@@ -276,18 +276,6 @@ static inline bool mlx5_sriov_is_enabled(struct mlx5_core_dev *dev)
        return pci_num_vf(dev->pdev) ? true : false;
 }
 
-static inline int mlx5_lag_is_lacp_owner(struct mlx5_core_dev *dev)
-{
-       /* LACP owner conditions:
-        * 1) Function is physical.
-        * 2) LAG is supported by FW.
-        * 3) LAG is managed by driver (currently the only option).
-        */
-       return  MLX5_CAP_GEN(dev, vport_group_manager) &&
-                  (MLX5_CAP_GEN(dev, num_lag_ports) > 1) &&
-                   MLX5_CAP_GEN(dev, lag_master);
-}
-
 int mlx5_rescan_drivers_locked(struct mlx5_core_dev *dev);
 static inline int mlx5_rescan_drivers(struct mlx5_core_dev *dev)
 {
index 2edd6bf..7776d3b 100644 (file)
@@ -1903,7 +1903,7 @@ void qed_get_vport_stats(struct qed_dev *cdev, struct qed_eth_stats *stats)
 {
        u32 i;
 
-       if (!cdev) {
+       if (!cdev || cdev->recov_in_prog) {
                memset(stats, 0, sizeof(*stats));
                return;
        }
index f9931ec..4d83cee 100644 (file)
@@ -269,6 +269,10 @@ struct qede_dev {
 #define QEDE_ERR_WARN                  3
 
        struct qede_dump_info           dump_info;
+       struct delayed_work             periodic_task;
+       unsigned long                   stats_coal_ticks;
+       u32                             stats_coal_usecs;
+       spinlock_t                      stats_lock; /* lock for vport stats access */
 };
 
 enum QEDE_STATE {
index 374a86b..95820cf 100644 (file)
@@ -429,6 +429,8 @@ static void qede_get_ethtool_stats(struct net_device *dev,
                }
        }
 
+       spin_lock(&edev->stats_lock);
+
        for (i = 0; i < QEDE_NUM_STATS; i++) {
                if (qede_is_irrelevant_stat(edev, i))
                        continue;
@@ -438,6 +440,8 @@ static void qede_get_ethtool_stats(struct net_device *dev,
                buf++;
        }
 
+       spin_unlock(&edev->stats_lock);
+
        __qede_unlock(edev);
 }
 
@@ -829,6 +833,7 @@ out:
 
        coal->rx_coalesce_usecs = rx_coal;
        coal->tx_coalesce_usecs = tx_coal;
+       coal->stats_block_coalesce_usecs = edev->stats_coal_usecs;
 
        return rc;
 }
@@ -842,6 +847,19 @@ int qede_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal,
        int i, rc = 0;
        u16 rxc, txc;
 
+       if (edev->stats_coal_usecs != coal->stats_block_coalesce_usecs) {
+               edev->stats_coal_usecs = coal->stats_block_coalesce_usecs;
+               if (edev->stats_coal_usecs) {
+                       edev->stats_coal_ticks = usecs_to_jiffies(edev->stats_coal_usecs);
+                       schedule_delayed_work(&edev->periodic_task, 0);
+
+                       DP_INFO(edev, "Configured stats coal ticks=%lu jiffies\n",
+                               edev->stats_coal_ticks);
+               } else {
+                       cancel_delayed_work_sync(&edev->periodic_task);
+               }
+       }
+
        if (!netif_running(dev)) {
                DP_INFO(edev, "Interface is down\n");
                return -EINVAL;
@@ -2252,7 +2270,8 @@ out:
 }
 
 static const struct ethtool_ops qede_ethtool_ops = {
-       .supported_coalesce_params      = ETHTOOL_COALESCE_USECS,
+       .supported_coalesce_params      = ETHTOOL_COALESCE_USECS |
+                                         ETHTOOL_COALESCE_STATS_BLOCK_USECS,
        .get_link_ksettings             = qede_get_link_ksettings,
        .set_link_ksettings             = qede_set_link_ksettings,
        .get_drvinfo                    = qede_get_drvinfo,
@@ -2303,7 +2322,8 @@ static const struct ethtool_ops qede_ethtool_ops = {
 };
 
 static const struct ethtool_ops qede_vf_ethtool_ops = {
-       .supported_coalesce_params      = ETHTOOL_COALESCE_USECS,
+       .supported_coalesce_params      = ETHTOOL_COALESCE_USECS |
+                                         ETHTOOL_COALESCE_STATS_BLOCK_USECS,
        .get_link_ksettings             = qede_get_link_ksettings,
        .get_drvinfo                    = qede_get_drvinfo,
        .get_msglevel                   = qede_get_msglevel,
index 4c6c685..4b004a7 100644 (file)
@@ -307,6 +307,8 @@ void qede_fill_by_demand_stats(struct qede_dev *edev)
 
        edev->ops->get_vport_stats(edev->cdev, &stats);
 
+       spin_lock(&edev->stats_lock);
+
        p_common->no_buff_discards = stats.common.no_buff_discards;
        p_common->packet_too_big_discard = stats.common.packet_too_big_discard;
        p_common->ttl0_discard = stats.common.ttl0_discard;
@@ -404,6 +406,8 @@ void qede_fill_by_demand_stats(struct qede_dev *edev)
                p_ah->tx_1519_to_max_byte_packets =
                    stats.ah.tx_1519_to_max_byte_packets;
        }
+
+       spin_unlock(&edev->stats_lock);
 }
 
 static void qede_get_stats64(struct net_device *dev,
@@ -412,9 +416,10 @@ static void qede_get_stats64(struct net_device *dev,
        struct qede_dev *edev = netdev_priv(dev);
        struct qede_stats_common *p_common;
 
-       qede_fill_by_demand_stats(edev);
        p_common = &edev->stats.common;
 
+       spin_lock(&edev->stats_lock);
+
        stats->rx_packets = p_common->rx_ucast_pkts + p_common->rx_mcast_pkts +
                            p_common->rx_bcast_pkts;
        stats->tx_packets = p_common->tx_ucast_pkts + p_common->tx_mcast_pkts +
@@ -434,6 +439,8 @@ static void qede_get_stats64(struct net_device *dev,
                stats->collisions = edev->stats.bb.tx_total_collisions;
        stats->rx_crc_errors = p_common->rx_crc_errors;
        stats->rx_frame_errors = p_common->rx_align_errors;
+
+       spin_unlock(&edev->stats_lock);
 }
 
 #ifdef CONFIG_QED_SRIOV
@@ -1063,6 +1070,23 @@ static void qede_unlock(struct qede_dev *edev)
        rtnl_unlock();
 }
 
+static void qede_periodic_task(struct work_struct *work)
+{
+       struct qede_dev *edev = container_of(work, struct qede_dev,
+                                            periodic_task.work);
+
+       qede_fill_by_demand_stats(edev);
+       schedule_delayed_work(&edev->periodic_task, edev->stats_coal_ticks);
+}
+
+static void qede_init_periodic_task(struct qede_dev *edev)
+{
+       INIT_DELAYED_WORK(&edev->periodic_task, qede_periodic_task);
+       spin_lock_init(&edev->stats_lock);
+       edev->stats_coal_usecs = USEC_PER_SEC;
+       edev->stats_coal_ticks = usecs_to_jiffies(USEC_PER_SEC);
+}
+
 static void qede_sp_task(struct work_struct *work)
 {
        struct qede_dev *edev = container_of(work, struct qede_dev,
@@ -1082,6 +1106,7 @@ static void qede_sp_task(struct work_struct *work)
         */
 
        if (test_and_clear_bit(QEDE_SP_RECOVERY, &edev->sp_flags)) {
+               cancel_delayed_work_sync(&edev->periodic_task);
 #ifdef CONFIG_QED_SRIOV
                /* SRIOV must be disabled outside the lock to avoid a deadlock.
                 * The recovery of the active VFs is currently not supported.
@@ -1272,6 +1297,7 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
                 */
                INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task);
                mutex_init(&edev->qede_lock);
+               qede_init_periodic_task(edev);
 
                rc = register_netdev(edev->ndev);
                if (rc) {
@@ -1296,6 +1322,11 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
        edev->rx_copybreak = QEDE_RX_HDR_SIZE;
 
        qede_log_probe(edev);
+
+       /* retain user config (for example - after recovery) */
+       if (edev->stats_coal_usecs)
+               schedule_delayed_work(&edev->periodic_task, 0);
+
        return 0;
 
 err4:
@@ -1364,6 +1395,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
                unregister_netdev(ndev);
 
                cancel_delayed_work_sync(&edev->sp_task);
+               cancel_delayed_work_sync(&edev->periodic_task);
 
                edev->ops->common->set_power_state(cdev, PCI_D0);
 
index aace871..fa6d620 100644 (file)
@@ -347,17 +347,6 @@ out:
        return -ENOMEM;
 }
 
-static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
-{
-       struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
-
-       gq->ring_size = TS_RING_SIZE;
-       gq->ts_ring = dma_alloc_coherent(&priv->pdev->dev,
-                                        sizeof(struct rswitch_ts_desc) *
-                                        (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
-       return !gq->ts_ring ? -ENOMEM : 0;
-}
-
 static void rswitch_desc_set_dptr(struct rswitch_desc *desc, dma_addr_t addr)
 {
        desc->dptrl = cpu_to_le32(lower_32_bits(addr));
@@ -533,6 +522,28 @@ static void rswitch_gwca_linkfix_free(struct rswitch_private *priv)
        gwca->linkfix_table = NULL;
 }
 
+static int rswitch_gwca_ts_queue_alloc(struct rswitch_private *priv)
+{
+       struct rswitch_gwca_queue *gq = &priv->gwca.ts_queue;
+       struct rswitch_ts_desc *desc;
+
+       gq->ring_size = TS_RING_SIZE;
+       gq->ts_ring = dma_alloc_coherent(&priv->pdev->dev,
+                                        sizeof(struct rswitch_ts_desc) *
+                                        (gq->ring_size + 1), &gq->ring_dma, GFP_KERNEL);
+
+       if (!gq->ts_ring)
+               return -ENOMEM;
+
+       rswitch_gwca_ts_queue_fill(priv, 0, TS_RING_SIZE);
+       desc = &gq->ts_ring[gq->ring_size];
+       desc->desc.die_dt = DT_LINKFIX;
+       rswitch_desc_set_dptr(&desc->desc, gq->ring_dma);
+       INIT_LIST_HEAD(&priv->gwca.ts_info_list);
+
+       return 0;
+}
+
 static struct rswitch_gwca_queue *rswitch_gwca_get(struct rswitch_private *priv)
 {
        struct rswitch_gwca_queue *gq;
@@ -1780,9 +1791,6 @@ static int rswitch_init(struct rswitch_private *priv)
        if (err < 0)
                goto err_ts_queue_alloc;
 
-       rswitch_gwca_ts_queue_fill(priv, 0, TS_RING_SIZE);
-       INIT_LIST_HEAD(&priv->gwca.ts_info_list);
-
        for (i = 0; i < RSWITCH_NUM_PORTS; i++) {
                err = rswitch_device_alloc(priv, i);
                if (err < 0) {
index fcea3ea..41b33a7 100644 (file)
@@ -301,6 +301,7 @@ int efx_probe_interrupts(struct efx_nic *efx)
                efx->tx_channel_offset = 0;
                efx->n_xdp_channels = 0;
                efx->xdp_channel_offset = efx->n_channels;
+               efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
                rc = pci_enable_msi(efx->pci_dev);
                if (rc == 0) {
                        efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
@@ -322,6 +323,7 @@ int efx_probe_interrupts(struct efx_nic *efx)
                efx->tx_channel_offset = efx_separate_tx_channels ? 1 : 0;
                efx->n_xdp_channels = 0;
                efx->xdp_channel_offset = efx->n_channels;
+               efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
                efx->legacy_irq = efx->pci_dev->irq;
        }
 
index 06ed749..1776f7f 100644 (file)
@@ -302,6 +302,7 @@ int efx_siena_probe_interrupts(struct efx_nic *efx)
                efx->tx_channel_offset = 0;
                efx->n_xdp_channels = 0;
                efx->xdp_channel_offset = efx->n_channels;
+               efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
                rc = pci_enable_msi(efx->pci_dev);
                if (rc == 0) {
                        efx_get_channel(efx, 0)->irq = efx->pci_dev->irq;
@@ -323,6 +324,7 @@ int efx_siena_probe_interrupts(struct efx_nic *efx)
                efx->tx_channel_offset = efx_siena_separate_tx_channels ? 1 : 0;
                efx->n_xdp_channels = 0;
                efx->xdp_channel_offset = efx->n_channels;
+               efx->xdp_txq_queues_mode = EFX_XDP_TX_QUEUES_BORROWED;
                efx->legacy_irq = efx->pci_dev->irq;
        }
 
index 16a8c36..f07905f 100644 (file)
@@ -644,7 +644,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
        plat_dat->fix_mac_speed = ethqos_fix_mac_speed;
        plat_dat->dump_debug_regs = rgmii_dump;
        plat_dat->has_gmac4 = 1;
-       plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
+       if (ethqos->has_emac3)
+               plat_dat->dwmac4_addrs = &data->dwmac4_addrs;
        plat_dat->pmt = 1;
        plat_dat->tso_en = of_property_read_bool(np, "snps,tso");
        if (of_device_is_compatible(np, "qcom,qcs404-ethqos"))
index 52cab9d..8751095 100644 (file)
@@ -3873,7 +3873,6 @@ irq_error:
 
        stmmac_hw_teardown(dev);
 init_error:
-       free_dma_desc_resources(priv, &priv->dma_conf);
        phylink_disconnect_phy(priv->phylink);
 init_phy_error:
        pm_runtime_put(priv->device);
@@ -3891,6 +3890,9 @@ static int stmmac_open(struct net_device *dev)
                return PTR_ERR(dma_conf);
 
        ret = __stmmac_open(dev, dma_conf);
+       if (ret)
+               free_dma_desc_resources(priv, dma_conf);
+
        kfree(dma_conf);
        return ret;
 }
@@ -5633,12 +5635,15 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
                stmmac_release(dev);
 
                ret = __stmmac_open(dev, dma_conf);
-               kfree(dma_conf);
                if (ret) {
+                       free_dma_desc_resources(priv, dma_conf);
+                       kfree(dma_conf);
                        netdev_err(priv->dev, "failed reopening the interface after MTU change\n");
                        return ret;
                }
 
+               kfree(dma_conf);
+
                stmmac_set_rx_mode(dev);
        }
 
index 11cbcd9..bebcfd5 100644 (file)
@@ -2068,7 +2068,7 @@ static int am65_cpsw_nuss_init_slave_ports(struct am65_cpsw_common *common)
                /* Initialize the Serdes PHY for the port */
                ret = am65_cpsw_init_serdes_phy(dev, port_np, port);
                if (ret)
-                       return ret;
+                       goto of_node_put;
 
                port->slave.mac_only =
                                of_property_read_bool(port_np, "ti,mac-only");
index 71712ea..d5b05e8 100644 (file)
@@ -102,6 +102,10 @@ static unsigned int ipvlan_nf_input(void *priv, struct sk_buff *skb,
 
        skb->dev = addr->master->dev;
        skb->skb_iif = skb->dev->ifindex;
+#if IS_ENABLED(CONFIG_IPV6)
+       if (addr->atype == IPVL_IPV6)
+               IP6CB(skb)->iif = skb->dev->ifindex;
+#endif
        len = skb->len + ETH_HLEN;
        ipvlan_count_rx(addr->master, len, true, false);
 out:
index 3427993..984dfa5 100644 (file)
@@ -3997,17 +3997,15 @@ static int macsec_add_dev(struct net_device *dev, sci_t sci, u8 icv_len)
                return -ENOMEM;
 
        secy->tx_sc.stats = netdev_alloc_pcpu_stats(struct pcpu_tx_sc_stats);
-       if (!secy->tx_sc.stats) {
-               free_percpu(macsec->stats);
+       if (!secy->tx_sc.stats)
                return -ENOMEM;
-       }
 
        secy->tx_sc.md_dst = metadata_dst_alloc(0, METADATA_MACSEC, GFP_KERNEL);
-       if (!secy->tx_sc.md_dst) {
-               free_percpu(secy->tx_sc.stats);
-               free_percpu(macsec->stats);
+       if (!secy->tx_sc.md_dst)
+               /* macsec and secy percpu stats will be freed when unregistering
+                * net_device in macsec_free_netdev()
+                */
                return -ENOMEM;
-       }
 
        if (sci == MACSEC_UNDEF_SCI)
                sci = dev_to_sci(dev, MACSEC_PORT_ES);
index e237949..5efdeb5 100644 (file)
@@ -188,6 +188,7 @@ static int phylink_interface_max_speed(phy_interface_t interface)
        case PHY_INTERFACE_MODE_RGMII_ID:
        case PHY_INTERFACE_MODE_RGMII:
        case PHY_INTERFACE_MODE_QSGMII:
+       case PHY_INTERFACE_MODE_QUSGMII:
        case PHY_INTERFACE_MODE_SGMII:
        case PHY_INTERFACE_MODE_GMII:
                return SPEED_1000;
@@ -204,7 +205,6 @@ static int phylink_interface_max_speed(phy_interface_t interface)
        case PHY_INTERFACE_MODE_10GBASER:
        case PHY_INTERFACE_MODE_10GKR:
        case PHY_INTERFACE_MODE_USXGMII:
-       case PHY_INTERFACE_MODE_QUSGMII:
                return SPEED_10000;
 
        case PHY_INTERFACE_MODE_25GBASER:
@@ -2225,11 +2225,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
 
        ASSERT_RTNL();
 
-       /* Mask out unsupported advertisements */
-       linkmode_and(config.advertising, kset->link_modes.advertising,
-                    pl->supported);
-
        if (pl->phydev) {
+               struct ethtool_link_ksettings phy_kset = *kset;
+
+               linkmode_and(phy_kset.link_modes.advertising,
+                            phy_kset.link_modes.advertising,
+                            pl->supported);
+
                /* We can rely on phylib for this update; we also do not need
                 * to update the pl->link_config settings:
                 * - the configuration returned via ksettings_get() will come
@@ -2248,10 +2250,13 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
                 *   the presence of a PHY, this should not be changed as that
                 *   should be determined from the media side advertisement.
                 */
-               return phy_ethtool_ksettings_set(pl->phydev, kset);
+               return phy_ethtool_ksettings_set(pl->phydev, &phy_kset);
        }
 
        config = pl->link_config;
+       /* Mask out unsupported advertisements */
+       linkmode_and(config.advertising, kset->link_modes.advertising,
+                    pl->supported);
 
        /* FIXME: should we reject autoneg if phy/mac does not support it? */
        switch (kset->base.autoneg) {
@@ -3294,6 +3299,41 @@ void phylink_decode_usxgmii_word(struct phylink_link_state *state,
 EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word);
 
 /**
+ * phylink_decode_usgmii_word() - decode the USGMII word from a MAC PCS
+ * @state: a pointer to a struct phylink_link_state.
+ * @lpa: a 16 bit value which stores the USGMII auto-negotiation word
+ *
+ * Helper for MAC PCS supporting the USGMII protocol and the auto-negotiation
+ * code word.  Decode the USGMII code word and populate the corresponding fields
+ * (speed, duplex) into the phylink_link_state structure. The structure for this
+ * word is the same as the USXGMII word, except it only supports speeds up to
+ * 1Gbps.
+ */
+static void phylink_decode_usgmii_word(struct phylink_link_state *state,
+                                      uint16_t lpa)
+{
+       switch (lpa & MDIO_USXGMII_SPD_MASK) {
+       case MDIO_USXGMII_10:
+               state->speed = SPEED_10;
+               break;
+       case MDIO_USXGMII_100:
+               state->speed = SPEED_100;
+               break;
+       case MDIO_USXGMII_1000:
+               state->speed = SPEED_1000;
+               break;
+       default:
+               state->link = false;
+               return;
+       }
+
+       if (lpa & MDIO_USXGMII_FULL_DUPLEX)
+               state->duplex = DUPLEX_FULL;
+       else
+               state->duplex = DUPLEX_HALF;
+}
+
+/**
  * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers
  * @state: a pointer to a &struct phylink_link_state.
  * @bmsr: The value of the %MII_BMSR register
@@ -3330,9 +3370,11 @@ void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
 
        case PHY_INTERFACE_MODE_SGMII:
        case PHY_INTERFACE_MODE_QSGMII:
-       case PHY_INTERFACE_MODE_QUSGMII:
                phylink_decode_sgmii_word(state, lpa);
                break;
+       case PHY_INTERFACE_MODE_QUSGMII:
+               phylink_decode_usgmii_word(state, lpa);
+               break;
 
        default:
                state->link = false;
index f1865d0..2e7c7b0 100644 (file)
@@ -1220,7 +1220,9 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
        {QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
        {QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
+       {QMI_QUIRK_SET_DTR(0x05c6, 0x9091, 2)}, /* Compal RXM-G1 */
        {QMI_FIXED_INTF(0x05c6, 0x90b2, 3)},    /* ublox R410M */
+       {QMI_QUIRK_SET_DTR(0x05c6, 0x90db, 2)}, /* Compal RXM-G1 */
        {QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
        {QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
        {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */
index 56ca1d2..486b584 100644 (file)
@@ -205,6 +205,8 @@ struct control_buf {
        __virtio16 vid;
        __virtio64 offloads;
        struct virtio_net_ctrl_rss rss;
+       struct virtio_net_ctrl_coal_tx coal_tx;
+       struct virtio_net_ctrl_coal_rx coal_rx;
 };
 
 struct virtnet_info {
@@ -2934,12 +2936,10 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
                                       struct ethtool_coalesce *ec)
 {
        struct scatterlist sgs_tx, sgs_rx;
-       struct virtio_net_ctrl_coal_tx coal_tx;
-       struct virtio_net_ctrl_coal_rx coal_rx;
 
-       coal_tx.tx_usecs = cpu_to_le32(ec->tx_coalesce_usecs);
-       coal_tx.tx_max_packets = cpu_to_le32(ec->tx_max_coalesced_frames);
-       sg_init_one(&sgs_tx, &coal_tx, sizeof(coal_tx));
+       vi->ctrl->coal_tx.tx_usecs = cpu_to_le32(ec->tx_coalesce_usecs);
+       vi->ctrl->coal_tx.tx_max_packets = cpu_to_le32(ec->tx_max_coalesced_frames);
+       sg_init_one(&sgs_tx, &vi->ctrl->coal_tx, sizeof(vi->ctrl->coal_tx));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
                                  VIRTIO_NET_CTRL_NOTF_COAL_TX_SET,
@@ -2950,9 +2950,9 @@ static int virtnet_send_notf_coal_cmds(struct virtnet_info *vi,
        vi->tx_usecs = ec->tx_coalesce_usecs;
        vi->tx_max_packets = ec->tx_max_coalesced_frames;
 
-       coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
-       coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
-       sg_init_one(&sgs_rx, &coal_rx, sizeof(coal_rx));
+       vi->ctrl->coal_rx.rx_usecs = cpu_to_le32(ec->rx_coalesce_usecs);
+       vi->ctrl->coal_rx.rx_max_packets = cpu_to_le32(ec->rx_max_coalesced_frames);
+       sg_init_one(&sgs_rx, &vi->ctrl->coal_rx, sizeof(vi->ctrl->coal_rx));
 
        if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_NOTF_COAL,
                                  VIRTIO_NET_CTRL_NOTF_COAL_RX_SET,
index d62a904..56326f3 100644 (file)
@@ -384,6 +384,9 @@ static int lapbeth_new_device(struct net_device *dev)
 
        ASSERT_RTNL();
 
+       if (dev->type != ARPHRD_ETHER)
+               return -EINVAL;
+
        ndev = alloc_netdev(sizeof(*lapbeth), "lapb%d", NET_NAME_UNKNOWN,
                            lapbeth_setup);
        if (!ndev)
index 37aa467..6d1007f 100644 (file)
@@ -2732,17 +2732,13 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait,
                if (wowlan_info_ver < 2) {
                        struct iwl_wowlan_info_notif_v1 *notif_v1 = (void *)pkt->data;
 
-                       notif = kmemdup(notif_v1,
-                                       offsetofend(struct iwl_wowlan_info_notif,
-                                                   received_beacons),
-                                       GFP_ATOMIC);
-
+                       notif = kmemdup(notif_v1, sizeof(*notif), GFP_ATOMIC);
                        if (!notif)
                                return false;
 
                        notif->tid_tear_down = notif_v1->tid_tear_down;
                        notif->station_id = notif_v1->station_id;
-
+                       memset_after(notif, 0, station_id);
                } else {
                        notif = (void *)pkt->data;
                }
index 23266d0..9a20468 100644 (file)
@@ -2692,7 +2692,7 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
 
        lq_sta = mvm_sta;
 
-       spin_lock(&lq_sta->pers.lock);
+       spin_lock_bh(&lq_sta->pers.lock);
        iwl_mvm_hwrate_to_tx_rate_v1(lq_sta->last_rate_n_flags,
                                     info->band, &info->control.rates[0]);
        info->control.rates[0].count = 1;
@@ -2707,7 +2707,7 @@ static void rs_drv_get_rate(void *mvm_r, struct ieee80211_sta *sta,
                iwl_mvm_hwrate_to_tx_rate_v1(last_ucode_rate, info->band,
                                             &txrc->reported_rate);
        }
-       spin_unlock(&lq_sta->pers.lock);
+       spin_unlock_bh(&lq_sta->pers.lock);
 }
 
 static void *rs_drv_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
@@ -3264,11 +3264,11 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        /* If it's locked we are in middle of init flow
         * just wait for next tx status to update the lq_sta data
         */
-       if (!spin_trylock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock))
+       if (!spin_trylock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock))
                return;
 
        __iwl_mvm_rs_tx_status(mvm, sta, tid, info, ndp);
-       spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
+       spin_unlock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
 }
 
 #ifdef CONFIG_MAC80211_DEBUGFS
@@ -4117,9 +4117,9 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm,
        } else {
                struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
 
-               spin_lock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
+               spin_lock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
                rs_drv_rate_init(mvm, sta, band);
-               spin_unlock(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
+               spin_unlock_bh(&mvmsta->deflink.lq_sta.rs_drv.pers.lock);
        }
 }
 
index da1d17b..6400248 100644 (file)
@@ -914,7 +914,10 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
 
                msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
                                        poll_list);
+
+               spin_lock_bh(&dev->sta_poll_lock);
                list_del_init(&msta->poll_list);
+               spin_unlock_bh(&dev->sta_poll_lock);
 
                addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
 
index 39a4a73..9b0f605 100644 (file)
@@ -1004,10 +1004,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_vif *vif = info->control.vif;
-       struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
        u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
        u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
        bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+       struct mt7996_vif *mvif;
        u16 tx_count = 15;
        u32 val;
        bool beacon = !!(changed & (BSS_CHANGED_BEACON |
@@ -1015,7 +1015,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
        bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
                                         BSS_CHANGED_FILS_DISCOVERY));
 
-       if (vif) {
+       mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
+       if (mvif) {
                omac_idx = mvif->mt76.omac_idx;
                wmm_idx = mvif->mt76.wmm_idx;
                band_idx = mvif->mt76.band_idx;
@@ -1081,12 +1082,16 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
                struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
                bool mcast = ieee80211_is_data(hdr->frame_control) &&
                             is_multicast_ether_addr(hdr->addr1);
-               u8 idx = mvif->basic_rates_idx;
+               u8 idx = MT7996_BASIC_RATES_TBL;
 
-               if (mcast && mvif->mcast_rates_idx)
-                       idx = mvif->mcast_rates_idx;
-               else if (beacon && mvif->beacon_rates_idx)
-                       idx = mvif->beacon_rates_idx;
+               if (mvif) {
+                       if (mcast && mvif->mcast_rates_idx)
+                               idx = mvif->mcast_rates_idx;
+                       else if (beacon && mvif->beacon_rates_idx)
+                               idx = mvif->beacon_rates_idx;
+                       else
+                               idx = mvif->basic_rates_idx;
+               }
 
                txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
                txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
index a6c024c..144618b 100644 (file)
@@ -88,15 +88,6 @@ static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_PS) {
-               if (hw->conf.flags & IEEE80211_CONF_PS) {
-                       rtwdev->ps_enabled = true;
-               } else {
-                       rtwdev->ps_enabled = false;
-                       rtw_leave_lps(rtwdev);
-               }
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
                rtw_set_channel(rtwdev);
 
@@ -213,6 +204,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
        config |= PORT_SET_BCN_CTRL;
        rtw_vif_port_config(rtwdev, rtwvif, config);
        rtw_core_port_switch(rtwdev, vif);
+       rtw_recalc_lps(rtwdev, vif);
 
        mutex_unlock(&rtwdev->mutex);
 
@@ -244,6 +236,7 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
        config |= PORT_SET_BCN_CTRL;
        rtw_vif_port_config(rtwdev, rtwvif, config);
        clear_bit(rtwvif->port, rtwdev->hw_port);
+       rtw_recalc_lps(rtwdev, NULL);
 
        mutex_unlock(&rtwdev->mutex);
 }
@@ -438,6 +431,9 @@ static void rtw_ops_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_ERP_SLOT)
                rtw_conf_tx(rtwdev, rtwvif);
 
+       if (changed & BSS_CHANGED_PS)
+               rtw_recalc_lps(rtwdev, NULL);
+
        rtw_vif_port_config(rtwdev, rtwvif, config);
 
        mutex_unlock(&rtwdev->mutex);
index d30a191..9447a3a 100644 (file)
@@ -271,8 +271,8 @@ static void rtw_watch_dog_work(struct work_struct *work)
         * more than two stations associated to the AP, then we can not enter
         * lps, because fw does not handle the overlapped beacon interval
         *
-        * mac80211 should iterate vifs and determine if driver can enter
-        * ps by passing IEEE80211_CONF_PS to us, all we need to do is to
+        * rtw_recalc_lps() iterate vifs and determine if driver can enter
+        * ps by vif->type and vif->cfg.ps, all we need to do here is to
         * get that vif and check if device is having traffic more than the
         * threshold.
         */
index 9963655..53933fb 100644 (file)
@@ -299,3 +299,46 @@ void rtw_leave_lps_deep(struct rtw_dev *rtwdev)
 
        __rtw_leave_lps_deep(rtwdev);
 }
+
+struct rtw_vif_recalc_lps_iter_data {
+       struct rtw_dev *rtwdev;
+       struct ieee80211_vif *found_vif;
+       int count;
+};
+
+static void __rtw_vif_recalc_lps(struct rtw_vif_recalc_lps_iter_data *data,
+                                struct ieee80211_vif *vif)
+{
+       if (data->count < 0)
+               return;
+
+       if (vif->type != NL80211_IFTYPE_STATION) {
+               data->count = -1;
+               return;
+       }
+
+       data->count++;
+       data->found_vif = vif;
+}
+
+static void rtw_vif_recalc_lps_iter(void *data, u8 *mac,
+                                   struct ieee80211_vif *vif)
+{
+       __rtw_vif_recalc_lps(data, vif);
+}
+
+void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif)
+{
+       struct rtw_vif_recalc_lps_iter_data data = { .rtwdev = rtwdev };
+
+       if (new_vif)
+               __rtw_vif_recalc_lps(&data, new_vif);
+       rtw_iterate_vifs(rtwdev, rtw_vif_recalc_lps_iter, &data);
+
+       if (data.count == 1 && data.found_vif->cfg.ps) {
+               rtwdev->ps_enabled = true;
+       } else {
+               rtwdev->ps_enabled = false;
+               rtw_leave_lps(rtwdev);
+       }
+}
index c194386..5ae83d2 100644 (file)
@@ -23,4 +23,6 @@ void rtw_enter_lps(struct rtw_dev *rtwdev, u8 port_id);
 void rtw_leave_lps(struct rtw_dev *rtwdev);
 void rtw_leave_lps_deep(struct rtw_dev *rtwdev);
 enum rtw_lps_deep_mode rtw_get_lps_deep_mode(struct rtw_dev *rtwdev);
+void rtw_recalc_lps(struct rtw_dev *rtwdev, struct ieee80211_vif *new_vif);
+
 #endif
index 7fc0a26..bad864d 100644 (file)
@@ -2531,9 +2531,6 @@ static void rtw89_vif_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwv
            rtwvif->tdls_peer)
                return;
 
-       if (rtwdev->total_sta_assoc > 1)
-               return;
-
        if (rtwvif->offchan)
                return;
 
index ee4588b..c42e310 100644 (file)
@@ -89,15 +89,6 @@ static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed)
            !(hw->conf.flags & IEEE80211_CONF_IDLE))
                rtw89_leave_ips(rtwdev);
 
-       if (changed & IEEE80211_CONF_CHANGE_PS) {
-               if (hw->conf.flags & IEEE80211_CONF_PS) {
-                       rtwdev->lps_enabled = true;
-               } else {
-                       rtw89_leave_lps(rtwdev);
-                       rtwdev->lps_enabled = false;
-               }
-       }
-
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
                rtw89_config_entity_chandef(rtwdev, RTW89_SUB_ENTITY_0,
                                            &hw->conf.chandef);
@@ -168,6 +159,8 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
        rtw89_core_txq_init(rtwdev, vif->txq);
 
        rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START);
+
+       rtw89_recalc_lps(rtwdev);
 out:
        mutex_unlock(&rtwdev->mutex);
 
@@ -192,6 +185,7 @@ static void rtw89_ops_remove_interface(struct ieee80211_hw *hw,
        rtw89_mac_remove_vif(rtwdev, rtwvif);
        rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port);
        list_del_init(&rtwvif->list);
+       rtw89_recalc_lps(rtwdev);
        rtw89_enter_ips_by_hwflags(rtwdev);
 
        mutex_unlock(&rtwdev->mutex);
@@ -451,6 +445,9 @@ static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw,
        if (changed & BSS_CHANGED_CQM)
                rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, true);
 
+       if (changed & BSS_CHANGED_PS)
+               rtw89_recalc_lps(rtwdev);
+
        mutex_unlock(&rtwdev->mutex);
 }
 
index fa94335..84201ef 100644 (file)
@@ -252,3 +252,29 @@ void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif)
        rtw89_p2p_disable_all_noa(rtwdev, vif);
        rtw89_p2p_update_noa(rtwdev, vif);
 }
+
+void rtw89_recalc_lps(struct rtw89_dev *rtwdev)
+{
+       struct ieee80211_vif *vif, *found_vif = NULL;
+       struct rtw89_vif *rtwvif;
+       int count = 0;
+
+       rtw89_for_each_rtwvif(rtwdev, rtwvif) {
+               vif = rtwvif_to_vif(rtwvif);
+
+               if (vif->type != NL80211_IFTYPE_STATION) {
+                       count = 0;
+                       break;
+               }
+
+               count++;
+               found_vif = vif;
+       }
+
+       if (count == 1 && found_vif->cfg.ps) {
+               rtwdev->lps_enabled = true;
+       } else {
+               rtw89_leave_lps(rtwdev);
+               rtwdev->lps_enabled = false;
+       }
+}
index 73c008d..4c18f49 100644 (file)
@@ -15,6 +15,7 @@ void rtw89_enter_ips(struct rtw89_dev *rtwdev);
 void rtw89_leave_ips(struct rtw89_dev *rtwdev);
 void rtw89_set_coex_ctrl_lps(struct rtw89_dev *rtwdev, bool btc_ctrl);
 void rtw89_process_p2p_ps(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif);
+void rtw89_recalc_lps(struct rtw89_dev *rtwdev);
 
 static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev)
 {
index 2e01960..7feb643 100644 (file)
@@ -811,6 +811,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs)
                if (!fragment->target) {
                        pr_err("symbols in overlay, but not in live tree\n");
                        ret = -EINVAL;
+                       of_node_put(node);
                        goto err_out;
                }
 
index bc32662..2d93d0c 100644 (file)
@@ -489,7 +489,10 @@ struct hv_pcibus_device {
        struct fwnode_handle *fwnode;
        /* Protocol version negotiated with the host */
        enum pci_protocol_version_t protocol_version;
+
+       struct mutex state_lock;
        enum hv_pcibus_state state;
+
        struct hv_device *hdev;
        resource_size_t low_mmio_space;
        resource_size_t high_mmio_space;
@@ -545,19 +548,10 @@ struct hv_dr_state {
        struct hv_pcidev_description func[];
 };
 
-enum hv_pcichild_state {
-       hv_pcichild_init = 0,
-       hv_pcichild_requirements,
-       hv_pcichild_resourced,
-       hv_pcichild_ejecting,
-       hv_pcichild_maximum
-};
-
 struct hv_pci_dev {
        /* List protected by pci_rescan_remove_lock */
        struct list_head list_entry;
        refcount_t refs;
-       enum hv_pcichild_state state;
        struct pci_slot *pci_slot;
        struct hv_pcidev_description desc;
        bool reported_missing;
@@ -635,6 +629,11 @@ static void hv_arch_irq_unmask(struct irq_data *data)
        pbus = pdev->bus;
        hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
        int_desc = data->chip_data;
+       if (!int_desc) {
+               dev_warn(&hbus->hdev->device, "%s() can not unmask irq %u\n",
+                        __func__, data->irq);
+               return;
+       }
 
        local_irq_save(flags);
 
@@ -2004,12 +2003,6 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
                hv_pci_onchannelcallback(hbus);
                spin_unlock_irqrestore(&channel->sched_lock, flags);
 
-               if (hpdev->state == hv_pcichild_ejecting) {
-                       dev_err_once(&hbus->hdev->device,
-                                    "the device is being ejected\n");
-                       goto enable_tasklet;
-               }
-
                udelay(100);
        }
 
@@ -2615,6 +2608,8 @@ static void pci_devices_present_work(struct work_struct *work)
        if (!dr)
                return;
 
+       mutex_lock(&hbus->state_lock);
+
        /* First, mark all existing children as reported missing. */
        spin_lock_irqsave(&hbus->device_list_lock, flags);
        list_for_each_entry(hpdev, &hbus->children, list_entry) {
@@ -2696,6 +2691,8 @@ static void pci_devices_present_work(struct work_struct *work)
                break;
        }
 
+       mutex_unlock(&hbus->state_lock);
+
        kfree(dr);
 }
 
@@ -2844,7 +2841,7 @@ static void hv_eject_device_work(struct work_struct *work)
        hpdev = container_of(work, struct hv_pci_dev, wrk);
        hbus = hpdev->hbus;
 
-       WARN_ON(hpdev->state != hv_pcichild_ejecting);
+       mutex_lock(&hbus->state_lock);
 
        /*
         * Ejection can come before or after the PCI bus has been set up, so
@@ -2882,6 +2879,8 @@ static void hv_eject_device_work(struct work_struct *work)
        put_pcichild(hpdev);
        put_pcichild(hpdev);
        /* hpdev has been freed. Do not use it any more. */
+
+       mutex_unlock(&hbus->state_lock);
 }
 
 /**
@@ -2902,7 +2901,6 @@ static void hv_pci_eject_device(struct hv_pci_dev *hpdev)
                return;
        }
 
-       hpdev->state = hv_pcichild_ejecting;
        get_pcichild(hpdev);
        INIT_WORK(&hpdev->wrk, hv_eject_device_work);
        queue_work(hbus->wq, &hpdev->wrk);
@@ -3331,8 +3329,10 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
        struct pci_bus_d0_entry *d0_entry;
        struct hv_pci_compl comp_pkt;
        struct pci_packet *pkt;
+       bool retry = true;
        int ret;
 
+enter_d0_retry:
        /*
         * Tell the host that the bus is ready to use, and moved into the
         * powered-on state.  This includes telling the host which region
@@ -3359,6 +3359,38 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
        if (ret)
                goto exit;
 
+       /*
+        * In certain case (Kdump) the pci device of interest was
+        * not cleanly shut down and resource is still held on host
+        * side, the host could return invalid device status.
+        * We need to explicitly request host to release the resource
+        * and try to enter D0 again.
+        */
+       if (comp_pkt.completion_status < 0 && retry) {
+               retry = false;
+
+               dev_err(&hdev->device, "Retrying D0 Entry\n");
+
+               /*
+                * Hv_pci_bus_exit() calls hv_send_resource_released()
+                * to free up resources of its child devices.
+                * In the kdump kernel we need to set the
+                * wslot_res_allocated to 255 so it scans all child
+                * devices to release resources allocated in the
+                * normal kernel before panic happened.
+                */
+               hbus->wslot_res_allocated = 255;
+
+               ret = hv_pci_bus_exit(hdev, true);
+
+               if (ret == 0) {
+                       kfree(pkt);
+                       goto enter_d0_retry;
+               }
+               dev_err(&hdev->device,
+                       "Retrying D0 failed with ret %d\n", ret);
+       }
+
        if (comp_pkt.completion_status < 0) {
                dev_err(&hdev->device,
                        "PCI Pass-through VSP failed D0 Entry with status %x\n",
@@ -3401,6 +3433,24 @@ static int hv_pci_query_relations(struct hv_device *hdev)
        if (!ret)
                ret = wait_for_response(hdev, &comp);
 
+       /*
+        * In the case of fast device addition/removal, it's possible that
+        * vmbus_sendpacket() or wait_for_response() returns -ENODEV but we
+        * already got a PCI_BUS_RELATIONS* message from the host and the
+        * channel callback already scheduled a work to hbus->wq, which can be
+        * running pci_devices_present_work() -> survey_child_resources() ->
+        * complete(&hbus->survey_event), even after hv_pci_query_relations()
+        * exits and the stack variable 'comp' is no longer valid; as a result,
+        * a hang or a page fault may happen when the complete() calls
+        * raw_spin_lock_irqsave(). Flush hbus->wq before we exit from
+        * hv_pci_query_relations() to avoid the issues. Note: if 'ret' is
+        * -ENODEV, there can't be any more work item scheduled to hbus->wq
+        * after the flush_workqueue(): see vmbus_onoffer_rescind() ->
+        * vmbus_reset_channel_cb(), vmbus_rescind_cleanup() ->
+        * channel->rescind = true.
+        */
+       flush_workqueue(hbus->wq);
+
        return ret;
 }
 
@@ -3586,7 +3636,6 @@ static int hv_pci_probe(struct hv_device *hdev,
        struct hv_pcibus_device *hbus;
        u16 dom_req, dom;
        char *name;
-       bool enter_d0_retry = true;
        int ret;
 
        bridge = devm_pci_alloc_host_bridge(&hdev->device, 0);
@@ -3598,6 +3647,7 @@ static int hv_pci_probe(struct hv_device *hdev,
                return -ENOMEM;
 
        hbus->bridge = bridge;
+       mutex_init(&hbus->state_lock);
        hbus->state = hv_pcibus_init;
        hbus->wslot_res_allocated = -1;
 
@@ -3703,49 +3753,15 @@ static int hv_pci_probe(struct hv_device *hdev,
        if (ret)
                goto free_fwnode;
 
-retry:
        ret = hv_pci_query_relations(hdev);
        if (ret)
                goto free_irq_domain;
 
-       ret = hv_pci_enter_d0(hdev);
-       /*
-        * In certain case (Kdump) the pci device of interest was
-        * not cleanly shut down and resource is still held on host
-        * side, the host could return invalid device status.
-        * We need to explicitly request host to release the resource
-        * and try to enter D0 again.
-        * Since the hv_pci_bus_exit() call releases structures
-        * of all its child devices, we need to start the retry from
-        * hv_pci_query_relations() call, requesting host to send
-        * the synchronous child device relations message before this
-        * information is needed in hv_send_resources_allocated()
-        * call later.
-        */
-       if (ret == -EPROTO && enter_d0_retry) {
-               enter_d0_retry = false;
-
-               dev_err(&hdev->device, "Retrying D0 Entry\n");
-
-               /*
-                * Hv_pci_bus_exit() calls hv_send_resources_released()
-                * to free up resources of its child devices.
-                * In the kdump kernel we need to set the
-                * wslot_res_allocated to 255 so it scans all child
-                * devices to release resources allocated in the
-                * normal kernel before panic happened.
-                */
-               hbus->wslot_res_allocated = 255;
-               ret = hv_pci_bus_exit(hdev, true);
-
-               if (ret == 0)
-                       goto retry;
+       mutex_lock(&hbus->state_lock);
 
-               dev_err(&hdev->device,
-                       "Retrying D0 failed with ret %d\n", ret);
-       }
+       ret = hv_pci_enter_d0(hdev);
        if (ret)
-               goto free_irq_domain;
+               goto release_state_lock;
 
        ret = hv_pci_allocate_bridge_windows(hbus);
        if (ret)
@@ -3763,12 +3779,15 @@ retry:
        if (ret)
                goto free_windows;
 
+       mutex_unlock(&hbus->state_lock);
        return 0;
 
 free_windows:
        hv_pci_free_bridge_windows(hbus);
 exit_d0:
        (void) hv_pci_bus_exit(hdev, true);
+release_state_lock:
+       mutex_unlock(&hbus->state_lock);
 free_irq_domain:
        irq_domain_remove(hbus->irq_domain);
 free_fwnode:
@@ -4018,20 +4037,26 @@ static int hv_pci_resume(struct hv_device *hdev)
        if (ret)
                goto out;
 
+       mutex_lock(&hbus->state_lock);
+
        ret = hv_pci_enter_d0(hdev);
        if (ret)
-               goto out;
+               goto release_state_lock;
 
        ret = hv_send_resources_allocated(hdev);
        if (ret)
-               goto out;
+               goto release_state_lock;
 
        prepopulate_bars(hbus);
 
        hv_pci_restore_msi_state(hbus);
 
        hbus->state = hv_pcibus_installed;
+       mutex_unlock(&hbus->state_lock);
        return 0;
+
+release_state_lock:
+       mutex_unlock(&hbus->state_lock);
 out:
        vmbus_close(hdev->channel);
        return ret;
index 7bfecdf..d249a03 100644 (file)
@@ -400,6 +400,7 @@ static struct meson_pmx_group meson_axg_periphs_groups[] = {
        GPIO_GROUP(GPIOA_15),
        GPIO_GROUP(GPIOA_16),
        GPIO_GROUP(GPIOA_17),
+       GPIO_GROUP(GPIOA_18),
        GPIO_GROUP(GPIOA_19),
        GPIO_GROUP(GPIOA_20),
 
index 535581c..7fc602e 100644 (file)
@@ -825,7 +825,7 @@ static int ssam_cplt_init(struct ssam_cplt *cplt, struct device *dev)
 
        cplt->dev = dev;
 
-       cplt->wq = create_workqueue(SSAM_CPLT_WQ_NAME);
+       cplt->wq = alloc_workqueue(SSAM_CPLT_WQ_NAME, WQ_UNBOUND | WQ_MEM_RECLAIM, 0);
        if (!cplt->wq)
                return -ENOMEM;
 
index 8f52b62..c0a1a58 100644 (file)
@@ -210,6 +210,7 @@ enum ssam_kip_cover_state {
        SSAM_KIP_COVER_STATE_LAPTOP        = 0x03,
        SSAM_KIP_COVER_STATE_FOLDED_CANVAS = 0x04,
        SSAM_KIP_COVER_STATE_FOLDED_BACK   = 0x05,
+       SSAM_KIP_COVER_STATE_BOOK          = 0x06,
 };
 
 static const char *ssam_kip_cover_state_name(struct ssam_tablet_sw *sw,
@@ -231,6 +232,9 @@ static const char *ssam_kip_cover_state_name(struct ssam_tablet_sw *sw,
        case SSAM_KIP_COVER_STATE_FOLDED_BACK:
                return "folded-back";
 
+       case SSAM_KIP_COVER_STATE_BOOK:
+               return "book";
+
        default:
                dev_warn(&sw->sdev->dev, "unknown KIP cover state: %u\n", state->state);
                return "<unknown>";
@@ -244,6 +248,7 @@ static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw,
        case SSAM_KIP_COVER_STATE_DISCONNECTED:
        case SSAM_KIP_COVER_STATE_FOLDED_CANVAS:
        case SSAM_KIP_COVER_STATE_FOLDED_BACK:
+       case SSAM_KIP_COVER_STATE_BOOK:
                return true;
 
        case SSAM_KIP_COVER_STATE_CLOSED:
@@ -335,6 +340,7 @@ enum ssam_pos_state_cover {
        SSAM_POS_COVER_LAPTOP        = 0x03,
        SSAM_POS_COVER_FOLDED_CANVAS = 0x04,
        SSAM_POS_COVER_FOLDED_BACK   = 0x05,
+       SSAM_POS_COVER_BOOK          = 0x06,
 };
 
 enum ssam_pos_state_sls {
@@ -367,6 +373,9 @@ static const char *ssam_pos_state_name_cover(struct ssam_tablet_sw *sw, u32 stat
        case SSAM_POS_COVER_FOLDED_BACK:
                return "folded-back";
 
+       case SSAM_POS_COVER_BOOK:
+               return "book";
+
        default:
                dev_warn(&sw->sdev->dev, "unknown device posture for type-cover: %u\n", state);
                return "<unknown>";
@@ -416,6 +425,7 @@ static bool ssam_pos_state_is_tablet_mode_cover(struct ssam_tablet_sw *sw, u32 s
        case SSAM_POS_COVER_DISCONNECTED:
        case SSAM_POS_COVER_FOLDED_CANVAS:
        case SSAM_POS_COVER_FOLDED_BACK:
+       case SSAM_POS_COVER_BOOK:
                return true;
 
        case SSAM_POS_COVER_CLOSED:
index 1086c3d..399f062 100644 (file)
@@ -101,9 +101,11 @@ int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
 
        int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
                                                             "int3472,clk-enable");
-       if (IS_ERR(int3472->clock.ena_gpio))
-               return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio),
-                                    "getting clk-enable GPIO\n");
+       if (IS_ERR(int3472->clock.ena_gpio)) {
+               ret = PTR_ERR(int3472->clock.ena_gpio);
+               int3472->clock.ena_gpio = NULL;
+               return dev_err_probe(int3472->dev, ret, "getting clk-enable GPIO\n");
+       }
 
        if (polarity == GPIO_ACTIVE_LOW)
                gpiod_toggle_active_low(int3472->clock.ena_gpio);
@@ -199,8 +201,9 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
        int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
                                                             "int3472,regulator");
        if (IS_ERR(int3472->regulator.gpio)) {
-               dev_err(int3472->dev, "Failed to get regulator GPIO line\n");
-               return PTR_ERR(int3472->regulator.gpio);
+               ret = PTR_ERR(int3472->regulator.gpio);
+               int3472->regulator.gpio = NULL;
+               return dev_err_probe(int3472->dev, ret, "getting regulator GPIO\n");
        }
 
        /* Ensure the pin is in output mode and non-active state */
index b0a58c6..f3b280a 100644 (file)
@@ -1057,21 +1057,21 @@ static const struct rpmh_vreg_init_data pm8450_vreg_data[] = {
 };
 
 static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
-       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_pldo,    "vdd-l1-l4-l10"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo515,    "vdd-l1-l4-l10"),
        RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_pldo,    "vdd-l2-l13-l14"),
-       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,    "vdd-l3"),
-       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo,    "vdd-l1-l4-l10"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo515,    "vdd-l3"),
+       RPMH_VREG("ldo4",   "ldo%s4",  &pmic5_nldo515,    "vdd-l1-l4-l10"),
        RPMH_VREG("ldo5",   "ldo%s5",  &pmic5_pldo,    "vdd-l5-l16"),
-       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo_lv, "vdd-l6-l7"),
-       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo_lv, "vdd-l6-l7"),
-       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_pldo_lv, "vdd-l8-l9"),
+       RPMH_VREG("ldo6",   "ldo%s6",  &pmic5_pldo, "vdd-l6-l7"),
+       RPMH_VREG("ldo7",   "ldo%s7",  &pmic5_pldo, "vdd-l6-l7"),
+       RPMH_VREG("ldo8",   "ldo%s8",  &pmic5_pldo, "vdd-l8-l9"),
        RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_pldo,    "vdd-l8-l9"),
-       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_nldo,    "vdd-l1-l4-l10"),
-       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_nldo,    "vdd-l11"),
+       RPMH_VREG("ldo10",  "ldo%s10", &pmic5_nldo515,    "vdd-l1-l4-l10"),
+       RPMH_VREG("ldo11",  "ldo%s11", &pmic5_nldo515,    "vdd-l11"),
        RPMH_VREG("ldo12",  "ldo%s12", &pmic5_pldo,    "vdd-l12"),
        RPMH_VREG("ldo13",  "ldo%s13", &pmic5_pldo,    "vdd-l2-l13-l14"),
        RPMH_VREG("ldo14",  "ldo%s14", &pmic5_pldo,    "vdd-l2-l13-l14"),
-       RPMH_VREG("ldo15",  "ldo%s15", &pmic5_pldo,    "vdd-l15"),
+       RPMH_VREG("ldo15",  "ldo%s15", &pmic5_nldo515,    "vdd-l15"),
        RPMH_VREG("ldo16",  "ldo%s16", &pmic5_pldo,    "vdd-l5-l16"),
        RPMH_VREG("ldo17",  "ldo%s17", &pmic5_pldo,    "vdd-l17"),
        RPMH_VREG("bob1",   "bob%s1",  &pmic5_bob,     "vdd-bob1"),
@@ -1086,9 +1086,9 @@ static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
        RPMH_VREG("smps4",  "smp%s4",  &pmic5_ftsmps525_lv, "vdd-s4"),
        RPMH_VREG("smps5",  "smp%s5",  &pmic5_ftsmps525_lv, "vdd-s5"),
        RPMH_VREG("smps6",  "smp%s6",  &pmic5_ftsmps525_mv, "vdd-s6"),
-       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo,   "vdd-l1"),
-       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo,   "vdd-l2"),
-       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo,   "vdd-l3"),
+       RPMH_VREG("ldo1",   "ldo%s1",  &pmic5_nldo515,   "vdd-l1"),
+       RPMH_VREG("ldo2",   "ldo%s2",  &pmic5_nldo515,   "vdd-l2"),
+       RPMH_VREG("ldo3",   "ldo%s3",  &pmic5_nldo515,   "vdd-l3"),
        {}
 };
 
@@ -1101,9 +1101,9 @@ static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
        RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
        RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
        RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
-       RPMH_VREG("ldo1",  "ldo%s1", &pmic5_nldo,   "vdd-l1"),
-       RPMH_VREG("ldo2",  "ldo%s2", &pmic5_nldo,   "vdd-l2"),
-       RPMH_VREG("ldo3",  "ldo%s3", &pmic5_nldo,   "vdd-l3"),
+       RPMH_VREG("ldo1",  "ldo%s1", &pmic5_nldo515,   "vdd-l1"),
+       RPMH_VREG("ldo2",  "ldo%s2", &pmic5_nldo515,   "vdd-l2"),
+       RPMH_VREG("ldo3",  "ldo%s3", &pmic5_nldo515,   "vdd-l3"),
        {}
 };
 
index 9327dcd..8fca725 100644 (file)
@@ -552,10 +552,10 @@ static int __dasd_ioctl_information(struct dasd_block *block,
 
        memcpy(dasd_info->type, base->discipline->name, 4);
 
-       spin_lock_irqsave(&block->queue_lock, flags);
+       spin_lock_irqsave(get_ccwdev_lock(base->cdev), flags);
        list_for_each(l, &base->ccw_queue)
                dasd_info->chanq_len++;
-       spin_unlock_irqrestore(&block->queue_lock, flags);
+       spin_unlock_irqrestore(get_ccwdev_lock(base->cdev), flags);
        return 0;
 }
 
index d5c43e9..c0d620f 100644 (file)
@@ -1376,6 +1376,7 @@ void ccw_device_set_notoper(struct ccw_device *cdev)
 enum io_sch_action {
        IO_SCH_UNREG,
        IO_SCH_ORPH_UNREG,
+       IO_SCH_UNREG_CDEV,
        IO_SCH_ATTACH,
        IO_SCH_UNREG_ATTACH,
        IO_SCH_ORPH_ATTACH,
@@ -1408,7 +1409,7 @@ static enum io_sch_action sch_get_action(struct subchannel *sch)
        }
        if ((sch->schib.pmcw.pam & sch->opm) == 0) {
                if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK)
-                       return IO_SCH_UNREG;
+                       return IO_SCH_UNREG_CDEV;
                return IO_SCH_DISC;
        }
        if (device_is_disconnected(cdev))
@@ -1470,6 +1471,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
        case IO_SCH_ORPH_ATTACH:
                ccw_device_set_disconnected(cdev);
                break;
+       case IO_SCH_UNREG_CDEV:
        case IO_SCH_UNREG_ATTACH:
        case IO_SCH_UNREG:
                if (!cdev)
@@ -1503,6 +1505,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int process)
                if (rc)
                        goto out;
                break;
+       case IO_SCH_UNREG_CDEV:
        case IO_SCH_UNREG_ATTACH:
                spin_lock_irqsave(sch->lock, flags);
                sch_set_cdev(sch, NULL);
index 8acb9eb..c2096e4 100644 (file)
@@ -771,14 +771,6 @@ static int __init ism_init(void)
 
 static void __exit ism_exit(void)
 {
-       struct ism_dev *ism;
-
-       mutex_lock(&ism_dev_list.mutex);
-       list_for_each_entry(ism, &ism_dev_list.list, list) {
-               ism_dev_exit(ism);
-       }
-       mutex_unlock(&ism_dev_list.mutex);
-
        pci_unregister_driver(&ism_driver);
        debug_unregister(ism_debug_info);
 }
index 5e115e8..7c6efde 100644 (file)
@@ -1678,6 +1678,7 @@ struct aac_dev
        u32                     handle_pci_error;
        bool                    init_reset;
        u8                      soft_reset_support;
+       u8                      use_map_queue;
 };
 
 #define aac_adapter_interrupt(dev) \
index deb32c9..3f062e4 100644 (file)
@@ -223,8 +223,12 @@ int aac_fib_setup(struct aac_dev * dev)
 struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd)
 {
        struct fib *fibptr;
+       u32 blk_tag;
+       int i;
 
-       fibptr = &dev->fibs[scsi_cmd_to_rq(scmd)->tag];
+       blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
+       i = blk_mq_unique_tag_to_tag(blk_tag);
+       fibptr = &dev->fibs[i];
        /*
         *      Null out fields that depend on being zero at the start of
         *      each I/O
index 68f4dbc..c4a36c0 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/compat.h>
 #include <linux/blkdev.h>
+#include <linux/blk-mq-pci.h>
 #include <linux/completion.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
@@ -504,6 +505,15 @@ common_config:
        return 0;
 }
 
+static void aac_map_queues(struct Scsi_Host *shost)
+{
+       struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+
+       blk_mq_pci_map_queues(&shost->tag_set.map[HCTX_TYPE_DEFAULT],
+                             aac->pdev, 0);
+       aac->use_map_queue = true;
+}
+
 /**
  *     aac_change_queue_depth          -       alter queue depths
  *     @sdev:  SCSI device we are considering
@@ -1488,6 +1498,7 @@ static const struct scsi_host_template aac_driver_template = {
        .bios_param                     = aac_biosparm,
        .shost_groups                   = aac_host_groups,
        .slave_configure                = aac_slave_configure,
+       .map_queues                     = aac_map_queues,
        .change_queue_depth             = aac_change_queue_depth,
        .sdev_groups                    = aac_dev_groups,
        .eh_abort_handler               = aac_eh_abort,
@@ -1775,6 +1786,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        shost->max_lun = AAC_MAX_LUN;
 
        pci_set_drvdata(pdev, shost);
+       shost->nr_hw_queues = aac->max_msix;
+       shost->host_tagset = 1;
 
        error = scsi_add_host(shost, &pdev->dev);
        if (error)
@@ -1906,6 +1919,7 @@ static void aac_remove_one(struct pci_dev *pdev)
        struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
 
        aac_cancel_rescan_worker(aac);
+       aac->use_map_queue = false;
        scsi_remove_host(shost);
 
        __aac_shutdown(aac);
index 11ef582..61949f3 100644 (file)
@@ -493,6 +493,10 @@ static int aac_src_deliver_message(struct fib *fib)
 #endif
 
        u16 vector_no;
+       struct scsi_cmnd *scmd;
+       u32 blk_tag;
+       struct Scsi_Host *shost = dev->scsi_host_ptr;
+       struct blk_mq_queue_map *qmap;
 
        atomic_inc(&q->numpending);
 
@@ -505,8 +509,25 @@ static int aac_src_deliver_message(struct fib *fib)
                if ((dev->comm_interface == AAC_COMM_MESSAGE_TYPE3)
                        && dev->sa_firmware)
                        vector_no = aac_get_vector(dev);
-               else
-                       vector_no = fib->vector_no;
+               else {
+                       if (!fib->vector_no || !fib->callback_data) {
+                               if (shost && dev->use_map_queue) {
+                                       qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
+                                       vector_no = qmap->mq_map[raw_smp_processor_id()];
+                               }
+                               /*
+                                *      We hardcode the vector_no for
+                                *      reserved commands as a valid shost is
+                                *      absent during the init
+                                */
+                               else
+                                       vector_no = 0;
+                       } else {
+                               scmd = (struct scsi_cmnd *)fib->callback_data;
+                               blk_tag = blk_mq_unique_tag(scsi_cmd_to_rq(scmd));
+                               vector_no = blk_mq_unique_tag_to_hwq(blk_tag);
+                       }
+               }
 
                if (native_hba) {
                        if (fib->flags & FIB_CONTEXT_FLAG_NATIVE_HBA_TMF) {
index 9a322a3..595dca9 100644 (file)
@@ -889,7 +889,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        struct lpfc_iocbq *piocbq)
 {
        uint32_t evt_req_id = 0;
-       uint32_t cmd;
+       u16 cmd;
        struct lpfc_dmabuf *dmabuf = NULL;
        struct lpfc_bsg_event *evt;
        struct event_data *evt_dat = NULL;
@@ -915,7 +915,7 @@ lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
 
        ct_req = (struct lpfc_sli_ct_request *)bdeBuf1->virt;
        evt_req_id = ct_req->FsType;
-       cmd = ct_req->CommandResponse.bits.CmdRsp;
+       cmd = be16_to_cpu(ct_req->CommandResponse.bits.CmdRsp);
 
        spin_lock_irqsave(&phba->ct_ev_lock, flags);
        list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
@@ -3186,8 +3186,8 @@ lpfc_bsg_diag_loopback_run(struct bsg_job *job)
                        ctreq->RevisionId.bits.InId = 0;
                        ctreq->FsType = SLI_CT_ELX_LOOPBACK;
                        ctreq->FsSubType = 0;
-                       ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA;
-                       ctreq->CommandResponse.bits.Size   = size;
+                       ctreq->CommandResponse.bits.CmdRsp = cpu_to_be16(ELX_LOOPBACK_DATA);
+                       ctreq->CommandResponse.bits.Size   = cpu_to_be16(size);
                        segment_offset = ELX_LOOPBACK_HEADER_SZ;
                } else
                        segment_offset = 0;
index e6bc622..659196a 100644 (file)
@@ -1567,6 +1567,8 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
 {
        blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
 
+       /* storvsc devices don't support MAINTENANCE_IN SCSI cmd */
+       sdevice->no_report_opcodes = 1;
        sdevice->no_write_same = 1;
 
        /*
index 0f43a88..89b7755 100644 (file)
@@ -32,4 +32,5 @@ obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o
 obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o
 obj-$(CONFIG_QCOM_KRYO_L2_ACCESSORS) +=        kryo-l2-accessors.o
 obj-$(CONFIG_QCOM_ICC_BWMON)   += icc-bwmon.o
-obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE)        += ice.o
+qcom_ice-objs                  += ice.o
+obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE)        += qcom_ice.o
index fd58c5b..f65bfec 100644 (file)
@@ -773,12 +773,12 @@ static int bwmon_probe(struct platform_device *pdev)
        bwmon->max_bw_kbps = UINT_MAX;
        opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0);
        if (IS_ERR(opp))
-               return dev_err_probe(dev, ret, "failed to find max peak bandwidth\n");
+               return dev_err_probe(dev, PTR_ERR(opp), "failed to find max peak bandwidth\n");
 
        bwmon->min_bw_kbps = 0;
        opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0);
        if (IS_ERR(opp))
-               return dev_err_probe(dev, ret, "failed to find min peak bandwidth\n");
+               return dev_err_probe(dev, PTR_ERR(opp), "failed to find min peak bandwidth\n");
 
        bwmon->dev = dev;
 
index dc74d2a..5e3ba0b 100644 (file)
@@ -296,7 +296,7 @@ static int qcom_ramp_controller_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        qrc->desc = device_get_match_data(&pdev->dev);
-       if (!qrc)
+       if (!qrc->desc)
                return -EINVAL;
 
        qrc->regmap = devm_regmap_init_mmio(&pdev->dev, base, &qrc_regmap_config);
index ce48a9f..f83811f 100644 (file)
@@ -233,6 +233,7 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
                num_vmids = 0;
        } else if (num_vmids < 0) {
                dev_err(&pdev->dev, "failed to count qcom,vmid elements: %d\n", num_vmids);
+               ret = num_vmids;
                goto remove_cdev;
        } else if (num_vmids > NUM_MAX_VMIDS) {
                dev_warn(&pdev->dev,
index f93544f..0dd4363 100644 (file)
@@ -1073,7 +1073,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
        drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
        drv->ver.minor >>= MINOR_VER_SHIFT;
 
-       if (drv->ver.major == 3 && drv->ver.minor >= 0)
+       if (drv->ver.major == 3)
                drv->regs = rpmh_rsc_reg_offset_ver_3_0;
        else
                drv->regs = rpmh_rsc_reg_offset_ver_2_7;
index f20e2a4..63c35a3 100644 (file)
@@ -342,6 +342,21 @@ static const struct rpmhpd_desc sm8150_desc = {
        .num_pds = ARRAY_SIZE(sm8150_rpmhpds),
 };
 
+static struct rpmhpd *sa8155p_rpmhpds[] = {
+       [SA8155P_CX] = &cx_w_mx_parent,
+       [SA8155P_CX_AO] = &cx_ao_w_mx_parent,
+       [SA8155P_EBI] = &ebi,
+       [SA8155P_GFX] = &gfx,
+       [SA8155P_MSS] = &mss,
+       [SA8155P_MX] = &mx,
+       [SA8155P_MX_AO] = &mx_ao,
+};
+
+static const struct rpmhpd_desc sa8155p_desc = {
+       .rpmhpds = sa8155p_rpmhpds,
+       .num_pds = ARRAY_SIZE(sa8155p_rpmhpds),
+};
+
 /* SM8250 RPMH powerdomains */
 static struct rpmhpd *sm8250_rpmhpds[] = {
        [SM8250_CX] = &cx_w_mx_parent,
@@ -519,6 +534,7 @@ static const struct rpmhpd_desc sc8280xp_desc = {
 
 static const struct of_device_id rpmhpd_match_table[] = {
        { .compatible = "qcom,qdu1000-rpmhpd", .data = &qdu1000_desc },
+       { .compatible = "qcom,sa8155p-rpmhpd", .data = &sa8155p_desc },
        { .compatible = "qcom,sa8540p-rpmhpd", .data = &sa8540p_desc },
        { .compatible = "qcom,sa8775p-rpmhpd", .data = &sa8775p_desc },
        { .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
index 58ea013..2a1096d 100644 (file)
@@ -100,6 +100,13 @@ static const struct dmi_system_id adr_remap_quirk_table[] = {
                .driver_data = (void *)intel_tgl_bios,
        },
        {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "HP"),
+                       DMI_MATCH(DMI_BOARD_NAME, "8709"),
+               },
+               .driver_data = (void *)intel_tgl_bios,
+       },
+       {
                /* quirk used for NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
index c296e0b..280455f 100644 (file)
@@ -1099,8 +1099,10 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
        }
 
        sruntime = sdw_alloc_stream(dai->name);
-       if (!sruntime)
-               return -ENOMEM;
+       if (!sruntime) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
 
        ctrl->sruntime[dai->id] = sruntime;
 
@@ -1110,12 +1112,19 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
                if (ret < 0 && ret != -ENOTSUPP) {
                        dev_err(dai->dev, "Failed to set sdw stream on %s\n",
                                codec_dai->name);
-                       sdw_release_stream(sruntime);
-                       return ret;
+                       goto err_set_stream;
                }
        }
 
        return 0;
+
+err_set_stream:
+       sdw_release_stream(sruntime);
+err_alloc:
+       pm_runtime_mark_last_busy(ctrl->dev);
+       pm_runtime_put_autosuspend(ctrl->dev);
+
+       return ret;
 }
 
 static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
index c2191c0..379228f 100644 (file)
@@ -2021,8 +2021,10 @@ int sdw_stream_add_slave(struct sdw_slave *slave,
 
 skip_alloc_master_rt:
        s_rt = sdw_slave_rt_find(slave, stream);
-       if (s_rt)
+       if (s_rt) {
+               alloc_slave_rt = false;
                goto skip_alloc_slave_rt;
+       }
 
        s_rt = sdw_slave_rt_alloc(slave, m_rt);
        if (!s_rt) {
index 6ddb2df..32449be 100644 (file)
@@ -1756,8 +1756,11 @@ static int cqspi_probe(struct platform_device *pdev)
                        cqspi->slow_sram = true;
 
                if (of_device_is_compatible(pdev->dev.of_node,
-                                           "xlnx,versal-ospi-1.0"))
-                       dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+                                           "xlnx,versal-ospi-1.0")) {
+                       ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
+                       if (ret)
+                               goto probe_reset_failed;
+               }
        }
 
        ret = devm_request_irq(dev, irq, cqspi_irq_handler, 0,
index 5f2aee6..15f5e9c 100644 (file)
@@ -274,7 +274,7 @@ static void dw_spi_elba_set_cs(struct spi_device *spi, bool enable)
         */
        spi_set_chipselect(spi, 0, 0);
        dw_spi_set_cs(spi, enable);
-       spi_get_chipselect(spi, cs);
+       spi_set_chipselect(spi, 0, cs);
 }
 
 static int dw_spi_elba_init(struct platform_device *pdev,
index 4339485..674cfe0 100644 (file)
@@ -1002,7 +1002,9 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,
 static int dspi_setup(struct spi_device *spi)
 {
        struct fsl_dspi *dspi = spi_controller_get_devdata(spi->controller);
+       u32 period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->max_speed_hz);
        unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
+       u32 quarter_period_ns = DIV_ROUND_UP(period_ns, 4);
        u32 cs_sck_delay = 0, sck_cs_delay = 0;
        struct fsl_dspi_platform_data *pdata;
        unsigned char pasc = 0, asc = 0;
@@ -1031,6 +1033,19 @@ static int dspi_setup(struct spi_device *spi)
                sck_cs_delay = pdata->sck_cs_delay;
        }
 
+       /* Since tCSC and tASC apply to continuous transfers too, avoid SCK
+        * glitches of half a cycle by never allowing tCSC + tASC to go below
+        * half a SCK period.
+        */
+       if (cs_sck_delay < quarter_period_ns)
+               cs_sck_delay = quarter_period_ns;
+       if (sck_cs_delay < quarter_period_ns)
+               sck_cs_delay = quarter_period_ns;
+
+       dev_dbg(&spi->dev,
+               "DSPI controller timing params: CS-to-SCK delay %u ns, SCK-to-CS delay %u ns\n",
+               cs_sck_delay, sck_cs_delay);
+
        clkrate = clk_get_rate(dspi->clk);
        hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
 
index f2341ab..4b70038 100644 (file)
@@ -910,9 +910,14 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
        ret = fsl_lpspi_dma_init(&pdev->dev, fsl_lpspi, controller);
        if (ret == -EPROBE_DEFER)
                goto out_pm_get;
-
        if (ret < 0)
                dev_err(&pdev->dev, "dma setup error %d, use pio\n", ret);
+       else
+               /*
+                * disable LPSPI module IRQ when enable DMA mode successfully,
+                * to prevent the unexpected LPSPI module IRQ events.
+                */
+               disable_irq(irq);
 
        ret = devm_spi_register_controller(&pdev->dev, controller);
        if (ret < 0) {
index 21c321f..d7432e2 100644 (file)
@@ -1275,6 +1275,9 @@ static int mtk_spi_remove(struct platform_device *pdev)
        struct mtk_spi *mdata = spi_master_get_devdata(master);
        int ret;
 
+       if (mdata->use_spimem && !completion_done(&mdata->spimem_done))
+               complete(&mdata->spimem_done);
+
        ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret < 0)
                return ret;
index 944ef6b..00e5e88 100644 (file)
@@ -1028,23 +1028,8 @@ static int spi_qup_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       ret = clk_prepare_enable(cclk);
-       if (ret) {
-               dev_err(dev, "cannot enable core clock\n");
-               return ret;
-       }
-
-       ret = clk_prepare_enable(iclk);
-       if (ret) {
-               clk_disable_unprepare(cclk);
-               dev_err(dev, "cannot enable iface clock\n");
-               return ret;
-       }
-
        master = spi_alloc_master(dev, sizeof(struct spi_qup));
        if (!master) {
-               clk_disable_unprepare(cclk);
-               clk_disable_unprepare(iclk);
                dev_err(dev, "cannot allocate master\n");
                return -ENOMEM;
        }
@@ -1092,6 +1077,19 @@ static int spi_qup_probe(struct platform_device *pdev)
        spin_lock_init(&controller->lock);
        init_completion(&controller->done);
 
+       ret = clk_prepare_enable(cclk);
+       if (ret) {
+               dev_err(dev, "cannot enable core clock\n");
+               goto error_dma;
+       }
+
+       ret = clk_prepare_enable(iclk);
+       if (ret) {
+               clk_disable_unprepare(cclk);
+               dev_err(dev, "cannot enable iface clock\n");
+               goto error_dma;
+       }
+
        iomode = readl_relaxed(base + QUP_IO_M_MODES);
 
        size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
@@ -1121,7 +1119,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        ret = spi_qup_set_state(controller, QUP_STATE_RESET);
        if (ret) {
                dev_err(dev, "cannot set RESET state\n");
-               goto error_dma;
+               goto error_clk;
        }
 
        writel_relaxed(0, base + QUP_OPERATIONAL);
@@ -1145,7 +1143,7 @@ static int spi_qup_probe(struct platform_device *pdev)
        ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
                               IRQF_TRIGGER_HIGH, pdev->name, controller);
        if (ret)
-               goto error_dma;
+               goto error_clk;
 
        pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
        pm_runtime_use_autosuspend(dev);
@@ -1160,11 +1158,12 @@ static int spi_qup_probe(struct platform_device *pdev)
 
 disable_pm:
        pm_runtime_disable(&pdev->dev);
+error_clk:
+       clk_disable_unprepare(cclk);
+       clk_disable_unprepare(iclk);
 error_dma:
        spi_qup_release_dma(master);
 error:
-       clk_disable_unprepare(cclk);
-       clk_disable_unprepare(iclk);
        spi_master_put(master);
        return ret;
 }
index 67a0a1f..044e48e 100644 (file)
@@ -6,4 +6,3 @@ TODO:
        - make driver self-contained instead of being split between staging and
          arch/mips/cavium-octeon.
 
-Contact: Aaro Koskinen <aaro.koskinen@iki.fi>
index 86adff2..687adc9 100644 (file)
@@ -504,6 +504,8 @@ target_setup_session(struct se_portal_group *tpg,
 
 free_sess:
        transport_free_session(sess);
+       return ERR_PTR(rc);
+
 free_cnt:
        target_free_cmd_counter(cmd_cnt);
        return ERR_PTR(rc);
index ff48c3e..e2014e2 100644 (file)
@@ -118,16 +118,18 @@ struct tee_cmd_unmap_shared_mem {
 
 /**
  * struct tee_cmd_load_ta - load Trusted Application (TA) binary into TEE
- * @low_addr:    [in] bits [31:0] of the physical address of the TA binary
- * @hi_addr:     [in] bits [63:32] of the physical address of the TA binary
- * @size:        [in] size of TA binary in bytes
- * @ta_handle:   [out] return handle of the loaded TA
+ * @low_addr:       [in] bits [31:0] of the physical address of the TA binary
+ * @hi_addr:        [in] bits [63:32] of the physical address of the TA binary
+ * @size:           [in] size of TA binary in bytes
+ * @ta_handle:      [out] return handle of the loaded TA
+ * @return_origin:  [out] origin of return code after TEE processing
  */
 struct tee_cmd_load_ta {
        u32 low_addr;
        u32 hi_addr;
        u32 size;
        u32 ta_handle;
+       u32 return_origin;
 };
 
 /**
index e8cd9aa..e9b63dc 100644 (file)
@@ -423,19 +423,23 @@ int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
        if (ret) {
                arg->ret_origin = TEEC_ORIGIN_COMMS;
                arg->ret = TEEC_ERROR_COMMUNICATION;
-       } else if (arg->ret == TEEC_SUCCESS) {
-               ret = get_ta_refcount(load_cmd.ta_handle);
-               if (!ret) {
-                       arg->ret_origin = TEEC_ORIGIN_COMMS;
-                       arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
-
-                       /* Unload the TA on error */
-                       unload_cmd.ta_handle = load_cmd.ta_handle;
-                       psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA,
-                                           (void *)&unload_cmd,
-                                           sizeof(unload_cmd), &ret);
-               } else {
-                       set_session_id(load_cmd.ta_handle, 0, &arg->session);
+       } else {
+               arg->ret_origin = load_cmd.return_origin;
+
+               if (arg->ret == TEEC_SUCCESS) {
+                       ret = get_ta_refcount(load_cmd.ta_handle);
+                       if (!ret) {
+                               arg->ret_origin = TEEC_ORIGIN_COMMS;
+                               arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
+
+                               /* Unload the TA on error */
+                               unload_cmd.ta_handle = load_cmd.ta_handle;
+                               psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA,
+                                                   (void *)&unload_cmd,
+                                                   sizeof(unload_cmd), &ret);
+                       } else {
+                               set_session_id(load_cmd.ta_handle, 0, &arg->session);
+                       }
                }
        }
        mutex_unlock(&ta_refcount_mutex);
index f99dc7e..db97499 100644 (file)
@@ -398,7 +398,7 @@ struct intel_soc_dts_sensors *intel_soc_dts_iosf_init(
        spin_lock_init(&sensors->intr_notify_lock);
        mutex_init(&sensors->dts_update_lock);
        sensors->intr_type = intr_type;
-       sensors->tj_max = tj_max;
+       sensors->tj_max = tj_max * 1000;
        if (intr_type == INTEL_SOC_DTS_INTERRUPT_NONE)
                notification = false;
        else
index 3bedecb..14bb6de 100644 (file)
@@ -192,9 +192,9 @@ static int dma_test_start_rings(struct dma_test *dt)
        }
 
        ret = tb_xdomain_enable_paths(dt->xd, dt->tx_hopid,
-                                     dt->tx_ring ? dt->tx_ring->hop : 0,
+                                     dt->tx_ring ? dt->tx_ring->hop : -1,
                                      dt->rx_hopid,
-                                     dt->rx_ring ? dt->rx_ring->hop : 0);
+                                     dt->rx_ring ? dt->rx_ring->hop : -1);
        if (ret) {
                dma_test_free_rings(dt);
                return ret;
@@ -218,9 +218,9 @@ static void dma_test_stop_rings(struct dma_test *dt)
                tb_ring_stop(dt->tx_ring);
 
        ret = tb_xdomain_disable_paths(dt->xd, dt->tx_hopid,
-                                      dt->tx_ring ? dt->tx_ring->hop : 0,
+                                      dt->tx_ring ? dt->tx_ring->hop : -1,
                                       dt->rx_hopid,
-                                      dt->rx_ring ? dt->rx_ring->hop : 0);
+                                      dt->rx_ring ? dt->rx_ring->hop : -1);
        if (ret)
                dev_warn(&dt->svc->dev, "failed to disable DMA paths\n");
 
index c0aee5d..e58beac 100644 (file)
@@ -56,9 +56,14 @@ static int ring_interrupt_index(const struct tb_ring *ring)
 
 static void nhi_mask_interrupt(struct tb_nhi *nhi, int mask, int ring)
 {
-       if (nhi->quirks & QUIRK_AUTO_CLEAR_INT)
-               return;
-       iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
+       if (nhi->quirks & QUIRK_AUTO_CLEAR_INT) {
+               u32 val;
+
+               val = ioread32(nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
+               iowrite32(val & ~mask, nhi->iobase + REG_RING_INTERRUPT_BASE + ring);
+       } else {
+               iowrite32(mask, nhi->iobase + REG_RING_INTERRUPT_MASK_CLEAR_BASE + ring);
+       }
 }
 
 static void nhi_clear_interrupt(struct tb_nhi *nhi, int ring)
index 7bfbc9c..c1af712 100644 (file)
@@ -737,6 +737,7 @@ static void tb_scan_port(struct tb_port *port)
 {
        struct tb_cm *tcm = tb_priv(port->sw->tb);
        struct tb_port *upstream_port;
+       bool discovery = false;
        struct tb_switch *sw;
        int ret;
 
@@ -804,8 +805,10 @@ static void tb_scan_port(struct tb_port *port)
         * tunnels and know which switches were authorized already by
         * the boot firmware.
         */
-       if (!tcm->hotplug_active)
+       if (!tcm->hotplug_active) {
                dev_set_uevent_suppress(&sw->dev, true);
+               discovery = true;
+       }
 
        /*
         * At the moment Thunderbolt 2 and beyond (devices with LC) we
@@ -835,10 +838,14 @@ static void tb_scan_port(struct tb_port *port)
         * CL0s and CL1 are enabled and supported together.
         * Silently ignore CLx enabling in case CLx is not supported.
         */
-       ret = tb_switch_enable_clx(sw, TB_CL1);
-       if (ret && ret != -EOPNOTSUPP)
-               tb_sw_warn(sw, "failed to enable %s on upstream port\n",
-                          tb_switch_clx_name(TB_CL1));
+       if (discovery) {
+               tb_sw_dbg(sw, "discovery, not touching CL states\n");
+       } else {
+               ret = tb_switch_enable_clx(sw, TB_CL1);
+               if (ret && ret != -EOPNOTSUPP)
+                       tb_sw_warn(sw, "failed to enable %s on upstream port\n",
+                                  tb_switch_clx_name(TB_CL1));
+       }
 
        if (tb_switch_is_clx_enabled(sw, TB_CL1))
                /*
index 9099ae7..4f22267 100644 (file)
@@ -526,7 +526,7 @@ static int tb_dp_xchg_caps(struct tb_tunnel *tunnel)
         * Perform connection manager handshake between IN and OUT ports
         * before capabilities exchange can take place.
         */
-       ret = tb_dp_cm_handshake(in, out, 1500);
+       ret = tb_dp_cm_handshake(in, out, 3000);
        if (ret)
                return ret;
 
index 7486a2b..7fd30fc 100644 (file)
@@ -310,7 +310,7 @@ static const struct lpuart_soc_data ls1021a_data = {
 static const struct lpuart_soc_data ls1028a_data = {
        .devtype = LS1028A_LPUART,
        .iotype = UPIO_MEM32,
-       .rx_watermark = 1,
+       .rx_watermark = 0,
 };
 
 static struct lpuart_soc_data imx7ulp_data = {
index a58e927..f1387f1 100644 (file)
@@ -250,6 +250,7 @@ lqasc_err_int(int irq, void *_port)
        struct ltq_uart_port *ltq_port = to_ltq_uart_port(port);
 
        spin_lock_irqsave(&ltq_port->lock, flags);
+       __raw_writel(ASC_IRNCR_EIR, port->membase + LTQ_ASC_IRNCR);
        /* clear any pending interrupts */
        asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE |
                ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE);
index 7b2ce01..d68958e 100644 (file)
@@ -1929,6 +1929,11 @@ static int dwc3_remove(struct platform_device *pdev)
        pm_runtime_disable(&pdev->dev);
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_put_noidle(&pdev->dev);
+       /*
+        * HACK: Clear the driver data, which is currently accessed by parent
+        * glue drivers, before allowing the parent to suspend.
+        */
+       platform_set_drvdata(pdev, NULL);
        pm_runtime_set_suspended(&pdev->dev);
 
        dwc3_free_event_buffers(dwc);
index 959fc92..79b22ab 100644 (file)
@@ -308,7 +308,16 @@ static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
 /* Only usable in contexts where the role can not change. */
 static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
 {
-       struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
+       struct dwc3 *dwc;
+
+       /*
+        * FIXME: Fix this layering violation.
+        */
+       dwc = platform_get_drvdata(qcom->dwc3);
+
+       /* Core driver may not have probed yet. */
+       if (!dwc)
+               return false;
 
        return dwc->xhci;
 }
index d831f5a..b78599d 100644 (file)
@@ -198,6 +198,7 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
        list_del(&req->list);
        req->remaining = 0;
        req->needs_extra_trb = false;
+       req->num_trbs = 0;
 
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
index 52e6d2e..83fd1de 100644 (file)
@@ -37,6 +37,14 @@ static const struct bus_type gadget_bus_type;
  * @vbus: for udcs who care about vbus status, this value is real vbus status;
  * for udcs who do not care about vbus status, this value is always true
  * @started: the UDC's started state. True if the UDC had started.
+ * @allow_connect: Indicates whether UDC is allowed to be pulled up.
+ * Set/cleared by gadget_(un)bind_driver() after gadget driver is bound or
+ * unbound.
+ * @connect_lock: protects udc->started, gadget->connect,
+ * gadget->allow_connect and gadget->deactivate. The routines
+ * usb_gadget_connect_locked(), usb_gadget_disconnect_locked(),
+ * usb_udc_connect_control_locked(), usb_gadget_udc_start_locked() and
+ * usb_gadget_udc_stop_locked() are called with this lock held.
  *
  * This represents the internal data structure which is used by the UDC-class
  * to hold information about udc driver and gadget together.
@@ -48,6 +56,9 @@ struct usb_udc {
        struct list_head                list;
        bool                            vbus;
        bool                            started;
+       bool                            allow_connect;
+       struct work_struct              vbus_work;
+       struct mutex                    connect_lock;
 };
 
 static struct class *udc_class;
@@ -687,17 +698,8 @@ out:
 }
 EXPORT_SYMBOL_GPL(usb_gadget_vbus_disconnect);
 
-/**
- * usb_gadget_connect - software-controlled connect to USB host
- * @gadget:the peripheral being connected
- *
- * Enables the D+ (or potentially D-) pullup.  The host will start
- * enumerating this gadget when the pullup is active and a VBUS session
- * is active (the link is powered).
- *
- * Returns zero on success, else negative errno.
- */
-int usb_gadget_connect(struct usb_gadget *gadget)
+static int usb_gadget_connect_locked(struct usb_gadget *gadget)
+       __must_hold(&gadget->udc->connect_lock)
 {
        int ret = 0;
 
@@ -706,10 +708,12 @@ int usb_gadget_connect(struct usb_gadget *gadget)
                goto out;
        }
 
-       if (gadget->deactivated) {
+       if (gadget->deactivated || !gadget->udc->allow_connect || !gadget->udc->started) {
                /*
-                * If gadget is deactivated we only save new state.
-                * Gadget will be connected automatically after activation.
+                * If the gadget isn't usable (because it is deactivated,
+                * unbound, or not yet started), we only save the new state.
+                * The gadget will be connected automatically when it is
+                * activated/bound/started.
                 */
                gadget->connected = true;
                goto out;
@@ -724,22 +728,31 @@ out:
 
        return ret;
 }
-EXPORT_SYMBOL_GPL(usb_gadget_connect);
 
 /**
- * usb_gadget_disconnect - software-controlled disconnect from USB host
- * @gadget:the peripheral being disconnected
- *
- * Disables the D+ (or potentially D-) pullup, which the host may see
- * as a disconnect (when a VBUS session is active).  Not all systems
- * support software pullup controls.
+ * usb_gadget_connect - software-controlled connect to USB host
+ * @gadget:the peripheral being connected
  *
- * Following a successful disconnect, invoke the ->disconnect() callback
- * for the current gadget driver so that UDC drivers don't need to.
+ * Enables the D+ (or potentially D-) pullup.  The host will start
+ * enumerating this gadget when the pullup is active and a VBUS session
+ * is active (the link is powered).
  *
  * Returns zero on success, else negative errno.
  */
-int usb_gadget_disconnect(struct usb_gadget *gadget)
+int usb_gadget_connect(struct usb_gadget *gadget)
+{
+       int ret;
+
+       mutex_lock(&gadget->udc->connect_lock);
+       ret = usb_gadget_connect_locked(gadget);
+       mutex_unlock(&gadget->udc->connect_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_connect);
+
+static int usb_gadget_disconnect_locked(struct usb_gadget *gadget)
+       __must_hold(&gadget->udc->connect_lock)
 {
        int ret = 0;
 
@@ -751,7 +764,7 @@ int usb_gadget_disconnect(struct usb_gadget *gadget)
        if (!gadget->connected)
                goto out;
 
-       if (gadget->deactivated) {
+       if (gadget->deactivated || !gadget->udc->started) {
                /*
                 * If gadget is deactivated we only save new state.
                 * Gadget will stay disconnected after activation.
@@ -774,6 +787,30 @@ out:
 
        return ret;
 }
+
+/**
+ * usb_gadget_disconnect - software-controlled disconnect from USB host
+ * @gadget:the peripheral being disconnected
+ *
+ * Disables the D+ (or potentially D-) pullup, which the host may see
+ * as a disconnect (when a VBUS session is active).  Not all systems
+ * support software pullup controls.
+ *
+ * Following a successful disconnect, invoke the ->disconnect() callback
+ * for the current gadget driver so that UDC drivers don't need to.
+ *
+ * Returns zero on success, else negative errno.
+ */
+int usb_gadget_disconnect(struct usb_gadget *gadget)
+{
+       int ret;
+
+       mutex_lock(&gadget->udc->connect_lock);
+       ret = usb_gadget_disconnect_locked(gadget);
+       mutex_unlock(&gadget->udc->connect_lock);
+
+       return ret;
+}
 EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
 
 /**
@@ -791,13 +828,14 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
 {
        int ret = 0;
 
+       mutex_lock(&gadget->udc->connect_lock);
        if (gadget->deactivated)
-               goto out;
+               goto unlock;
 
        if (gadget->connected) {
-               ret = usb_gadget_disconnect(gadget);
+               ret = usb_gadget_disconnect_locked(gadget);
                if (ret)
-                       goto out;
+                       goto unlock;
 
                /*
                 * If gadget was being connected before deactivation, we want
@@ -807,7 +845,8 @@ int usb_gadget_deactivate(struct usb_gadget *gadget)
        }
        gadget->deactivated = true;
 
-out:
+unlock:
+       mutex_unlock(&gadget->udc->connect_lock);
        trace_usb_gadget_deactivate(gadget, ret);
 
        return ret;
@@ -827,8 +866,9 @@ int usb_gadget_activate(struct usb_gadget *gadget)
 {
        int ret = 0;
 
+       mutex_lock(&gadget->udc->connect_lock);
        if (!gadget->deactivated)
-               goto out;
+               goto unlock;
 
        gadget->deactivated = false;
 
@@ -837,9 +877,11 @@ int usb_gadget_activate(struct usb_gadget *gadget)
         * while it was being deactivated, we call usb_gadget_connect().
         */
        if (gadget->connected)
-               ret = usb_gadget_connect(gadget);
+               ret = usb_gadget_connect_locked(gadget);
+       mutex_unlock(&gadget->udc->connect_lock);
 
-out:
+unlock:
+       mutex_unlock(&gadget->udc->connect_lock);
        trace_usb_gadget_activate(gadget, ret);
 
        return ret;
@@ -1078,12 +1120,22 @@ EXPORT_SYMBOL_GPL(usb_gadget_set_state);
 
 /* ------------------------------------------------------------------------- */
 
-static void usb_udc_connect_control(struct usb_udc *udc)
+/* Acquire connect_lock before calling this function. */
+static void usb_udc_connect_control_locked(struct usb_udc *udc) __must_hold(&udc->connect_lock)
 {
        if (udc->vbus)
-               usb_gadget_connect(udc->gadget);
+               usb_gadget_connect_locked(udc->gadget);
        else
-               usb_gadget_disconnect(udc->gadget);
+               usb_gadget_disconnect_locked(udc->gadget);
+}
+
+static void vbus_event_work(struct work_struct *work)
+{
+       struct usb_udc *udc = container_of(work, struct usb_udc, vbus_work);
+
+       mutex_lock(&udc->connect_lock);
+       usb_udc_connect_control_locked(udc);
+       mutex_unlock(&udc->connect_lock);
 }
 
 /**
@@ -1094,6 +1146,14 @@ static void usb_udc_connect_control(struct usb_udc *udc)
  *
  * The udc driver calls it when it wants to connect or disconnect gadget
  * according to vbus status.
+ *
+ * This function can be invoked from interrupt context by irq handlers of
+ * the gadget drivers, however, usb_udc_connect_control() has to run in
+ * non-atomic context due to the following:
+ * a. Some of the gadget driver implementations expect the ->pullup
+ * callback to be invoked in non-atomic context.
+ * b. usb_gadget_disconnect() acquires udc_lock which is a mutex.
+ * Hence offload invocation of usb_udc_connect_control() to workqueue.
  */
 void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
 {
@@ -1101,7 +1161,7 @@ void usb_udc_vbus_handler(struct usb_gadget *gadget, bool status)
 
        if (udc) {
                udc->vbus = status;
-               usb_udc_connect_control(udc);
+               schedule_work(&udc->vbus_work);
        }
 }
 EXPORT_SYMBOL_GPL(usb_udc_vbus_handler);
@@ -1124,7 +1184,7 @@ void usb_gadget_udc_reset(struct usb_gadget *gadget,
 EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
 
 /**
- * usb_gadget_udc_start - tells usb device controller to start up
+ * usb_gadget_udc_start_locked - tells usb device controller to start up
  * @udc: The UDC to be started
  *
  * This call is issued by the UDC Class driver when it's about
@@ -1135,8 +1195,11 @@ EXPORT_SYMBOL_GPL(usb_gadget_udc_reset);
  * necessary to have it powered on.
  *
  * Returns zero on success, else negative errno.
+ *
+ * Caller should acquire connect_lock before invoking this function.
  */
-static inline int usb_gadget_udc_start(struct usb_udc *udc)
+static inline int usb_gadget_udc_start_locked(struct usb_udc *udc)
+       __must_hold(&udc->connect_lock)
 {
        int ret;
 
@@ -1153,7 +1216,7 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
 }
 
 /**
- * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * usb_gadget_udc_stop_locked - tells usb device controller we don't need it anymore
  * @udc: The UDC to be stopped
  *
  * This call is issued by the UDC Class driver after calling
@@ -1162,8 +1225,11 @@ static inline int usb_gadget_udc_start(struct usb_udc *udc)
  * The details are implementation specific, but it can go as
  * far as powering off UDC completely and disable its data
  * line pullups.
+ *
+ * Caller should acquire connect lock before invoking this function.
  */
-static inline void usb_gadget_udc_stop(struct usb_udc *udc)
+static inline void usb_gadget_udc_stop_locked(struct usb_udc *udc)
+       __must_hold(&udc->connect_lock)
 {
        if (!udc->started) {
                dev_err(&udc->dev, "UDC had already stopped\n");
@@ -1322,12 +1388,14 @@ int usb_add_gadget(struct usb_gadget *gadget)
 
        udc->gadget = gadget;
        gadget->udc = udc;
+       mutex_init(&udc->connect_lock);
 
        udc->started = false;
 
        mutex_lock(&udc_lock);
        list_add_tail(&udc->list, &udc_list);
        mutex_unlock(&udc_lock);
+       INIT_WORK(&udc->vbus_work, vbus_event_work);
 
        ret = device_add(&udc->dev);
        if (ret)
@@ -1459,6 +1527,7 @@ void usb_del_gadget(struct usb_gadget *gadget)
        flush_work(&gadget->work);
        device_del(&gadget->dev);
        ida_free(&gadget_id_numbers, gadget->id_number);
+       cancel_work_sync(&udc->vbus_work);
        device_unregister(&udc->dev);
 }
 EXPORT_SYMBOL_GPL(usb_del_gadget);
@@ -1523,11 +1592,16 @@ static int gadget_bind_driver(struct device *dev)
        if (ret)
                goto err_bind;
 
-       ret = usb_gadget_udc_start(udc);
-       if (ret)
+       mutex_lock(&udc->connect_lock);
+       ret = usb_gadget_udc_start_locked(udc);
+       if (ret) {
+               mutex_unlock(&udc->connect_lock);
                goto err_start;
+       }
        usb_gadget_enable_async_callbacks(udc);
-       usb_udc_connect_control(udc);
+       udc->allow_connect = true;
+       usb_udc_connect_control_locked(udc);
+       mutex_unlock(&udc->connect_lock);
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
        return 0;
@@ -1558,12 +1632,16 @@ static void gadget_unbind_driver(struct device *dev)
 
        kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
 
-       usb_gadget_disconnect(gadget);
+       udc->allow_connect = false;
+       cancel_work_sync(&udc->vbus_work);
+       mutex_lock(&udc->connect_lock);
+       usb_gadget_disconnect_locked(gadget);
        usb_gadget_disable_async_callbacks(udc);
        if (gadget->irq)
                synchronize_irq(gadget->irq);
        udc->driver->unbind(gadget);
-       usb_gadget_udc_stop(udc);
+       usb_gadget_udc_stop_locked(udc);
+       mutex_unlock(&udc->connect_lock);
 
        mutex_lock(&udc_lock);
        driver->is_bound = false;
@@ -1649,11 +1727,15 @@ static ssize_t soft_connect_store(struct device *dev,
        }
 
        if (sysfs_streq(buf, "connect")) {
-               usb_gadget_udc_start(udc);
-               usb_gadget_connect(udc->gadget);
+               mutex_lock(&udc->connect_lock);
+               usb_gadget_udc_start_locked(udc);
+               usb_gadget_connect_locked(udc->gadget);
+               mutex_unlock(&udc->connect_lock);
        } else if (sysfs_streq(buf, "disconnect")) {
-               usb_gadget_disconnect(udc->gadget);
-               usb_gadget_udc_stop(udc);
+               mutex_lock(&udc->connect_lock);
+               usb_gadget_disconnect_locked(udc->gadget);
+               usb_gadget_udc_stop_locked(udc);
+               mutex_unlock(&udc->connect_lock);
        } else {
                dev_err(dev, "unsupported command '%s'\n", buf);
                ret = -EINVAL;
index aac8bc1..eb008e8 100644 (file)
@@ -2877,9 +2877,9 @@ static int renesas_usb3_probe(struct platform_device *pdev)
                struct rzv2m_usb3drd *ddata = dev_get_drvdata(pdev->dev.parent);
 
                usb3->drd_reg = ddata->reg;
-               ret = devm_request_irq(ddata->dev, ddata->drd_irq,
+               ret = devm_request_irq(&pdev->dev, ddata->drd_irq,
                                       renesas_usb3_otg_irq, 0,
-                                      dev_name(ddata->dev), usb3);
+                                      dev_name(&pdev->dev), usb3);
                if (ret < 0)
                        return ret;
        }
index 644a554..fd42e3a 100644 (file)
@@ -248,6 +248,8 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_VENDOR_ID                      0x2c7c
 /* These Quectel products use Quectel's vendor ID */
 #define QUECTEL_PRODUCT_EC21                   0x0121
+#define QUECTEL_PRODUCT_EM061K_LTA             0x0123
+#define QUECTEL_PRODUCT_EM061K_LMS             0x0124
 #define QUECTEL_PRODUCT_EC25                   0x0125
 #define QUECTEL_PRODUCT_EG91                   0x0191
 #define QUECTEL_PRODUCT_EG95                   0x0195
@@ -266,6 +268,8 @@ static void option_instat_callback(struct urb *urb);
 #define QUECTEL_PRODUCT_RM520N                 0x0801
 #define QUECTEL_PRODUCT_EC200U                 0x0901
 #define QUECTEL_PRODUCT_EC200S_CN              0x6002
+#define QUECTEL_PRODUCT_EM061K_LWW             0x6008
+#define QUECTEL_PRODUCT_EM061K_LCN             0x6009
 #define QUECTEL_PRODUCT_EC200T                 0x6026
 #define QUECTEL_PRODUCT_RM500K                 0x7001
 
@@ -1189,6 +1193,18 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0x00, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x30) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM060K, 0xff, 0xff, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LCN, 0xff, 0xff, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LMS, 0xff, 0xff, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LTA, 0xff, 0xff, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x30) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0x00, 0x40) },
+       { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM061K_LWW, 0xff, 0xff, 0x40) },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0xff, 0xff),
          .driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
        { USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EM12, 0xff, 0, 0) },
index 0bcde1f..8cc66e4 100644 (file)
@@ -95,7 +95,7 @@ peak_current_show(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t
 fast_role_swap_current_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return sysfs_emit(buf, "%u\n", to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3;
+       return sysfs_emit(buf, "%u\n", (to_pdo(dev)->pdo >> PDO_FIXED_FRS_CURR_SHIFT) & 3);
 }
 static DEVICE_ATTR_RO(fast_role_swap_current);
 
index 2b472ec..b664ecb 100644 (file)
@@ -132,10 +132,8 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
        if (ret)
                return ret;
 
-       if (cci & UCSI_CCI_BUSY) {
-               ucsi->ops->async_write(ucsi, UCSI_CANCEL, NULL, 0);
-               return -EBUSY;
-       }
+       if (cmd != UCSI_CANCEL && cci & UCSI_CCI_BUSY)
+               return ucsi_exec_command(ucsi, UCSI_CANCEL);
 
        if (!(cci & UCSI_CCI_COMMAND_COMPLETE))
                return -EIO;
@@ -149,6 +147,11 @@ static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd)
                return ucsi_read_error(ucsi);
        }
 
+       if (cmd == UCSI_CANCEL && cci & UCSI_CCI_CANCEL_COMPLETE) {
+               ret = ucsi_acknowledge_command(ucsi);
+               return ret ? ret : -EBUSY;
+       }
+
        return UCSI_CCI_LENGTH(cci);
 }
 
index e29e32b..279ac6a 100644 (file)
@@ -3349,10 +3349,10 @@ static void mlx5_vdpa_dev_del(struct vdpa_mgmt_dev *v_mdev, struct vdpa_device *
        mlx5_vdpa_remove_debugfs(ndev->debugfs);
        ndev->debugfs = NULL;
        unregister_link_notifier(ndev);
+       _vdpa_unregister_device(dev);
        wq = mvdev->wq;
        mvdev->wq = NULL;
        destroy_workqueue(wq);
-       _vdpa_unregister_device(dev);
        mgtdev->ndev = NULL;
 }
 
index de97e38..5f5c216 100644 (file)
@@ -1685,6 +1685,9 @@ static bool vduse_validate_config(struct vduse_dev_config *config)
        if (config->vq_num > 0xffff)
                return false;
 
+       if (!config->name[0])
+               return false;
+
        if (!device_is_allowed(config->device_id))
                return false;
 
index 07181cd..ae22731 100644 (file)
@@ -935,13 +935,18 @@ static void handle_tx_zerocopy(struct vhost_net *net, struct socket *sock)
 
                err = sock->ops->sendmsg(sock, &msg, len);
                if (unlikely(err < 0)) {
+                       bool retry = err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS;
+
                        if (zcopy_used) {
                                if (vq->heads[ubuf->desc].len == VHOST_DMA_IN_PROGRESS)
                                        vhost_net_ubuf_put(ubufs);
-                               nvq->upend_idx = ((unsigned)nvq->upend_idx - 1)
-                                       % UIO_MAXIOV;
+                               if (retry)
+                                       nvq->upend_idx = ((unsigned)nvq->upend_idx - 1)
+                                               % UIO_MAXIOV;
+                               else
+                                       vq->heads[ubuf->desc].len = VHOST_DMA_DONE_LEN;
                        }
-                       if (err == -EAGAIN || err == -ENOMEM || err == -ENOBUFS) {
+                       if (retry) {
                                vhost_discard_vq_desc(vq, 1);
                                vhost_net_enable_vq(net, vq);
                                break;
index 8c1aefc..bf77924 100644 (file)
@@ -407,7 +407,10 @@ static long vhost_vdpa_set_features(struct vhost_vdpa *v, u64 __user *featurep)
 {
        struct vdpa_device *vdpa = v->vdpa;
        const struct vdpa_config_ops *ops = vdpa->config;
+       struct vhost_dev *d = &v->vdev;
+       u64 actual_features;
        u64 features;
+       int i;
 
        /*
         * It's not allowed to change the features after they have
@@ -422,6 +425,16 @@ static long vhost_vdpa_set_features(struct vhost_vdpa *v, u64 __user *featurep)
        if (vdpa_set_features(vdpa, features))
                return -EINVAL;
 
+       /* let the vqs know what has been configured */
+       actual_features = ops->get_driver_features(vdpa);
+       for (i = 0; i < d->nvqs; ++i) {
+               struct vhost_virtqueue *vq = d->vqs[i];
+
+               mutex_lock(&vq->mutex);
+               vq->acked_features = actual_features;
+               mutex_unlock(&vq->mutex);
+       }
+
        return 0;
 }
 
@@ -594,7 +607,14 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
                if (r)
                        return r;
 
-               vq->last_avail_idx = vq_state.split.avail_index;
+               if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) {
+                       vq->last_avail_idx = vq_state.packed.last_avail_idx |
+                                            (vq_state.packed.last_avail_counter << 15);
+                       vq->last_used_idx = vq_state.packed.last_used_idx |
+                                           (vq_state.packed.last_used_counter << 15);
+               } else {
+                       vq->last_avail_idx = vq_state.split.avail_index;
+               }
                break;
        }
 
@@ -612,9 +632,15 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
                break;
 
        case VHOST_SET_VRING_BASE:
-               vq_state.split.avail_index = vq->last_avail_idx;
-               if (ops->set_vq_state(vdpa, idx, &vq_state))
-                       r = -EINVAL;
+               if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) {
+                       vq_state.packed.last_avail_idx = vq->last_avail_idx & 0x7fff;
+                       vq_state.packed.last_avail_counter = !!(vq->last_avail_idx & 0x8000);
+                       vq_state.packed.last_used_idx = vq->last_used_idx & 0x7fff;
+                       vq_state.packed.last_used_counter = !!(vq->last_used_idx & 0x8000);
+               } else {
+                       vq_state.split.avail_index = vq->last_avail_idx;
+               }
+               r = ops->set_vq_state(vdpa, idx, &vq_state);
                break;
 
        case VHOST_SET_VRING_CALL:
index 0742730..60c9ebd 100644 (file)
@@ -235,7 +235,7 @@ void vhost_dev_flush(struct vhost_dev *dev)
 {
        struct vhost_flush_struct flush;
 
-       if (dev->worker) {
+       if (dev->worker.vtsk) {
                init_completion(&flush.wait_event);
                vhost_work_init(&flush.work, vhost_flush_work);
 
@@ -247,7 +247,7 @@ EXPORT_SYMBOL_GPL(vhost_dev_flush);
 
 void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
 {
-       if (!dev->worker)
+       if (!dev->worker.vtsk)
                return;
 
        if (!test_and_set_bit(VHOST_WORK_QUEUED, &work->flags)) {
@@ -255,8 +255,8 @@ void vhost_work_queue(struct vhost_dev *dev, struct vhost_work *work)
                 * sure it was not in the list.
                 * test_and_set_bit() implies a memory barrier.
                 */
-               llist_add(&work->node, &dev->worker->work_list);
-               vhost_task_wake(dev->worker->vtsk);
+               llist_add(&work->node, &dev->worker.work_list);
+               vhost_task_wake(dev->worker.vtsk);
        }
 }
 EXPORT_SYMBOL_GPL(vhost_work_queue);
@@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(vhost_work_queue);
 /* A lockless hint for busy polling code to exit the loop */
 bool vhost_has_work(struct vhost_dev *dev)
 {
-       return dev->worker && !llist_empty(&dev->worker->work_list);
+       return !llist_empty(&dev->worker.work_list);
 }
 EXPORT_SYMBOL_GPL(vhost_has_work);
 
@@ -341,6 +341,8 @@ static bool vhost_worker(void *data)
 
        node = llist_del_all(&worker->work_list);
        if (node) {
+               __set_current_state(TASK_RUNNING);
+
                node = llist_reverse_order(node);
                /* make sure flag is seen after deletion */
                smp_wmb();
@@ -456,7 +458,8 @@ void vhost_dev_init(struct vhost_dev *dev,
        dev->umem = NULL;
        dev->iotlb = NULL;
        dev->mm = NULL;
-       dev->worker = NULL;
+       memset(&dev->worker, 0, sizeof(dev->worker));
+       init_llist_head(&dev->worker.work_list);
        dev->iov_limit = iov_limit;
        dev->weight = weight;
        dev->byte_weight = byte_weight;
@@ -530,47 +533,30 @@ static void vhost_detach_mm(struct vhost_dev *dev)
 
 static void vhost_worker_free(struct vhost_dev *dev)
 {
-       struct vhost_worker *worker = dev->worker;
-
-       if (!worker)
+       if (!dev->worker.vtsk)
                return;
 
-       dev->worker = NULL;
-       WARN_ON(!llist_empty(&worker->work_list));
-       vhost_task_stop(worker->vtsk);
-       kfree(worker);
+       WARN_ON(!llist_empty(&dev->worker.work_list));
+       vhost_task_stop(dev->worker.vtsk);
+       dev->worker.kcov_handle = 0;
+       dev->worker.vtsk = NULL;
 }
 
 static int vhost_worker_create(struct vhost_dev *dev)
 {
-       struct vhost_worker *worker;
        struct vhost_task *vtsk;
        char name[TASK_COMM_LEN];
-       int ret;
-
-       worker = kzalloc(sizeof(*worker), GFP_KERNEL_ACCOUNT);
-       if (!worker)
-               return -ENOMEM;
 
-       dev->worker = worker;
-       worker->kcov_handle = kcov_common_handle();
-       init_llist_head(&worker->work_list);
        snprintf(name, sizeof(name), "vhost-%d", current->pid);
 
-       vtsk = vhost_task_create(vhost_worker, worker, name);
-       if (!vtsk) {
-               ret = -ENOMEM;
-               goto free_worker;
-       }
+       vtsk = vhost_task_create(vhost_worker, &dev->worker, name);
+       if (!vtsk)
+               return -ENOMEM;
 
-       worker->vtsk = vtsk;
+       dev->worker.kcov_handle = kcov_common_handle();
+       dev->worker.vtsk = vtsk;
        vhost_task_start(vtsk);
        return 0;
-
-free_worker:
-       kfree(worker);
-       dev->worker = NULL;
-       return ret;
 }
 
 /* Caller should have device mutex */
@@ -1614,17 +1600,25 @@ long vhost_vring_ioctl(struct vhost_dev *d, unsigned int ioctl, void __user *arg
                        r = -EFAULT;
                        break;
                }
-               if (s.num > 0xffff) {
-                       r = -EINVAL;
-                       break;
+               if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED)) {
+                       vq->last_avail_idx = s.num & 0xffff;
+                       vq->last_used_idx = (s.num >> 16) & 0xffff;
+               } else {
+                       if (s.num > 0xffff) {
+                               r = -EINVAL;
+                               break;
+                       }
+                       vq->last_avail_idx = s.num;
                }
-               vq->last_avail_idx = s.num;
                /* Forget the cached index value. */
                vq->avail_idx = vq->last_avail_idx;
                break;
        case VHOST_GET_VRING_BASE:
                s.index = idx;
-               s.num = vq->last_avail_idx;
+               if (vhost_has_feature(vq, VIRTIO_F_RING_PACKED))
+                       s.num = (u32)vq->last_avail_idx | ((u32)vq->last_used_idx << 16);
+               else
+                       s.num = vq->last_avail_idx;
                if (copy_to_user(argp, &s, sizeof s))
                        r = -EFAULT;
                break;
@@ -2563,12 +2557,11 @@ EXPORT_SYMBOL_GPL(vhost_disable_notify);
 /* Create a new message. */
 struct vhost_msg_node *vhost_new_msg(struct vhost_virtqueue *vq, int type)
 {
-       struct vhost_msg_node *node = kmalloc(sizeof *node, GFP_KERNEL);
+       /* Make sure all padding within the structure is initialized. */
+       struct vhost_msg_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
        if (!node)
                return NULL;
 
-       /* Make sure all padding within the structure is initialized. */
-       memset(&node->msg, 0, sizeof node->msg);
        node->vq = vq;
        node->msg.type = type;
        return node;
index 0308638..fc900be 100644 (file)
@@ -92,13 +92,17 @@ struct vhost_virtqueue {
        /* The routine to call when the Guest pings us, or timeout. */
        vhost_work_fn_t handle_kick;
 
-       /* Last available index we saw. */
+       /* Last available index we saw.
+        * Values are limited to 0x7fff, and the high bit is used as
+        * a wrap counter when using VIRTIO_F_RING_PACKED. */
        u16 last_avail_idx;
 
        /* Caches available index value from user. */
        u16 avail_idx;
 
-       /* Last index we used. */
+       /* Last index we used.
+        * Values are limited to 0x7fff, and the high bit is used as
+        * a wrap counter when using VIRTIO_F_RING_PACKED. */
        u16 last_used_idx;
 
        /* Used flags */
@@ -154,7 +158,7 @@ struct vhost_dev {
        struct vhost_virtqueue **vqs;
        int nvqs;
        struct eventfd_ctx *log_ctx;
-       struct vhost_worker *worker;
+       struct vhost_worker worker;
        struct vhost_iotlb *umem;
        struct vhost_iotlb *iotlb;
        spinlock_t iotlb_lock;
index 4dd97af..5219182 100644 (file)
@@ -1358,6 +1358,7 @@ static int afs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
        op->dentry      = dentry;
        op->create.mode = S_IFDIR | mode;
        op->create.reason = afs_edit_dir_for_mkdir;
+       op->mtime       = current_time(dir);
        op->ops         = &afs_mkdir_operation;
        return afs_do_sync_operation(op);
 }
@@ -1661,6 +1662,7 @@ static int afs_create(struct mnt_idmap *idmap, struct inode *dir,
        op->dentry      = dentry;
        op->create.mode = S_IFREG | mode;
        op->create.reason = afs_edit_dir_for_create;
+       op->mtime       = current_time(dir);
        op->ops         = &afs_create_operation;
        return afs_do_sync_operation(op);
 
@@ -1796,6 +1798,7 @@ static int afs_symlink(struct mnt_idmap *idmap, struct inode *dir,
        op->ops                 = &afs_symlink_operation;
        op->create.reason       = afs_edit_dir_for_symlink;
        op->create.symlink      = content;
+       op->mtime               = current_time(dir);
        return afs_do_sync_operation(op);
 
 error:
index d1c7068..58452b8 100644 (file)
@@ -115,8 +115,8 @@ responded:
                }
        }
 
-       if (rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us) &&
-           rtt_us < server->probe.rtt) {
+       rxrpc_kernel_get_srtt(call->net->socket, call->rxcall, &rtt_us);
+       if (rtt_us < server->probe.rtt) {
                server->probe.rtt = rtt_us;
                server->rtt = rtt_us;
                alist->preferred = index;
index c822d60..8750b99 100644 (file)
@@ -731,6 +731,7 @@ static int afs_writepages_region(struct address_space *mapping,
                         * (changing page->mapping to NULL), or even swizzled
                         * back from swapper_space to tmpfs file mapping
                         */
+try_again:
                        if (wbc->sync_mode != WB_SYNC_NONE) {
                                ret = folio_lock_killable(folio);
                                if (ret < 0) {
@@ -757,12 +758,14 @@ static int afs_writepages_region(struct address_space *mapping,
 #ifdef CONFIG_AFS_FSCACHE
                                        folio_wait_fscache(folio);
 #endif
-                               } else {
-                                       start += folio_size(folio);
+                                       goto try_again;
                                }
+
+                               start += folio_size(folio);
                                if (wbc->sync_mode == WB_SYNC_NONE) {
                                        if (skips >= 5 || need_resched()) {
                                                *_next = start;
+                                               folio_batch_release(&fbatch);
                                                _leave(" = 0 [%llx]", *_next);
                                                return 0;
                                        }
index 2b1b227..dabc79c 100644 (file)
@@ -242,7 +242,6 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
                                      int mirror_num)
 {
        struct btrfs_fs_info *fs_info = eb->fs_info;
-       u64 start = eb->start;
        int i, num_pages = num_extent_pages(eb);
        int ret = 0;
 
@@ -251,12 +250,14 @@ static int btrfs_repair_eb_io_failure(const struct extent_buffer *eb,
 
        for (i = 0; i < num_pages; i++) {
                struct page *p = eb->pages[i];
+               u64 start = max_t(u64, eb->start, page_offset(p));
+               u64 end = min_t(u64, eb->start + eb->len, page_offset(p) + PAGE_SIZE);
+               u32 len = end - start;
 
-               ret = btrfs_repair_io_failure(fs_info, 0, start, PAGE_SIZE,
-                               start, p, start - page_offset(p), mirror_num);
+               ret = btrfs_repair_io_failure(fs_info, 0, start, len,
+                               start, p, offset_in_page(start), mirror_num);
                if (ret)
                        break;
-               start += PAGE_SIZE;
        }
 
        return ret;
@@ -995,13 +996,18 @@ int btrfs_global_root_insert(struct btrfs_root *root)
 {
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct rb_node *tmp;
+       int ret = 0;
 
        write_lock(&fs_info->global_root_lock);
        tmp = rb_find_add(&root->rb_node, &fs_info->global_root_tree, global_root_cmp);
        write_unlock(&fs_info->global_root_lock);
-       ASSERT(!tmp);
 
-       return tmp ? -EEXIST : 0;
+       if (tmp) {
+               ret = -EEXIST;
+               btrfs_warn(fs_info, "global root %llu %llu already exists",
+                               root->root_key.objectid, root->root_key.offset);
+       }
+       return ret;
 }
 
 void btrfs_global_root_delete(struct btrfs_root *root)
@@ -2841,6 +2847,7 @@ static int __cold init_tree_roots(struct btrfs_fs_info *fs_info)
                        /* We can't trust the free space cache either */
                        btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE);
 
+                       btrfs_warn(fs_info, "try to load backup roots slot %d", i);
                        ret = read_backup_root(fs_info, i);
                        backup_index = ret;
                        if (ret < 0)
index 19c707b..7fcafcc 100644 (file)
@@ -1864,7 +1864,7 @@ static int can_nocow_file_extent(struct btrfs_path *path,
 
        ret = btrfs_cross_ref_exist(root, btrfs_ino(inode),
                                    key->offset - args->extent_offset,
-                                   args->disk_bytenr, false, path);
+                                   args->disk_bytenr, args->strict, path);
        WARN_ON_ONCE(ret > 0 && is_freespace_inode);
        if (ret != 0)
                goto out;
@@ -7264,7 +7264,7 @@ static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
 static int btrfs_get_blocks_direct_write(struct extent_map **map,
                                         struct inode *inode,
                                         struct btrfs_dio_data *dio_data,
-                                        u64 start, u64 len,
+                                        u64 start, u64 *lenp,
                                         unsigned int iomap_flags)
 {
        const bool nowait = (iomap_flags & IOMAP_NOWAIT);
@@ -7275,6 +7275,7 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
        struct btrfs_block_group *bg;
        bool can_nocow = false;
        bool space_reserved = false;
+       u64 len = *lenp;
        u64 prev_len;
        int ret = 0;
 
@@ -7345,15 +7346,19 @@ static int btrfs_get_blocks_direct_write(struct extent_map **map,
                free_extent_map(em);
                *map = NULL;
 
-               if (nowait)
-                       return -EAGAIN;
+               if (nowait) {
+                       ret = -EAGAIN;
+                       goto out;
+               }
 
                /*
                 * If we could not allocate data space before locking the file
                 * range and we can't do a NOCOW write, then we have to fail.
                 */
-               if (!dio_data->data_space_reserved)
-                       return -ENOSPC;
+               if (!dio_data->data_space_reserved) {
+                       ret = -ENOSPC;
+                       goto out;
+               }
 
                /*
                 * We have to COW and we have already reserved data space before,
@@ -7394,6 +7399,7 @@ out:
                btrfs_delalloc_release_extents(BTRFS_I(inode), len);
                btrfs_delalloc_release_metadata(BTRFS_I(inode), len, true);
        }
+       *lenp = len;
        return ret;
 }
 
@@ -7570,7 +7576,7 @@ static int btrfs_dio_iomap_begin(struct inode *inode, loff_t start,
 
        if (write) {
                ret = btrfs_get_blocks_direct_write(&em, inode, dio_data,
-                                                   start, len, flags);
+                                                   start, &len, flags);
                if (ret < 0)
                        goto unlock_err;
                unlock_extents = true;
index 7c66651..bceaa8c 100644 (file)
@@ -134,8 +134,14 @@ struct scrub_stripe {
         * The errors hit during the initial read of the stripe.
         *
         * Would be utilized for error reporting and repair.
+        *
+        * The remaining init_nr_* records the number of errors hit, only used
+        * by error reporting.
         */
        unsigned long init_error_bitmap;
+       unsigned int init_nr_io_errors;
+       unsigned int init_nr_csum_errors;
+       unsigned int init_nr_meta_errors;
 
        /*
         * The following error bitmaps are all for the current status.
@@ -1003,12 +1009,9 @@ skip:
        sctx->stat.data_bytes_scrubbed += nr_data_sectors << fs_info->sectorsize_bits;
        sctx->stat.tree_bytes_scrubbed += nr_meta_sectors << fs_info->sectorsize_bits;
        sctx->stat.no_csum += nr_nodatacsum_sectors;
-       sctx->stat.read_errors +=
-               bitmap_weight(&stripe->io_error_bitmap, stripe->nr_sectors);
-       sctx->stat.csum_errors +=
-               bitmap_weight(&stripe->csum_error_bitmap, stripe->nr_sectors);
-       sctx->stat.verify_errors +=
-               bitmap_weight(&stripe->meta_error_bitmap, stripe->nr_sectors);
+       sctx->stat.read_errors += stripe->init_nr_io_errors;
+       sctx->stat.csum_errors += stripe->init_nr_csum_errors;
+       sctx->stat.verify_errors += stripe->init_nr_meta_errors;
        sctx->stat.uncorrectable_errors +=
                bitmap_weight(&stripe->error_bitmap, stripe->nr_sectors);
        sctx->stat.corrected_errors += nr_repaired_sectors;
@@ -1041,6 +1044,12 @@ static void scrub_stripe_read_repair_worker(struct work_struct *work)
        scrub_verify_one_stripe(stripe, stripe->extent_sector_bitmap);
        /* Save the initial failed bitmap for later repair and report usage. */
        stripe->init_error_bitmap = stripe->error_bitmap;
+       stripe->init_nr_io_errors = bitmap_weight(&stripe->io_error_bitmap,
+                                                 stripe->nr_sectors);
+       stripe->init_nr_csum_errors = bitmap_weight(&stripe->csum_error_bitmap,
+                                                   stripe->nr_sectors);
+       stripe->init_nr_meta_errors = bitmap_weight(&stripe->meta_error_bitmap,
+                                                   stripe->nr_sectors);
 
        if (bitmap_empty(&stripe->init_error_bitmap, stripe->nr_sectors))
                goto out;
@@ -1490,6 +1499,9 @@ static void scrub_stripe_reset_bitmaps(struct scrub_stripe *stripe)
 {
        stripe->extent_sector_bitmap = 0;
        stripe->init_error_bitmap = 0;
+       stripe->init_nr_io_errors = 0;
+       stripe->init_nr_csum_errors = 0;
+       stripe->init_nr_meta_errors = 0;
        stripe->error_bitmap = 0;
        stripe->io_error_bitmap = 0;
        stripe->csum_error_bitmap = 0;
@@ -1730,7 +1742,7 @@ static int flush_scrub_stripes(struct scrub_ctx *sctx)
                                break;
                        }
                }
-       } else {
+       } else if (!sctx->readonly) {
                for (int i = 0; i < nr_stripes; i++) {
                        unsigned long repaired;
 
@@ -2254,7 +2266,7 @@ next:
        }
 out:
        ret2 = flush_scrub_stripes(sctx);
-       if (!ret2)
+       if (!ret)
                ret = ret2;
        if (sctx->raid56_data_stripes) {
                for (int i = 0; i < nr_data_stripes(map); i++)
index ec18e22..efeb1a9 100644 (file)
@@ -1841,6 +1841,12 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                btrfs_clear_sb_rdonly(sb);
 
                set_bit(BTRFS_FS_OPEN, &fs_info->flags);
+
+               /*
+                * If we've gone from readonly -> read/write, we need to get
+                * our sync/async discard lists in the right state.
+                */
+               btrfs_discard_resume(fs_info);
        }
 out:
        /*
index 841e799..e60beb1 100644 (file)
@@ -5975,12 +5975,12 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
        stripe_nr = offset >> BTRFS_STRIPE_LEN_SHIFT;
 
        /* stripe_offset is the offset of this block in its stripe */
-       stripe_offset = offset - (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
+       stripe_offset = offset - ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 
        stripe_nr_end = round_up(offset + length, BTRFS_STRIPE_LEN) >>
                        BTRFS_STRIPE_LEN_SHIFT;
        stripe_cnt = stripe_nr_end - stripe_nr;
-       stripe_end_offset = (stripe_nr_end << BTRFS_STRIPE_LEN_SHIFT) -
+       stripe_end_offset = ((u64)stripe_nr_end << BTRFS_STRIPE_LEN_SHIFT) -
                            (offset + length);
        /*
         * after this, stripe_nr is the number of stripes on this
@@ -6023,7 +6023,7 @@ struct btrfs_discard_stripe *btrfs_map_discard(struct btrfs_fs_info *fs_info,
        for (i = 0; i < *num_stripes; i++) {
                stripes[i].physical =
                        map->stripes[stripe_index].physical +
-                       stripe_offset + (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
+                       stripe_offset + ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
                stripes[i].dev = map->stripes[stripe_index].dev;
 
                if (map->type & (BTRFS_BLOCK_GROUP_RAID0 |
@@ -6196,9 +6196,11 @@ static u64 btrfs_max_io_len(struct map_lookup *map, enum btrfs_map_op op,
                 * not ensured to be power of 2.
                 */
                *full_stripe_start =
-                       rounddown(*stripe_nr, nr_data_stripes(map)) <<
+                       (u64)rounddown(*stripe_nr, nr_data_stripes(map)) <<
                        BTRFS_STRIPE_LEN_SHIFT;
 
+               ASSERT(*full_stripe_start + full_stripe_len > offset);
+               ASSERT(*full_stripe_start <= offset);
                /*
                 * For writes to RAID56, allow to write a full stripe set, but
                 * no straddling of stripe sets.
@@ -6221,7 +6223,7 @@ static void set_io_stripe(struct btrfs_io_stripe *dst, const struct map_lookup *
 {
        dst->dev = map->stripes[stripe_index].dev;
        dst->physical = map->stripes[stripe_index].physical +
-                       stripe_offset + (stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
+                       stripe_offset + ((u64)stripe_nr << BTRFS_STRIPE_LEN_SHIFT);
 }
 
 int __btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
index 789be30..2321e5d 100644 (file)
@@ -1627,6 +1627,7 @@ void ceph_flush_snaps(struct ceph_inode_info *ci,
        struct inode *inode = &ci->netfs.inode;
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
        struct ceph_mds_session *session = NULL;
+       bool need_put = false;
        int mds;
 
        dout("ceph_flush_snaps %p\n", inode);
@@ -1671,8 +1672,13 @@ out:
                ceph_put_mds_session(session);
        /* we flushed them all; remove this inode from the queue */
        spin_lock(&mdsc->snap_flush_lock);
+       if (!list_empty(&ci->i_snap_flush_item))
+               need_put = true;
        list_del_init(&ci->i_snap_flush_item);
        spin_unlock(&mdsc->snap_flush_lock);
+
+       if (need_put)
+               iput(inode);
 }
 
 /*
index 0b236eb..2e73ba6 100644 (file)
@@ -693,8 +693,10 @@ int __ceph_finish_cap_snap(struct ceph_inode_info *ci,
             capsnap->size);
 
        spin_lock(&mdsc->snap_flush_lock);
-       if (list_empty(&ci->i_snap_flush_item))
+       if (list_empty(&ci->i_snap_flush_item)) {
+               ihold(inode);
                list_add_tail(&ci->i_snap_flush_item, &mdsc->snap_flush_list);
+       }
        spin_unlock(&mdsc->snap_flush_lock);
        return 1;  /* caller may want to ceph_flush_snaps */
 }
index 9804834..266d45c 100644 (file)
@@ -1805,7 +1805,11 @@ static int ep_autoremove_wake_function(struct wait_queue_entry *wq_entry,
 {
        int ret = default_wake_function(wq_entry, mode, sync, key);
 
-       list_del_init(&wq_entry->entry);
+       /*
+        * Pairs with list_empty_careful in ep_poll, and ensures future loop
+        * iterations see the cause of this wakeup.
+        */
+       list_del_init_careful(&wq_entry->entry);
        return ret;
 }
 
index c1edde8..1f72f97 100644 (file)
@@ -324,17 +324,15 @@ static ext4_fsblk_t ext4_valid_block_bitmap_padding(struct super_block *sb,
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
                                            ext4_group_t group)
 {
-        struct ext4_group_info **grp_info;
-        long indexv, indexh;
-
-        if (unlikely(group >= EXT4_SB(sb)->s_groups_count)) {
-                ext4_error(sb, "invalid group %u", group);
-                return NULL;
-        }
-        indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
-        indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
-        grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
-        return grp_info[indexh];
+       struct ext4_group_info **grp_info;
+       long indexv, indexh;
+
+       if (unlikely(group >= EXT4_SB(sb)->s_groups_count))
+               return NULL;
+       indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
+       indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
+       grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
+       return grp_info[indexh];
 }
 
 /*
@@ -886,7 +884,10 @@ static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
        if (!ext4_bg_has_super(sb, group))
                return 0;
 
-       return EXT4_SB(sb)->s_gdb_count;
+       if (ext4_has_feature_meta_bg(sb))
+               return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
+       else
+               return EXT4_SB(sb)->s_gdb_count;
 }
 
 /**
index 56a5d1c..05fcecc 100644 (file)
@@ -6388,7 +6388,6 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
        struct ext4_mount_options old_opts;
        ext4_group_t g;
        int err = 0;
-       int enable_rw = 0;
 #ifdef CONFIG_QUOTA
        int enable_quota = 0;
        int i, j;
@@ -6575,7 +6574,7 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
                        if (err)
                                goto restore_opts;
 
-                       enable_rw = 1;
+                       sb->s_flags &= ~SB_RDONLY;
                        if (ext4_has_feature_mmp(sb)) {
                                err = ext4_multi_mount_protect(sb,
                                                le64_to_cpu(es->s_mmp_block));
@@ -6622,9 +6621,6 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
        if (!test_opt(sb, BLOCK_VALIDITY) && sbi->s_system_blks)
                ext4_release_system_zone(sb);
 
-       if (enable_rw)
-               sb->s_flags &= ~SB_RDONLY;
-
        /*
         * Reinitialize lazy itable initialization thread based on
         * current settings
index 13d7f17..321e3a8 100644 (file)
@@ -2056,8 +2056,9 @@ inserted:
                        else {
                                u32 ref;
 
+#ifdef EXT4_XATTR_DEBUG
                                WARN_ON_ONCE(dquot_initialize_needed(inode));
-
+#endif
                                /* The old block is released after updating
                                   the inode. */
                                error = dquot_alloc_block(inode,
@@ -2120,8 +2121,9 @@ inserted:
                        /* We need to allocate a new block */
                        ext4_fsblk_t goal, block;
 
+#ifdef EXT4_XATTR_DEBUG
                        WARN_ON_ONCE(dquot_initialize_needed(inode));
-
+#endif
                        goal = ext4_group_first_block_no(sb,
                                                EXT4_I(inode)->i_block_group);
                        block = ext4_new_meta_blocks(handle, inode, goal, 0,
index 300844f..cb62c8f 100644 (file)
@@ -784,9 +784,13 @@ static inline bool should_fault_in_pages(struct iov_iter *i,
        if (!user_backed_iter(i))
                return false;
 
+       /*
+        * Try to fault in multiple pages initially.  When that doesn't result
+        * in any progress, fall back to a single page.
+        */
        size = PAGE_SIZE;
        offs = offset_in_page(iocb->ki_pos);
-       if (*prev_count != count || !*window_size) {
+       if (*prev_count != count) {
                size_t nr_dirtied;
 
                nr_dirtied = max(current->nr_dirtied_pause -
@@ -870,6 +874,7 @@ static ssize_t gfs2_file_direct_write(struct kiocb *iocb, struct iov_iter *from,
        struct gfs2_inode *ip = GFS2_I(inode);
        size_t prev_count = 0, window_size = 0;
        size_t written = 0;
+       bool enough_retries;
        ssize_t ret;
 
        /*
@@ -913,11 +918,17 @@ retry:
        if (ret > 0)
                written = ret;
 
+       enough_retries = prev_count == iov_iter_count(from) &&
+                        window_size <= PAGE_SIZE;
        if (should_fault_in_pages(from, iocb, &prev_count, &window_size)) {
                gfs2_glock_dq(gh);
                window_size -= fault_in_iov_iter_readable(from, window_size);
-               if (window_size)
-                       goto retry;
+               if (window_size) {
+                       if (!enough_retries)
+                               goto retry;
+                       /* fall back to buffered I/O */
+                       ret = 0;
+               }
        }
 out_unlock:
        if (gfs2_holder_queued(gh))
index e956f88..5710833 100644 (file)
@@ -285,6 +285,14 @@ void nilfs_btnode_abort_change_key(struct address_space *btnc,
        if (nbh == NULL) {      /* blocksize == pagesize */
                xa_erase_irq(&btnc->i_pages, newkey);
                unlock_page(ctxt->bh->b_page);
-       } else
-               brelse(nbh);
+       } else {
+               /*
+                * When canceling a buffer that a prepare operation has
+                * allocated to copy a node block to another location, use
+                * nilfs_btnode_delete() to initialize and release the buffer
+                * so that the buffer flags will not be in an inconsistent
+                * state when it is reallocated.
+                */
+               nilfs_btnode_delete(nbh);
+       }
 }
index dc359b5..2c6078a 100644 (file)
@@ -779,6 +779,15 @@ int nilfs_sufile_resize(struct inode *sufile, __u64 newnsegs)
                        goto out_header;
 
                sui->ncleansegs -= nsegs - newnsegs;
+
+               /*
+                * If the sufile is successfully truncated, immediately adjust
+                * the segment allocation space while locking the semaphore
+                * "mi_sem" so that nilfs_sufile_alloc() never allocates
+                * segments in the truncated space.
+                */
+               sui->allocmax = newnsegs - 1;
+               sui->allocmin = 0;
        }
 
        kaddr = kmap_atomic(header_bh->b_page);
index 2894152..0f06679 100644 (file)
@@ -405,6 +405,18 @@ unsigned long nilfs_nrsvsegs(struct the_nilfs *nilfs, unsigned long nsegs)
                                  100));
 }
 
+/**
+ * nilfs_max_segment_count - calculate the maximum number of segments
+ * @nilfs: nilfs object
+ */
+static u64 nilfs_max_segment_count(struct the_nilfs *nilfs)
+{
+       u64 max_count = U64_MAX;
+
+       do_div(max_count, nilfs->ns_blocks_per_segment);
+       return min_t(u64, max_count, ULONG_MAX);
+}
+
 void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs)
 {
        nilfs->ns_nsegments = nsegs;
@@ -414,6 +426,8 @@ void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs)
 static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                                   struct nilfs_super_block *sbp)
 {
+       u64 nsegments, nblocks;
+
        if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) {
                nilfs_err(nilfs->ns_sb,
                          "unsupported revision (superblock rev.=%d.%d, current rev.=%d.%d). Please check the version of mkfs.nilfs(2).",
@@ -457,7 +471,34 @@ static int nilfs_store_disk_layout(struct the_nilfs *nilfs,
                return -EINVAL;
        }
 
-       nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments));
+       nsegments = le64_to_cpu(sbp->s_nsegments);
+       if (nsegments > nilfs_max_segment_count(nilfs)) {
+               nilfs_err(nilfs->ns_sb,
+                         "segment count %llu exceeds upper limit (%llu segments)",
+                         (unsigned long long)nsegments,
+                         (unsigned long long)nilfs_max_segment_count(nilfs));
+               return -EINVAL;
+       }
+
+       nblocks = sb_bdev_nr_blocks(nilfs->ns_sb);
+       if (nblocks) {
+               u64 min_block_count = nsegments * nilfs->ns_blocks_per_segment;
+               /*
+                * To avoid failing to mount early device images without a
+                * second superblock, exclude that block count from the
+                * "min_block_count" calculation.
+                */
+
+               if (nblocks < min_block_count) {
+                       nilfs_err(nilfs->ns_sb,
+                                 "total number of segment blocks %llu exceeds device size (%llu blocks)",
+                                 (unsigned long long)min_block_count,
+                                 (unsigned long long)nblocks);
+                       return -EINVAL;
+               }
+       }
+
+       nilfs_set_nsegments(nilfs, nsegments);
        nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed);
        return 0;
 }
index efb09de..b173c36 100644 (file)
@@ -2100,14 +2100,20 @@ static long ocfs2_fallocate(struct file *file, int mode, loff_t offset,
        struct ocfs2_space_resv sr;
        int change_size = 1;
        int cmd = OCFS2_IOC_RESVSP64;
+       int ret = 0;
 
        if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
                return -EOPNOTSUPP;
        if (!ocfs2_writes_unwritten_extents(osb))
                return -EOPNOTSUPP;
 
-       if (mode & FALLOC_FL_KEEP_SIZE)
+       if (mode & FALLOC_FL_KEEP_SIZE) {
                change_size = 0;
+       } else {
+               ret = inode_newsize_ok(inode, offset + len);
+               if (ret)
+                       return ret;
+       }
 
        if (mode & FALLOC_FL_PUNCH_HOLE)
                cmd = OCFS2_IOC_UNRESVSP64;
index 0b0e6a1..988d1c0 100644 (file)
@@ -952,8 +952,10 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
        for (type = 0; type < OCFS2_MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
-               oinfo = sb_dqinfo(sb, type)->dqi_priv;
-               cancel_delayed_work_sync(&oinfo->dqi_sync_work);
+               if (!sb_has_quota_suspended(sb, type)) {
+                       oinfo = sb_dqinfo(sb, type)->dqi_priv;
+                       cancel_delayed_work_sync(&oinfo->dqi_sync_work);
+               }
                inode = igrab(sb->s_dquot.files[type]);
                /* Turn off quotas. This will remove all dquot structures from
                 * memory and so they will be automatically synced to global
index 5034b86..b279f74 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/proc_fs.h>
 #include <linux/uaccess.h>
+#include <uapi/linux/ethtool.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -130,12 +131,14 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
        struct TCP_Server_Info *server = chan->server;
 
        seq_printf(m, "\n\n\t\tChannel: %d ConnectionId: 0x%llx"
-                  "\n\t\tNumber of credits: %d Dialect 0x%x"
+                  "\n\t\tNumber of credits: %d,%d,%d Dialect 0x%x"
                   "\n\t\tTCP status: %d Instance: %d"
                   "\n\t\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d"
                   "\n\t\tIn Send: %d In MaxReq Wait: %d",
                   i+1, server->conn_id,
                   server->credits,
+                  server->echo_credits,
+                  server->oplock_credits,
                   server->dialect,
                   server->tcpStatus,
                   server->reconnect_instance,
@@ -146,18 +149,62 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
                   atomic_read(&server->num_waiters));
 }
 
+static inline const char *smb_speed_to_str(size_t bps)
+{
+       size_t mbps = bps / 1000 / 1000;
+
+       switch (mbps) {
+       case SPEED_10:
+               return "10Mbps";
+       case SPEED_100:
+               return "100Mbps";
+       case SPEED_1000:
+               return "1Gbps";
+       case SPEED_2500:
+               return "2.5Gbps";
+       case SPEED_5000:
+               return "5Gbps";
+       case SPEED_10000:
+               return "10Gbps";
+       case SPEED_14000:
+               return "14Gbps";
+       case SPEED_20000:
+               return "20Gbps";
+       case SPEED_25000:
+               return "25Gbps";
+       case SPEED_40000:
+               return "40Gbps";
+       case SPEED_50000:
+               return "50Gbps";
+       case SPEED_56000:
+               return "56Gbps";
+       case SPEED_100000:
+               return "100Gbps";
+       case SPEED_200000:
+               return "200Gbps";
+       case SPEED_400000:
+               return "400Gbps";
+       case SPEED_800000:
+               return "800Gbps";
+       default:
+               return "Unknown";
+       }
+}
+
 static void
 cifs_dump_iface(struct seq_file *m, struct cifs_server_iface *iface)
 {
        struct sockaddr_in *ipv4 = (struct sockaddr_in *)&iface->sockaddr;
        struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)&iface->sockaddr;
 
-       seq_printf(m, "\tSpeed: %zu bps\n", iface->speed);
+       seq_printf(m, "\tSpeed: %s\n", smb_speed_to_str(iface->speed));
        seq_puts(m, "\t\tCapabilities: ");
        if (iface->rdma_capable)
                seq_puts(m, "rdma ");
        if (iface->rss_capable)
                seq_puts(m, "rss ");
+       if (!iface->rdma_capable && !iface->rss_capable)
+               seq_puts(m, "None");
        seq_putc(m, '\n');
        if (iface->sockaddr.ss_family == AF_INET)
                seq_printf(m, "\t\tIPv4: %pI4\n", &ipv4->sin_addr);
@@ -350,8 +397,11 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
                        atomic_read(&server->smbd_conn->mr_used_count));
 skip_rdma:
 #endif
-               seq_printf(m, "\nNumber of credits: %d Dialect 0x%x",
-                       server->credits,  server->dialect);
+               seq_printf(m, "\nNumber of credits: %d,%d,%d Dialect 0x%x",
+                       server->credits,
+                       server->echo_credits,
+                       server->oplock_credits,
+                       server->dialect);
                if (server->compress_algorithm == SMB3_COMPRESS_LZNT1)
                        seq_printf(m, " COMPRESS_LZNT1");
                else if (server->compress_algorithm == SMB3_COMPRESS_LZ77)
index 0d84bb1..b212a4e 100644 (file)
@@ -970,43 +970,6 @@ release_iface(struct kref *ref)
        kfree(iface);
 }
 
-/*
- * compare two interfaces a and b
- * return 0 if everything matches.
- * return 1 if a has higher link speed, or rdma capable, or rss capable
- * return -1 otherwise.
- */
-static inline int
-iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
-{
-       int cmp_ret = 0;
-
-       WARN_ON(!a || !b);
-       if (a->speed == b->speed) {
-               if (a->rdma_capable == b->rdma_capable) {
-                       if (a->rss_capable == b->rss_capable) {
-                               cmp_ret = memcmp(&a->sockaddr, &b->sockaddr,
-                                                sizeof(a->sockaddr));
-                               if (!cmp_ret)
-                                       return 0;
-                               else if (cmp_ret > 0)
-                                       return 1;
-                               else
-                                       return -1;
-                       } else if (a->rss_capable > b->rss_capable)
-                               return 1;
-                       else
-                               return -1;
-               } else if (a->rdma_capable > b->rdma_capable)
-                       return 1;
-               else
-                       return -1;
-       } else if (a->speed > b->speed)
-               return 1;
-       else
-               return -1;
-}
-
 struct cifs_chan {
        unsigned int in_reconnect : 1; /* if session setup in progress for this channel */
        struct TCP_Server_Info *server;
index c1c7049..d127ade 100644 (file)
@@ -87,6 +87,7 @@ extern int cifs_handle_standard(struct TCP_Server_Info *server,
                                struct mid_q_entry *mid);
 extern int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx);
 extern int smb3_parse_opt(const char *options, const char *key, char **val);
+extern int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs);
 extern int cifs_discard_remaining_data(struct TCP_Server_Info *server);
 extern int cifs_call_async(struct TCP_Server_Info *server,
index 8e9a672..9d16626 100644 (file)
@@ -1288,6 +1288,56 @@ next_pdu:
        module_put_and_kthread_exit(0);
 }
 
+int
+cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs)
+{
+       struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
+       struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
+       struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
+       struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)rhs;
+
+       switch (srcaddr->sa_family) {
+       case AF_UNSPEC:
+               switch (rhs->sa_family) {
+               case AF_UNSPEC:
+                       return 0;
+               case AF_INET:
+               case AF_INET6:
+                       return 1;
+               default:
+                       return -1;
+               }
+       case AF_INET: {
+               switch (rhs->sa_family) {
+               case AF_UNSPEC:
+                       return -1;
+               case AF_INET:
+                       return memcmp(saddr4, vaddr4,
+                                     sizeof(struct sockaddr_in));
+               case AF_INET6:
+                       return 1;
+               default:
+                       return -1;
+               }
+       }
+       case AF_INET6: {
+               switch (rhs->sa_family) {
+               case AF_UNSPEC:
+               case AF_INET:
+                       return -1;
+               case AF_INET6:
+                       return memcmp(saddr6,
+                                     vaddr6,
+                                     sizeof(struct sockaddr_in6));
+               default:
+                       return -1;
+               }
+       }
+       default:
+               return -1; /* don't expect to be here */
+       }
+}
+
 /*
  * Returns true if srcaddr isn't specified and rhs isn't specified, or
  * if srcaddr is specified and matches the IP address of the rhs argument
@@ -4086,16 +4136,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
 
        /* only send once per connect */
        spin_lock(&tcon->tc_lock);
+       if (tcon->status == TID_GOOD) {
+               spin_unlock(&tcon->tc_lock);
+               return 0;
+       }
+
        if (tcon->status != TID_NEW &&
            tcon->status != TID_NEED_TCON) {
                spin_unlock(&tcon->tc_lock);
                return -EHOSTDOWN;
        }
 
-       if (tcon->status == TID_GOOD) {
-               spin_unlock(&tcon->tc_lock);
-               return 0;
-       }
        tcon->status = TID_IN_TCON;
        spin_unlock(&tcon->tc_lock);
 
index 2f93bf8..2390b2f 100644 (file)
@@ -575,16 +575,17 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
 
        /* only send once per connect */
        spin_lock(&tcon->tc_lock);
+       if (tcon->status == TID_GOOD) {
+               spin_unlock(&tcon->tc_lock);
+               return 0;
+       }
+
        if (tcon->status != TID_NEW &&
            tcon->status != TID_NEED_TCON) {
                spin_unlock(&tcon->tc_lock);
                return -EHOSTDOWN;
        }
 
-       if (tcon->status == TID_GOOD) {
-               spin_unlock(&tcon->tc_lock);
-               return 0;
-       }
        tcon->status = TID_IN_TCON;
        spin_unlock(&tcon->tc_lock);
 
index df88b8c..0512833 100644 (file)
@@ -4942,9 +4942,13 @@ oplock_break_ack:
         * disconnected since oplock already released by the server
         */
        if (!oplock_break_cancelled) {
-               rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
+               /* check for server null since can race with kill_sb calling tree disconnect */
+               if (tcon->ses && tcon->ses->server) {
+                       rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
                                volatile_fid, net_fid, cinode);
-               cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
+                       cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
+               } else
+                       pr_warn_once("lease break not sent for unmounted share\n");
        }
 
        cifs_done_oplock_break(cinode);
index 6e3be58..a8bb9d0 100644 (file)
@@ -34,6 +34,8 @@ static int
 change_conf(struct TCP_Server_Info *server)
 {
        server->credits += server->echo_credits + server->oplock_credits;
+       if (server->credits > server->max_credits)
+               server->credits = server->max_credits;
        server->oplock_credits = server->echo_credits = 0;
        switch (server->credits) {
        case 0:
@@ -91,6 +93,7 @@ smb2_add_credits(struct TCP_Server_Info *server,
                                            server->conn_id, server->hostname, *val,
                                            add, server->in_flight);
        }
+       WARN_ON_ONCE(server->in_flight == 0);
        server->in_flight--;
        if (server->in_flight == 0 &&
           ((optype & CIFS_OP_MASK) != CIFS_NEG_OP) &&
@@ -510,6 +513,43 @@ smb3_negotiate_rsize(struct cifs_tcon *tcon, struct smb3_fs_context *ctx)
        return rsize;
 }
 
+/*
+ * compare two interfaces a and b
+ * return 0 if everything matches.
+ * return 1 if a is rdma capable, or rss capable, or has higher link speed
+ * return -1 otherwise.
+ */
+static int
+iface_cmp(struct cifs_server_iface *a, struct cifs_server_iface *b)
+{
+       int cmp_ret = 0;
+
+       WARN_ON(!a || !b);
+       if (a->rdma_capable == b->rdma_capable) {
+               if (a->rss_capable == b->rss_capable) {
+                       if (a->speed == b->speed) {
+                               cmp_ret = cifs_ipaddr_cmp((struct sockaddr *) &a->sockaddr,
+                                                         (struct sockaddr *) &b->sockaddr);
+                               if (!cmp_ret)
+                                       return 0;
+                               else if (cmp_ret > 0)
+                                       return 1;
+                               else
+                                       return -1;
+                       } else if (a->speed > b->speed)
+                               return 1;
+                       else
+                               return -1;
+               } else if (a->rss_capable > b->rss_capable)
+                       return 1;
+               else
+                       return -1;
+       } else if (a->rdma_capable > b->rdma_capable)
+               return 1;
+       else
+               return -1;
+}
+
 static int
 parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                        size_t buf_len, struct cifs_ses *ses, bool in_mount)
index 7063b39..17fe212 100644 (file)
@@ -1305,7 +1305,12 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data)
        }
 
        /* enough to enable echos and oplocks and one max size write */
-       req->hdr.CreditRequest = cpu_to_le16(130);
+       if (server->credits >= server->max_credits)
+               req->hdr.CreditRequest = cpu_to_le16(0);
+       else
+               req->hdr.CreditRequest = cpu_to_le16(
+                       min_t(int, server->max_credits -
+                             server->credits, 130));
 
        /* only one of SMB2 signing flags may be set in SMB2 request */
        if (server->sign)
@@ -1899,7 +1904,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree,
        rqst.rq_nvec = 2;
 
        /* Need 64 for max size write so ask for more in case not there yet */
-       req->hdr.CreditRequest = cpu_to_le16(64);
+       if (server->credits >= server->max_credits)
+               req->hdr.CreditRequest = cpu_to_le16(0);
+       else
+               req->hdr.CreditRequest = cpu_to_le16(
+                       min_t(int, server->max_credits -
+                             server->credits, 64));
 
        rc = cifs_send_recv(xid, ses, server,
                            &rqst, &resp_buftype, flags, &rsp_iov);
@@ -4227,6 +4237,7 @@ smb2_async_readv(struct cifs_readdata *rdata)
        struct TCP_Server_Info *server;
        struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
        unsigned int total_len;
+       int credit_request;
 
        cifs_dbg(FYI, "%s: offset=%llu bytes=%u\n",
                 __func__, rdata->offset, rdata->bytes);
@@ -4258,7 +4269,13 @@ smb2_async_readv(struct cifs_readdata *rdata)
        if (rdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes,
                                                SMB2_MAX_BUFFER_SIZE));
-               shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8);
+               credit_request = le16_to_cpu(shdr->CreditCharge) + 8;
+               if (server->credits >= server->max_credits)
+                       shdr->CreditRequest = cpu_to_le16(0);
+               else
+                       shdr->CreditRequest = cpu_to_le16(
+                               min_t(int, server->max_credits -
+                                               server->credits, credit_request));
 
                rc = adjust_credits(server, &rdata->credits, rdata->bytes);
                if (rc)
@@ -4468,6 +4485,7 @@ smb2_async_writev(struct cifs_writedata *wdata,
        unsigned int total_len;
        struct cifs_io_parms _io_parms;
        struct cifs_io_parms *io_parms = NULL;
+       int credit_request;
 
        if (!wdata->server)
                server = wdata->server = cifs_pick_channel(tcon->ses);
@@ -4572,7 +4590,13 @@ smb2_async_writev(struct cifs_writedata *wdata,
        if (wdata->credits.value > 0) {
                shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes,
                                                    SMB2_MAX_BUFFER_SIZE));
-               shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8);
+               credit_request = le16_to_cpu(shdr->CreditCharge) + 8;
+               if (server->credits >= server->max_credits)
+                       shdr->CreditRequest = cpu_to_le16(0);
+               else
+                       shdr->CreditRequest = cpu_to_le16(
+                               min_t(int, server->max_credits -
+                                               server->credits, credit_request));
 
                rc = adjust_credits(server, &wdata->credits, io_parms->length);
                if (rc)
index 24bdd5f..0474d0b 100644 (file)
@@ -55,7 +55,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server)
        temp->pid = current->pid;
        temp->command = cpu_to_le16(smb_buffer->Command);
        cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command);
-       /*      do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */
+       /* easier to use jiffies */
        /* when mid allocated can be before when sent */
        temp->when_alloc = jiffies;
        temp->server = server;
index 4882a81..2a717d1 100644 (file)
@@ -294,6 +294,9 @@ bool ksmbd_conn_alive(struct ksmbd_conn *conn)
        return true;
 }
 
+#define SMB1_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb_hdr))
+#define SMB2_MIN_SUPPORTED_HEADER_SIZE (sizeof(struct smb2_hdr) + 4)
+
 /**
  * ksmbd_conn_handler_loop() - session thread to listen on new smb requests
  * @p:         connection instance
@@ -350,6 +353,9 @@ int ksmbd_conn_handler_loop(void *p)
                if (pdu_size > MAX_STREAM_PROT_LEN)
                        break;
 
+               if (pdu_size < SMB1_MIN_SUPPORTED_HEADER_SIZE)
+                       break;
+
                /* 4 for rfc1002 length field */
                /* 1 for implied bcc[0] */
                size = pdu_size + 4 + 1;
@@ -358,8 +364,6 @@ int ksmbd_conn_handler_loop(void *p)
                        break;
 
                memcpy(conn->request_buf, hdr_buf, sizeof(hdr_buf));
-               if (!ksmbd_smb_request(conn))
-                       break;
 
                /*
                 * We already read 4 bytes to find out PDU size, now
@@ -377,6 +381,15 @@ int ksmbd_conn_handler_loop(void *p)
                        continue;
                }
 
+               if (!ksmbd_smb_request(conn))
+                       break;
+
+               if (((struct smb2_hdr *)smb2_get_msg(conn->request_buf))->ProtocolId ==
+                   SMB2_PROTO_NUMBER) {
+                       if (pdu_size < SMB2_MIN_SUPPORTED_HEADER_SIZE)
+                               break;
+               }
+
                if (!default_conn_ops.process_fn) {
                        pr_err("No connection request callback\n");
                        break;
index db181bd..844b303 100644 (file)
@@ -1415,56 +1415,38 @@ void create_lease_buf(u8 *rbuf, struct lease *lease)
  */
 struct lease_ctx_info *parse_lease_state(void *open_req)
 {
-       char *data_offset;
        struct create_context *cc;
-       unsigned int next = 0;
-       char *name;
-       bool found = false;
        struct smb2_create_req *req = (struct smb2_create_req *)open_req;
-       struct lease_ctx_info *lreq = kzalloc(sizeof(struct lease_ctx_info),
-               GFP_KERNEL);
+       struct lease_ctx_info *lreq;
+
+       cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
+       if (IS_ERR_OR_NULL(cc))
+               return NULL;
+
+       lreq = kzalloc(sizeof(struct lease_ctx_info), GFP_KERNEL);
        if (!lreq)
                return NULL;
 
-       data_offset = (char *)req + le32_to_cpu(req->CreateContextsOffset);
-       cc = (struct create_context *)data_offset;
-       do {
-               cc = (struct create_context *)((char *)cc + next);
-               name = le16_to_cpu(cc->NameOffset) + (char *)cc;
-               if (le16_to_cpu(cc->NameLength) != 4 ||
-                   strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) {
-                       next = le32_to_cpu(cc->Next);
-                       continue;
-               }
-               found = true;
-               break;
-       } while (next != 0);
+       if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
+               struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
 
-       if (found) {
-               if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
-                       struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
-
-                       memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
-                       lreq->req_state = lc->lcontext.LeaseState;
-                       lreq->flags = lc->lcontext.LeaseFlags;
-                       lreq->duration = lc->lcontext.LeaseDuration;
-                       memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
-                              SMB2_LEASE_KEY_SIZE);
-                       lreq->version = 2;
-               } else {
-                       struct create_lease *lc = (struct create_lease *)cc;
+               memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
+               lreq->req_state = lc->lcontext.LeaseState;
+               lreq->flags = lc->lcontext.LeaseFlags;
+               lreq->duration = lc->lcontext.LeaseDuration;
+               memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
+                               SMB2_LEASE_KEY_SIZE);
+               lreq->version = 2;
+       } else {
+               struct create_lease *lc = (struct create_lease *)cc;
 
-                       memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
-                       lreq->req_state = lc->lcontext.LeaseState;
-                       lreq->flags = lc->lcontext.LeaseFlags;
-                       lreq->duration = lc->lcontext.LeaseDuration;
-                       lreq->version = 1;
-               }
-               return lreq;
+               memcpy(lreq->lease_key, lc->lcontext.LeaseKey, SMB2_LEASE_KEY_SIZE);
+               lreq->req_state = lc->lcontext.LeaseState;
+               lreq->flags = lc->lcontext.LeaseFlags;
+               lreq->duration = lc->lcontext.LeaseDuration;
+               lreq->version = 1;
        }
-
-       kfree(lreq);
-       return NULL;
+       return lreq;
 }
 
 /**
index f9b2e0f..ced7a9e 100644 (file)
@@ -185,24 +185,31 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
                goto send;
        }
 
-       if (conn->ops->check_user_session) {
-               rc = conn->ops->check_user_session(work);
-               if (rc < 0) {
-                       command = conn->ops->get_cmd_val(work);
-                       conn->ops->set_rsp_status(work,
-                                       STATUS_USER_SESSION_DELETED);
-                       goto send;
-               } else if (rc > 0) {
-                       rc = conn->ops->get_ksmbd_tcon(work);
+       do {
+               if (conn->ops->check_user_session) {
+                       rc = conn->ops->check_user_session(work);
                        if (rc < 0) {
-                               conn->ops->set_rsp_status(work,
-                                       STATUS_NETWORK_NAME_DELETED);
+                               if (rc == -EINVAL)
+                                       conn->ops->set_rsp_status(work,
+                                               STATUS_INVALID_PARAMETER);
+                               else
+                                       conn->ops->set_rsp_status(work,
+                                               STATUS_USER_SESSION_DELETED);
                                goto send;
+                       } else if (rc > 0) {
+                               rc = conn->ops->get_ksmbd_tcon(work);
+                               if (rc < 0) {
+                                       if (rc == -EINVAL)
+                                               conn->ops->set_rsp_status(work,
+                                                       STATUS_INVALID_PARAMETER);
+                                       else
+                                               conn->ops->set_rsp_status(work,
+                                                       STATUS_NETWORK_NAME_DELETED);
+                                       goto send;
+                               }
                        }
                }
-       }
 
-       do {
                rc = __process_request(work, conn, &command);
                if (rc == SERVER_HANDLER_ABORT)
                        break;
index 0ffe663..33b7e6c 100644 (file)
@@ -351,9 +351,16 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
        int command;
        __u32 clc_len;  /* calculated length */
        __u32 len = get_rfc1002_len(work->request_buf);
+       __u32 req_struct_size, next_cmd = le32_to_cpu(hdr->NextCommand);
 
-       if (le32_to_cpu(hdr->NextCommand) > 0)
-               len = le32_to_cpu(hdr->NextCommand);
+       if ((u64)work->next_smb2_rcv_hdr_off + next_cmd > len) {
+               pr_err("next command(%u) offset exceeds smb msg size\n",
+                               next_cmd);
+               return 1;
+       }
+
+       if (next_cmd > 0)
+               len = next_cmd;
        else if (work->next_smb2_rcv_hdr_off)
                len -= work->next_smb2_rcv_hdr_off;
 
@@ -373,17 +380,9 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
        }
 
        if (smb2_req_struct_sizes[command] != pdu->StructureSize2) {
-               if (command != SMB2_OPLOCK_BREAK_HE &&
-                   (hdr->Status == 0 || pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2_LE)) {
-                       /* error packets have 9 byte structure size */
-                       ksmbd_debug(SMB,
-                                   "Illegal request size %u for command %d\n",
-                                   le16_to_cpu(pdu->StructureSize2), command);
-                       return 1;
-               } else if (command == SMB2_OPLOCK_BREAK_HE &&
-                          hdr->Status == 0 &&
-                          le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 &&
-                          le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) {
+               if (command == SMB2_OPLOCK_BREAK_HE &&
+                   le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_20 &&
+                   le16_to_cpu(pdu->StructureSize2) != OP_BREAK_STRUCT_SIZE_21) {
                        /* special case for SMB2.1 lease break message */
                        ksmbd_debug(SMB,
                                    "Illegal request size %d for oplock break\n",
@@ -392,6 +391,14 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
                }
        }
 
+       req_struct_size = le16_to_cpu(pdu->StructureSize2) +
+               __SMB2_HEADER_STRUCTURE_SIZE;
+       if (command == SMB2_LOCK_HE)
+               req_struct_size -= sizeof(struct smb2_lock_element);
+
+       if (req_struct_size > len + 1)
+               return 1;
+
        if (smb2_calc_size(hdr, &clc_len))
                return 1;
 
index 7a81541..da1787c 100644 (file)
@@ -91,7 +91,6 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
        unsigned int cmd = le16_to_cpu(req_hdr->Command);
        int tree_id;
 
-       work->tcon = NULL;
        if (cmd == SMB2_TREE_CONNECT_HE ||
            cmd ==  SMB2_CANCEL_HE ||
            cmd ==  SMB2_LOGOFF_HE) {
@@ -105,10 +104,28 @@ int smb2_get_ksmbd_tcon(struct ksmbd_work *work)
        }
 
        tree_id = le32_to_cpu(req_hdr->Id.SyncId.TreeId);
+
+       /*
+        * If request is not the first in Compound request,
+        * Just validate tree id in header with work->tcon->id.
+        */
+       if (work->next_smb2_rcv_hdr_off) {
+               if (!work->tcon) {
+                       pr_err("The first operation in the compound does not have tcon\n");
+                       return -EINVAL;
+               }
+               if (work->tcon->id != tree_id) {
+                       pr_err("tree id(%u) is different with id(%u) in first operation\n",
+                                       tree_id, work->tcon->id);
+                       return -EINVAL;
+               }
+               return 1;
+       }
+
        work->tcon = ksmbd_tree_conn_lookup(work->sess, tree_id);
        if (!work->tcon) {
                pr_err("Invalid tid %d\n", tree_id);
-               return -EINVAL;
+               return -ENOENT;
        }
 
        return 1;
@@ -547,7 +564,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
        unsigned int cmd = conn->ops->get_cmd_val(work);
        unsigned long long sess_id;
 
-       work->sess = NULL;
        /*
         * SMB2_ECHO, SMB2_NEGOTIATE, SMB2_SESSION_SETUP command do not
         * require a session id, so no need to validate user session's for
@@ -558,15 +574,33 @@ int smb2_check_user_session(struct ksmbd_work *work)
                return 0;
 
        if (!ksmbd_conn_good(conn))
-               return -EINVAL;
+               return -EIO;
 
        sess_id = le64_to_cpu(req_hdr->SessionId);
+
+       /*
+        * If request is not the first in Compound request,
+        * Just validate session id in header with work->sess->id.
+        */
+       if (work->next_smb2_rcv_hdr_off) {
+               if (!work->sess) {
+                       pr_err("The first operation in the compound does not have sess\n");
+                       return -EINVAL;
+               }
+               if (work->sess->id != sess_id) {
+                       pr_err("session id(%llu) is different with the first operation(%lld)\n",
+                                       sess_id, work->sess->id);
+                       return -EINVAL;
+               }
+               return 1;
+       }
+
        /* Check for validity of user session */
        work->sess = ksmbd_session_lookup_all(conn, sess_id);
        if (work->sess)
                return 1;
        ksmbd_debug(SMB, "Invalid user session, Uid %llu\n", sess_id);
-       return -EINVAL;
+       return -ENOENT;
 }
 
 static void destroy_previous_session(struct ksmbd_conn *conn,
@@ -963,13 +997,13 @@ static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
 
 static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
                                      struct smb2_negotiate_req *req,
-                                     int len_of_smb)
+                                     unsigned int len_of_smb)
 {
        /* +4 is to account for the RFC1001 len field */
        struct smb2_neg_context *pctx = (struct smb2_neg_context *)req;
        int i = 0, len_of_ctxts;
-       int offset = le32_to_cpu(req->NegotiateContextOffset);
-       int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
+       unsigned int offset = le32_to_cpu(req->NegotiateContextOffset);
+       unsigned int neg_ctxt_cnt = le16_to_cpu(req->NegotiateContextCount);
        __le32 status = STATUS_INVALID_PARAMETER;
 
        ksmbd_debug(SMB, "decoding %d negotiate contexts\n", neg_ctxt_cnt);
@@ -983,7 +1017,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
        while (i++ < neg_ctxt_cnt) {
                int clen, ctxt_len;
 
-               if (len_of_ctxts < sizeof(struct smb2_neg_context))
+               if (len_of_ctxts < (int)sizeof(struct smb2_neg_context))
                        break;
 
                pctx = (struct smb2_neg_context *)((char *)pctx + offset);
@@ -1038,9 +1072,8 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
                }
 
                /* offsets must be 8 byte aligned */
-               clen = (clen + 7) & ~0x7;
-               offset = clen + sizeof(struct smb2_neg_context);
-               len_of_ctxts -= clen + sizeof(struct smb2_neg_context);
+               offset = (ctxt_len + 7) & ~0x7;
+               len_of_ctxts -= offset;
        }
        return status;
 }
@@ -2250,7 +2283,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
                        /* delete the EA only when it exits */
                        if (rc > 0) {
                                rc = ksmbd_vfs_remove_xattr(idmap,
-                                                           path->dentry,
+                                                           path,
                                                            attr_name);
 
                                if (rc < 0) {
@@ -2264,8 +2297,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
                        /* if the EA doesn't exist, just do nothing. */
                        rc = 0;
                } else {
-                       rc = ksmbd_vfs_setxattr(idmap,
-                                               path->dentry, attr_name, value,
+                       rc = ksmbd_vfs_setxattr(idmap, path, attr_name, value,
                                                le16_to_cpu(eabuf->EaValueLength), 0);
                        if (rc < 0) {
                                ksmbd_debug(SMB,
@@ -2322,8 +2354,7 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
                return -EBADF;
        }
 
-       rc = ksmbd_vfs_setxattr(idmap, path->dentry,
-                               xattr_stream_name, NULL, 0, 0);
+       rc = ksmbd_vfs_setxattr(idmap, path, xattr_stream_name, NULL, 0, 0);
        if (rc < 0)
                pr_err("Failed to store XATTR stream name :%d\n", rc);
        return 0;
@@ -2351,7 +2382,7 @@ static int smb2_remove_smb_xattrs(const struct path *path)
                if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) &&
                    !strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
                             STREAM_PREFIX_LEN)) {
-                       err = ksmbd_vfs_remove_xattr(idmap, path->dentry,
+                       err = ksmbd_vfs_remove_xattr(idmap, path,
                                                     name);
                        if (err)
                                ksmbd_debug(SMB, "remove xattr failed : %s\n",
@@ -2398,8 +2429,7 @@ static void smb2_new_xattrs(struct ksmbd_tree_connect *tcon, const struct path *
        da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
                XATTR_DOSINFO_ITIME;
 
-       rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt),
-                                           path->dentry, &da);
+       rc = ksmbd_vfs_set_dos_attrib_xattr(mnt_idmap(path->mnt), path, &da);
        if (rc)
                ksmbd_debug(SMB, "failed to store file attribute into xattr\n");
 }
@@ -2973,7 +3003,7 @@ int smb2_open(struct ksmbd_work *work)
                struct inode *inode = d_inode(path.dentry);
 
                posix_acl_rc = ksmbd_vfs_inherit_posix_acl(idmap,
-                                                          path.dentry,
+                                                          &path,
                                                           d_inode(path.dentry->d_parent));
                if (posix_acl_rc)
                        ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
@@ -2989,7 +3019,7 @@ int smb2_open(struct ksmbd_work *work)
                        if (rc) {
                                if (posix_acl_rc)
                                        ksmbd_vfs_set_init_posix_acl(idmap,
-                                                                    path.dentry);
+                                                                    &path);
 
                                if (test_share_config_flag(work->tcon->share_conf,
                                                           KSMBD_SHARE_FLAG_ACL_XATTR)) {
@@ -3029,7 +3059,7 @@ int smb2_open(struct ksmbd_work *work)
 
                                        rc = ksmbd_vfs_set_sd_xattr(conn,
                                                                    idmap,
-                                                                   path.dentry,
+                                                                   &path,
                                                                    pntsd,
                                                                    pntsd_size);
                                        kfree(pntsd);
@@ -5465,7 +5495,7 @@ static int smb2_rename(struct ksmbd_work *work,
                        goto out;
 
                rc = ksmbd_vfs_setxattr(file_mnt_idmap(fp->filp),
-                                       fp->filp->f_path.dentry,
+                                       &fp->filp->f_path,
                                        xattr_stream_name,
                                        NULL, 0, 0);
                if (rc < 0) {
@@ -5630,8 +5660,7 @@ static int set_file_basic_info(struct ksmbd_file *fp,
                da.flags = XATTR_DOSINFO_ATTRIB | XATTR_DOSINFO_CREATE_TIME |
                        XATTR_DOSINFO_ITIME;
 
-               rc = ksmbd_vfs_set_dos_attrib_xattr(idmap,
-                                                   filp->f_path.dentry, &da);
+               rc = ksmbd_vfs_set_dos_attrib_xattr(idmap, &filp->f_path, &da);
                if (rc)
                        ksmbd_debug(SMB,
                                    "failed to restore file attribute in EA\n");
@@ -7486,7 +7515,7 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,
 
                da.attr = le32_to_cpu(fp->f_ci->m_fattr);
                ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,
-                                                    fp->filp->f_path.dentry, &da);
+                                                    &fp->filp->f_path, &da);
                if (ret)
                        fp->f_ci->m_fattr = old_fattr;
        }
index af0c2a9..569e5ee 100644 (file)
@@ -158,7 +158,19 @@ int ksmbd_verify_smb_message(struct ksmbd_work *work)
  */
 bool ksmbd_smb_request(struct ksmbd_conn *conn)
 {
-       return conn->request_buf[0] == 0;
+       __le32 *proto = (__le32 *)smb2_get_msg(conn->request_buf);
+
+       if (*proto == SMB2_COMPRESSION_TRANSFORM_ID) {
+               pr_err_ratelimited("smb2 compression not support yet");
+               return false;
+       }
+
+       if (*proto != SMB1_PROTO_NUMBER &&
+           *proto != SMB2_PROTO_NUMBER &&
+           *proto != SMB2_TRANSFORM_PROTO_NUM)
+               return false;
+
+       return true;
 }
 
 static bool supported_protocol(int idx)
index 6d6cfb6..ad919a4 100644 (file)
@@ -1162,8 +1162,7 @@ pass:
                        pntsd_size += sizeof(struct smb_acl) + nt_size;
                }
 
-               ksmbd_vfs_set_sd_xattr(conn, idmap,
-                                      path->dentry, pntsd, pntsd_size);
+               ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, pntsd_size);
                kfree(pntsd);
        }
 
@@ -1290,7 +1289,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
 
        if (IS_ENABLED(CONFIG_FS_POSIX_ACL)) {
                posix_acls = get_inode_acl(d_inode(path->dentry), ACL_TYPE_ACCESS);
-               if (posix_acls && !found) {
+               if (!IS_ERR_OR_NULL(posix_acls) && !found) {
                        unsigned int id = -1;
 
                        pa_entry = posix_acls->a_entries;
@@ -1314,7 +1313,7 @@ int smb_check_perm_dacl(struct ksmbd_conn *conn, const struct path *path,
                                }
                        }
                }
-               if (posix_acls)
+               if (!IS_ERR_OR_NULL(posix_acls))
                        posix_acl_release(posix_acls);
        }
 
@@ -1383,7 +1382,7 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
        newattrs.ia_valid |= ATTR_MODE;
        newattrs.ia_mode = (inode->i_mode & ~0777) | (fattr.cf_mode & 0777);
 
-       ksmbd_vfs_remove_acl_xattrs(idmap, path->dentry);
+       ksmbd_vfs_remove_acl_xattrs(idmap, path);
        /* Update posix acls */
        if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && fattr.cf_dacls) {
                rc = set_posix_acl(idmap, path->dentry,
@@ -1414,9 +1413,8 @@ int set_info_sec(struct ksmbd_conn *conn, struct ksmbd_tree_connect *tcon,
 
        if (test_share_config_flag(tcon->share_conf, KSMBD_SHARE_FLAG_ACL_XATTR)) {
                /* Update WinACL in xattr */
-               ksmbd_vfs_remove_sd_xattrs(idmap, path->dentry);
-               ksmbd_vfs_set_sd_xattr(conn, idmap,
-                                      path->dentry, pntsd, ntsd_len);
+               ksmbd_vfs_remove_sd_xattrs(idmap, path);
+               ksmbd_vfs_set_sd_xattr(conn, idmap, path, pntsd, ntsd_len);
        }
 
 out:
index 6f30291..81489fd 100644 (file)
@@ -170,6 +170,10 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
                return err;
        }
 
+       err = mnt_want_write(path.mnt);
+       if (err)
+               goto out_err;
+
        mode |= S_IFREG;
        err = vfs_create(mnt_idmap(path.mnt), d_inode(path.dentry),
                         dentry, mode, true);
@@ -179,6 +183,9 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
        } else {
                pr_err("File(%s): creation failed (err:%d)\n", name, err);
        }
+       mnt_drop_write(path.mnt);
+
+out_err:
        done_path_create(&path, dentry);
        return err;
 }
@@ -209,30 +216,35 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
                return err;
        }
 
+       err = mnt_want_write(path.mnt);
+       if (err)
+               goto out_err2;
+
        idmap = mnt_idmap(path.mnt);
        mode |= S_IFDIR;
        err = vfs_mkdir(idmap, d_inode(path.dentry), dentry, mode);
-       if (err) {
-               goto out;
-       } else if (d_unhashed(dentry)) {
+       if (!err && d_unhashed(dentry)) {
                struct dentry *d;
 
                d = lookup_one(idmap, dentry->d_name.name, dentry->d_parent,
                               dentry->d_name.len);
                if (IS_ERR(d)) {
                        err = PTR_ERR(d);
-                       goto out;
+                       goto out_err1;
                }
                if (unlikely(d_is_negative(d))) {
                        dput(d);
                        err = -ENOENT;
-                       goto out;
+                       goto out_err1;
                }
 
                ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(d));
                dput(d);
        }
-out:
+
+out_err1:
+       mnt_drop_write(path.mnt);
+out_err2:
        done_path_create(&path, dentry);
        if (err)
                pr_err("mkdir(%s): creation failed (err:%d)\n", name, err);
@@ -443,7 +455,7 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
        memcpy(&stream_buf[*pos], buf, count);
 
        err = ksmbd_vfs_setxattr(idmap,
-                                fp->filp->f_path.dentry,
+                                &fp->filp->f_path,
                                 fp->stream.name,
                                 (void *)stream_buf,
                                 size,
@@ -589,6 +601,10 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
                goto out_err;
        }
 
+       err = mnt_want_write(path->mnt);
+       if (err)
+               goto out_err;
+
        idmap = mnt_idmap(path->mnt);
        if (S_ISDIR(d_inode(path->dentry)->i_mode)) {
                err = vfs_rmdir(idmap, d_inode(parent), path->dentry);
@@ -599,6 +615,7 @@ int ksmbd_vfs_remove_file(struct ksmbd_work *work, const struct path *path)
                if (err)
                        ksmbd_debug(VFS, "unlink failed, err %d\n", err);
        }
+       mnt_drop_write(path->mnt);
 
 out_err:
        ksmbd_revert_fsids(work);
@@ -644,11 +661,16 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
                goto out3;
        }
 
+       err = mnt_want_write(newpath.mnt);
+       if (err)
+               goto out3;
+
        err = vfs_link(oldpath.dentry, mnt_idmap(newpath.mnt),
                       d_inode(newpath.dentry),
                       dentry, NULL);
        if (err)
                ksmbd_debug(VFS, "vfs_link failed err %d\n", err);
+       mnt_drop_write(newpath.mnt);
 
 out3:
        done_path_create(&newpath, dentry);
@@ -694,6 +716,10 @@ retry:
                goto out2;
        }
 
+       err = mnt_want_write(old_path->mnt);
+       if (err)
+               goto out2;
+
        trap = lock_rename_child(old_child, new_path.dentry);
 
        old_parent = dget(old_child->d_parent);
@@ -757,6 +783,7 @@ out4:
 out3:
        dput(old_parent);
        unlock_rename(old_parent, new_path.dentry);
+       mnt_drop_write(old_path->mnt);
 out2:
        path_put(&new_path);
 
@@ -897,19 +924,24 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
  * Return:     0 on success, otherwise error
  */
 int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
-                      struct dentry *dentry, const char *attr_name,
+                      const struct path *path, const char *attr_name,
                       void *attr_value, size_t attr_size, int flags)
 {
        int err;
 
+       err = mnt_want_write(path->mnt);
+       if (err)
+               return err;
+
        err = vfs_setxattr(idmap,
-                          dentry,
+                          path->dentry,
                           attr_name,
                           attr_value,
                           attr_size,
                           flags);
        if (err)
                ksmbd_debug(VFS, "setxattr failed, err %d\n", err);
+       mnt_drop_write(path->mnt);
        return err;
 }
 
@@ -1013,9 +1045,18 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
 }
 
 int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
-                          struct dentry *dentry, char *attr_name)
+                          const struct path *path, char *attr_name)
 {
-       return vfs_removexattr(idmap, dentry, attr_name);
+       int err;
+
+       err = mnt_want_write(path->mnt);
+       if (err)
+               return err;
+
+       err = vfs_removexattr(idmap, path->dentry, attr_name);
+       mnt_drop_write(path->mnt);
+
+       return err;
 }
 
 int ksmbd_vfs_unlink(struct file *filp)
@@ -1024,6 +1065,10 @@ int ksmbd_vfs_unlink(struct file *filp)
        struct dentry *dir, *dentry = filp->f_path.dentry;
        struct mnt_idmap *idmap = file_mnt_idmap(filp);
 
+       err = mnt_want_write(filp->f_path.mnt);
+       if (err)
+               return err;
+
        dir = dget_parent(dentry);
        err = ksmbd_vfs_lock_parent(dir, dentry);
        if (err)
@@ -1041,6 +1086,7 @@ int ksmbd_vfs_unlink(struct file *filp)
                ksmbd_debug(VFS, "failed to delete, err %d\n", err);
 out:
        dput(dir);
+       mnt_drop_write(filp->f_path.mnt);
 
        return err;
 }
@@ -1244,13 +1290,13 @@ struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
 }
 
 int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
-                               struct dentry *dentry)
+                               const struct path *path)
 {
        char *name, *xattr_list = NULL;
        ssize_t xattr_list_len;
        int err = 0;
 
-       xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);
+       xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
        if (xattr_list_len < 0) {
                goto out;
        } else if (!xattr_list_len) {
@@ -1258,6 +1304,10 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
                goto out;
        }
 
+       err = mnt_want_write(path->mnt);
+       if (err)
+               goto out;
+
        for (name = xattr_list; name - xattr_list < xattr_list_len;
             name += strlen(name) + 1) {
                ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
@@ -1266,25 +1316,26 @@ int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
                             sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1) ||
                    !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
                             sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1)) {
-                       err = vfs_remove_acl(idmap, dentry, name);
+                       err = vfs_remove_acl(idmap, path->dentry, name);
                        if (err)
                                ksmbd_debug(SMB,
                                            "remove acl xattr failed : %s\n", name);
                }
        }
+       mnt_drop_write(path->mnt);
+
 out:
        kvfree(xattr_list);
        return err;
 }
 
-int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
-                              struct dentry *dentry)
+int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path)
 {
        char *name, *xattr_list = NULL;
        ssize_t xattr_list_len;
        int err = 0;
 
-       xattr_list_len = ksmbd_vfs_listxattr(dentry, &xattr_list);
+       xattr_list_len = ksmbd_vfs_listxattr(path->dentry, &xattr_list);
        if (xattr_list_len < 0) {
                goto out;
        } else if (!xattr_list_len) {
@@ -1297,7 +1348,7 @@ int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
                ksmbd_debug(SMB, "%s, len %zd\n", name, strlen(name));
 
                if (!strncmp(name, XATTR_NAME_SD, XATTR_NAME_SD_LEN)) {
-                       err = ksmbd_vfs_remove_xattr(idmap, dentry, name);
+                       err = ksmbd_vfs_remove_xattr(idmap, path, name);
                        if (err)
                                ksmbd_debug(SMB, "remove xattr failed : %s\n", name);
                }
@@ -1321,7 +1372,7 @@ static struct xattr_smb_acl *ksmbd_vfs_make_xattr_posix_acl(struct mnt_idmap *id
                return NULL;
 
        posix_acls = get_inode_acl(inode, acl_type);
-       if (!posix_acls)
+       if (IS_ERR_OR_NULL(posix_acls))
                return NULL;
 
        smb_acl = kzalloc(sizeof(struct xattr_smb_acl) +
@@ -1374,13 +1425,14 @@ out:
 
 int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
                           struct mnt_idmap *idmap,
-                          struct dentry *dentry,
+                          const struct path *path,
                           struct smb_ntsd *pntsd, int len)
 {
        int rc;
        struct ndr sd_ndr = {0}, acl_ndr = {0};
        struct xattr_ntacl acl = {0};
        struct xattr_smb_acl *smb_acl, *def_smb_acl = NULL;
+       struct dentry *dentry = path->dentry;
        struct inode *inode = d_inode(dentry);
 
        acl.version = 4;
@@ -1432,7 +1484,7 @@ int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
                goto out;
        }
 
-       rc = ksmbd_vfs_setxattr(idmap, dentry,
+       rc = ksmbd_vfs_setxattr(idmap, path,
                                XATTR_NAME_SD, sd_ndr.data,
                                sd_ndr.offset, 0);
        if (rc < 0)
@@ -1522,7 +1574,7 @@ free_n_data:
 }
 
 int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
-                                  struct dentry *dentry,
+                                  const struct path *path,
                                   struct xattr_dos_attrib *da)
 {
        struct ndr n;
@@ -1532,7 +1584,7 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
        if (err)
                return err;
 
-       err = ksmbd_vfs_setxattr(idmap, dentry, XATTR_NAME_DOS_ATTRIBUTE,
+       err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE,
                                 (void *)n.data, n.offset, 0);
        if (err)
                ksmbd_debug(SMB, "failed to store dos attribute in xattr\n");
@@ -1769,10 +1821,11 @@ void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock)
 }
 
 int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
-                                struct dentry *dentry)
+                                struct path *path)
 {
        struct posix_acl_state acl_state;
        struct posix_acl *acls;
+       struct dentry *dentry = path->dentry;
        struct inode *inode = d_inode(dentry);
        int rc;
 
@@ -1802,6 +1855,11 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
                return -ENOMEM;
        }
        posix_state_to_acl(&acl_state, acls->a_entries);
+
+       rc = mnt_want_write(path->mnt);
+       if (rc)
+               goto out_err;
+
        rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
        if (rc < 0)
                ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
@@ -1813,16 +1871,20 @@ int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
                        ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
                                    rc);
        }
+       mnt_drop_write(path->mnt);
+
+out_err:
        free_acl_state(&acl_state);
        posix_acl_release(acls);
        return rc;
 }
 
 int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
-                               struct dentry *dentry, struct inode *parent_inode)
+                               struct path *path, struct inode *parent_inode)
 {
        struct posix_acl *acls;
        struct posix_acl_entry *pace;
+       struct dentry *dentry = path->dentry;
        struct inode *inode = d_inode(dentry);
        int rc, i;
 
@@ -1830,7 +1892,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
                return -EOPNOTSUPP;
 
        acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
-       if (!acls)
+       if (IS_ERR_OR_NULL(acls))
                return -ENOENT;
        pace = acls->a_entries;
 
@@ -1841,6 +1903,10 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
                }
        }
 
+       rc = mnt_want_write(path->mnt);
+       if (rc)
+               goto out_err;
+
        rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
        if (rc < 0)
                ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
@@ -1852,6 +1918,9 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
                        ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
                                    rc);
        }
+       mnt_drop_write(path->mnt);
+
+out_err:
        posix_acl_release(acls);
        return rc;
 }
index a4ae89f..8c0931d 100644 (file)
@@ -108,12 +108,12 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
                                struct dentry *dentry, char *attr_name,
                                int attr_name_len);
 int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
-                      struct dentry *dentry, const char *attr_name,
+                      const struct path *path, const char *attr_name,
                       void *attr_value, size_t attr_size, int flags);
 int ksmbd_vfs_xattr_stream_name(char *stream_name, char **xattr_stream_name,
                                size_t *xattr_stream_name_size, int s_type);
 int ksmbd_vfs_remove_xattr(struct mnt_idmap *idmap,
-                          struct dentry *dentry, char *attr_name);
+                          const struct path *path, char *attr_name);
 int ksmbd_vfs_kern_path_locked(struct ksmbd_work *work, char *name,
                               unsigned int flags, struct path *path,
                               bool caseless);
@@ -139,26 +139,25 @@ void ksmbd_vfs_posix_lock_wait(struct file_lock *flock);
 int ksmbd_vfs_posix_lock_wait_timeout(struct file_lock *flock, long timeout);
 void ksmbd_vfs_posix_lock_unblock(struct file_lock *flock);
 int ksmbd_vfs_remove_acl_xattrs(struct mnt_idmap *idmap,
-                               struct dentry *dentry);
-int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap,
-                              struct dentry *dentry);
+                               const struct path *path);
+int ksmbd_vfs_remove_sd_xattrs(struct mnt_idmap *idmap, const struct path *path);
 int ksmbd_vfs_set_sd_xattr(struct ksmbd_conn *conn,
                           struct mnt_idmap *idmap,
-                          struct dentry *dentry,
+                          const struct path *path,
                           struct smb_ntsd *pntsd, int len);
 int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
                           struct mnt_idmap *idmap,
                           struct dentry *dentry,
                           struct smb_ntsd **pntsd);
 int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
-                                  struct dentry *dentry,
+                                  const struct path *path,
                                   struct xattr_dos_attrib *da);
 int ksmbd_vfs_get_dos_attrib_xattr(struct mnt_idmap *idmap,
                                   struct dentry *dentry,
                                   struct xattr_dos_attrib *da);
 int ksmbd_vfs_set_init_posix_acl(struct mnt_idmap *idmap,
-                                struct dentry *dentry);
+                                struct path *path);
 int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
-                               struct dentry *dentry,
+                               struct path *path,
                                struct inode *parent_inode);
 #endif /* __KSMBD_VFS_H__ */
index 2d0138e..f41f8d6 100644 (file)
@@ -252,7 +252,7 @@ static void __ksmbd_inode_close(struct ksmbd_file *fp)
        if (ksmbd_stream_fd(fp) && (ci->m_flags & S_DEL_ON_CLS_STREAM)) {
                ci->m_flags &= ~S_DEL_ON_CLS_STREAM;
                err = ksmbd_vfs_remove_xattr(file_mnt_idmap(filp),
-                                            filp->f_path.dentry,
+                                            &filp->f_path,
                                             fp->stream.name);
                if (err)
                        pr_err("remove xattr failed : %s\n",
index 0fd96d6..4e800bb 100644 (file)
@@ -1332,6 +1332,7 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
        bool basic_ioctls;
        unsigned long start, end, vma_end;
        struct vma_iterator vmi;
+       pgoff_t pgoff;
 
        user_uffdio_register = (struct uffdio_register __user *) arg;
 
@@ -1459,6 +1460,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
 
        vma_iter_set(&vmi, start);
        prev = vma_prev(&vmi);
+       if (vma->vm_start < start)
+               prev = vma;
 
        ret = 0;
        for_each_vma_range(vmi, vma, end) {
@@ -1482,8 +1485,9 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
                vma_end = min(end, vma->vm_end);
 
                new_flags = (vma->vm_flags & ~__VM_UFFD_FLAGS) | vm_flags;
+               pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
                prev = vma_merge(&vmi, mm, prev, start, vma_end, new_flags,
-                                vma->anon_vma, vma->vm_file, vma->vm_pgoff,
+                                vma->anon_vma, vma->vm_file, pgoff,
                                 vma_policy(vma),
                                 ((struct vm_userfaultfd_ctx){ ctx }),
                                 anon_vma_name(vma));
@@ -1563,6 +1567,7 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
        unsigned long start, end, vma_end;
        const void __user *buf = (void __user *)arg;
        struct vma_iterator vmi;
+       pgoff_t pgoff;
 
        ret = -EFAULT;
        if (copy_from_user(&uffdio_unregister, buf, sizeof(uffdio_unregister)))
@@ -1625,6 +1630,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
 
        vma_iter_set(&vmi, start);
        prev = vma_prev(&vmi);
+       if (vma->vm_start < start)
+               prev = vma;
+
        ret = 0;
        for_each_vma_range(vmi, vma, end) {
                cond_resched();
@@ -1662,8 +1670,9 @@ static int userfaultfd_unregister(struct userfaultfd_ctx *ctx,
                        uffd_wp_range(vma, start, vma_end - start, false);
 
                new_flags = vma->vm_flags & ~__VM_UFFD_FLAGS;
+               pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT);
                prev = vma_merge(&vmi, mm, prev, start, vma_end, new_flags,
-                                vma->anon_vma, vma->vm_file, vma->vm_pgoff,
+                                vma->anon_vma, vma->vm_file, pgoff,
                                 vma_policy(vma),
                                 NULL_VM_UFFD_CTX, anon_vma_name(vma));
                if (prev) {
index 9b373a0..ee84835 100644 (file)
@@ -984,7 +984,10 @@ xfs_ag_shrink_space(
                if (err2 != -ENOSPC)
                        goto resv_err;
 
-               __xfs_free_extent_later(*tpp, args.fsbno, delta, NULL, true);
+               err2 = __xfs_free_extent_later(*tpp, args.fsbno, delta, NULL,
+                               true);
+               if (err2)
+                       goto resv_err;
 
                /*
                 * Roll the transaction before trying to re-init the per-ag
index fdfa08c..c20fe99 100644 (file)
@@ -628,6 +628,25 @@ xfs_alloc_fixup_trees(
        return 0;
 }
 
+/*
+ * We do not verify the AGFL contents against AGF-based index counters here,
+ * even though we may have access to the perag that contains shadow copies. We
+ * don't know if the AGF based counters have been checked, and if they have they
+ * still may be inconsistent because they haven't yet been reset on the first
+ * allocation after the AGF has been read in.
+ *
+ * This means we can only check that all agfl entries contain valid or null
+ * values because we can't reliably determine the active range to exclude
+ * NULLAGBNO as a valid value.
+ *
+ * However, we can't even do that for v4 format filesystems because there are
+ * old versions of mkfs out there that does not initialise the AGFL to known,
+ * verifiable values. HEnce we can't tell the difference between a AGFL block
+ * allocated by mkfs and a corrupted AGFL block here on v4 filesystems.
+ *
+ * As a result, we can only fully validate AGFL block numbers when we pull them
+ * from the freelist in xfs_alloc_get_freelist().
+ */
 static xfs_failaddr_t
 xfs_agfl_verify(
        struct xfs_buf  *bp)
@@ -637,12 +656,6 @@ xfs_agfl_verify(
        __be32          *agfl_bno = xfs_buf_to_agfl_bno(bp);
        int             i;
 
-       /*
-        * There is no verification of non-crc AGFLs because mkfs does not
-        * initialise the AGFL to zero or NULL. Hence the only valid part of the
-        * AGFL is what the AGF says is active. We can't get to the AGF, so we
-        * can't verify just those entries are valid.
-        */
        if (!xfs_has_crc(mp))
                return NULL;
 
@@ -2321,12 +2334,16 @@ xfs_free_agfl_block(
 }
 
 /*
- * Check the agfl fields of the agf for inconsistency or corruption. The purpose
- * is to detect an agfl header padding mismatch between current and early v5
- * kernels. This problem manifests as a 1-slot size difference between the
- * on-disk flcount and the active [first, last] range of a wrapped agfl. This
- * may also catch variants of agfl count corruption unrelated to padding. Either
- * way, we'll reset the agfl and warn the user.
+ * Check the agfl fields of the agf for inconsistency or corruption.
+ *
+ * The original purpose was to detect an agfl header padding mismatch between
+ * current and early v5 kernels. This problem manifests as a 1-slot size
+ * difference between the on-disk flcount and the active [first, last] range of
+ * a wrapped agfl.
+ *
+ * However, we need to use these same checks to catch agfl count corruptions
+ * unrelated to padding. This could occur on any v4 or v5 filesystem, so either
+ * way, we need to reset the agfl and warn the user.
  *
  * Return true if a reset is required before the agfl can be used, false
  * otherwise.
@@ -2342,10 +2359,6 @@ xfs_agfl_needs_reset(
        int                     agfl_size = xfs_agfl_size(mp);
        int                     active;
 
-       /* no agfl header on v4 supers */
-       if (!xfs_has_crc(mp))
-               return false;
-
        /*
         * The agf read verifier catches severe corruption of these fields.
         * Repeat some sanity checks to cover a packed -> unpacked mismatch if
@@ -2418,7 +2431,7 @@ xfs_agfl_reset(
  * the real allocation can proceed. Deferring the free disconnects freeing up
  * the AGFL slot from freeing the block.
  */
-STATIC void
+static int
 xfs_defer_agfl_block(
        struct xfs_trans                *tp,
        xfs_agnumber_t                  agno,
@@ -2437,17 +2450,21 @@ xfs_defer_agfl_block(
        xefi->xefi_blockcount = 1;
        xefi->xefi_owner = oinfo->oi_owner;
 
+       if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, xefi->xefi_startblock)))
+               return -EFSCORRUPTED;
+
        trace_xfs_agfl_free_defer(mp, agno, 0, agbno, 1);
 
        xfs_extent_free_get_group(mp, xefi);
        xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_AGFL_FREE, &xefi->xefi_list);
+       return 0;
 }
 
 /*
  * Add the extent to the list of extents to be free at transaction end.
  * The list is maintained sorted (by block number).
  */
-void
+int
 __xfs_free_extent_later(
        struct xfs_trans                *tp,
        xfs_fsblock_t                   bno,
@@ -2474,6 +2491,9 @@ __xfs_free_extent_later(
 #endif
        ASSERT(xfs_extfree_item_cache != NULL);
 
+       if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbext(mp, bno, len)))
+               return -EFSCORRUPTED;
+
        xefi = kmem_cache_zalloc(xfs_extfree_item_cache,
                               GFP_KERNEL | __GFP_NOFAIL);
        xefi->xefi_startblock = bno;
@@ -2497,6 +2517,7 @@ __xfs_free_extent_later(
 
        xfs_extent_free_get_group(mp, xefi);
        xfs_defer_add(tp, XFS_DEFER_OPS_TYPE_FREE, &xefi->xefi_list);
+       return 0;
 }
 
 #ifdef DEBUG
@@ -2657,7 +2678,9 @@ xfs_alloc_fix_freelist(
                        goto out_agbp_relse;
 
                /* defer agfl frees */
-               xfs_defer_agfl_block(tp, args->agno, bno, &targs.oinfo);
+               error = xfs_defer_agfl_block(tp, args->agno, bno, &targs.oinfo);
+               if (error)
+                       goto out_agbp_relse;
        }
 
        targs.tp = tp;
@@ -2767,6 +2790,9 @@ xfs_alloc_get_freelist(
         */
        agfl_bno = xfs_buf_to_agfl_bno(agflbp);
        bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
+       if (XFS_IS_CORRUPT(tp->t_mountp, !xfs_verify_agbno(pag, bno)))
+               return -EFSCORRUPTED;
+
        be32_add_cpu(&agf->agf_flfirst, 1);
        xfs_trans_brelse(tp, agflbp);
        if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp))
@@ -2889,6 +2915,19 @@ xfs_alloc_put_freelist(
        return 0;
 }
 
+/*
+ * Verify the AGF is consistent.
+ *
+ * We do not verify the AGFL indexes in the AGF are fully consistent here
+ * because of issues with variable on-disk structure sizes. Instead, we check
+ * the agfl indexes for consistency when we initialise the perag from the AGF
+ * information after a read completes.
+ *
+ * If the index is inconsistent, then we mark the perag as needing an AGFL
+ * reset. The first AGFL update performed then resets the AGFL indexes and
+ * refills the AGFL with known good free blocks, allowing the filesystem to
+ * continue operating normally at the cost of a few leaked free space blocks.
+ */
 static xfs_failaddr_t
 xfs_agf_verify(
        struct xfs_buf          *bp)
@@ -2962,7 +3001,6 @@ xfs_agf_verify(
                return __this_address;
 
        return NULL;
-
 }
 
 static void
@@ -3187,7 +3225,8 @@ xfs_alloc_vextent_check_args(
  */
 static int
 xfs_alloc_vextent_prepare_ag(
-       struct xfs_alloc_arg    *args)
+       struct xfs_alloc_arg    *args,
+       uint32_t                flags)
 {
        bool                    need_pag = !args->pag;
        int                     error;
@@ -3196,7 +3235,7 @@ xfs_alloc_vextent_prepare_ag(
                args->pag = xfs_perag_get(args->mp, args->agno);
 
        args->agbp = NULL;
-       error = xfs_alloc_fix_freelist(args, 0);
+       error = xfs_alloc_fix_freelist(args, flags);
        if (error) {
                trace_xfs_alloc_vextent_nofix(args);
                if (need_pag)
@@ -3336,7 +3375,7 @@ xfs_alloc_vextent_this_ag(
                return error;
        }
 
-       error = xfs_alloc_vextent_prepare_ag(args);
+       error = xfs_alloc_vextent_prepare_ag(args, 0);
        if (!error && args->agbp)
                error = xfs_alloc_ag_vextent_size(args);
 
@@ -3380,7 +3419,7 @@ restart:
        for_each_perag_wrap_range(mp, start_agno, restart_agno,
                        mp->m_sb.sb_agcount, agno, args->pag) {
                args->agno = agno;
-               error = xfs_alloc_vextent_prepare_ag(args);
+               error = xfs_alloc_vextent_prepare_ag(args, flags);
                if (error)
                        break;
                if (!args->agbp) {
@@ -3546,7 +3585,7 @@ xfs_alloc_vextent_exact_bno(
                return error;
        }
 
-       error = xfs_alloc_vextent_prepare_ag(args);
+       error = xfs_alloc_vextent_prepare_ag(args, 0);
        if (!error && args->agbp)
                error = xfs_alloc_ag_vextent_exact(args);
 
@@ -3587,7 +3626,7 @@ xfs_alloc_vextent_near_bno(
        if (needs_perag)
                args->pag = xfs_perag_grab(mp, args->agno);
 
-       error = xfs_alloc_vextent_prepare_ag(args);
+       error = xfs_alloc_vextent_prepare_ag(args, 0);
        if (!error && args->agbp)
                error = xfs_alloc_ag_vextent_near(args);
 
index 5dbb255..85ac470 100644 (file)
@@ -230,7 +230,7 @@ xfs_buf_to_agfl_bno(
        return bp->b_addr;
 }
 
-void __xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
+int __xfs_free_extent_later(struct xfs_trans *tp, xfs_fsblock_t bno,
                xfs_filblks_t len, const struct xfs_owner_info *oinfo,
                bool skip_discard);
 
@@ -254,14 +254,14 @@ void xfs_extent_free_get_group(struct xfs_mount *mp,
 #define XFS_EFI_ATTR_FORK      (1U << 1) /* freeing attr fork block */
 #define XFS_EFI_BMBT_BLOCK     (1U << 2) /* freeing bmap btree block */
 
-static inline void
+static inline int
 xfs_free_extent_later(
        struct xfs_trans                *tp,
        xfs_fsblock_t                   bno,
        xfs_filblks_t                   len,
        const struct xfs_owner_info     *oinfo)
 {
-       __xfs_free_extent_later(tp, bno, len, oinfo, false);
+       return __xfs_free_extent_later(tp, bno, len, oinfo, false);
 }
 
 
index cd8870a..fef3569 100644 (file)
@@ -572,8 +572,12 @@ xfs_bmap_btree_to_extents(
        cblock = XFS_BUF_TO_BLOCK(cbp);
        if ((error = xfs_btree_check_block(cur, cblock, 0, cbp)))
                return error;
+
        xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork);
-       xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo);
+       error = xfs_free_extent_later(cur->bc_tp, cbno, 1, &oinfo);
+       if (error)
+               return error;
+
        ip->i_nblocks--;
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        xfs_trans_binval(tp, cbp);
@@ -5230,10 +5234,12 @@ xfs_bmap_del_extent_real(
                if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) {
                        xfs_refcount_decrease_extent(tp, del);
                } else {
-                       __xfs_free_extent_later(tp, del->br_startblock,
+                       error = __xfs_free_extent_later(tp, del->br_startblock,
                                        del->br_blockcount, NULL,
                                        (bflags & XFS_BMAPI_NODISCARD) ||
                                        del->br_state == XFS_EXT_UNWRITTEN);
+                       if (error)
+                               goto done;
                }
        }
 
index 1b40e5f..36564ae 100644 (file)
@@ -268,11 +268,14 @@ xfs_bmbt_free_block(
        struct xfs_trans        *tp = cur->bc_tp;
        xfs_fsblock_t           fsbno = XFS_DADDR_TO_FSB(mp, xfs_buf_daddr(bp));
        struct xfs_owner_info   oinfo;
+       int                     error;
 
        xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_ino.whichfork);
-       xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo);
-       ip->i_nblocks--;
+       error = xfs_free_extent_later(cur->bc_tp, fsbno, 1, &oinfo);
+       if (error)
+               return error;
 
+       ip->i_nblocks--;
        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L);
        return 0;
index a16d5de..34600f9 100644 (file)
@@ -1834,7 +1834,7 @@ retry:
  * might be sparse and only free the regions that are allocated as part of the
  * chunk.
  */
-STATIC void
+static int
 xfs_difree_inode_chunk(
        struct xfs_trans                *tp,
        xfs_agnumber_t                  agno,
@@ -1851,10 +1851,10 @@ xfs_difree_inode_chunk(
 
        if (!xfs_inobt_issparse(rec->ir_holemask)) {
                /* not sparse, calculate extent info directly */
-               xfs_free_extent_later(tp, XFS_AGB_TO_FSB(mp, agno, sagbno),
-                                 M_IGEO(mp)->ialloc_blks,
-                                 &XFS_RMAP_OINFO_INODES);
-               return;
+               return xfs_free_extent_later(tp,
+                               XFS_AGB_TO_FSB(mp, agno, sagbno),
+                               M_IGEO(mp)->ialloc_blks,
+                               &XFS_RMAP_OINFO_INODES);
        }
 
        /* holemask is only 16-bits (fits in an unsigned long) */
@@ -1871,6 +1871,8 @@ xfs_difree_inode_chunk(
                                                XFS_INOBT_HOLEMASK_BITS);
        nextbit = startidx + 1;
        while (startidx < XFS_INOBT_HOLEMASK_BITS) {
+               int error;
+
                nextbit = find_next_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS,
                                             nextbit);
                /*
@@ -1896,8 +1898,11 @@ xfs_difree_inode_chunk(
 
                ASSERT(agbno % mp->m_sb.sb_spino_align == 0);
                ASSERT(contigblk % mp->m_sb.sb_spino_align == 0);
-               xfs_free_extent_later(tp, XFS_AGB_TO_FSB(mp, agno, agbno),
-                                 contigblk, &XFS_RMAP_OINFO_INODES);
+               error = xfs_free_extent_later(tp,
+                               XFS_AGB_TO_FSB(mp, agno, agbno),
+                               contigblk, &XFS_RMAP_OINFO_INODES);
+               if (error)
+                       return error;
 
                /* reset range to current bit and carry on... */
                startidx = endidx = nextbit;
@@ -1905,6 +1910,7 @@ xfs_difree_inode_chunk(
 next:
                nextbit++;
        }
+       return 0;
 }
 
 STATIC int
@@ -2003,7 +2009,9 @@ xfs_difree_inobt(
                        goto error0;
                }
 
-               xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
+               error = xfs_difree_inode_chunk(tp, pag->pag_agno, &rec);
+               if (error)
+                       goto error0;
        } else {
                xic->deleted = false;
 
index f13e080..269573c 100644 (file)
@@ -324,7 +324,6 @@ struct xfs_inode_log_format_32 {
 #define XFS_ILOG_DOWNER        0x200   /* change the data fork owner on replay */
 #define XFS_ILOG_AOWNER        0x400   /* change the attr fork owner on replay */
 
-
 /*
  * The timestamps are dirty, but not necessarily anything else in the inode
  * core.  Unlike the other fields above this one must never make it to disk
@@ -333,6 +332,14 @@ struct xfs_inode_log_format_32 {
  */
 #define XFS_ILOG_TIMESTAMP     0x4000
 
+/*
+ * The version field has been changed, but not necessarily anything else of
+ * interest. This must never make it to disk - it is used purely to ensure that
+ * the inode item ->precommit operation can update the fsync flag triggers
+ * in the inode item correctly.
+ */
+#define XFS_ILOG_IVERSION      0x8000
+
 #define        XFS_ILOG_NONCORE        (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
                                 XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
                                 XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
index c1c6577..b6e2143 100644 (file)
@@ -1151,8 +1151,10 @@ xfs_refcount_adjust_extents(
                                fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
                                                cur->bc_ag.pag->pag_agno,
                                                tmp.rc_startblock);
-                               xfs_free_extent_later(cur->bc_tp, fsbno,
+                               error = xfs_free_extent_later(cur->bc_tp, fsbno,
                                                  tmp.rc_blockcount, NULL);
+                               if (error)
+                                       goto out_error;
                        }
 
                        (*agbno) += tmp.rc_blockcount;
@@ -1210,8 +1212,10 @@ xfs_refcount_adjust_extents(
                        fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
                                        cur->bc_ag.pag->pag_agno,
                                        ext.rc_startblock);
-                       xfs_free_extent_later(cur->bc_tp, fsbno,
+                       error = xfs_free_extent_later(cur->bc_tp, fsbno,
                                        ext.rc_blockcount, NULL);
+                       if (error)
+                               goto out_error;
                }
 
 skip:
@@ -1976,7 +1980,10 @@ xfs_refcount_recover_cow_leftovers(
                                rr->rr_rrec.rc_blockcount);
 
                /* Free the block. */
-               xfs_free_extent_later(tp, fsb, rr->rr_rrec.rc_blockcount, NULL);
+               error = xfs_free_extent_later(tp, fsb,
+                               rr->rr_rrec.rc_blockcount, NULL);
+               if (error)
+                       goto out_trans;
 
                error = xfs_trans_commit(tp);
                if (error)
index 8b55470..cb4796b 100644 (file)
@@ -40,9 +40,8 @@ xfs_trans_ijoin(
        iip->ili_lock_flags = lock_flags;
        ASSERT(!xfs_iflags_test(ip, XFS_ISTALE));
 
-       /*
-        * Get a log_item_desc to point at the new item.
-        */
+       /* Reset the per-tx dirty context and add the item to the tx. */
+       iip->ili_dirty_flags = 0;
        xfs_trans_add_item(tp, &iip->ili_item);
 }
 
@@ -76,17 +75,10 @@ xfs_trans_ichgtime(
 /*
  * This is called to mark the fields indicated in fieldmask as needing to be
  * logged when the transaction is committed.  The inode must already be
- * associated with the given transaction.
- *
- * The values for fieldmask are defined in xfs_inode_item.h.  We always log all
- * of the core inode if any of it has changed, and we always log all of the
- * inline data/extents/b-tree root if any of them has changed.
- *
- * Grab and pin the cluster buffer associated with this inode to avoid RMW
- * cycles at inode writeback time. Avoid the need to add error handling to every
- * xfs_trans_log_inode() call by shutting down on read error.  This will cause
- * transactions to fail and everything to error out, just like if we return a
- * read error in a dirty transaction and cancel it.
+ * associated with the given transaction. All we do here is record where the
+ * inode was dirtied and mark the transaction and inode log item dirty;
+ * everything else is done in the ->precommit log item operation after the
+ * changes in the transaction have been completed.
  */
 void
 xfs_trans_log_inode(
@@ -96,7 +88,6 @@ xfs_trans_log_inode(
 {
        struct xfs_inode_log_item *iip = ip->i_itemp;
        struct inode            *inode = VFS_I(ip);
-       uint                    iversion_flags = 0;
 
        ASSERT(iip);
        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
@@ -105,18 +96,6 @@ xfs_trans_log_inode(
        tp->t_flags |= XFS_TRANS_DIRTY;
 
        /*
-        * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
-        * don't matter - we either will need an extra transaction in 24 hours
-        * to log the timestamps, or will clear already cleared fields in the
-        * worst case.
-        */
-       if (inode->i_state & I_DIRTY_TIME) {
-               spin_lock(&inode->i_lock);
-               inode->i_state &= ~I_DIRTY_TIME;
-               spin_unlock(&inode->i_lock);
-       }
-
-       /*
         * First time we log the inode in a transaction, bump the inode change
         * counter if it is configured for this to occur. While we have the
         * inode locked exclusively for metadata modification, we can usually
@@ -128,86 +107,10 @@ xfs_trans_log_inode(
        if (!test_and_set_bit(XFS_LI_DIRTY, &iip->ili_item.li_flags)) {
                if (IS_I_VERSION(inode) &&
                    inode_maybe_inc_iversion(inode, flags & XFS_ILOG_CORE))
-                       iversion_flags = XFS_ILOG_CORE;
-       }
-
-       /*
-        * If we're updating the inode core or the timestamps and it's possible
-        * to upgrade this inode to bigtime format, do so now.
-        */
-       if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
-           xfs_has_bigtime(ip->i_mount) &&
-           !xfs_inode_has_bigtime(ip)) {
-               ip->i_diflags2 |= XFS_DIFLAG2_BIGTIME;
-               flags |= XFS_ILOG_CORE;
-       }
-
-       /*
-        * Inode verifiers do not check that the extent size hint is an integer
-        * multiple of the rt extent size on a directory with both rtinherit
-        * and extszinherit flags set.  If we're logging a directory that is
-        * misconfigured in this way, clear the hint.
-        */
-       if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
-           (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
-           (ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) {
-               ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
-                                  XFS_DIFLAG_EXTSZINHERIT);
-               ip->i_extsize = 0;
-               flags |= XFS_ILOG_CORE;
+                       flags |= XFS_ILOG_IVERSION;
        }
 
-       /*
-        * Record the specific change for fdatasync optimisation. This allows
-        * fdatasync to skip log forces for inodes that are only timestamp
-        * dirty.
-        */
-       spin_lock(&iip->ili_lock);
-       iip->ili_fsync_fields |= flags;
-
-       if (!iip->ili_item.li_buf) {
-               struct xfs_buf  *bp;
-               int             error;
-
-               /*
-                * We hold the ILOCK here, so this inode is not going to be
-                * flushed while we are here. Further, because there is no
-                * buffer attached to the item, we know that there is no IO in
-                * progress, so nothing will clear the ili_fields while we read
-                * in the buffer. Hence we can safely drop the spin lock and
-                * read the buffer knowing that the state will not change from
-                * here.
-                */
-               spin_unlock(&iip->ili_lock);
-               error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &bp);
-               if (error) {
-                       xfs_force_shutdown(ip->i_mount, SHUTDOWN_META_IO_ERROR);
-                       return;
-               }
-
-               /*
-                * We need an explicit buffer reference for the log item but
-                * don't want the buffer to remain attached to the transaction.
-                * Hold the buffer but release the transaction reference once
-                * we've attached the inode log item to the buffer log item
-                * list.
-                */
-               xfs_buf_hold(bp);
-               spin_lock(&iip->ili_lock);
-               iip->ili_item.li_buf = bp;
-               bp->b_flags |= _XBF_INODES;
-               list_add_tail(&iip->ili_item.li_bio_list, &bp->b_li_list);
-               xfs_trans_brelse(tp, bp);
-       }
-
-       /*
-        * Always OR in the bits from the ili_last_fields field.  This is to
-        * coordinate with the xfs_iflush() and xfs_buf_inode_iodone() routines
-        * in the eventual clearing of the ili_fields bits.  See the big comment
-        * in xfs_iflush() for an explanation of this coordination mechanism.
-        */
-       iip->ili_fields |= (flags | iip->ili_last_fields | iversion_flags);
-       spin_unlock(&iip->ili_lock);
+       iip->ili_dirty_flags |= flags;
 }
 
 int
index 69bc89d..5bf4326 100644 (file)
@@ -769,14 +769,14 @@ xchk_are_bmaps_contiguous(
  * mapping or false if there are no more mappings.  Caller must ensure that
  * @info.icur is zeroed before the first call.
  */
-static int
+static bool
 xchk_bmap_iext_iter(
        struct xchk_bmap_info   *info,
        struct xfs_bmbt_irec    *irec)
 {
        struct xfs_bmbt_irec    got;
        struct xfs_ifork        *ifp;
-       xfs_filblks_t           prev_len;
+       unsigned int            nr = 0;
 
        ifp = xfs_ifork_ptr(info->sc->ip, info->whichfork);
 
@@ -790,12 +790,12 @@ xchk_bmap_iext_iter(
                                irec->br_startoff);
                return false;
        }
+       nr++;
 
        /*
         * Iterate subsequent iextent records and merge them with the one
         * that we just read, if possible.
         */
-       prev_len = irec->br_blockcount;
        while (xfs_iext_peek_next_extent(ifp, &info->icur, &got)) {
                if (!xchk_are_bmaps_contiguous(irec, &got))
                        break;
@@ -805,20 +805,21 @@ xchk_bmap_iext_iter(
                                        got.br_startoff);
                        return false;
                }
-
-               /*
-                * Notify the user of mergeable records in the data or attr
-                * forks.  CoW forks only exist in memory so we ignore them.
-                */
-               if (info->whichfork != XFS_COW_FORK &&
-                   prev_len + got.br_blockcount > BMBT_BLOCKCOUNT_MASK)
-                       xchk_ino_set_preen(info->sc, info->sc->ip->i_ino);
+               nr++;
 
                irec->br_blockcount += got.br_blockcount;
-               prev_len = got.br_blockcount;
                xfs_iext_next(ifp, &info->icur);
        }
 
+       /*
+        * If the merged mapping could be expressed with fewer bmbt records
+        * than we actually found, notify the user that this fork could be
+        * optimized.  CoW forks only exist in memory so we ignore them.
+        */
+       if (nr > 1 && info->whichfork != XFS_COW_FORK &&
+           howmany_64(irec->br_blockcount, XFS_MAX_BMBT_EXTLEN) < nr)
+               xchk_ino_set_preen(info->sc, info->sc->ip->i_ino);
+
        return true;
 }
 
index b38e938..e113f2f 100644 (file)
@@ -105,10 +105,10 @@ struct xfs_scrub {
 };
 
 /* XCHK state flags grow up from zero, XREP state flags grown down from 2^31 */
-#define XCHK_TRY_HARDER                (1 << 0)  /* can't get resources, try again */
-#define XCHK_FSGATES_DRAIN     (1 << 2)  /* defer ops draining enabled */
-#define XCHK_NEED_DRAIN                (1 << 3)  /* scrub needs to drain defer ops */
-#define XREP_ALREADY_FIXED     (1 << 31) /* checking our repair work */
+#define XCHK_TRY_HARDER                (1U << 0)  /* can't get resources, try again */
+#define XCHK_FSGATES_DRAIN     (1U << 2)  /* defer ops draining enabled */
+#define XCHK_NEED_DRAIN                (1U << 3)  /* scrub needs to drain defer ops */
+#define XREP_ALREADY_FIXED     (1U << 31) /* checking our repair work */
 
 /*
  * The XCHK_FSGATES* flags reflect functionality in the main filesystem that
index df7322e..023d4e0 100644 (file)
@@ -452,10 +452,18 @@ xfs_buf_item_format(
  * This is called to pin the buffer associated with the buf log item in memory
  * so it cannot be written out.
  *
- * We also always take a reference to the buffer log item here so that the bli
- * is held while the item is pinned in memory. This means that we can
- * unconditionally drop the reference count a transaction holds when the
- * transaction is completed.
+ * We take a reference to the buffer log item here so that the BLI life cycle
+ * extends at least until the buffer is unpinned via xfs_buf_item_unpin() and
+ * inserted into the AIL.
+ *
+ * We also need to take a reference to the buffer itself as the BLI unpin
+ * processing requires accessing the buffer after the BLI has dropped the final
+ * BLI reference. See xfs_buf_item_unpin() for an explanation.
+ * If unpins race to drop the final BLI reference and only the
+ * BLI owns a reference to the buffer, then the loser of the race can have the
+ * buffer fgreed from under it (e.g. on shutdown). Taking a buffer reference per
+ * pin count ensures the life cycle of the buffer extends for as
+ * long as we hold the buffer pin reference in xfs_buf_item_unpin().
  */
 STATIC void
 xfs_buf_item_pin(
@@ -470,13 +478,30 @@ xfs_buf_item_pin(
 
        trace_xfs_buf_item_pin(bip);
 
+       xfs_buf_hold(bip->bli_buf);
        atomic_inc(&bip->bli_refcount);
        atomic_inc(&bip->bli_buf->b_pin_count);
 }
 
 /*
- * This is called to unpin the buffer associated with the buf log item which
- * was previously pinned with a call to xfs_buf_item_pin().
+ * This is called to unpin the buffer associated with the buf log item which was
+ * previously pinned with a call to xfs_buf_item_pin().  We enter this function
+ * with a buffer pin count, a buffer reference and a BLI reference.
+ *
+ * We must drop the BLI reference before we unpin the buffer because the AIL
+ * doesn't acquire a BLI reference whenever it accesses it. Therefore if the
+ * refcount drops to zero, the bli could still be AIL resident and the buffer
+ * submitted for I/O at any point before we return. This can result in IO
+ * completion freeing the buffer while we are still trying to access it here.
+ * This race condition can also occur in shutdown situations where we abort and
+ * unpin buffers from contexts other that journal IO completion.
+ *
+ * Hence we have to hold a buffer reference per pin count to ensure that the
+ * buffer cannot be freed until we have finished processing the unpin operation.
+ * The reference is taken in xfs_buf_item_pin(), and we must hold it until we
+ * are done processing the buffer state. In the case of an abort (remove =
+ * true) then we re-use the current pin reference as the IO reference we hand
+ * off to IO failure handling.
  */
 STATIC void
 xfs_buf_item_unpin(
@@ -493,24 +518,18 @@ xfs_buf_item_unpin(
 
        trace_xfs_buf_item_unpin(bip);
 
-       /*
-        * Drop the bli ref associated with the pin and grab the hold required
-        * for the I/O simulation failure in the abort case. We have to do this
-        * before the pin count drops because the AIL doesn't acquire a bli
-        * reference. Therefore if the refcount drops to zero, the bli could
-        * still be AIL resident and the buffer submitted for I/O (and freed on
-        * completion) at any point before we return. This can be removed once
-        * the AIL properly holds a reference on the bli.
-        */
        freed = atomic_dec_and_test(&bip->bli_refcount);
-       if (freed && !stale && remove)
-               xfs_buf_hold(bp);
        if (atomic_dec_and_test(&bp->b_pin_count))
                wake_up_all(&bp->b_waiters);
 
-        /* nothing to do but drop the pin count if the bli is active */
-       if (!freed)
+       /*
+        * Nothing to do but drop the buffer pin reference if the BLI is
+        * still active.
+        */
+       if (!freed) {
+               xfs_buf_rele(bp);
                return;
+       }
 
        if (stale) {
                ASSERT(bip->bli_flags & XFS_BLI_STALE);
@@ -523,6 +542,15 @@ xfs_buf_item_unpin(
                trace_xfs_buf_item_unpin_stale(bip);
 
                /*
+                * The buffer has been locked and referenced since it was marked
+                * stale so we own both lock and reference exclusively here. We
+                * do not need the pin reference any more, so drop it now so
+                * that we only have one reference to drop once item completion
+                * processing is complete.
+                */
+               xfs_buf_rele(bp);
+
+               /*
                 * If we get called here because of an IO error, we may or may
                 * not have the item on the AIL. xfs_trans_ail_delete() will
                 * take care of that situation. xfs_trans_ail_delete() drops
@@ -538,16 +566,30 @@ xfs_buf_item_unpin(
                        ASSERT(bp->b_log_item == NULL);
                }
                xfs_buf_relse(bp);
-       } else if (remove) {
+               return;
+       }
+
+       if (remove) {
                /*
-                * The buffer must be locked and held by the caller to simulate
-                * an async I/O failure. We acquired the hold for this case
-                * before the buffer was unpinned.
+                * We need to simulate an async IO failures here to ensure that
+                * the correct error completion is run on this buffer. This
+                * requires a reference to the buffer and for the buffer to be
+                * locked. We can safely pass ownership of the pin reference to
+                * the IO to ensure that nothing can free the buffer while we
+                * wait for the lock and then run the IO failure completion.
                 */
                xfs_buf_lock(bp);
                bp->b_flags |= XBF_ASYNC;
                xfs_buf_ioend_fail(bp);
+               return;
        }
+
+       /*
+        * BLI has no more active references - it will be moved to the AIL to
+        * manage the remaining BLI/buffer life cycle. There is nothing left for
+        * us to do here so drop the pin reference to the buffer.
+        */
+       xfs_buf_rele(bp);
 }
 
 STATIC uint
index 22c1393..2fc98d3 100644 (file)
@@ -78,7 +78,6 @@ restart:
                *longest = 0;
                err = xfs_bmap_longest_free_extent(pag, NULL, longest);
                if (err) {
-                       xfs_perag_rele(pag);
                        if (err != -EAGAIN)
                                break;
                        /* Couldn't lock the AGF, skip this AG. */
index 0f60e30..4538909 100644 (file)
@@ -454,6 +454,27 @@ xfs_inodegc_queue_all(
        return ret;
 }
 
+/* Wait for all queued work and collect errors */
+static int
+xfs_inodegc_wait_all(
+       struct xfs_mount        *mp)
+{
+       int                     cpu;
+       int                     error = 0;
+
+       flush_workqueue(mp->m_inodegc_wq);
+       for_each_online_cpu(cpu) {
+               struct xfs_inodegc      *gc;
+
+               gc = per_cpu_ptr(mp->m_inodegc, cpu);
+               if (gc->error && !error)
+                       error = gc->error;
+               gc->error = 0;
+       }
+
+       return error;
+}
+
 /*
  * Check the validity of the inode we just found it the cache
  */
@@ -1491,15 +1512,14 @@ xfs_blockgc_free_space(
        if (error)
                return error;
 
-       xfs_inodegc_flush(mp);
-       return 0;
+       return xfs_inodegc_flush(mp);
 }
 
 /*
  * Reclaim all the free space that we can by scheduling the background blockgc
  * and inodegc workers immediately and waiting for them all to clear.
  */
-void
+int
 xfs_blockgc_flush_all(
        struct xfs_mount        *mp)
 {
@@ -1520,7 +1540,7 @@ xfs_blockgc_flush_all(
        for_each_perag_tag(mp, agno, pag, XFS_ICI_BLOCKGC_TAG)
                flush_delayed_work(&pag->pag_blockgc_work);
 
-       xfs_inodegc_flush(mp);
+       return xfs_inodegc_flush(mp);
 }
 
 /*
@@ -1842,13 +1862,17 @@ xfs_inodegc_set_reclaimable(
  * This is the last chance to make changes to an otherwise unreferenced file
  * before incore reclamation happens.
  */
-static void
+static int
 xfs_inodegc_inactivate(
        struct xfs_inode        *ip)
 {
+       int                     error;
+
        trace_xfs_inode_inactivating(ip);
-       xfs_inactive(ip);
+       error = xfs_inactive(ip);
        xfs_inodegc_set_reclaimable(ip);
+       return error;
+
 }
 
 void
@@ -1880,8 +1904,12 @@ xfs_inodegc_worker(
 
        WRITE_ONCE(gc->shrinker_hits, 0);
        llist_for_each_entry_safe(ip, n, node, i_gclist) {
+               int     error;
+
                xfs_iflags_set(ip, XFS_INACTIVATING);
-               xfs_inodegc_inactivate(ip);
+               error = xfs_inodegc_inactivate(ip);
+               if (error && !gc->error)
+                       gc->error = error;
        }
 
        memalloc_nofs_restore(nofs_flag);
@@ -1905,13 +1933,13 @@ xfs_inodegc_push(
  * Force all currently queued inode inactivation work to run immediately and
  * wait for the work to finish.
  */
-void
+int
 xfs_inodegc_flush(
        struct xfs_mount        *mp)
 {
        xfs_inodegc_push(mp);
        trace_xfs_inodegc_flush(mp, __return_address);
-       flush_workqueue(mp->m_inodegc_wq);
+       return xfs_inodegc_wait_all(mp);
 }
 
 /*
index 8791019..1dcdcb2 100644 (file)
@@ -62,7 +62,7 @@ int xfs_blockgc_free_dquots(struct xfs_mount *mp, struct xfs_dquot *udqp,
                unsigned int iwalk_flags);
 int xfs_blockgc_free_quota(struct xfs_inode *ip, unsigned int iwalk_flags);
 int xfs_blockgc_free_space(struct xfs_mount *mp, struct xfs_icwalk *icm);
-void xfs_blockgc_flush_all(struct xfs_mount *mp);
+int xfs_blockgc_flush_all(struct xfs_mount *mp);
 
 void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip);
 void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip);
@@ -80,7 +80,7 @@ void xfs_blockgc_start(struct xfs_mount *mp);
 
 void xfs_inodegc_worker(struct work_struct *work);
 void xfs_inodegc_push(struct xfs_mount *mp);
-void xfs_inodegc_flush(struct xfs_mount *mp);
+int xfs_inodegc_flush(struct xfs_mount *mp);
 void xfs_inodegc_stop(struct xfs_mount *mp);
 void xfs_inodegc_start(struct xfs_mount *mp);
 void xfs_inodegc_cpu_dead(struct xfs_mount *mp, unsigned int cpu);
index 5808aba..9e62cc5 100644 (file)
@@ -1620,16 +1620,7 @@ xfs_inactive_ifree(
         */
        xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
 
-       /*
-        * Just ignore errors at this point.  There is nothing we can do except
-        * to try to keep going. Make sure it's not a silent error.
-        */
-       error = xfs_trans_commit(tp);
-       if (error)
-               xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
-                       __func__, error);
-
-       return 0;
+       return xfs_trans_commit(tp);
 }
 
 /*
@@ -1693,12 +1684,12 @@ xfs_inode_needs_inactive(
  * now be truncated.  Also, we clear all of the read-ahead state
  * kept for the inode here since the file is now closed.
  */
-void
+int
 xfs_inactive(
        xfs_inode_t     *ip)
 {
        struct xfs_mount        *mp;
-       int                     error;
+       int                     error = 0;
        int                     truncate = 0;
 
        /*
@@ -1736,7 +1727,7 @@ xfs_inactive(
                 * reference to the inode at this point anyways.
                 */
                if (xfs_can_free_eofblocks(ip, true))
-                       xfs_free_eofblocks(ip);
+                       error = xfs_free_eofblocks(ip);
 
                goto out;
        }
@@ -1773,7 +1764,7 @@ xfs_inactive(
        /*
         * Free the inode.
         */
-       xfs_inactive_ifree(ip);
+       error = xfs_inactive_ifree(ip);
 
 out:
        /*
@@ -1781,6 +1772,7 @@ out:
         * the attached dquots.
         */
        xfs_qm_dqdetach(ip);
+       return error;
 }
 
 /*
index 69d21e4..7547caf 100644 (file)
@@ -470,7 +470,7 @@ enum layout_break_reason {
        (xfs_has_grpid((pip)->i_mount) || (VFS_I(pip)->i_mode & S_ISGID))
 
 int            xfs_release(struct xfs_inode *ip);
-void           xfs_inactive(struct xfs_inode *ip);
+int            xfs_inactive(struct xfs_inode *ip);
 int            xfs_lookup(struct xfs_inode *dp, const struct xfs_name *name,
                           struct xfs_inode **ipp, struct xfs_name *ci_name);
 int            xfs_create(struct mnt_idmap *idmap,
index ca2941a..91c847a 100644 (file)
@@ -29,6 +29,153 @@ static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip)
        return container_of(lip, struct xfs_inode_log_item, ili_item);
 }
 
+static uint64_t
+xfs_inode_item_sort(
+       struct xfs_log_item     *lip)
+{
+       return INODE_ITEM(lip)->ili_inode->i_ino;
+}
+
+/*
+ * Prior to finally logging the inode, we have to ensure that all the
+ * per-modification inode state changes are applied. This includes VFS inode
+ * state updates, format conversions, verifier state synchronisation and
+ * ensuring the inode buffer remains in memory whilst the inode is dirty.
+ *
+ * We have to be careful when we grab the inode cluster buffer due to lock
+ * ordering constraints. The unlinked inode modifications (xfs_iunlink_item)
+ * require AGI -> inode cluster buffer lock order. The inode cluster buffer is
+ * not locked until ->precommit, so it happens after everything else has been
+ * modified.
+ *
+ * Further, we have AGI -> AGF lock ordering, and with O_TMPFILE handling we
+ * have AGI -> AGF -> iunlink item -> inode cluster buffer lock order. Hence we
+ * cannot safely lock the inode cluster buffer in xfs_trans_log_inode() because
+ * it can be called on a inode (e.g. via bumplink/droplink) before we take the
+ * AGF lock modifying directory blocks.
+ *
+ * Rather than force a complete rework of all the transactions to call
+ * xfs_trans_log_inode() once and once only at the end of every transaction, we
+ * move the pinning of the inode cluster buffer to a ->precommit operation. This
+ * matches how the xfs_iunlink_item locks the inode cluster buffer, and it
+ * ensures that the inode cluster buffer locking is always done last in a
+ * transaction. i.e. we ensure the lock order is always AGI -> AGF -> inode
+ * cluster buffer.
+ *
+ * If we return the inode number as the precommit sort key then we'll also
+ * guarantee that the order all inode cluster buffer locking is the same all the
+ * inodes and unlink items in the transaction.
+ */
+static int
+xfs_inode_item_precommit(
+       struct xfs_trans        *tp,
+       struct xfs_log_item     *lip)
+{
+       struct xfs_inode_log_item *iip = INODE_ITEM(lip);
+       struct xfs_inode        *ip = iip->ili_inode;
+       struct inode            *inode = VFS_I(ip);
+       unsigned int            flags = iip->ili_dirty_flags;
+
+       /*
+        * Don't bother with i_lock for the I_DIRTY_TIME check here, as races
+        * don't matter - we either will need an extra transaction in 24 hours
+        * to log the timestamps, or will clear already cleared fields in the
+        * worst case.
+        */
+       if (inode->i_state & I_DIRTY_TIME) {
+               spin_lock(&inode->i_lock);
+               inode->i_state &= ~I_DIRTY_TIME;
+               spin_unlock(&inode->i_lock);
+       }
+
+       /*
+        * If we're updating the inode core or the timestamps and it's possible
+        * to upgrade this inode to bigtime format, do so now.
+        */
+       if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
+           xfs_has_bigtime(ip->i_mount) &&
+           !xfs_inode_has_bigtime(ip)) {
+               ip->i_diflags2 |= XFS_DIFLAG2_BIGTIME;
+               flags |= XFS_ILOG_CORE;
+       }
+
+       /*
+        * Inode verifiers do not check that the extent size hint is an integer
+        * multiple of the rt extent size on a directory with both rtinherit
+        * and extszinherit flags set.  If we're logging a directory that is
+        * misconfigured in this way, clear the hint.
+        */
+       if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
+           (ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
+           (ip->i_extsize % ip->i_mount->m_sb.sb_rextsize) > 0) {
+               ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
+                                  XFS_DIFLAG_EXTSZINHERIT);
+               ip->i_extsize = 0;
+               flags |= XFS_ILOG_CORE;
+       }
+
+       /*
+        * Record the specific change for fdatasync optimisation. This allows
+        * fdatasync to skip log forces for inodes that are only timestamp
+        * dirty. Once we've processed the XFS_ILOG_IVERSION flag, convert it
+        * to XFS_ILOG_CORE so that the actual on-disk dirty tracking
+        * (ili_fields) correctly tracks that the version has changed.
+        */
+       spin_lock(&iip->ili_lock);
+       iip->ili_fsync_fields |= (flags & ~XFS_ILOG_IVERSION);
+       if (flags & XFS_ILOG_IVERSION)
+               flags = ((flags & ~XFS_ILOG_IVERSION) | XFS_ILOG_CORE);
+
+       if (!iip->ili_item.li_buf) {
+               struct xfs_buf  *bp;
+               int             error;
+
+               /*
+                * We hold the ILOCK here, so this inode is not going to be
+                * flushed while we are here. Further, because there is no
+                * buffer attached to the item, we know that there is no IO in
+                * progress, so nothing will clear the ili_fields while we read
+                * in the buffer. Hence we can safely drop the spin lock and
+                * read the buffer knowing that the state will not change from
+                * here.
+                */
+               spin_unlock(&iip->ili_lock);
+               error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &bp);
+               if (error)
+                       return error;
+
+               /*
+                * We need an explicit buffer reference for the log item but
+                * don't want the buffer to remain attached to the transaction.
+                * Hold the buffer but release the transaction reference once
+                * we've attached the inode log item to the buffer log item
+                * list.
+                */
+               xfs_buf_hold(bp);
+               spin_lock(&iip->ili_lock);
+               iip->ili_item.li_buf = bp;
+               bp->b_flags |= _XBF_INODES;
+               list_add_tail(&iip->ili_item.li_bio_list, &bp->b_li_list);
+               xfs_trans_brelse(tp, bp);
+       }
+
+       /*
+        * Always OR in the bits from the ili_last_fields field.  This is to
+        * coordinate with the xfs_iflush() and xfs_buf_inode_iodone() routines
+        * in the eventual clearing of the ili_fields bits.  See the big comment
+        * in xfs_iflush() for an explanation of this coordination mechanism.
+        */
+       iip->ili_fields |= (flags | iip->ili_last_fields);
+       spin_unlock(&iip->ili_lock);
+
+       /*
+        * We are done with the log item transaction dirty state, so clear it so
+        * that it doesn't pollute future transactions.
+        */
+       iip->ili_dirty_flags = 0;
+       return 0;
+}
+
 /*
  * The logged size of an inode fork is always the current size of the inode
  * fork. This means that when an inode fork is relogged, the size of the logged
@@ -662,6 +809,8 @@ xfs_inode_item_committing(
 }
 
 static const struct xfs_item_ops xfs_inode_item_ops = {
+       .iop_sort       = xfs_inode_item_sort,
+       .iop_precommit  = xfs_inode_item_precommit,
        .iop_size       = xfs_inode_item_size,
        .iop_format     = xfs_inode_item_format,
        .iop_pin        = xfs_inode_item_pin,
index bbd836a..377e060 100644 (file)
@@ -17,6 +17,7 @@ struct xfs_inode_log_item {
        struct xfs_log_item     ili_item;          /* common portion */
        struct xfs_inode        *ili_inode;        /* inode ptr */
        unsigned short          ili_lock_flags;    /* inode lock flags */
+       unsigned int            ili_dirty_flags;   /* dirty in current tx */
        /*
         * The ili_lock protects the interactions between the dirty state and
         * the flush state of the inode log item. This allows us to do atomic
index 322eb2e..82c81d2 100644 (file)
@@ -2711,7 +2711,9 @@ xlog_recover_iunlink_bucket(
                         * just to flush the inodegc queue and wait for it to
                         * complete.
                         */
-                       xfs_inodegc_flush(mp);
+                       error = xfs_inodegc_flush(mp);
+                       if (error)
+                               break;
                }
 
                prev_agino = agino;
@@ -2719,10 +2721,15 @@ xlog_recover_iunlink_bucket(
        }
 
        if (prev_ip) {
+               int     error2;
+
                ip->i_prev_unlinked = prev_agino;
                xfs_irele(prev_ip);
+
+               error2 = xfs_inodegc_flush(mp);
+               if (error2 && !error)
+                       return error2;
        }
-       xfs_inodegc_flush(mp);
        return error;
 }
 
@@ -2789,7 +2796,6 @@ xlog_recover_iunlink_ag(
                         * bucket and remaining inodes on it unreferenced and
                         * unfreeable.
                         */
-                       xfs_inodegc_flush(pag->pag_mount);
                        xlog_recover_clear_agi_bucket(pag, bucket);
                }
        }
@@ -2806,13 +2812,6 @@ xlog_recover_process_iunlinks(
 
        for_each_perag(log->l_mp, agno, pag)
                xlog_recover_iunlink_ag(pag);
-
-       /*
-        * Flush the pending unlinked inodes to ensure that the inactivations
-        * are fully completed on disk and the incore inodes can be reclaimed
-        * before we signal that recovery is complete.
-        */
-       xfs_inodegc_flush(log->l_mp);
 }
 
 STATIC void
index aaaf5ec..6c09f89 100644 (file)
@@ -62,6 +62,7 @@ struct xfs_error_cfg {
 struct xfs_inodegc {
        struct llist_head       list;
        struct delayed_work     work;
+       int                     error;
 
        /* approximate count of inodes in the list */
        unsigned int            items;
index f5dc46c..abcc559 100644 (file)
@@ -616,8 +616,10 @@ xfs_reflink_cancel_cow_blocks(
                        xfs_refcount_free_cow_extent(*tpp, del.br_startblock,
                                        del.br_blockcount);
 
-                       xfs_free_extent_later(*tpp, del.br_startblock,
+                       error = xfs_free_extent_later(*tpp, del.br_startblock,
                                          del.br_blockcount, NULL);
+                       if (error)
+                               break;
 
                        /* Roll the transaction */
                        error = xfs_defer_finish(tpp);
index 7e70625..4120bd1 100644 (file)
@@ -1100,6 +1100,7 @@ xfs_inodegc_init_percpu(
 #endif
                init_llist_head(&gc->list);
                gc->items = 0;
+               gc->error = 0;
                INIT_DELAYED_WORK(&gc->work, xfs_inodegc_worker);
        }
        return 0;
index 8afc0c0..8c0bfc9 100644 (file)
@@ -290,7 +290,9 @@ retry:
                 * Do not perform a synchronous scan because callers can hold
                 * other locks.
                 */
-               xfs_blockgc_flush_all(mp);
+               error = xfs_blockgc_flush_all(mp);
+               if (error)
+                       return error;
                want_retry = false;
                goto retry;
        }
@@ -970,6 +972,11 @@ __xfs_trans_commit(
                error = xfs_defer_finish_noroll(&tp);
                if (error)
                        goto out_unreserve;
+
+               /* Run precommits from final tx in defer chain. */
+               error = xfs_trans_run_precommits(tp);
+               if (error)
+                       goto out_unreserve;
        }
 
        /*
index a6affc0..c941d99 100644 (file)
@@ -289,6 +289,8 @@ struct acpi_dep_data {
        acpi_handle supplier;
        acpi_handle consumer;
        bool honor_dep;
+       bool met;
+       bool free_when_met;
 };
 
 /* Performance Management */
index e6098a0..9ffdc04 100644 (file)
@@ -761,6 +761,7 @@ ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status
                                                     acpi_event_status
                                                     *event_status))
 ACPI_HW_DEPENDENT_RETURN_UINT32(u32 acpi_dispatch_gpe(acpi_handle gpe_device, u32 gpe_number))
+ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_hw_disable_all_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void))
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void))
index 1bf8e87..867b18e 100644 (file)
 #define SM8150_MMCX    9
 #define SM8150_MMCX_AO 10
 
+/* SA8155P is a special case, kept for backwards compatibility */
+#define SA8155P_CX     SM8150_CX
+#define SA8155P_CX_AO  SM8150_CX_AO
+#define SA8155P_EBI    SM8150_EBI
+#define SA8155P_GFX    SM8150_GFX
+#define SA8155P_MSS    SM8150_MSS
+#define SA8155P_MX     SM8150_MX
+#define SA8155P_MX_AO  SM8150_MX_AO
+
 /* SM8250 Power Domain Indexes */
 #define SM8250_CX      0
 #define SM8250_CX_AO   1
index 0f1001d..3ceb9df 100644 (file)
@@ -200,6 +200,7 @@ enum cpuhp_state {
 
        /* Online section invoked on the hotplugged CPU from the hotplug thread */
        CPUHP_AP_ONLINE_IDLE,
+       CPUHP_AP_HYPERV_ONLINE,
        CPUHP_AP_KVM_ONLINE,
        CPUHP_AP_SCHED_WAIT_EMPTY,
        CPUHP_AP_SMPBOOT_THREADS,
index 311cd93..dd5797f 100644 (file)
@@ -836,7 +836,7 @@ struct ata_port {
 
        struct mutex            scsi_scan_mutex;
        struct delayed_work     hotplug_task;
-       struct work_struct      scsi_rescan_task;
+       struct delayed_work     scsi_rescan_task;
 
        unsigned int            hsm_task_state;
 
index 94d2be5..4b9626c 100644 (file)
@@ -1238,6 +1238,18 @@ static inline u16 mlx5_core_max_vfs(const struct mlx5_core_dev *dev)
        return dev->priv.sriov.max_vfs;
 }
 
+static inline int mlx5_lag_is_lacp_owner(struct mlx5_core_dev *dev)
+{
+       /* LACP owner conditions:
+        * 1) Function is physical.
+        * 2) LAG is supported by FW.
+        * 3) LAG is managed by driver (currently the only option).
+        */
+       return  MLX5_CAP_GEN(dev, vport_group_manager) &&
+                  (MLX5_CAP_GEN(dev, num_lag_ports) > 1) &&
+                   MLX5_CAP_GEN(dev, lag_master);
+}
+
 static inline int mlx5_get_gid_table_len(u16 param)
 {
        if (param > 4) {
index 08fbd46..c2f0c60 100644 (file)
@@ -620,7 +620,7 @@ struct netdev_queue {
        netdevice_tracker       dev_tracker;
 
        struct Qdisc __rcu      *qdisc;
-       struct Qdisc            *qdisc_sleeping;
+       struct Qdisc __rcu      *qdisc_sleeping;
 #ifdef CONFIG_SYSFS
        struct kobject          kobj;
 #endif
@@ -768,8 +768,11 @@ static inline void rps_record_sock_flow(struct rps_sock_flow_table *table,
                /* We only give a hint, preemption can change CPU under us */
                val |= raw_smp_processor_id();
 
-               if (table->ents[index] != val)
-                       table->ents[index] = val;
+               /* The following WRITE_ONCE() is paired with the READ_ONCE()
+                * here, and another one in get_rps_cpu().
+                */
+               if (READ_ONCE(table->ents[index]) != val)
+                       WRITE_ONCE(table->ents[index], val);
        }
 }
 
index 2aba751..8654470 100644 (file)
@@ -106,12 +106,22 @@ extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
 #define RAW_NOTIFIER_INIT(name)        {                               \
                .head = NULL }
 
+#ifdef CONFIG_TREE_SRCU
 #define SRCU_NOTIFIER_INIT(name, pcpu)                         \
        {                                                       \
                .mutex = __MUTEX_INITIALIZER(name.mutex),       \
                .head = NULL,                                   \
+               .srcuu = __SRCU_USAGE_INIT(name.srcuu),         \
                .srcu = __SRCU_STRUCT_INIT(name.srcu, name.srcuu, pcpu), \
        }
+#else
+#define SRCU_NOTIFIER_INIT(name, pcpu)                         \
+       {                                                       \
+               .mutex = __MUTEX_INITIALIZER(name.mutex),       \
+               .head = NULL,                                   \
+               .srcu = __SRCU_STRUCT_INIT(name.srcu, name.srcuu, pcpu), \
+       }
+#endif
 
 #define ATOMIC_NOTIFIER_HEAD(name)                             \
        struct atomic_notifier_head name =                      \
index 423220e..93417ba 100644 (file)
@@ -69,9 +69,6 @@ struct llcc_slice_desc {
 /**
  * struct llcc_edac_reg_data - llcc edac registers data for each error type
  * @name: Name of the error
- * @synd_reg: Syndrome register address
- * @count_status_reg: Status register address to read the error count
- * @ways_status_reg: Status register address to read the error ways
  * @reg_cnt: Number of registers
  * @count_mask: Mask value to get the error count
  * @ways_mask: Mask value to get the error ways
@@ -80,9 +77,6 @@ struct llcc_slice_desc {
  */
 struct llcc_edac_reg_data {
        char *name;
-       u64 synd_reg;
-       u64 count_status_reg;
-       u64 ways_status_reg;
        u32 reg_cnt;
        u32 count_mask;
        u32 ways_mask;
index df81043..42b249b 100644 (file)
@@ -243,11 +243,7 @@ static inline bool is_ssam_device(struct device *d)
  * Return: Returns the pointer to the &struct ssam_device_driver wrapping the
  * given device driver @d.
  */
-static inline
-struct ssam_device_driver *to_ssam_device_driver(struct device_driver *d)
-{
-       return container_of(d, struct ssam_device_driver, driver);
-}
+#define to_ssam_device_driver(d)       container_of_const(d, struct ssam_device_driver, driver)
 
 const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table,
                                                  const struct ssam_device_uid uid);
index 367d538..e7c4487 100644 (file)
@@ -686,10 +686,7 @@ struct dtv_frontend_properties {
  * @id:                        Frontend ID
  * @exit:              Used to inform the DVB core that the frontend
  *                     thread should exit (usually, means that the hardware
- *                     got disconnected).
- * @remove_mutex:      mutex that avoids a race condition between a callback
- *                     called when the hardware is disconnected and the
- *                     file_operations of dvb_frontend.
+ *                     got disconnected.
  */
 
 struct dvb_frontend {
@@ -707,7 +704,6 @@ struct dvb_frontend {
        int (*callback)(void *adapter_priv, int component, int cmd, int arg);
        int id;
        unsigned int exit;
-       struct mutex remove_mutex;
 };
 
 /**
index 07df96c..872dcb9 100644 (file)
@@ -350,6 +350,7 @@ enum {
 enum {
        HCI_SETUP,
        HCI_CONFIG,
+       HCI_DEBUGFS_CREATED,
        HCI_AUTO_OFF,
        HCI_RFKILLED,
        HCI_MGMT,
index 8baf346..9654567 100644 (file)
@@ -515,6 +515,7 @@ struct hci_dev {
        struct work_struct      cmd_sync_work;
        struct list_head        cmd_sync_work_list;
        struct mutex            cmd_sync_work_lock;
+       struct mutex            unregister_lock;
        struct work_struct      cmd_sync_cancel_work;
        struct work_struct      reenable_adv_work;
 
@@ -1201,7 +1202,8 @@ static inline struct hci_conn *hci_conn_hash_lookup_cis(struct hci_dev *hdev,
                if (id != BT_ISO_QOS_CIS_UNSET && id != c->iso_qos.ucast.cis)
                        continue;
 
-               if (ba_type == c->dst_type && !bacmp(&c->dst, ba)) {
+               /* Match destination address if set */
+               if (!ba || (ba_type == c->dst_type && !bacmp(&c->dst, ba))) {
                        rcu_read_unlock();
                        return c;
                }
index 3fa5774..f6a8ecc 100644 (file)
@@ -180,7 +180,7 @@ struct pneigh_entry {
        netdevice_tracker       dev_tracker;
        u32                     flags;
        u8                      protocol;
-       u                     key[];
+       u32                     key[];
 };
 
 /*
index ebb28ec..f37f9f3 100644 (file)
@@ -268,7 +268,7 @@ int flow_offload_route_init(struct flow_offload *flow,
 
 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
 void flow_offload_refresh(struct nf_flowtable *flow_table,
-                         struct flow_offload *flow);
+                         struct flow_offload *flow, bool force);
 
 struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
                                                     struct flow_offload_tuple *tuple);
index 2e24ea1..83db182 100644 (file)
@@ -462,7 +462,8 @@ struct nft_set_ops {
                                               const struct nft_set *set,
                                               const struct nft_set_elem *elem,
                                               unsigned int flags);
-
+       void                            (*commit)(const struct nft_set *set);
+       void                            (*abort)(const struct nft_set *set);
        u64                             (*privsize)(const struct nlattr * const nla[],
                                                    const struct nft_set_desc *desc);
        bool                            (*estimate)(const struct nft_set_desc *desc,
@@ -557,6 +558,7 @@ struct nft_set {
        u16                             policy;
        u16                             udlen;
        unsigned char                   *udata;
+       struct list_head                pending_update;
        /* runtime data below here */
        const struct nft_set_ops        *ops ____cacheline_aligned;
        u16                             flags:14,
index 3cceb3e..5f2cfd8 100644 (file)
@@ -53,7 +53,7 @@ struct netns_sysctl_ipv6 {
        int seg6_flowlabel;
        u32 ioam6_id;
        u64 ioam6_id_wide;
-       bool skip_notify_on_dev_down;
+       u8 skip_notify_on_dev_down;
        u8 fib_notify_on_flag_change;
        u8 icmpv6_error_anycast_as_unicast;
 };
index 9233ad3..bc77792 100644 (file)
 #define PING_HTABLE_SIZE       64
 #define PING_HTABLE_MASK       (PING_HTABLE_SIZE-1)
 
-/*
- * gid_t is either uint or ushort.  We want to pass it to
- * proc_dointvec_minmax(), so it must not be larger than MAX_INT
- */
-#define GID_T_MAX (((gid_t)~0U) >> 1)
+#define GID_T_MAX (((gid_t)~0U) - 1)
 
 /* Compatibility glue so we can support IPv6 when it's compiled as a module */
 struct pingv6_ops {
index f436688..5722931 100644 (file)
@@ -127,6 +127,8 @@ static inline void qdisc_run(struct Qdisc *q)
        }
 }
 
+extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
+
 /* Calculate maximal size of packet seen by hard_start_xmit
    routine of this device.
  */
index 308ef0a..30fe780 100644 (file)
@@ -23,9 +23,6 @@ static inline int rpl_init(void)
 static inline void rpl_exit(void) {}
 #endif
 
-/* Worst decompression memory usage ipv6 address (16) + pad 7 */
-#define IPV6_RPL_SRH_WORST_SWAP_SIZE (sizeof(struct in6_addr) + 7)
-
 size_t ipv6_rpl_srh_size(unsigned char n, unsigned char cmpri,
                         unsigned char cmpre);
 
index fab5ba3..12eadec 100644 (file)
@@ -137,6 +137,13 @@ static inline void qdisc_refcount_inc(struct Qdisc *qdisc)
        refcount_inc(&qdisc->refcnt);
 }
 
+static inline bool qdisc_refcount_dec_if_one(struct Qdisc *qdisc)
+{
+       if (qdisc->flags & TCQ_F_BUILTIN)
+               return true;
+       return refcount_dec_if_one(&qdisc->refcnt);
+}
+
 /* Intended to be used by unlocked users, when concurrent qdisc release is
  * possible.
  */
@@ -545,7 +552,7 @@ static inline struct Qdisc *qdisc_root_bh(const struct Qdisc *qdisc)
 
 static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc)
 {
-       return qdisc->dev_queue->qdisc_sleeping;
+       return rcu_dereference_rtnl(qdisc->dev_queue->qdisc_sleeping);
 }
 
 static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc)
@@ -652,6 +659,7 @@ void dev_deactivate_many(struct list_head *head);
 struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
                              struct Qdisc *qdisc);
 void qdisc_reset(struct Qdisc *qdisc);
+void qdisc_destroy(struct Qdisc *qdisc);
 void qdisc_put(struct Qdisc *qdisc);
 void qdisc_put_unlocked(struct Qdisc *qdisc);
 void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, int n, int len);
@@ -754,7 +762,9 @@ static inline bool qdisc_tx_changing(const struct net_device *dev)
 
        for (i = 0; i < dev->num_tx_queues; i++) {
                struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
-               if (rcu_access_pointer(txq->qdisc) != txq->qdisc_sleeping)
+
+               if (rcu_access_pointer(txq->qdisc) !=
+                   rcu_access_pointer(txq->qdisc_sleeping))
                        return true;
        }
        return false;
index b418425..6f428a7 100644 (file)
@@ -1152,8 +1152,12 @@ static inline void sock_rps_record_flow(const struct sock *sk)
                 * OR   an additional socket flag
                 * [1] : sk_state and sk_prot are in the same cache line.
                 */
-               if (sk->sk_state == TCP_ESTABLISHED)
-                       sock_rps_record_flow_hash(sk->sk_rxhash);
+               if (sk->sk_state == TCP_ESTABLISHED) {
+                       /* This READ_ONCE() is paired with the WRITE_ONCE()
+                        * from sock_rps_save_rxhash() and sock_rps_reset_rxhash().
+                        */
+                       sock_rps_record_flow_hash(READ_ONCE(sk->sk_rxhash));
+               }
        }
 #endif
 }
@@ -1162,15 +1166,19 @@ static inline void sock_rps_save_rxhash(struct sock *sk,
                                        const struct sk_buff *skb)
 {
 #ifdef CONFIG_RPS
-       if (unlikely(sk->sk_rxhash != skb->hash))
-               sk->sk_rxhash = skb->hash;
+       /* The following WRITE_ONCE() is paired with the READ_ONCE()
+        * here, and another one in sock_rps_record_flow().
+        */
+       if (unlikely(READ_ONCE(sk->sk_rxhash) != skb->hash))
+               WRITE_ONCE(sk->sk_rxhash, skb->hash);
 #endif
 }
 
 static inline void sock_rps_reset_rxhash(struct sock *sk)
 {
 #ifdef CONFIG_RPS
-       sk->sk_rxhash = 0;
+       /* Paired with READ_ONCE() in sock_rps_record_flow() */
+       WRITE_ONCE(sk->sk_rxhash, 0);
 #endif
 }
 
index d808dc3..811a0f1 100644 (file)
@@ -194,29 +194,6 @@ static inline enum ib_mtu iboe_get_mtu(int mtu)
                return 0;
 }
 
-static inline int iboe_get_rate(struct net_device *dev)
-{
-       struct ethtool_link_ksettings cmd;
-       int err;
-
-       rtnl_lock();
-       err = __ethtool_get_link_ksettings(dev, &cmd);
-       rtnl_unlock();
-       if (err)
-               return IB_RATE_PORT_CURRENT;
-
-       if (cmd.base.speed >= 40000)
-               return IB_RATE_40_GBPS;
-       else if (cmd.base.speed >= 30000)
-               return IB_RATE_30_GBPS;
-       else if (cmd.base.speed >= 20000)
-               return IB_RATE_20_GBPS;
-       else if (cmd.base.speed >= 10000)
-               return IB_RATE_10_GBPS;
-       else
-               return IB_RATE_PORT_CURRENT;
-}
-
 static inline int rdma_link_local_addr(struct in6_addr *addr)
 {
        if (addr->s6_addr32[0] == htonl(0xfe800000) &&
index 1bb11a6..c994ff5 100644 (file)
@@ -1035,6 +1035,7 @@ enum bpf_attach_type {
        BPF_TRACE_KPROBE_MULTI,
        BPF_LSM_CGROUP,
        BPF_STRUCT_OPS,
+       BPF_NETFILTER,
        __MAX_BPF_ATTACH_TYPE
 };
 
index 1ebf8d4..73e2c10 100644 (file)
@@ -783,7 +783,7 @@ enum {
 
        /* add new constants above here */
        __ETHTOOL_A_STATS_GRP_CNT,
-       ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_CNT - 1)
+       ETHTOOL_A_STATS_GRP_MAX = (__ETHTOOL_A_STATS_GRP_CNT - 1)
 };
 
 enum {
index b271598..399e9a1 100644 (file)
@@ -220,10 +220,12 @@ static void io_worker_exit(struct io_worker *worker)
        list_del_rcu(&worker->all_list);
        raw_spin_unlock(&wq->lock);
        io_wq_dec_running(worker);
-       worker->flags = 0;
-       preempt_disable();
-       current->flags &= ~PF_IO_WORKER;
-       preempt_enable();
+       /*
+        * this worker is a goner, clear ->worker_private to avoid any
+        * inc/dec running calls that could happen as part of exit from
+        * touching 'worker'.
+        */
+       current->worker_private = NULL;
 
        kfree_rcu(worker, rcu);
        io_worker_ref_put(wq);
index 89e8390..51b0f7f 100644 (file)
@@ -65,6 +65,7 @@ struct io_sr_msg {
        u16                             addr_len;
        u16                             buf_group;
        void __user                     *addr;
+       void __user                     *msg_control;
        /* used only for send zerocopy */
        struct io_kiocb                 *notif;
 };
@@ -195,11 +196,15 @@ static int io_sendmsg_copy_hdr(struct io_kiocb *req,
                               struct io_async_msghdr *iomsg)
 {
        struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
+       int ret;
 
        iomsg->msg.msg_name = &iomsg->addr;
        iomsg->free_iov = iomsg->fast_iov;
-       return sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
+       ret = sendmsg_copy_msghdr(&iomsg->msg, sr->umsg, sr->msg_flags,
                                        &iomsg->free_iov);
+       /* save msg_control as sys_sendmsg() overwrites it */
+       sr->msg_control = iomsg->msg.msg_control;
+       return ret;
 }
 
 int io_send_prep_async(struct io_kiocb *req)
@@ -297,6 +302,7 @@ int io_sendmsg(struct io_kiocb *req, unsigned int issue_flags)
 
        if (req_has_async_data(req)) {
                kmsg = req->async_data;
+               kmsg->msg.msg_control = sr->msg_control;
        } else {
                ret = io_sendmsg_copy_hdr(req, &iomsg);
                if (ret)
index 2c5c64c..cd5eafa 100644 (file)
@@ -69,9 +69,13 @@ struct bpf_map *bpf_map_meta_alloc(int inner_map_ufd)
        /* Misc members not needed in bpf_map_meta_equal() check. */
        inner_map_meta->ops = inner_map->ops;
        if (inner_map->ops == &array_map_ops) {
+               struct bpf_array *inner_array_meta =
+                       container_of(inner_map_meta, struct bpf_array, map);
+               struct bpf_array *inner_array = container_of(inner_map, struct bpf_array, map);
+
+               inner_array_meta->index_mask = inner_array->index_mask;
+               inner_array_meta->elem_size = inner_array->elem_size;
                inner_map_meta->bypass_spec_v1 = inner_map->bypass_spec_v1;
-               container_of(inner_map_meta, struct bpf_array, map)->index_mask =
-                    container_of(inner_map, struct bpf_array, map)->index_mask;
        }
 
        fdput(f);
index 14f39c1..0c21d0d 100644 (file)
@@ -2433,6 +2433,10 @@ bpf_prog_load_check_attach(enum bpf_prog_type prog_type,
                default:
                        return -EINVAL;
                }
+       case BPF_PROG_TYPE_NETFILTER:
+               if (expected_attach_type == BPF_NETFILTER)
+                       return 0;
+               return -EINVAL;
        case BPF_PROG_TYPE_SYSCALL:
        case BPF_PROG_TYPE_EXT:
                if (expected_attach_type)
@@ -4590,7 +4594,12 @@ static int link_create(union bpf_attr *attr, bpfptr_t uattr)
 
        switch (prog->type) {
        case BPF_PROG_TYPE_EXT:
+               break;
        case BPF_PROG_TYPE_NETFILTER:
+               if (attr->link_create.attach_type != BPF_NETFILTER) {
+                       ret = -EINVAL;
+                       goto out;
+               }
                break;
        case BPF_PROG_TYPE_PERF_EVENT:
        case BPF_PROG_TYPE_TRACEPOINT:
index aeef06c..5407241 100644 (file)
@@ -108,7 +108,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
 
        cgroup_lock();
 
-       percpu_down_write(&cgroup_threadgroup_rwsem);
+       cgroup_attach_lock(true);
 
        /* all tasks in @from are being moved, all csets are source */
        spin_lock_irq(&css_set_lock);
@@ -144,7 +144,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
        } while (task && !ret);
 out_err:
        cgroup_migrate_finish(&mgctx);
-       percpu_up_write(&cgroup_threadgroup_rwsem);
+       cgroup_attach_unlock(true);
        cgroup_unlock();
        return ret;
 }
index 625d748..245cf62 100644 (file)
@@ -6486,19 +6486,18 @@ err:
 static void cgroup_css_set_put_fork(struct kernel_clone_args *kargs)
        __releases(&cgroup_threadgroup_rwsem) __releases(&cgroup_mutex)
 {
+       struct cgroup *cgrp = kargs->cgrp;
+       struct css_set *cset = kargs->cset;
+
        cgroup_threadgroup_change_end(current);
 
-       if (kargs->flags & CLONE_INTO_CGROUP) {
-               struct cgroup *cgrp = kargs->cgrp;
-               struct css_set *cset = kargs->cset;
+       if (cset) {
+               put_css_set(cset);
+               kargs->cset = NULL;
+       }
 
+       if (kargs->flags & CLONE_INTO_CGROUP) {
                cgroup_unlock();
-
-               if (cset) {
-                       put_css_set(cset);
-                       kargs->cset = NULL;
-               }
-
                if (cgrp) {
                        cgroup_put(cgrp);
                        kargs->cgrp = NULL;
index 81cba91..41c9641 100644 (file)
@@ -627,6 +627,7 @@ void free_task(struct task_struct *tsk)
        arch_release_task_struct(tsk);
        if (tsk->flags & PF_KTHREAD)
                free_kthread_struct(tsk);
+       bpf_task_storage_free(tsk);
        free_task_struct(tsk);
 }
 EXPORT_SYMBOL(free_task);
@@ -979,7 +980,6 @@ void __put_task_struct(struct task_struct *tsk)
        cgroup_free(tsk);
        task_numa_free(tsk, true);
        security_task_free(tsk);
-       bpf_task_storage_free(tsk);
        exit_creds(tsk);
        delayacct_tsk_free(tsk);
        put_signal_struct(tsk->signal);
index f989f5f..69ee4a2 100644 (file)
@@ -901,10 +901,22 @@ static int kexec_purgatory_setup_sechdrs(struct purgatory_info *pi,
                }
 
                offset = ALIGN(offset, align);
+
+               /*
+                * Check if the segment contains the entry point, if so,
+                * calculate the value of image->start based on it.
+                * If the compiler has produced more than one .text section
+                * (Eg: .text.hot), they are generally after the main .text
+                * section, and they shall not be used to calculate
+                * image->start. So do not re-calculate image->start if it
+                * is not set to the initial value, and warn the user so they
+                * have a chance to fix their purgatory's linker script.
+                */
                if (sechdrs[i].sh_flags & SHF_EXECINSTR &&
                    pi->ehdr->e_entry >= sechdrs[i].sh_addr &&
                    pi->ehdr->e_entry < (sechdrs[i].sh_addr
-                                        + sechdrs[i].sh_size)) {
+                                        + sechdrs[i].sh_size) &&
+                   !WARN_ON(kbuf->image->start != pi->ehdr->e_entry)) {
                        kbuf->image->start -= sechdrs[i].sh_addr;
                        kbuf->image->start += kbuf->mem + offset;
                }
index 9a050e3..1f4b07d 100644 (file)
@@ -900,13 +900,23 @@ static const struct bpf_func_proto bpf_send_signal_thread_proto = {
 
 BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz)
 {
+       struct path copy;
        long len;
        char *p;
 
        if (!sz)
                return 0;
 
-       p = d_path(path, buf, sz);
+       /*
+        * The path pointer is verified as trusted and safe to use,
+        * but let's double check it's valid anyway to workaround
+        * potentially broken verifier.
+        */
+       len = copy_from_kernel_nofault(&copy, path, sizeof(*path));
+       if (len < 0)
+               return len;
+
+       p = d_path(&copy, buf, sz);
        if (IS_ERR(p)) {
                len = PTR_ERR(p);
        } else {
index dbb1470..8df0550 100644 (file)
 #define EVENT_STATUS_OTHER BIT(7)
 
 /*
+ * User register flags are not allowed yet, keep them here until we are
+ * ready to expose them out to the user ABI.
+ */
+enum user_reg_flag {
+       /* Event will not delete upon last reference closing */
+       USER_EVENT_REG_PERSIST          = 1U << 0,
+
+       /* This value or above is currently non-ABI */
+       USER_EVENT_REG_MAX              = 1U << 1,
+};
+
+/*
  * Stores the system name, tables, and locks for a group of events. This
  * allows isolation for events by various means.
  */
@@ -85,8 +97,10 @@ struct user_event {
        struct hlist_node               node;
        struct list_head                fields;
        struct list_head                validators;
+       struct work_struct              put_work;
        refcount_t                      refcnt;
        int                             min_size;
+       int                             reg_flags;
        char                            status;
 };
 
@@ -165,76 +179,151 @@ typedef void (*user_event_func_t) (struct user_event *user, struct iov_iter *i,
 
 static int user_event_parse(struct user_event_group *group, char *name,
                            char *args, char *flags,
-                           struct user_event **newuser);
+                           struct user_event **newuser, int reg_flags);
 
 static struct user_event_mm *user_event_mm_get(struct user_event_mm *mm);
 static struct user_event_mm *user_event_mm_get_all(struct user_event *user);
 static void user_event_mm_put(struct user_event_mm *mm);
+static int destroy_user_event(struct user_event *user);
 
 static u32 user_event_key(char *name)
 {
        return jhash(name, strlen(name), 0);
 }
 
-static void user_event_group_destroy(struct user_event_group *group)
+static struct user_event *user_event_get(struct user_event *user)
 {
-       kfree(group->system_name);
-       kfree(group);
+       refcount_inc(&user->refcnt);
+
+       return user;
 }
 
-static char *user_event_group_system_name(struct user_namespace *user_ns)
+static void delayed_destroy_user_event(struct work_struct *work)
 {
-       char *system_name;
-       int len = sizeof(USER_EVENTS_SYSTEM) + 1;
+       struct user_event *user = container_of(
+               work, struct user_event, put_work);
 
-       if (user_ns != &init_user_ns) {
+       mutex_lock(&event_mutex);
+
+       if (!refcount_dec_and_test(&user->refcnt))
+               goto out;
+
+       if (destroy_user_event(user)) {
                /*
-                * Unexpected at this point:
-                * We only currently support init_user_ns.
-                * When we enable more, this will trigger a failure so log.
+                * The only reason this would fail here is if we cannot
+                * update the visibility of the event. In this case the
+                * event stays in the hashtable, waiting for someone to
+                * attempt to delete it later.
                 */
-               pr_warn("user_events: Namespace other than init_user_ns!\n");
-               return NULL;
+               pr_warn("user_events: Unable to delete event\n");
+               refcount_set(&user->refcnt, 1);
        }
+out:
+       mutex_unlock(&event_mutex);
+}
 
-       system_name = kmalloc(len, GFP_KERNEL);
+static void user_event_put(struct user_event *user, bool locked)
+{
+       bool delete;
 
-       if (!system_name)
-               return NULL;
+       if (unlikely(!user))
+               return;
 
-       snprintf(system_name, len, "%s", USER_EVENTS_SYSTEM);
+       /*
+        * When the event is not enabled for auto-delete there will always
+        * be at least 1 reference to the event. During the event creation
+        * we initially set the refcnt to 2 to achieve this. In those cases
+        * the caller must acquire event_mutex and after decrement check if
+        * the refcnt is 1, meaning this is the last reference. When auto
+        * delete is enabled, there will only be 1 ref, IE: refcnt will be
+        * only set to 1 during creation to allow the below checks to go
+        * through upon the last put. The last put must always be done with
+        * the event mutex held.
+        */
+       if (!locked) {
+               lockdep_assert_not_held(&event_mutex);
+               delete = refcount_dec_and_mutex_lock(&user->refcnt, &event_mutex);
+       } else {
+               lockdep_assert_held(&event_mutex);
+               delete = refcount_dec_and_test(&user->refcnt);
+       }
 
-       return system_name;
+       if (!delete)
+               return;
+
+       /*
+        * We now have the event_mutex in all cases, which ensures that
+        * no new references will be taken until event_mutex is released.
+        * New references come through find_user_event(), which requires
+        * the event_mutex to be held.
+        */
+
+       if (user->reg_flags & USER_EVENT_REG_PERSIST) {
+               /* We should not get here when persist flag is set */
+               pr_alert("BUG: Auto-delete engaged on persistent event\n");
+               goto out;
+       }
+
+       /*
+        * Unfortunately we have to attempt the actual destroy in a work
+        * queue. This is because not all cases handle a trace_event_call
+        * being removed within the class->reg() operation for unregister.
+        */
+       INIT_WORK(&user->put_work, delayed_destroy_user_event);
+
+       /*
+        * Since the event is still in the hashtable, we have to re-inc
+        * the ref count to 1. This count will be decremented and checked
+        * in the work queue to ensure it's still the last ref. This is
+        * needed because a user-process could register the same event in
+        * between the time of event_mutex release and the work queue
+        * running the delayed destroy. If we removed the item now from
+        * the hashtable, this would result in a timing window where a
+        * user process would fail a register because the trace_event_call
+        * register would fail in the tracing layers.
+        */
+       refcount_set(&user->refcnt, 1);
+
+       if (WARN_ON_ONCE(!schedule_work(&user->put_work))) {
+               /*
+                * If we fail we must wait for an admin to attempt delete or
+                * another register/close of the event, whichever is first.
+                */
+               pr_warn("user_events: Unable to queue delayed destroy\n");
+       }
+out:
+       /* Ensure if we didn't have event_mutex before we unlock it */
+       if (!locked)
+               mutex_unlock(&event_mutex);
 }
 
-static inline struct user_event_group
-*user_event_group_from_user_ns(struct user_namespace *user_ns)
+static void user_event_group_destroy(struct user_event_group *group)
 {
-       if (user_ns == &init_user_ns)
-               return init_group;
-
-       return NULL;
+       kfree(group->system_name);
+       kfree(group);
 }
 
-static struct user_event_group *current_user_event_group(void)
+static char *user_event_group_system_name(void)
 {
-       struct user_namespace *user_ns = current_user_ns();
-       struct user_event_group *group = NULL;
+       char *system_name;
+       int len = sizeof(USER_EVENTS_SYSTEM) + 1;
 
-       while (user_ns) {
-               group = user_event_group_from_user_ns(user_ns);
+       system_name = kmalloc(len, GFP_KERNEL);
 
-               if (group)
-                       break;
+       if (!system_name)
+               return NULL;
 
-               user_ns = user_ns->parent;
-       }
+       snprintf(system_name, len, "%s", USER_EVENTS_SYSTEM);
 
-       return group;
+       return system_name;
 }
 
-static struct user_event_group
-*user_event_group_create(struct user_namespace *user_ns)
+static struct user_event_group *current_user_event_group(void)
+{
+       return init_group;
+}
+
+static struct user_event_group *user_event_group_create(void)
 {
        struct user_event_group *group;
 
@@ -243,7 +332,7 @@ static struct user_event_group
        if (!group)
                return NULL;
 
-       group->system_name = user_event_group_system_name(user_ns);
+       group->system_name = user_event_group_system_name();
 
        if (!group->system_name)
                goto error;
@@ -259,12 +348,13 @@ error:
        return NULL;
 };
 
-static void user_event_enabler_destroy(struct user_event_enabler *enabler)
+static void user_event_enabler_destroy(struct user_event_enabler *enabler,
+                                      bool locked)
 {
        list_del_rcu(&enabler->mm_enablers_link);
 
        /* No longer tracking the event via the enabler */
-       refcount_dec(&enabler->event->refcnt);
+       user_event_put(enabler->event, locked);
 
        kfree(enabler);
 }
@@ -326,7 +416,7 @@ static void user_event_enabler_fault_fixup(struct work_struct *work)
 
        /* User asked for enabler to be removed during fault */
        if (test_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler))) {
-               user_event_enabler_destroy(enabler);
+               user_event_enabler_destroy(enabler, true);
                goto out;
        }
 
@@ -501,14 +591,12 @@ static bool user_event_enabler_dup(struct user_event_enabler *orig,
        if (!enabler)
                return false;
 
-       enabler->event = orig->event;
+       enabler->event = user_event_get(orig->event);
        enabler->addr = orig->addr;
 
        /* Only dup part of value (ignore future flags, etc) */
        enabler->values = orig->values & ENABLE_VAL_DUP_MASK;
 
-       refcount_inc(&enabler->event->refcnt);
-
        /* Enablers not exposed yet, RCU not required */
        list_add(&enabler->mm_enablers_link, &mm->enablers);
 
@@ -625,7 +713,7 @@ static void user_event_mm_destroy(struct user_event_mm *mm)
        struct user_event_enabler *enabler, *next;
 
        list_for_each_entry_safe(enabler, next, &mm->enablers, mm_enablers_link)
-               user_event_enabler_destroy(enabler);
+               user_event_enabler_destroy(enabler, false);
 
        mmdrop(mm->mm);
        kfree(mm);
@@ -780,7 +868,7 @@ retry:
         * exit or run exec(), which includes forks and clones.
         */
        if (!*write_result) {
-               refcount_inc(&enabler->event->refcnt);
+               user_event_get(user);
                list_add_rcu(&enabler->mm_enablers_link, &user_mm->enablers);
        }
 
@@ -803,7 +891,12 @@ out:
 static __always_inline __must_check
 bool user_event_last_ref(struct user_event *user)
 {
-       return refcount_read(&user->refcnt) == 1;
+       int last = 0;
+
+       if (user->reg_flags & USER_EVENT_REG_PERSIST)
+               last = 1;
+
+       return refcount_read(&user->refcnt) == last;
 }
 
 static __always_inline __must_check
@@ -842,7 +935,8 @@ static struct list_head *user_event_get_fields(struct trace_event_call *call)
  * Upon success user_event has its ref count increased by 1.
  */
 static int user_event_parse_cmd(struct user_event_group *group,
-                               char *raw_command, struct user_event **newuser)
+                               char *raw_command, struct user_event **newuser,
+                               int reg_flags)
 {
        char *name = raw_command;
        char *args = strpbrk(name, " ");
@@ -856,7 +950,7 @@ static int user_event_parse_cmd(struct user_event_group *group,
        if (flags)
                *flags++ = '\0';
 
-       return user_event_parse(group, name, args, flags, newuser);
+       return user_event_parse(group, name, args, flags, newuser, reg_flags);
 }
 
 static int user_field_array_size(const char *type)
@@ -1367,10 +1461,8 @@ static struct user_event *find_user_event(struct user_event_group *group,
        *outkey = key;
 
        hash_for_each_possible(group->register_table, user, node, key)
-               if (!strcmp(EVENT_NAME(user), name)) {
-                       refcount_inc(&user->refcnt);
-                       return user;
-               }
+               if (!strcmp(EVENT_NAME(user), name))
+                       return user_event_get(user);
 
        return NULL;
 }
@@ -1432,7 +1524,7 @@ static void user_event_ftrace(struct user_event *user, struct iov_iter *i,
        if (unlikely(!entry))
                return;
 
-       if (unlikely(!copy_nofault(entry + 1, i->count, i)))
+       if (unlikely(i->count != 0 && !copy_nofault(entry + 1, i->count, i)))
                goto discard;
 
        if (!list_empty(&user->validators) &&
@@ -1473,7 +1565,7 @@ static void user_event_perf(struct user_event *user, struct iov_iter *i,
 
                perf_fetch_caller_regs(regs);
 
-               if (unlikely(!copy_nofault(perf_entry + 1, i->count, i)))
+               if (unlikely(i->count != 0 && !copy_nofault(perf_entry + 1, i->count, i)))
                        goto discard;
 
                if (!list_empty(&user->validators) &&
@@ -1584,12 +1676,12 @@ static int user_event_reg(struct trace_event_call *call,
 
        return ret;
 inc:
-       refcount_inc(&user->refcnt);
+       user_event_get(user);
        update_enable_bit_for(user);
        return 0;
 dec:
        update_enable_bit_for(user);
-       refcount_dec(&user->refcnt);
+       user_event_put(user, true);
        return 0;
 }
 
@@ -1620,10 +1712,11 @@ static int user_event_create(const char *raw_command)
 
        mutex_lock(&group->reg_mutex);
 
-       ret = user_event_parse_cmd(group, name, &user);
+       /* Dyn events persist, otherwise they would cleanup immediately */
+       ret = user_event_parse_cmd(group, name, &user, USER_EVENT_REG_PERSIST);
 
        if (!ret)
-               refcount_dec(&user->refcnt);
+               user_event_put(user, false);
 
        mutex_unlock(&group->reg_mutex);
 
@@ -1745,6 +1838,8 @@ static bool user_event_match(const char *system, const char *event,
 
        if (match && argc > 0)
                match = user_fields_match(user, argc, argv);
+       else if (match && argc == 0)
+               match = list_empty(&user->fields);
 
        return match;
 }
@@ -1781,11 +1876,17 @@ static int user_event_trace_register(struct user_event *user)
  */
 static int user_event_parse(struct user_event_group *group, char *name,
                            char *args, char *flags,
-                           struct user_event **newuser)
+                           struct user_event **newuser, int reg_flags)
 {
        int ret;
        u32 key;
        struct user_event *user;
+       int argc = 0;
+       char **argv;
+
+       /* User register flags are not ready yet */
+       if (reg_flags != 0 || flags != NULL)
+               return -EINVAL;
 
        /* Prevent dyn_event from racing */
        mutex_lock(&event_mutex);
@@ -1793,13 +1894,35 @@ static int user_event_parse(struct user_event_group *group, char *name,
        mutex_unlock(&event_mutex);
 
        if (user) {
-               *newuser = user;
-               /*
-                * Name is allocated by caller, free it since it already exists.
-                * Caller only worries about failure cases for freeing.
-                */
-               kfree(name);
+               if (args) {
+                       argv = argv_split(GFP_KERNEL, args, &argc);
+                       if (!argv) {
+                               ret = -ENOMEM;
+                               goto error;
+                       }
+
+                       ret = user_fields_match(user, argc, (const char **)argv);
+                       argv_free(argv);
+
+               } else
+                       ret = list_empty(&user->fields);
+
+               if (ret) {
+                       *newuser = user;
+                       /*
+                        * Name is allocated by caller, free it since it already exists.
+                        * Caller only worries about failure cases for freeing.
+                        */
+                       kfree(name);
+               } else {
+                       ret = -EADDRINUSE;
+                       goto error;
+               }
+
                return 0;
+error:
+               user_event_put(user, false);
+               return ret;
        }
 
        user = kzalloc(sizeof(*user), GFP_KERNEL_ACCOUNT);
@@ -1852,8 +1975,15 @@ static int user_event_parse(struct user_event_group *group, char *name,
        if (ret)
                goto put_user_lock;
 
-       /* Ensure we track self ref and caller ref (2) */
-       refcount_set(&user->refcnt, 2);
+       user->reg_flags = reg_flags;
+
+       if (user->reg_flags & USER_EVENT_REG_PERSIST) {
+               /* Ensure we track self ref and caller ref (2) */
+               refcount_set(&user->refcnt, 2);
+       } else {
+               /* Ensure we track only caller ref (1) */
+               refcount_set(&user->refcnt, 1);
+       }
 
        dyn_event_init(&user->devent, &user_event_dops);
        dyn_event_add(&user->devent, &user->call);
@@ -1885,7 +2015,7 @@ static int delete_user_event(struct user_event_group *group, char *name)
        if (!user)
                return -ENOENT;
 
-       refcount_dec(&user->refcnt);
+       user_event_put(user, true);
 
        if (!user_event_last_ref(user))
                return -EBUSY;
@@ -2044,9 +2174,7 @@ static int user_events_ref_add(struct user_event_file_info *info,
        for (i = 0; i < count; ++i)
                new_refs->events[i] = refs->events[i];
 
-       new_refs->events[i] = user;
-
-       refcount_inc(&user->refcnt);
+       new_refs->events[i] = user_event_get(user);
 
        rcu_assign_pointer(info->refs, new_refs);
 
@@ -2077,8 +2205,8 @@ static long user_reg_get(struct user_reg __user *ureg, struct user_reg *kreg)
        if (ret)
                return ret;
 
-       /* Ensure no flags, since we don't support any yet */
-       if (kreg->flags != 0)
+       /* Ensure only valid flags */
+       if (kreg->flags & ~(USER_EVENT_REG_MAX-1))
                return -EINVAL;
 
        /* Ensure supported size */
@@ -2150,7 +2278,7 @@ static long user_events_ioctl_reg(struct user_event_file_info *info,
                return ret;
        }
 
-       ret = user_event_parse_cmd(info->group, name, &user);
+       ret = user_event_parse_cmd(info->group, name, &user, reg.flags);
 
        if (ret) {
                kfree(name);
@@ -2160,7 +2288,7 @@ static long user_events_ioctl_reg(struct user_event_file_info *info,
        ret = user_events_ref_add(info, user);
 
        /* No longer need parse ref, ref_add either worked or not */
-       refcount_dec(&user->refcnt);
+       user_event_put(user, false);
 
        /* Positive number is index and valid */
        if (ret < 0)
@@ -2309,7 +2437,7 @@ static long user_events_ioctl_unreg(unsigned long uarg)
                        set_bit(ENABLE_VAL_FREEING_BIT, ENABLE_BITOPS(enabler));
 
                        if (!test_bit(ENABLE_VAL_FAULTING_BIT, ENABLE_BITOPS(enabler)))
-                               user_event_enabler_destroy(enabler);
+                               user_event_enabler_destroy(enabler, true);
 
                        /* Removed at least one */
                        ret = 0;
@@ -2367,7 +2495,6 @@ static int user_events_release(struct inode *node, struct file *file)
        struct user_event_file_info *info = file->private_data;
        struct user_event_group *group;
        struct user_event_refs *refs;
-       struct user_event *user;
        int i;
 
        if (!info)
@@ -2391,12 +2518,9 @@ static int user_events_release(struct inode *node, struct file *file)
         * The underlying user_events are ref counted, and cannot be freed.
         * After this decrement, the user_events may be freed elsewhere.
         */
-       for (i = 0; i < refs->count; ++i) {
-               user = refs->events[i];
+       for (i = 0; i < refs->count; ++i)
+               user_event_put(refs->events[i], false);
 
-               if (user)
-                       refcount_dec(&user->refcnt);
-       }
 out:
        file->private_data = NULL;
 
@@ -2577,7 +2701,7 @@ static int __init trace_events_user_init(void)
        if (!fault_cache)
                return -ENOMEM;
 
-       init_group = user_event_group_create(&init_user_ns);
+       init_group = user_event_group_create();
 
        if (!init_group) {
                kmem_cache_destroy(fault_cache);
index 15f05fa..1e33f36 100644 (file)
@@ -847,7 +847,7 @@ static void print_fields(struct trace_iterator *iter, struct trace_event_call *c
        int ret;
        void *pos;
 
-       list_for_each_entry(field, head, link) {
+       list_for_each_entry_reverse(field, head, link) {
                trace_seq_printf(&iter->seq, " %s=", field->name);
                if (field->offset + field->size > iter->ent_size) {
                        trace_seq_puts(&iter->seq, "<OVERFLOW>");
index f80d5c5..da35e5b 100644 (file)
@@ -28,10 +28,6 @@ static int vhost_task_fn(void *data)
        for (;;) {
                bool did_work;
 
-               /* mb paired w/ vhost_task_stop */
-               if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags))
-                       break;
-
                if (!dead && signal_pending(current)) {
                        struct ksignal ksig;
                        /*
@@ -48,11 +44,17 @@ static int vhost_task_fn(void *data)
                                clear_thread_flag(TIF_SIGPENDING);
                }
 
+               /* mb paired w/ vhost_task_stop */
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags)) {
+                       __set_current_state(TASK_RUNNING);
+                       break;
+               }
+
                did_work = vtsk->fn(vtsk->data);
-               if (!did_work) {
-                       set_current_state(TASK_INTERRUPTIBLE);
+               if (!did_work)
                        schedule();
-               }
        }
 
        complete(&vtsk->exited);
index 73c1636..4c34867 100644 (file)
@@ -280,8 +280,8 @@ static void irq_cpu_rmap_release(struct kref *ref)
        struct irq_glue *glue =
                container_of(ref, struct irq_glue, notify.kref);
 
-       cpu_rmap_put(glue->rmap);
        glue->rmap->obj[glue->index] = NULL;
+       cpu_rmap_put(glue->rmap);
        kfree(glue);
 }
 
index 049ba13..1a31065 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/string.h>
 #include <linux/xarray.h>
 
+#include "radix-tree.h"
+
 /*
  * Radix tree node cache.
  */
diff --git a/lib/radix-tree.h b/lib/radix-tree.h
new file mode 100644 (file)
index 0000000..40d5c03
--- /dev/null
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* radix-tree helpers that are only shared with xarray */
+
+struct kmem_cache;
+struct rcu_head;
+
+extern struct kmem_cache *radix_tree_node_cachep;
+extern void radix_tree_node_rcu_free(struct rcu_head *head);
index 9dd9745..3718d98 100644 (file)
@@ -369,7 +369,7 @@ vm_map_ram_test(void)
        int i;
 
        map_nr_pages = nr_pages > 0 ? nr_pages:1;
-       pages = kmalloc(map_nr_pages * sizeof(struct page), GFP_KERNEL);
+       pages = kcalloc(map_nr_pages, sizeof(struct page *), GFP_KERNEL);
        if (!pages)
                return -1;
 
index ea9ce1f..2071a37 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/slab.h>
 #include <linux/xarray.h>
 
+#include "radix-tree.h"
+
 /*
  * Coding conventions in this file:
  *
@@ -247,10 +249,6 @@ void *xas_load(struct xa_state *xas)
 }
 EXPORT_SYMBOL_GPL(xas_load);
 
-/* Move the radix tree node cache here */
-extern struct kmem_cache *radix_tree_node_cachep;
-extern void radix_tree_node_rcu_free(struct rcu_head *head);
-
 #define XA_RCU_FREE    ((struct xarray *)1)
 
 static void xa_node_free(struct xa_node *node)
index d9ef620..91cff7f 100644 (file)
@@ -551,6 +551,8 @@ int damon_set_attrs(struct damon_ctx *ctx, struct damon_attrs *attrs)
                return -EINVAL;
        if (attrs->min_nr_regions > attrs->max_nr_regions)
                return -EINVAL;
+       if (attrs->sample_interval > attrs->aggr_interval)
+               return -EINVAL;
 
        damon_update_monitoring_results(ctx, attrs);
        ctx->attrs = *attrs;
index b4c9bd3..83dda76 100644 (file)
@@ -1760,7 +1760,9 @@ bool __folio_lock_or_retry(struct folio *folio, struct mm_struct *mm,
  *
  * Return: The index of the gap if found, otherwise an index outside the
  * range specified (in which case 'return - index >= max_scan' will be true).
- * In the rare case of index wrap-around, 0 will be returned.
+ * In the rare case of index wrap-around, 0 will be returned.  0 will also
+ * be returned if index == 0 and there is a gap at the index.  We can not
+ * wrap-around if passed index == 0.
  */
 pgoff_t page_cache_next_miss(struct address_space *mapping,
                             pgoff_t index, unsigned long max_scan)
@@ -1770,12 +1772,13 @@ pgoff_t page_cache_next_miss(struct address_space *mapping,
        while (max_scan--) {
                void *entry = xas_next(&xas);
                if (!entry || xa_is_value(entry))
-                       break;
-               if (xas.xa_index == 0)
-                       break;
+                       return xas.xa_index;
+               if (xas.xa_index == 0 && index != 0)
+                       return xas.xa_index;
        }
 
-       return xas.xa_index;
+       /* No gaps in range and no wrap-around, return index beyond range */
+       return xas.xa_index + 1;
 }
 EXPORT_SYMBOL(page_cache_next_miss);
 
@@ -1796,7 +1799,9 @@ EXPORT_SYMBOL(page_cache_next_miss);
  *
  * Return: The index of the gap if found, otherwise an index outside the
  * range specified (in which case 'index - return >= max_scan' will be true).
- * In the rare case of wrap-around, ULONG_MAX will be returned.
+ * In the rare case of wrap-around, ULONG_MAX will be returned.  ULONG_MAX
+ * will also be returned if index == ULONG_MAX and there is a gap at the
+ * index.  We can not wrap-around if passed index == ULONG_MAX.
  */
 pgoff_t page_cache_prev_miss(struct address_space *mapping,
                             pgoff_t index, unsigned long max_scan)
@@ -1806,12 +1811,13 @@ pgoff_t page_cache_prev_miss(struct address_space *mapping,
        while (max_scan--) {
                void *entry = xas_prev(&xas);
                if (!entry || xa_is_value(entry))
-                       break;
-               if (xas.xa_index == ULONG_MAX)
-                       break;
+                       return xas.xa_index;
+               if (xas.xa_index == ULONG_MAX && index != ULONG_MAX)
+                       return xas.xa_index;
        }
 
-       return xas.xa_index;
+       /* No gaps in range and no wrap-around, return index beyond range */
+       return xas.xa_index - 1;
 }
 EXPORT_SYMBOL(page_cache_prev_miss);
 
index 8ae7307..c0421b7 100644 (file)
@@ -381,6 +381,7 @@ static int gup_test_release(struct inode *inode, struct file *file)
 static const struct file_operations gup_test_fops = {
        .open = nonseekable_open,
        .unlocked_ioctl = gup_test_ioctl,
+       .compat_ioctl = compat_ptr_ioctl,
        .release = gup_test_release,
 };
 
index 13678ed..d600404 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2318,21 +2318,6 @@ int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
        return __split_vma(vmi, vma, addr, new_below);
 }
 
-static inline int munmap_sidetree(struct vm_area_struct *vma,
-                                  struct ma_state *mas_detach)
-{
-       vma_start_write(vma);
-       mas_set_range(mas_detach, vma->vm_start, vma->vm_end - 1);
-       if (mas_store_gfp(mas_detach, vma, GFP_KERNEL))
-               return -ENOMEM;
-
-       vma_mark_detached(vma, true);
-       if (vma->vm_flags & VM_LOCKED)
-               vma->vm_mm->locked_vm -= vma_pages(vma);
-
-       return 0;
-}
-
 /*
  * do_vmi_align_munmap() - munmap the aligned region from @start to @end.
  * @vmi: The vma iterator
@@ -2354,6 +2339,7 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
        struct maple_tree mt_detach;
        int count = 0;
        int error = -ENOMEM;
+       unsigned long locked_vm = 0;
        MA_STATE(mas_detach, &mt_detach, 0, 0);
        mt_init_flags(&mt_detach, vmi->mas.tree->ma_flags & MT_FLAGS_LOCK_MASK);
        mt_set_external_lock(&mt_detach, &mm->mmap_lock);
@@ -2399,9 +2385,13 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
                        if (error)
                                goto end_split_failed;
                }
-               error = munmap_sidetree(next, &mas_detach);
-               if (error)
-                       goto munmap_sidetree_failed;
+               vma_start_write(next);
+               mas_set_range(&mas_detach, next->vm_start, next->vm_end - 1);
+               if (mas_store_gfp(&mas_detach, next, GFP_KERNEL))
+                       goto munmap_gather_failed;
+               vma_mark_detached(next, true);
+               if (next->vm_flags & VM_LOCKED)
+                       locked_vm += vma_pages(next);
 
                count++;
 #ifdef CONFIG_DEBUG_VM_MAPLE_TREE
@@ -2447,10 +2437,12 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
        }
 #endif
        /* Point of no return */
+       error = -ENOMEM;
        vma_iter_set(vmi, start);
        if (vma_iter_clear_gfp(vmi, start, end, GFP_KERNEL))
-               return -ENOMEM;
+               goto clear_tree_failed;
 
+       mm->locked_vm -= locked_vm;
        mm->map_count -= count;
        /*
         * Do not downgrade mmap_lock if we are next to VM_GROWSDOWN or
@@ -2480,9 +2472,14 @@ do_vmi_align_munmap(struct vma_iterator *vmi, struct vm_area_struct *vma,
        validate_mm(mm);
        return downgrade ? 1 : 0;
 
+clear_tree_failed:
 userfaultfd_error:
-munmap_sidetree_failed:
+munmap_gather_failed:
 end_split_failed:
+       mas_set(&mas_detach, 0);
+       mas_for_each(&mas_detach, next, end)
+               vma_mark_detached(next, false);
+
        __mt_destroy(&mt_detach);
 start_split_failed:
 map_count_exceeded:
index 59da2a4..30092d9 100644 (file)
@@ -1174,9 +1174,16 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
                goto reject;
        }
 
+       /*
+        * XXX: zswap reclaim does not work with cgroups yet. Without a
+        * cgroup-aware entry LRU, we will push out entries system-wide based on
+        * local cgroup limits.
+        */
        objcg = get_obj_cgroup_from_page(page);
-       if (objcg && !obj_cgroup_may_zswap(objcg))
-               goto shrink;
+       if (objcg && !obj_cgroup_may_zswap(objcg)) {
+               ret = -ENOMEM;
+               goto reject;
+       }
 
        /* reclaim space if needed */
        if (zswap_is_full()) {
index 6968e55..28a939d 100644 (file)
@@ -101,7 +101,6 @@ static void batadv_dat_purge(struct work_struct *work);
  */
 static void batadv_dat_start_timer(struct batadv_priv *bat_priv)
 {
-       INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge);
        queue_delayed_work(batadv_event_workqueue, &bat_priv->dat.work,
                           msecs_to_jiffies(10000));
 }
@@ -819,6 +818,7 @@ int batadv_dat_init(struct batadv_priv *bat_priv)
        if (!bat_priv->dat.hash)
                return -ENOMEM;
 
+       INIT_DELAYED_WORK(&bat_priv->dat.work, batadv_dat_purge);
        batadv_dat_start_timer(bat_priv);
 
        batadv_tvlv_handler_register(bat_priv, batadv_dat_tvlv_ogm_handler_v1,
index f75ef12..1ef952b 100644 (file)
@@ -947,8 +947,8 @@ static void find_cis(struct hci_conn *conn, void *data)
 {
        struct iso_list_data *d = data;
 
-       /* Ignore broadcast */
-       if (!bacmp(&conn->dst, BDADDR_ANY))
+       /* Ignore broadcast or if CIG don't match */
+       if (!bacmp(&conn->dst, BDADDR_ANY) || d->cig != conn->iso_qos.ucast.cig)
                return;
 
        d->count++;
@@ -963,12 +963,17 @@ static void cis_cleanup(struct hci_conn *conn)
        struct hci_dev *hdev = conn->hdev;
        struct iso_list_data d;
 
+       if (conn->iso_qos.ucast.cig == BT_ISO_QOS_CIG_UNSET)
+               return;
+
        memset(&d, 0, sizeof(d));
        d.cig = conn->iso_qos.ucast.cig;
 
        /* Check if ISO connection is a CIS and remove CIG if there are
         * no other connections using it.
         */
+       hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_BOUND, &d);
+       hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECT, &d);
        hci_conn_hash_list_state(hdev, find_cis, ISO_LINK, BT_CONNECTED, &d);
        if (d.count)
                return;
@@ -1766,24 +1771,23 @@ static bool hci_le_set_cig_params(struct hci_conn *conn, struct bt_iso_qos *qos)
 
        memset(&data, 0, sizeof(data));
 
-       /* Allocate a CIG if not set */
+       /* Allocate first still reconfigurable CIG if not set */
        if (qos->ucast.cig == BT_ISO_QOS_CIG_UNSET) {
-               for (data.cig = 0x00; data.cig < 0xff; data.cig++) {
+               for (data.cig = 0x00; data.cig < 0xf0; data.cig++) {
                        data.count = 0;
-                       data.cis = 0xff;
 
-                       hci_conn_hash_list_state(hdev, cis_list, ISO_LINK,
-                                                BT_BOUND, &data);
+                       hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
+                                                BT_CONNECT, &data);
                        if (data.count)
                                continue;
 
-                       hci_conn_hash_list_state(hdev, cis_list, ISO_LINK,
+                       hci_conn_hash_list_state(hdev, find_cis, ISO_LINK,
                                                 BT_CONNECTED, &data);
                        if (!data.count)
                                break;
                }
 
-               if (data.cig == 0xff)
+               if (data.cig == 0xf0)
                        return false;
 
                /* Update CIG */
index a856b10..48917c6 100644 (file)
@@ -1416,10 +1416,10 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
 int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
 {
-       struct smp_ltk *k;
+       struct smp_ltk *k, *tmp;
        int removed = 0;
 
-       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
+       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
                if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_type)
                        continue;
 
@@ -1435,9 +1435,9 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
 
 void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
 {
-       struct smp_irk *k;
+       struct smp_irk *k, *tmp;
 
-       list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
+       list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
                if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type)
                        continue;
 
@@ -2686,7 +2686,9 @@ void hci_unregister_dev(struct hci_dev *hdev)
 {
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
+       mutex_lock(&hdev->unregister_lock);
        hci_dev_set_flag(hdev, HCI_UNREGISTER);
+       mutex_unlock(&hdev->unregister_lock);
 
        write_lock(&hci_dev_list_lock);
        list_del(&hdev->list);
index d00ef6e..09ba6d8 100644 (file)
@@ -3804,48 +3804,56 @@ static u8 hci_cc_le_set_cig_params(struct hci_dev *hdev, void *data,
                                   struct sk_buff *skb)
 {
        struct hci_rp_le_set_cig_params *rp = data;
+       struct hci_cp_le_set_cig_params *cp;
        struct hci_conn *conn;
-       int i = 0;
+       u8 status = rp->status;
+       int i;
 
        bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
 
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_CIG_PARAMS);
+       if (!cp || rp->num_handles != cp->num_cis || rp->cig_id != cp->cig_id) {
+               bt_dev_err(hdev, "unexpected Set CIG Parameters response data");
+               status = HCI_ERROR_UNSPECIFIED;
+       }
+
        hci_dev_lock(hdev);
 
-       if (rp->status) {
+       if (status) {
                while ((conn = hci_conn_hash_lookup_cig(hdev, rp->cig_id))) {
                        conn->state = BT_CLOSED;
-                       hci_connect_cfm(conn, rp->status);
+                       hci_connect_cfm(conn, status);
                        hci_conn_del(conn);
                }
                goto unlock;
        }
 
-       rcu_read_lock();
+       /* BLUETOOTH CORE SPECIFICATION Version 5.3 | Vol 4, Part E page 2553
+        *
+        * If the Status return parameter is zero, then the Controller shall
+        * set the Connection_Handle arrayed return parameter to the connection
+        * handle(s) corresponding to the CIS configurations specified in
+        * the CIS_IDs command parameter, in the same order.
+        */
+       for (i = 0; i < rp->num_handles; ++i) {
+               conn = hci_conn_hash_lookup_cis(hdev, NULL, 0, rp->cig_id,
+                                               cp->cis[i].cis_id);
+               if (!conn || !bacmp(&conn->dst, BDADDR_ANY))
+                       continue;
 
-       list_for_each_entry_rcu(conn, &hdev->conn_hash.list, list) {
-               if (conn->type != ISO_LINK ||
-                   conn->iso_qos.ucast.cig != rp->cig_id ||
-                   conn->state == BT_CONNECTED)
+               if (conn->state != BT_BOUND && conn->state != BT_CONNECT)
                        continue;
 
-               conn->handle = __le16_to_cpu(rp->handle[i++]);
+               conn->handle = __le16_to_cpu(rp->handle[i]);
 
                bt_dev_dbg(hdev, "%p handle 0x%4.4x parent %p", conn,
                           conn->handle, conn->parent);
 
                /* Create CIS if LE is already connected */
-               if (conn->parent && conn->parent->state == BT_CONNECTED) {
-                       rcu_read_unlock();
+               if (conn->parent && conn->parent->state == BT_CONNECTED)
                        hci_le_create_cis(conn);
-                       rcu_read_lock();
-               }
-
-               if (i == rp->num_handles)
-                       break;
        }
 
-       rcu_read_unlock();
-
 unlock:
        hci_dev_unlock(hdev);
 
index 647a8ce..804cde4 100644 (file)
@@ -629,6 +629,7 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
        INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
        INIT_LIST_HEAD(&hdev->cmd_sync_work_list);
        mutex_init(&hdev->cmd_sync_work_lock);
+       mutex_init(&hdev->unregister_lock);
 
        INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
        INIT_WORK(&hdev->reenable_adv_work, reenable_adv);
@@ -692,14 +693,19 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
                        void *data, hci_cmd_sync_work_destroy_t destroy)
 {
        struct hci_cmd_sync_work_entry *entry;
+       int err = 0;
 
-       if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
-               return -ENODEV;
+       mutex_lock(&hdev->unregister_lock);
+       if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) {
+               err = -ENODEV;
+               goto unlock;
+       }
 
        entry = kmalloc(sizeof(*entry), GFP_KERNEL);
-       if (!entry)
-               return -ENOMEM;
-
+       if (!entry) {
+               err = -ENOMEM;
+               goto unlock;
+       }
        entry->func = func;
        entry->data = data;
        entry->destroy = destroy;
@@ -710,7 +716,9 @@ int hci_cmd_sync_submit(struct hci_dev *hdev, hci_cmd_sync_work_func_t func,
 
        queue_work(hdev->req_workqueue, &hdev->cmd_sync_work);
 
-       return 0;
+unlock:
+       mutex_unlock(&hdev->unregister_lock);
+       return err;
 }
 EXPORT_SYMBOL(hci_cmd_sync_submit);
 
@@ -4543,6 +4551,9 @@ static int hci_init_sync(struct hci_dev *hdev)
            !hci_dev_test_flag(hdev, HCI_CONFIG))
                return 0;
 
+       if (hci_dev_test_and_set_flag(hdev, HCI_DEBUGFS_CREATED))
+               return 0;
+
        hci_debugfs_create_common(hdev);
 
        if (lmp_bredr_capable(hdev))
index 376b523..c5e8798 100644 (file)
@@ -4306,6 +4306,10 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
        result = __le16_to_cpu(rsp->result);
        status = __le16_to_cpu(rsp->status);
 
+       if (result == L2CAP_CR_SUCCESS && (dcid < L2CAP_CID_DYN_START ||
+                                          dcid > L2CAP_CID_DYN_END))
+               return -EPROTO;
+
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
               dcid, scid, result, status);
 
@@ -4337,6 +4341,11 @@ static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
 
        switch (result) {
        case L2CAP_CR_SUCCESS:
+               if (__l2cap_get_chan_by_dcid(conn, dcid)) {
+                       err = -EBADSLT;
+                       break;
+               }
+
                l2cap_state_change(chan, BT_CONFIG);
                chan->ident = 0;
                chan->dcid = dcid;
@@ -4663,7 +4672,9 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
 
        chan->ops->set_shutdown(chan);
 
+       l2cap_chan_unlock(chan);
        mutex_lock(&conn->chan_lock);
+       l2cap_chan_lock(chan);
        l2cap_chan_del(chan, ECONNRESET);
        mutex_unlock(&conn->chan_lock);
 
@@ -4702,7 +4713,9 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
                return 0;
        }
 
+       l2cap_chan_unlock(chan);
        mutex_lock(&conn->chan_lock);
+       l2cap_chan_lock(chan);
        l2cap_chan_del(chan, 0);
        mutex_unlock(&conn->chan_lock);
 
index 821d4ff..ecff1c9 100644 (file)
@@ -126,7 +126,7 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data)
 #define J1939_CAN_ID CAN_EFF_FLAG
 #define J1939_CAN_MASK (CAN_EFF_FLAG | CAN_RTR_FLAG)
 
-static DEFINE_SPINLOCK(j1939_netdev_lock);
+static DEFINE_MUTEX(j1939_netdev_lock);
 
 static struct j1939_priv *j1939_priv_create(struct net_device *ndev)
 {
@@ -220,7 +220,7 @@ static void __j1939_rx_release(struct kref *kref)
        j1939_can_rx_unregister(priv);
        j1939_ecu_unmap_all(priv);
        j1939_priv_set(priv->ndev, NULL);
-       spin_unlock(&j1939_netdev_lock);
+       mutex_unlock(&j1939_netdev_lock);
 }
 
 /* get pointer to priv without increasing ref counter */
@@ -248,9 +248,9 @@ static struct j1939_priv *j1939_priv_get_by_ndev(struct net_device *ndev)
 {
        struct j1939_priv *priv;
 
-       spin_lock(&j1939_netdev_lock);
+       mutex_lock(&j1939_netdev_lock);
        priv = j1939_priv_get_by_ndev_locked(ndev);
-       spin_unlock(&j1939_netdev_lock);
+       mutex_unlock(&j1939_netdev_lock);
 
        return priv;
 }
@@ -260,14 +260,14 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
        struct j1939_priv *priv, *priv_new;
        int ret;
 
-       spin_lock(&j1939_netdev_lock);
+       mutex_lock(&j1939_netdev_lock);
        priv = j1939_priv_get_by_ndev_locked(ndev);
        if (priv) {
                kref_get(&priv->rx_kref);
-               spin_unlock(&j1939_netdev_lock);
+               mutex_unlock(&j1939_netdev_lock);
                return priv;
        }
-       spin_unlock(&j1939_netdev_lock);
+       mutex_unlock(&j1939_netdev_lock);
 
        priv = j1939_priv_create(ndev);
        if (!priv)
@@ -277,29 +277,31 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
        spin_lock_init(&priv->j1939_socks_lock);
        INIT_LIST_HEAD(&priv->j1939_socks);
 
-       spin_lock(&j1939_netdev_lock);
+       mutex_lock(&j1939_netdev_lock);
        priv_new = j1939_priv_get_by_ndev_locked(ndev);
        if (priv_new) {
                /* Someone was faster than us, use their priv and roll
                 * back our's.
                 */
                kref_get(&priv_new->rx_kref);
-               spin_unlock(&j1939_netdev_lock);
+               mutex_unlock(&j1939_netdev_lock);
                dev_put(ndev);
                kfree(priv);
                return priv_new;
        }
        j1939_priv_set(ndev, priv);
-       spin_unlock(&j1939_netdev_lock);
 
        ret = j1939_can_rx_register(priv);
        if (ret < 0)
                goto out_priv_put;
 
+       mutex_unlock(&j1939_netdev_lock);
        return priv;
 
  out_priv_put:
        j1939_priv_set(ndev, NULL);
+       mutex_unlock(&j1939_netdev_lock);
+
        dev_put(ndev);
        kfree(priv);
 
@@ -308,7 +310,7 @@ struct j1939_priv *j1939_netdev_start(struct net_device *ndev)
 
 void j1939_netdev_stop(struct j1939_priv *priv)
 {
-       kref_put_lock(&priv->rx_kref, __j1939_rx_release, &j1939_netdev_lock);
+       kref_put_mutex(&priv->rx_kref, __j1939_rx_release, &j1939_netdev_lock);
        j1939_priv_put(priv);
 }
 
index 1790469..35970c2 100644 (file)
@@ -1088,6 +1088,11 @@ void j1939_sk_errqueue(struct j1939_session *session,
 
 void j1939_sk_send_loop_abort(struct sock *sk, int err)
 {
+       struct j1939_sock *jsk = j1939_sk(sk);
+
+       if (jsk->state & J1939_SOCK_ERRQUEUE)
+               return;
+
        sk->sk_err = err;
 
        sk_error_report(sk);
index b3c13e0..c29f3e1 100644 (file)
@@ -4471,8 +4471,10 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
                u32 next_cpu;
                u32 ident;
 
-               /* First check into global flow table if there is a match */
-               ident = sock_flow_table->ents[hash & sock_flow_table->mask];
+               /* First check into global flow table if there is a match.
+                * This READ_ONCE() pairs with WRITE_ONCE() from rps_record_sock_flow().
+                */
+               ident = READ_ONCE(sock_flow_table->ents[hash & sock_flow_table->mask]);
                if ((ident ^ hash) & ~rps_cpu_mask)
                        goto try_rps;
 
@@ -10541,7 +10543,7 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
                return NULL;
        netdev_init_one_queue(dev, queue, NULL);
        RCU_INIT_POINTER(queue->qdisc, &noop_qdisc);
-       queue->qdisc_sleeping = &noop_qdisc;
+       RCU_INIT_POINTER(queue->qdisc_sleeping, &noop_qdisc);
        rcu_assign_pointer(dev->ingress_queue, queue);
 #endif
        return queue;
index a9060e1..a29508e 100644 (file)
@@ -1210,7 +1210,8 @@ static void sk_psock_verdict_data_ready(struct sock *sk)
 
                rcu_read_lock();
                psock = sk_psock(sk);
-               psock->saved_data_ready(sk);
+               if (psock)
+                       psock->saved_data_ready(sk);
                rcu_read_unlock();
        }
 }
index a06b564..b0ebf85 100644 (file)
@@ -191,6 +191,9 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
        struct dccp_sock *dp = dccp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
 
+       pr_warn_once("DCCP is deprecated and scheduled to be removed in 2025, "
+                    "please contact the netdev mailing list\n");
+
        icsk->icsk_rto          = DCCP_TIMEOUT_INIT;
        icsk->icsk_syn_retries  = sysctl_dccp_request_retries;
        sk->sk_state            = DCCP_CLOSED;
index 8aeaadc..4dac965 100644 (file)
@@ -31,7 +31,6 @@ struct handshake_req {
        struct list_head                hr_list;
        struct rhash_head               hr_rhash;
        unsigned long                   hr_flags;
-       struct file                     *hr_file;
        const struct handshake_proto    *hr_proto;
        struct sock                     *hr_sk;
        void                            (*hr_odestruct)(struct sock *sk);
index d78d41a..94d5cef 100644 (file)
@@ -239,7 +239,6 @@ int handshake_req_submit(struct socket *sock, struct handshake_req *req,
        }
        req->hr_odestruct = req->hr_sk->sk_destruct;
        req->hr_sk->sk_destruct = handshake_sk_destruct;
-       req->hr_file = sock->file;
 
        ret = -EOPNOTSUPP;
        net = sock_net(req->hr_sk);
@@ -335,9 +334,6 @@ bool handshake_req_cancel(struct sock *sk)
                return false;
        }
 
-       /* Request accepted and waiting for DONE */
-       fput(req->hr_file);
-
 out_true:
        trace_handshake_cancel(net, req, sk);
 
index 40fe70f..88dfe51 100644 (file)
@@ -34,8 +34,8 @@ static int ip_ttl_min = 1;
 static int ip_ttl_max = 255;
 static int tcp_syn_retries_min = 1;
 static int tcp_syn_retries_max = MAX_TCP_SYNCNT;
-static int ip_ping_group_range_min[] = { 0, 0 };
-static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
+static unsigned long ip_ping_group_range_min[] = { 0, 0 };
+static unsigned long ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX };
 static u32 u32_max_div_HZ = UINT_MAX / HZ;
 static int one_day_secs = 24 * 3600;
 static u32 fib_multipath_hash_fields_all_mask __maybe_unused =
@@ -165,7 +165,7 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write,
 {
        struct user_namespace *user_ns = current_user_ns();
        int ret;
-       gid_t urange[2];
+       unsigned long urange[2];
        kgid_t low, high;
        struct ctl_table tmp = {
                .data = &urange,
@@ -178,7 +178,7 @@ static int ipv4_ping_group_range(struct ctl_table *table, int write,
        inet_get_ping_group_range_table(table, &low, &high);
        urange[0] = from_kgid_munged(user_ns, low);
        urange[1] = from_kgid_munged(user_ns, high);
-       ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+       ret = proc_doulongvec_minmax(&tmp, write, buffer, lenp, ppos);
 
        if (write && ret == 0) {
                low = make_kgid(user_ns, urange[0]);
index 45dda78..4851211 100644 (file)
@@ -60,12 +60,12 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
        struct tcphdr *th;
        unsigned int thlen;
        unsigned int seq;
-       __be32 delta;
        unsigned int oldlen;
        unsigned int mss;
        struct sk_buff *gso_skb = skb;
        __sum16 newcheck;
        bool ooo_okay, copy_destructor;
+       __wsum delta;
 
        th = tcp_hdr(skb);
        thlen = th->doff * 4;
@@ -75,7 +75,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
        if (!pskb_may_pull(skb, thlen))
                goto out;
 
-       oldlen = (u16)~skb->len;
+       oldlen = ~skb->len;
        __skb_pull(skb, thlen);
 
        mss = skb_shinfo(skb)->gso_size;
@@ -110,7 +110,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
        if (skb_is_gso(segs))
                mss *= skb_shinfo(segs)->gso_segs;
 
-       delta = htonl(oldlen + (thlen + mss));
+       delta = (__force __wsum)htonl(oldlen + thlen + mss);
 
        skb = segs;
        th = tcp_hdr(skb);
@@ -119,8 +119,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
        if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_SW_TSTAMP))
                tcp_gso_tstamp(segs, skb_shinfo(gso_skb)->tskey, seq, mss);
 
-       newcheck = ~csum_fold((__force __wsum)((__force u32)th->check +
-                                              (__force u32)delta));
+       newcheck = ~csum_fold(csum_add(csum_unfold(th->check), delta));
 
        while (skb->next) {
                th->fin = th->psh = 0;
@@ -165,11 +164,11 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
                        WARN_ON_ONCE(refcount_sub_and_test(-delta, &skb->sk->sk_wmem_alloc));
        }
 
-       delta = htonl(oldlen + (skb_tail_pointer(skb) -
-                               skb_transport_header(skb)) +
-                     skb->data_len);
-       th->check = ~csum_fold((__force __wsum)((__force u32)th->check +
-                               (__force u32)delta));
+       delta = (__force __wsum)htonl(oldlen +
+                                     (skb_tail_pointer(skb) -
+                                      skb_transport_header(skb)) +
+                                     skb->data_len);
+       th->check = ~csum_fold(csum_add(csum_unfold(th->check), delta));
        if (skb->ip_summed == CHECKSUM_PARTIAL)
                gso_reset_checksum(skb, ~th->check);
        else
index 56d94d2..143f93a 100644 (file)
@@ -22,6 +22,8 @@ static int udplite_sk_init(struct sock *sk)
 {
        udp_init_sock(sk);
        udp_sk(sk)->pcflag = UDPLITE_BIT;
+       pr_warn_once("UDP-Lite is deprecated and scheduled to be removed in 2025, "
+                    "please contact the netdev mailing list\n");
        return 0;
 }
 
index a8d961d..5fa0e37 100644 (file)
@@ -569,24 +569,6 @@ looped_back:
                return -1;
        }
 
-       if (skb_cloned(skb)) {
-               if (pskb_expand_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE, 0,
-                                    GFP_ATOMIC)) {
-                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
-                                       IPSTATS_MIB_OUTDISCARDS);
-                       kfree_skb(skb);
-                       return -1;
-               }
-       } else {
-               err = skb_cow_head(skb, IPV6_RPL_SRH_WORST_SWAP_SIZE);
-               if (unlikely(err)) {
-                       kfree_skb(skb);
-                       return -1;
-               }
-       }
-
-       hdr = (struct ipv6_rpl_sr_hdr *)skb_transport_header(skb);
-
        if (!pskb_may_pull(skb, ipv6_rpl_srh_size(n, hdr->cmpri,
                                                  hdr->cmpre))) {
                kfree_skb(skb);
@@ -630,6 +612,17 @@ looped_back:
        skb_pull(skb, ((hdr->hdrlen + 1) << 3));
        skb_postpull_rcsum(skb, oldhdr,
                           sizeof(struct ipv6hdr) + ((hdr->hdrlen + 1) << 3));
+       if (unlikely(!hdr->segments_left)) {
+               if (pskb_expand_head(skb, sizeof(struct ipv6hdr) + ((chdr->hdrlen + 1) << 3), 0,
+                                    GFP_ATOMIC)) {
+                       __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_OUTDISCARDS);
+                       kfree_skb(skb);
+                       kfree(buf);
+                       return -1;
+               }
+
+               oldhdr = ipv6_hdr(skb);
+       }
        skb_push(skb, ((chdr->hdrlen + 1) << 3) + sizeof(struct ipv6hdr));
        skb_reset_network_header(skb);
        skb_mac_header_rebuild(skb);
index c4835db..f804c11 100644 (file)
@@ -114,7 +114,8 @@ static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
        addr_type = ipv6_addr_type(daddr);
        if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) ||
            (addr_type & IPV6_ADDR_MAPPED) ||
-           (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if))
+           (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if &&
+            l3mdev_master_ifindex_by_index(sock_net(sk), oif) != sk->sk_bound_dev_if))
                return -EINVAL;
 
        ipcm6_init_sk(&ipc6, np);
index e3aec46..392aaa3 100644 (file)
@@ -6412,9 +6412,9 @@ static struct ctl_table ipv6_route_table_template[] = {
        {
                .procname       =       "skip_notify_on_dev_down",
                .data           =       &init_net.ipv6.sysctl.skip_notify_on_dev_down,
-               .maxlen         =       sizeof(int),
+               .maxlen         =       sizeof(u8),
                .mode           =       0644,
-               .proc_handler   =       proc_dointvec_minmax,
+               .proc_handler   =       proc_dou8vec_minmax,
                .extra1         =       SYSCTL_ZERO,
                .extra2         =       SYSCTL_ONE,
        },
index 3bab0cc..8e010d0 100644 (file)
@@ -8,6 +8,8 @@
  *  Changes:
  *  Fixes:
  */
+#define pr_fmt(fmt) "UDPLite6: " fmt
+
 #include <linux/export.h>
 #include <linux/proc_fs.h>
 #include "udp_impl.h"
@@ -16,6 +18,8 @@ static int udplitev6_sk_init(struct sock *sk)
 {
        udpv6_init_sock(sk);
        udp_sk(sk)->pcflag = UDPLITE_BIT;
+       pr_warn_once("UDP-Lite is deprecated and scheduled to be removed in 2025, "
+                    "please contact the netdev mailing list\n");
        return 0;
 }
 
index 86b2036..f2d08db 100644 (file)
@@ -4865,11 +4865,16 @@ static int ieee80211_add_intf_link(struct wiphy *wiphy,
                                   unsigned int link_id)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+       int res;
 
        if (wdev->use_4addr)
                return -EOPNOTSUPP;
 
-       return ieee80211_vif_set_links(sdata, wdev->valid_links);
+       mutex_lock(&sdata->local->mtx);
+       res = ieee80211_vif_set_links(sdata, wdev->valid_links);
+       mutex_unlock(&sdata->local->mtx);
+
+       return res;
 }
 
 static void ieee80211_del_intf_link(struct wiphy *wiphy,
@@ -4878,7 +4883,9 @@ static void ieee80211_del_intf_link(struct wiphy *wiphy,
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
+       mutex_lock(&sdata->local->mtx);
        ieee80211_vif_set_links(sdata, wdev->valid_links);
+       mutex_unlock(&sdata->local->mtx);
 }
 
 static int sta_add_link_station(struct ieee80211_local *local,
index 729f261..0322aba 100644 (file)
@@ -3,7 +3,7 @@
  * HE handling
  *
  * Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(c) 2019 - 2022 Intel Corporation
+ * Copyright(c) 2019 - 2023 Intel Corporation
  */
 
 #include "ieee80211_i.h"
@@ -114,6 +114,7 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
                                  struct link_sta_info *link_sta)
 {
        struct ieee80211_sta_he_cap *he_cap = &link_sta->pub->he_cap;
+       const struct ieee80211_sta_he_cap *own_he_cap_ptr;
        struct ieee80211_sta_he_cap own_he_cap;
        struct ieee80211_he_cap_elem *he_cap_ie_elem = (void *)he_cap_ie;
        u8 he_ppe_size;
@@ -123,12 +124,16 @@ ieee80211_he_cap_ie_to_sta_he_cap(struct ieee80211_sub_if_data *sdata,
 
        memset(he_cap, 0, sizeof(*he_cap));
 
-       if (!he_cap_ie ||
-           !ieee80211_get_he_iftype_cap(sband,
-                                        ieee80211_vif_type_p2p(&sdata->vif)))
+       if (!he_cap_ie)
                return;
 
-       own_he_cap = sband->iftype_data->he_cap;
+       own_he_cap_ptr =
+               ieee80211_get_he_iftype_cap(sband,
+                                           ieee80211_vif_type_p2p(&sdata->vif));
+       if (!own_he_cap_ptr)
+               return;
+
+       own_he_cap = *own_he_cap_ptr;
 
        /* Make sure size is OK */
        mcs_nss_size = ieee80211_he_mcs_nss_size(he_cap_ie_elem);
index b0372e7..4159fb6 100644 (file)
@@ -2312,7 +2312,7 @@ ieee802_11_parse_elems(const u8 *start, size_t len, bool action,
        return ieee802_11_parse_elems_crc(start, len, action, 0, 0, bss);
 }
 
-void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos);
+void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos, u8 frag_id);
 
 extern const int ieee802_1d_to_ac[8];
 
index e82db88..40f030b 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * MLO link handling
  *
- * Copyright (C) 2022 Intel Corporation
+ * Copyright (C) 2022-2023 Intel Corporation
  */
 #include <linux/slab.h>
 #include <linux/kernel.h>
@@ -409,6 +409,7 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
                                                 IEEE80211_CHANCTX_SHARED);
                WARN_ON_ONCE(ret);
 
+               ieee80211_mgd_set_link_qos_params(link);
                ieee80211_link_info_change_notify(sdata, link,
                                                  BSS_CHANGED_ERP_CTS_PROT |
                                                  BSS_CHANGED_ERP_PREAMBLE |
@@ -423,7 +424,6 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
                                                  BSS_CHANGED_TWT |
                                                  BSS_CHANGED_HE_OBSS_PD |
                                                  BSS_CHANGED_HE_BSS_COLOR);
-               ieee80211_mgd_set_link_qos_params(link);
        }
 
        old_active = sdata->vif.active_links;
index e13a035..5a43031 100644 (file)
@@ -1217,6 +1217,7 @@ static void ieee80211_add_non_inheritance_elem(struct sk_buff *skb,
                                               const u16 *inner)
 {
        unsigned int skb_len = skb->len;
+       bool at_extension = false;
        bool added = false;
        int i, j;
        u8 *len, *list_len = NULL;
@@ -1228,7 +1229,6 @@ static void ieee80211_add_non_inheritance_elem(struct sk_buff *skb,
        for (i = 0; i < PRESENT_ELEMS_MAX && outer[i]; i++) {
                u16 elem = outer[i];
                bool have_inner = false;
-               bool at_extension = false;
 
                /* should at least be sorted in the sense of normal -> ext */
                WARN_ON(at_extension && elem < PRESENT_ELEM_EXT_OFFS);
@@ -1257,8 +1257,14 @@ static void ieee80211_add_non_inheritance_elem(struct sk_buff *skb,
                }
                *list_len += 1;
                skb_put_u8(skb, (u8)elem);
+               added = true;
        }
 
+       /* if we added a list but no extension list, make a zero-len one */
+       if (added && (!at_extension || !list_len))
+               skb_put_u8(skb, 0);
+
+       /* if nothing added remove extension element completely */
        if (!added)
                skb_trim(skb, skb_len);
        else
@@ -1366,10 +1372,11 @@ static void ieee80211_assoc_add_ml_elem(struct ieee80211_sub_if_data *sdata,
                ieee80211_add_non_inheritance_elem(skb, outer_present_elems,
                                                   link_present_elems);
 
-               ieee80211_fragment_element(skb, subelem_len);
+               ieee80211_fragment_element(skb, subelem_len,
+                                          IEEE80211_MLE_SUBELEM_FRAGMENT);
        }
 
-       ieee80211_fragment_element(skb, ml_elem_len);
+       ieee80211_fragment_element(skb, ml_elem_len, WLAN_EID_FRAGMENT);
 }
 
 static int ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
index 58222c0..d996aa2 100644 (file)
@@ -4965,7 +4965,9 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
        }
 
        if (unlikely(rx->sta && rx->sta->sta.mlo) &&
-           is_unicast_ether_addr(hdr->addr1)) {
+           is_unicast_ether_addr(hdr->addr1) &&
+           !ieee80211_is_probe_resp(hdr->frame_control) &&
+           !ieee80211_is_beacon(hdr->frame_control)) {
                /* translate to MLD addresses */
                if (ether_addr_equal(link->conf->addr, hdr->addr1))
                        ether_addr_copy(hdr->addr1, rx->sdata->vif.addr);
index 0d9fbc8..13b522d 100644 (file)
@@ -4445,7 +4445,7 @@ static void ieee80211_mlo_multicast_tx(struct net_device *dev,
                                       struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       unsigned long links = sdata->vif.valid_links;
+       unsigned long links = sdata->vif.active_links;
        unsigned int link;
        u32 ctrl_flags = IEEE80211_TX_CTRL_MCAST_MLO_FIRST_TX;
 
@@ -5528,7 +5528,7 @@ ieee80211_beacon_get_template_ema_list(struct ieee80211_hw *hw,
 {
        struct ieee80211_ema_beacons *ema_beacons = NULL;
 
-       WARN_ON(__ieee80211_beacon_get(hw, vif, NULL, false, link_id, 0,
+       WARN_ON(__ieee80211_beacon_get(hw, vif, NULL, true, link_id, 0,
                                       &ema_beacons));
 
        return ema_beacons;
@@ -6040,7 +6040,7 @@ void __ieee80211_tx_skb_tid_band(struct ieee80211_sub_if_data *sdata,
                rcu_read_unlock();
 
                if (WARN_ON_ONCE(link == ARRAY_SIZE(sdata->vif.link_conf)))
-                       link = ffs(sdata->vif.valid_links) - 1;
+                       link = ffs(sdata->vif.active_links) - 1;
        }
 
        IEEE80211_SKB_CB(skb)->control.flags |=
@@ -6076,7 +6076,7 @@ void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
                band = chanctx_conf->def.chan->band;
        } else {
                WARN_ON(link_id >= 0 &&
-                       !(sdata->vif.valid_links & BIT(link_id)));
+                       !(sdata->vif.active_links & BIT(link_id)));
                /* MLD transmissions must not rely on the band */
                band = 0;
        }
index 4bf7615..3bd07a0 100644 (file)
@@ -5049,7 +5049,7 @@ u8 *ieee80211_ie_build_eht_cap(u8 *pos,
        return pos;
 }
 
-void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos)
+void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos, u8 frag_id)
 {
        unsigned int elem_len;
 
@@ -5069,7 +5069,7 @@ void ieee80211_fragment_element(struct sk_buff *skb, u8 *len_pos)
                memmove(len_pos + 255 + 3, len_pos + 255 + 1, elem_len);
                /* place the fragment ID */
                len_pos += 255 + 1;
-               *len_pos = WLAN_EID_FRAGMENT;
+               *len_pos = frag_id;
                /* and point to fragment length to update later */
                len_pos++;
        }
index 78c9245..76612bc 100644 (file)
@@ -87,8 +87,15 @@ bool mptcp_pm_allow_new_subflow(struct mptcp_sock *msk)
        unsigned int subflows_max;
        int ret = 0;
 
-       if (mptcp_pm_is_userspace(msk))
-               return mptcp_userspace_pm_active(msk);
+       if (mptcp_pm_is_userspace(msk)) {
+               if (mptcp_userspace_pm_active(msk)) {
+                       spin_lock_bh(&pm->lock);
+                       pm->subflows++;
+                       spin_unlock_bh(&pm->lock);
+                       return true;
+               }
+               return false;
+       }
 
        subflows_max = mptcp_pm_get_subflows_max(msk);
 
@@ -181,8 +188,16 @@ void mptcp_pm_subflow_check_next(struct mptcp_sock *msk, const struct sock *ssk,
        struct mptcp_pm_data *pm = &msk->pm;
        bool update_subflows;
 
-       update_subflows = (subflow->request_join || subflow->mp_join) &&
-                         mptcp_pm_is_kernel(msk);
+       update_subflows = subflow->request_join || subflow->mp_join;
+       if (mptcp_pm_is_userspace(msk)) {
+               if (update_subflows) {
+                       spin_lock_bh(&pm->lock);
+                       pm->subflows--;
+                       spin_unlock_bh(&pm->lock);
+               }
+               return;
+       }
+
        if (!READ_ONCE(pm->work_pending) && !update_subflows)
                return;
 
index bc343da..59f8f31 100644 (file)
@@ -1558,6 +1558,24 @@ static int mptcp_nl_cmd_del_addr(struct sk_buff *skb, struct genl_info *info)
        return ret;
 }
 
+void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list)
+{
+       struct mptcp_rm_list alist = { .nr = 0 };
+       struct mptcp_pm_addr_entry *entry;
+
+       list_for_each_entry(entry, rm_list, list) {
+               remove_anno_list_by_saddr(msk, &entry->addr);
+               if (alist.nr < MPTCP_RM_IDS_MAX)
+                       alist.ids[alist.nr++] = entry->addr.id;
+       }
+
+       if (alist.nr) {
+               spin_lock_bh(&msk->pm.lock);
+               mptcp_pm_remove_addr(msk, &alist);
+               spin_unlock_bh(&msk->pm.lock);
+       }
+}
+
 void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
                                        struct list_head *rm_list)
 {
index 27a2758..b06aa58 100644 (file)
@@ -69,6 +69,7 @@ static int mptcp_userspace_pm_append_new_local_addr(struct mptcp_sock *msk,
                                                        MPTCP_PM_MAX_ADDR_ID + 1,
                                                        1);
                list_add_tail_rcu(&e->list, &msk->pm.userspace_pm_local_addr_list);
+               msk->pm.local_addr_used++;
                ret = e->addr.id;
        } else if (match) {
                ret = entry->addr.id;
@@ -79,6 +80,31 @@ append_err:
        return ret;
 }
 
+/* If the subflow is closed from the other peer (not via a
+ * subflow destroy command then), we want to keep the entry
+ * not to assign the same ID to another address and to be
+ * able to send RM_ADDR after the removal of the subflow.
+ */
+static int mptcp_userspace_pm_delete_local_addr(struct mptcp_sock *msk,
+                                               struct mptcp_pm_addr_entry *addr)
+{
+       struct mptcp_pm_addr_entry *entry, *tmp;
+
+       list_for_each_entry_safe(entry, tmp, &msk->pm.userspace_pm_local_addr_list, list) {
+               if (mptcp_addresses_equal(&entry->addr, &addr->addr, false)) {
+                       /* TODO: a refcount is needed because the entry can
+                        * be used multiple times (e.g. fullmesh mode).
+                        */
+                       list_del_rcu(&entry->list);
+                       kfree(entry);
+                       msk->pm.local_addr_used--;
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
 int mptcp_userspace_pm_get_flags_and_ifindex_by_id(struct mptcp_sock *msk,
                                                   unsigned int id,
                                                   u8 *flags, int *ifindex)
@@ -171,6 +197,7 @@ int mptcp_nl_cmd_announce(struct sk_buff *skb, struct genl_info *info)
        spin_lock_bh(&msk->pm.lock);
 
        if (mptcp_pm_alloc_anno_list(msk, &addr_val)) {
+               msk->pm.add_addr_signaled++;
                mptcp_pm_announce_addr(msk, &addr_val.addr, false);
                mptcp_pm_nl_addr_send_ack(msk);
        }
@@ -232,7 +259,7 @@ int mptcp_nl_cmd_remove(struct sk_buff *skb, struct genl_info *info)
 
        list_move(&match->list, &free_list);
 
-       mptcp_pm_remove_addrs_and_subflows(msk, &free_list);
+       mptcp_pm_remove_addrs(msk, &free_list);
 
        release_sock((struct sock *)msk);
 
@@ -251,6 +278,7 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
        struct nlattr *raddr = info->attrs[MPTCP_PM_ATTR_ADDR_REMOTE];
        struct nlattr *token = info->attrs[MPTCP_PM_ATTR_TOKEN];
        struct nlattr *laddr = info->attrs[MPTCP_PM_ATTR_ADDR];
+       struct mptcp_pm_addr_entry local = { 0 };
        struct mptcp_addr_info addr_r;
        struct mptcp_addr_info addr_l;
        struct mptcp_sock *msk;
@@ -302,12 +330,26 @@ int mptcp_nl_cmd_sf_create(struct sk_buff *skb, struct genl_info *info)
                goto create_err;
        }
 
+       local.addr = addr_l;
+       err = mptcp_userspace_pm_append_new_local_addr(msk, &local);
+       if (err < 0) {
+               GENL_SET_ERR_MSG(info, "did not match address and id");
+               goto create_err;
+       }
+
        lock_sock(sk);
 
        err = __mptcp_subflow_connect(sk, &addr_l, &addr_r);
 
        release_sock(sk);
 
+       spin_lock_bh(&msk->pm.lock);
+       if (err)
+               mptcp_userspace_pm_delete_local_addr(msk, &local);
+       else
+               msk->pm.subflows++;
+       spin_unlock_bh(&msk->pm.lock);
+
  create_err:
        sock_put((struct sock *)msk);
        return err;
@@ -420,7 +462,11 @@ int mptcp_nl_cmd_sf_destroy(struct sk_buff *skb, struct genl_info *info)
        ssk = mptcp_nl_find_ssk(msk, &addr_l, &addr_r);
        if (ssk) {
                struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(ssk);
+               struct mptcp_pm_addr_entry entry = { .addr = addr_l };
 
+               spin_lock_bh(&msk->pm.lock);
+               mptcp_userspace_pm_delete_local_addr(msk, &entry);
+               spin_unlock_bh(&msk->pm.lock);
                mptcp_subflow_shutdown(sk, ssk, RCV_SHUTDOWN | SEND_SHUTDOWN);
                mptcp_close_ssk(sk, ssk, subflow);
                MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_RMSUBFLOW);
index c525525..70c957b 100644 (file)
@@ -832,6 +832,7 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk,
                           bool echo);
 int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
 int mptcp_pm_remove_subflow(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_list);
+void mptcp_pm_remove_addrs(struct mptcp_sock *msk, struct list_head *rm_list);
 void mptcp_pm_remove_addrs_and_subflows(struct mptcp_sock *msk,
                                        struct list_head *rm_list);
 
index 46ebee9..9a6b647 100644 (file)
@@ -1694,6 +1694,14 @@ call_ad(struct net *net, struct sock *ctnl, struct sk_buff *skb,
        bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
 
        do {
+               if (retried) {
+                       __ip_set_get(set);
+                       nfnl_unlock(NFNL_SUBSYS_IPSET);
+                       cond_resched();
+                       nfnl_lock(NFNL_SUBSYS_IPSET);
+                       __ip_set_put(set);
+               }
+
                ip_set_lock(set);
                ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
                ip_set_unlock(set);
index c4ccfec..d119f1d 100644 (file)
@@ -2260,6 +2260,9 @@ static int nf_confirm_cthelper(struct sk_buff *skb, struct nf_conn *ct,
                return 0;
 
        helper = rcu_dereference(help->helper);
+       if (!helper)
+               return 0;
+
        if (!(helper->flags & NF_CT_HELPER_F_USERSPACE))
                return 0;
 
index 04bd0ed..b0ef48b 100644 (file)
@@ -317,12 +317,12 @@ int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
 EXPORT_SYMBOL_GPL(flow_offload_add);
 
 void flow_offload_refresh(struct nf_flowtable *flow_table,
-                         struct flow_offload *flow)
+                         struct flow_offload *flow, bool force)
 {
        u32 timeout;
 
        timeout = nf_flowtable_time_stamp + flow_offload_get_timeout(flow);
-       if (timeout - READ_ONCE(flow->timeout) > HZ)
+       if (force || timeout - READ_ONCE(flow->timeout) > HZ)
                WRITE_ONCE(flow->timeout, timeout);
        else
                return;
@@ -334,6 +334,12 @@ void flow_offload_refresh(struct nf_flowtable *flow_table,
 }
 EXPORT_SYMBOL_GPL(flow_offload_refresh);
 
+static bool nf_flow_is_outdated(const struct flow_offload *flow)
+{
+       return test_bit(IPS_SEEN_REPLY_BIT, &flow->ct->status) &&
+               !test_bit(NF_FLOW_HW_ESTABLISHED, &flow->flags);
+}
+
 static inline bool nf_flow_has_expired(const struct flow_offload *flow)
 {
        return nf_flow_timeout_delta(flow->timeout) <= 0;
@@ -423,7 +429,8 @@ static void nf_flow_offload_gc_step(struct nf_flowtable *flow_table,
                                    struct flow_offload *flow, void *data)
 {
        if (nf_flow_has_expired(flow) ||
-           nf_ct_is_dying(flow->ct))
+           nf_ct_is_dying(flow->ct) ||
+           nf_flow_is_outdated(flow))
                flow_offload_teardown(flow);
 
        if (test_bit(NF_FLOW_TEARDOWN, &flow->flags)) {
index 19efba1..3bbaf9c 100644 (file)
@@ -384,7 +384,7 @@ nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
        if (skb_try_make_writable(skb, thoff + hdrsize))
                return NF_DROP;
 
-       flow_offload_refresh(flow_table, flow);
+       flow_offload_refresh(flow_table, flow, false);
 
        nf_flow_encap_pop(skb, tuplehash);
        thoff -= offset;
@@ -650,7 +650,7 @@ nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
        if (skb_try_make_writable(skb, thoff + hdrsize))
                return NF_DROP;
 
-       flow_offload_refresh(flow_table, flow);
+       flow_offload_refresh(flow_table, flow, false);
 
        nf_flow_encap_pop(skb, tuplehash);
 
index dc56759..69bceef 100644 (file)
@@ -1600,6 +1600,8 @@ static int nft_dump_basechain_hook(struct sk_buff *skb, int family,
 
        if (nft_base_chain_netdev(family, ops->hooknum)) {
                nest_devs = nla_nest_start_noflag(skb, NFTA_HOOK_DEVS);
+               if (!nest_devs)
+                       goto nla_put_failure;
 
                if (!hook_list)
                        hook_list = &basechain->hook_list;
@@ -3842,7 +3844,8 @@ err_destroy_flow_rule:
        if (flow)
                nft_flow_rule_destroy(flow);
 err_release_rule:
-       nf_tables_rule_release(&ctx, rule);
+       nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE);
+       nf_tables_rule_destroy(&ctx, rule);
 err_release_expr:
        for (i = 0; i < n; i++) {
                if (expr_info[i].ops) {
@@ -4917,6 +4920,7 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
 
        set->num_exprs = num_exprs;
        set->handle = nf_tables_alloc_handle(table);
+       INIT_LIST_HEAD(&set->pending_update);
 
        err = nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set);
        if (err < 0)
@@ -9005,7 +9009,7 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
                                continue;
                        }
 
-                       if (WARN_ON_ONCE(data + expr->ops->size > data_boundary))
+                       if (WARN_ON_ONCE(data + size + expr->ops->size > data_boundary))
                                return -ENOMEM;
 
                        memcpy(data + size, expr, expr->ops->size);
@@ -9273,10 +9277,25 @@ static void nf_tables_commit_audit_log(struct list_head *adl, u32 generation)
        }
 }
 
+static void nft_set_commit_update(struct list_head *set_update_list)
+{
+       struct nft_set *set, *next;
+
+       list_for_each_entry_safe(set, next, set_update_list, pending_update) {
+               list_del_init(&set->pending_update);
+
+               if (!set->ops->commit)
+                       continue;
+
+               set->ops->commit(set);
+       }
+}
+
 static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
        struct nft_trans *trans, *next;
+       LIST_HEAD(set_update_list);
        struct nft_trans_elem *te;
        struct nft_chain *chain;
        struct nft_table *table;
@@ -9451,6 +9470,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                        nf_tables_setelem_notify(&trans->ctx, te->set,
                                                 &te->elem,
                                                 NFT_MSG_NEWSETELEM);
+                       if (te->set->ops->commit &&
+                           list_empty(&te->set->pending_update)) {
+                               list_add_tail(&te->set->pending_update,
+                                             &set_update_list);
+                       }
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_DELSETELEM:
@@ -9465,6 +9489,11 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                                atomic_dec(&te->set->nelems);
                                te->set->ndeact--;
                        }
+                       if (te->set->ops->commit &&
+                           list_empty(&te->set->pending_update)) {
+                               list_add_tail(&te->set->pending_update,
+                                             &set_update_list);
+                       }
                        break;
                case NFT_MSG_NEWOBJ:
                        if (nft_trans_obj_update(trans)) {
@@ -9527,6 +9556,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                }
        }
 
+       nft_set_commit_update(&set_update_list);
+
        nft_commit_notify(net, NETLINK_CB(skb).portid);
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
        nf_tables_commit_audit_log(&adl, nft_net->base_seq);
@@ -9586,10 +9617,25 @@ static void nf_tables_abort_release(struct nft_trans *trans)
        kfree(trans);
 }
 
+static void nft_set_abort_update(struct list_head *set_update_list)
+{
+       struct nft_set *set, *next;
+
+       list_for_each_entry_safe(set, next, set_update_list, pending_update) {
+               list_del_init(&set->pending_update);
+
+               if (!set->ops->abort)
+                       continue;
+
+               set->ops->abort(set);
+       }
+}
+
 static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
        struct nft_trans *trans, *next;
+       LIST_HEAD(set_update_list);
        struct nft_trans_elem *te;
 
        if (action == NFNL_ABORT_VALIDATE &&
@@ -9699,6 +9745,12 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
                        nft_setelem_remove(net, te->set, &te->elem);
                        if (!nft_setelem_is_catchall(te->set, &te->elem))
                                atomic_dec(&te->set->nelems);
+
+                       if (te->set->ops->abort &&
+                           list_empty(&te->set->pending_update)) {
+                               list_add_tail(&te->set->pending_update,
+                                             &set_update_list);
+                       }
                        break;
                case NFT_MSG_DELSETELEM:
                case NFT_MSG_DESTROYSETELEM:
@@ -9709,6 +9761,11 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
                        if (!nft_setelem_is_catchall(te->set, &te->elem))
                                te->set->ndeact--;
 
+                       if (te->set->ops->abort &&
+                           list_empty(&te->set->pending_update)) {
+                               list_add_tail(&te->set->pending_update,
+                                             &set_update_list);
+                       }
                        nft_trans_destroy(trans);
                        break;
                case NFT_MSG_NEWOBJ:
@@ -9751,6 +9808,8 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
                }
        }
 
+       nft_set_abort_update(&set_update_list);
+
        synchronize_rcu();
 
        list_for_each_entry_safe_reverse(trans, next,
index ae71464..c9fbe0f 100644 (file)
@@ -533,7 +533,8 @@ ack:
                         * processed, this avoids that the same error is
                         * reported several times when replaying the batch.
                         */
-                       if (nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
+                       if (err == -ENOMEM ||
+                           nfnl_err_add(&err_list, nlh, err, &extack) < 0) {
                                /* We failed to enqueue an error, reset the
                                 * list of errors and send OOM to userspace
                                 * pointing to the batch header.
index 84eae7c..2527a01 100644 (file)
@@ -323,7 +323,7 @@ static bool nft_bitwise_reduce(struct nft_regs_track *track,
        dreg = priv->dreg;
        regcount = DIV_ROUND_UP(priv->len, NFT_REG32_SIZE);
        for (i = 0; i < regcount; i++, dreg++)
-               track->regs[priv->dreg].bitwise = expr;
+               track->regs[dreg].bitwise = expr;
 
        return false;
 }
index 06d46d1..15e451d 100644 (file)
@@ -1600,17 +1600,10 @@ static void pipapo_free_fields(struct nft_pipapo_match *m)
        }
 }
 
-/**
- * pipapo_reclaim_match - RCU callback to free fields from old matching data
- * @rcu:       RCU head
- */
-static void pipapo_reclaim_match(struct rcu_head *rcu)
+static void pipapo_free_match(struct nft_pipapo_match *m)
 {
-       struct nft_pipapo_match *m;
        int i;
 
-       m = container_of(rcu, struct nft_pipapo_match, rcu);
-
        for_each_possible_cpu(i)
                kfree(*per_cpu_ptr(m->scratch, i));
 
@@ -1625,7 +1618,19 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
 }
 
 /**
- * pipapo_commit() - Replace lookup data with current working copy
+ * pipapo_reclaim_match - RCU callback to free fields from old matching data
+ * @rcu:       RCU head
+ */
+static void pipapo_reclaim_match(struct rcu_head *rcu)
+{
+       struct nft_pipapo_match *m;
+
+       m = container_of(rcu, struct nft_pipapo_match, rcu);
+       pipapo_free_match(m);
+}
+
+/**
+ * nft_pipapo_commit() - Replace lookup data with current working copy
  * @set:       nftables API set representation
  *
  * While at it, check if we should perform garbage collection on the working
@@ -1635,7 +1640,7 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
  * We also need to create a new working copy for subsequent insertions and
  * deletions.
  */
-static void pipapo_commit(const struct nft_set *set)
+static void nft_pipapo_commit(const struct nft_set *set)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
        struct nft_pipapo_match *new_clone, *old;
@@ -1660,6 +1665,26 @@ static void pipapo_commit(const struct nft_set *set)
        priv->clone = new_clone;
 }
 
+static void nft_pipapo_abort(const struct nft_set *set)
+{
+       struct nft_pipapo *priv = nft_set_priv(set);
+       struct nft_pipapo_match *new_clone, *m;
+
+       if (!priv->dirty)
+               return;
+
+       m = rcu_dereference(priv->match);
+
+       new_clone = pipapo_clone(m);
+       if (IS_ERR(new_clone))
+               return;
+
+       priv->dirty = false;
+
+       pipapo_free_match(priv->clone);
+       priv->clone = new_clone;
+}
+
 /**
  * nft_pipapo_activate() - Mark element reference as active given key, commit
  * @net:       Network namespace
@@ -1667,8 +1692,7 @@ static void pipapo_commit(const struct nft_set *set)
  * @elem:      nftables API element representation containing key data
  *
  * On insertion, elements are added to a copy of the matching data currently
- * in use for lookups, and not directly inserted into current lookup data, so
- * we'll take care of that by calling pipapo_commit() here. Both
+ * in use for lookups, and not directly inserted into current lookup data. Both
  * nft_pipapo_insert() and nft_pipapo_activate() are called once for each
  * element, hence we can't purpose either one as a real commit operation.
  */
@@ -1684,8 +1708,6 @@ static void nft_pipapo_activate(const struct net *net,
 
        nft_set_elem_change_active(net, set, &e->ext);
        nft_set_elem_clear_busy(&e->ext);
-
-       pipapo_commit(set);
 }
 
 /**
@@ -1931,7 +1953,6 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
                if (i == m->field_count) {
                        priv->dirty = true;
                        pipapo_drop(m, rulemap);
-                       pipapo_commit(set);
                        return;
                }
 
@@ -2230,6 +2251,8 @@ const struct nft_set_type nft_set_pipapo_type = {
                .init           = nft_pipapo_init,
                .destroy        = nft_pipapo_destroy,
                .gc_init        = nft_pipapo_gc_init,
+               .commit         = nft_pipapo_commit,
+               .abort          = nft_pipapo_abort,
                .elemsize       = offsetof(struct nft_pipapo_elem, ext),
        },
 };
@@ -2252,6 +2275,8 @@ const struct nft_set_type nft_set_pipapo_avx2_type = {
                .init           = nft_pipapo_init,
                .destroy        = nft_pipapo_destroy,
                .gc_init        = nft_pipapo_gc_init,
+               .commit         = nft_pipapo_commit,
+               .abort          = nft_pipapo_abort,
                .elemsize       = offsetof(struct nft_pipapo_elem, ext),
        },
 };
index 54c0830..27511c9 100644 (file)
@@ -857,7 +857,8 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
 
        offset -= iter->startbit;
        idx = offset / NETLBL_CATMAP_MAPSIZE;
-       iter->bitmap[idx] |= bitmap << (offset % NETLBL_CATMAP_MAPSIZE);
+       iter->bitmap[idx] |= (NETLBL_CATMAP_MAPTYPE)bitmap
+                            << (offset % NETLBL_CATMAP_MAPSIZE);
 
        return 0;
 }
index fcee601..58f530f 100644 (file)
@@ -236,9 +236,6 @@ void ovs_dp_detach_port(struct vport *p)
        /* First drop references to device. */
        hlist_del_rcu(&p->dp_hash_node);
 
-       /* Free percpu memory */
-       free_percpu(p->upcall_stats);
-
        /* Then destroy it. */
        ovs_vport_del(p);
 }
@@ -1858,12 +1855,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                goto err_destroy_portids;
        }
 
-       vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
-       if (!vport->upcall_stats) {
-               err = -ENOMEM;
-               goto err_destroy_vport;
-       }
-
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
                                   info->snd_seq, 0, OVS_DP_CMD_NEW);
        BUG_ON(err < 0);
@@ -1876,8 +1867,6 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        ovs_notify(&dp_datapath_genl_family, reply, info);
        return 0;
 
-err_destroy_vport:
-       ovs_dp_detach_port(vport);
 err_destroy_portids:
        kfree(rcu_dereference_raw(dp->upcall_portids));
 err_unlock_and_destroy_meters:
@@ -2322,12 +2311,6 @@ restart:
                goto exit_unlock_free;
        }
 
-       vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
-       if (!vport->upcall_stats) {
-               err = -ENOMEM;
-               goto exit_unlock_free_vport;
-       }
-
        err = ovs_vport_cmd_fill_info(vport, reply, genl_info_net(info),
                                      info->snd_portid, info->snd_seq, 0,
                                      OVS_VPORT_CMD_NEW, GFP_KERNEL);
@@ -2345,8 +2328,6 @@ restart:
        ovs_notify(&dp_vport_genl_family, reply, info);
        return 0;
 
-exit_unlock_free_vport:
-       ovs_dp_detach_port(vport);
 exit_unlock_free:
        ovs_unlock();
        kfree_skb(reply);
index 7e0f5c4..972ae01 100644 (file)
@@ -124,6 +124,7 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
 {
        struct vport *vport;
        size_t alloc_size;
+       int err;
 
        alloc_size = sizeof(struct vport);
        if (priv_size) {
@@ -135,17 +136,29 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
        if (!vport)
                return ERR_PTR(-ENOMEM);
 
+       vport->upcall_stats = netdev_alloc_pcpu_stats(struct vport_upcall_stats_percpu);
+       if (!vport->upcall_stats) {
+               err = -ENOMEM;
+               goto err_kfree_vport;
+       }
+
        vport->dp = parms->dp;
        vport->port_no = parms->port_no;
        vport->ops = ops;
        INIT_HLIST_NODE(&vport->dp_hash_node);
 
        if (ovs_vport_set_upcall_portids(vport, parms->upcall_portids)) {
-               kfree(vport);
-               return ERR_PTR(-EINVAL);
+               err = -EINVAL;
+               goto err_free_percpu;
        }
 
        return vport;
+
+err_free_percpu:
+       free_percpu(vport->upcall_stats);
+err_kfree_vport:
+       kfree(vport);
+       return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(ovs_vport_alloc);
 
@@ -165,6 +178,7 @@ void ovs_vport_free(struct vport *vport)
         * it is safe to use raw dereference.
         */
        kfree(rcu_dereference_raw(vport->upcall_portids));
+       free_percpu(vport->upcall_stats);
        kfree(vport);
 }
 EXPORT_SYMBOL_GPL(ovs_vport_free);
index 9cc0bc7..abc71a0 100644 (file)
@@ -610,6 +610,7 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
        struct flow_offload_tuple tuple = {};
        enum ip_conntrack_info ctinfo;
        struct tcphdr *tcph = NULL;
+       bool force_refresh = false;
        struct flow_offload *flow;
        struct nf_conn *ct;
        u8 dir;
@@ -647,6 +648,7 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
                         * established state, then don't refresh.
                         */
                        return false;
+               force_refresh = true;
        }
 
        if (tcph && (unlikely(tcph->fin || tcph->rst))) {
@@ -660,7 +662,12 @@ static bool tcf_ct_flow_table_lookup(struct tcf_ct_params *p,
        else
                ctinfo = IP_CT_ESTABLISHED_REPLY;
 
-       flow_offload_refresh(nf_ft, flow);
+       flow_offload_refresh(nf_ft, flow, force_refresh);
+       if (!test_bit(IPS_ASSURED_BIT, &ct->status)) {
+               /* Process this flow in SW to allow promoting to ASSURED */
+               return false;
+       }
+
        nf_conntrack_get(&ct->ct_general);
        nf_ct_set(skb, ct, ctinfo);
        if (nf_ft->flags & NF_FLOWTABLE_COUNTER)
index fc945c7..c819b81 100644 (file)
 #include <linux/rtnetlink.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
 #include <linux/slab.h>
+#include <net/ipv6.h>
 #include <net/netlink.h>
 #include <net/pkt_sched.h>
 #include <linux/tc_act/tc_pedit.h>
@@ -327,28 +330,58 @@ static bool offset_valid(struct sk_buff *skb, int offset)
        return true;
 }
 
-static void pedit_skb_hdr_offset(struct sk_buff *skb,
+static int pedit_l4_skb_offset(struct sk_buff *skb, int *hoffset, const int header_type)
+{
+       const int noff = skb_network_offset(skb);
+       int ret = -EINVAL;
+       struct iphdr _iph;
+
+       switch (skb->protocol) {
+       case htons(ETH_P_IP): {
+               const struct iphdr *iph = skb_header_pointer(skb, noff, sizeof(_iph), &_iph);
+
+               if (!iph)
+                       goto out;
+               *hoffset = noff + iph->ihl * 4;
+               ret = 0;
+               break;
+       }
+       case htons(ETH_P_IPV6):
+               ret = ipv6_find_hdr(skb, hoffset, header_type, NULL, NULL) == header_type ? 0 : -EINVAL;
+               break;
+       }
+out:
+       return ret;
+}
+
+static int pedit_skb_hdr_offset(struct sk_buff *skb,
                                 enum pedit_header_type htype, int *hoffset)
 {
+       int ret = -EINVAL;
        /* 'htype' is validated in the netlink parsing */
        switch (htype) {
        case TCA_PEDIT_KEY_EX_HDR_TYPE_ETH:
-               if (skb_mac_header_was_set(skb))
+               if (skb_mac_header_was_set(skb)) {
                        *hoffset = skb_mac_offset(skb);
+                       ret = 0;
+               }
                break;
        case TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK:
        case TCA_PEDIT_KEY_EX_HDR_TYPE_IP4:
        case TCA_PEDIT_KEY_EX_HDR_TYPE_IP6:
                *hoffset = skb_network_offset(skb);
+               ret = 0;
                break;
        case TCA_PEDIT_KEY_EX_HDR_TYPE_TCP:
+               ret = pedit_l4_skb_offset(skb, hoffset, IPPROTO_TCP);
+               break;
        case TCA_PEDIT_KEY_EX_HDR_TYPE_UDP:
-               if (skb_transport_header_was_set(skb))
-                       *hoffset = skb_transport_offset(skb);
+               ret = pedit_l4_skb_offset(skb, hoffset, IPPROTO_UDP);
                break;
        default:
                break;
        }
+       return ret;
 }
 
 TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
@@ -384,6 +417,7 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
                int hoffset = 0;
                u32 *ptr, hdata;
                u32 val;
+               int rc;
 
                if (tkey_ex) {
                        htype = tkey_ex->htype;
@@ -392,7 +426,11 @@ TC_INDIRECT_SCOPE int tcf_pedit_act(struct sk_buff *skb,
                        tkey_ex++;
                }
 
-               pedit_skb_hdr_offset(skb, htype, &hoffset);
+               rc = pedit_skb_hdr_offset(skb, htype, &hoffset);
+               if (rc) {
+                       pr_info_ratelimited("tc action pedit unable to extract header offset for header type (0x%x)\n", htype);
+                       goto bad;
+               }
 
                if (tkey->offmask) {
                        u8 *d, _d;
index 227cba5..2e9dce0 100644 (file)
@@ -357,23 +357,23 @@ static int tcf_police_dump(struct sk_buff *skb, struct tc_action *a,
        opt.burst = PSCHED_NS2TICKS(p->tcfp_burst);
        if (p->rate_present) {
                psched_ratecfg_getrate(&opt.rate, &p->rate);
-               if ((police->params->rate.rate_bytes_ps >= (1ULL << 32)) &&
+               if ((p->rate.rate_bytes_ps >= (1ULL << 32)) &&
                    nla_put_u64_64bit(skb, TCA_POLICE_RATE64,
-                                     police->params->rate.rate_bytes_ps,
+                                     p->rate.rate_bytes_ps,
                                      TCA_POLICE_PAD))
                        goto nla_put_failure;
        }
        if (p->peak_present) {
                psched_ratecfg_getrate(&opt.peakrate, &p->peak);
-               if ((police->params->peak.rate_bytes_ps >= (1ULL << 32)) &&
+               if ((p->peak.rate_bytes_ps >= (1ULL << 32)) &&
                    nla_put_u64_64bit(skb, TCA_POLICE_PEAKRATE64,
-                                     police->params->peak.rate_bytes_ps,
+                                     p->peak.rate_bytes_ps,
                                      TCA_POLICE_PAD))
                        goto nla_put_failure;
        }
        if (p->pps_present) {
                if (nla_put_u64_64bit(skb, TCA_POLICE_PKTRATE64,
-                                     police->params->ppsrate.rate_pkts_ps,
+                                     p->ppsrate.rate_pkts_ps,
                                      TCA_POLICE_PAD))
                        goto nla_put_failure;
                if (nla_put_u64_64bit(skb, TCA_POLICE_PKTBURST64,
index 2621550..a193cc7 100644 (file)
@@ -43,8 +43,6 @@
 #include <net/flow_offload.h>
 #include <net/tc_wrapper.h>
 
-extern const struct nla_policy rtm_tca_policy[TCA_MAX + 1];
-
 /* The list of all installed classifier types */
 static LIST_HEAD(tcf_proto_base);
 
@@ -659,8 +657,8 @@ static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
 {
        struct tcf_block *block = chain->block;
        const struct tcf_proto_ops *tmplt_ops;
+       unsigned int refcnt, non_act_refcnt;
        bool free_block = false;
-       unsigned int refcnt;
        void *tmplt_priv;
 
        mutex_lock(&block->lock);
@@ -680,13 +678,15 @@ static void __tcf_chain_put(struct tcf_chain *chain, bool by_act,
         * save these to temporary variables.
         */
        refcnt = --chain->refcnt;
+       non_act_refcnt = refcnt - chain->action_refcnt;
        tmplt_ops = chain->tmplt_ops;
        tmplt_priv = chain->tmplt_priv;
 
-       /* The last dropped non-action reference will trigger notification. */
-       if (refcnt - chain->action_refcnt == 0 && !by_act) {
-               tc_chain_notify_delete(tmplt_ops, tmplt_priv, chain->index,
-                                      block, NULL, 0, 0, false);
+       if (non_act_refcnt == chain->explicitly_created && !by_act) {
+               if (non_act_refcnt == 0)
+                       tc_chain_notify_delete(tmplt_ops, tmplt_priv,
+                                              chain->index, block, NULL, 0, 0,
+                                              false);
                /* Last reference to chain, no need to lock. */
                chain->flushing = false;
        }
@@ -2952,6 +2952,7 @@ static int tc_chain_tmplt_add(struct tcf_chain *chain, struct net *net,
                return PTR_ERR(ops);
        if (!ops->tmplt_create || !ops->tmplt_destroy || !ops->tmplt_dump) {
                NL_SET_ERR_MSG(extack, "Chain templates are not supported with specified classifier");
+               module_put(ops->owner);
                return -EOPNOTSUPP;
        }
 
index 4e2e269..d15d50d 100644 (file)
@@ -718,13 +718,19 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp,
                         struct nlattr *est, u32 flags, u32 fl_flags,
                         struct netlink_ext_ack *extack)
 {
-       int err;
+       int err, ifindex = -1;
 
        err = tcf_exts_validate_ex(net, tp, tb, est, &n->exts, flags,
                                   fl_flags, extack);
        if (err < 0)
                return err;
 
+       if (tb[TCA_U32_INDEV]) {
+               ifindex = tcf_change_indev(net, tb[TCA_U32_INDEV], extack);
+               if (ifindex < 0)
+                       return -EINVAL;
+       }
+
        if (tb[TCA_U32_LINK]) {
                u32 handle = nla_get_u32(tb[TCA_U32_LINK]);
                struct tc_u_hnode *ht_down = NULL, *ht_old;
@@ -759,13 +765,9 @@ static int u32_set_parms(struct net *net, struct tcf_proto *tp,
                tcf_bind_filter(tp, &n->res, base);
        }
 
-       if (tb[TCA_U32_INDEV]) {
-               int ret;
-               ret = tcf_change_indev(net, tb[TCA_U32_INDEV], extack);
-               if (ret < 0)
-                       return -EINVAL;
-               n->ifindex = ret;
-       }
+       if (ifindex >= 0)
+               n->ifindex = ifindex;
+
        return 0;
 }
 
index 014209b..aa6b1fe 100644 (file)
@@ -309,7 +309,7 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
 
        if (dev_ingress_queue(dev))
                q = qdisc_match_from_root(
-                       dev_ingress_queue(dev)->qdisc_sleeping,
+                       rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping),
                        handle);
 out:
        return q;
@@ -328,7 +328,8 @@ struct Qdisc *qdisc_lookup_rcu(struct net_device *dev, u32 handle)
 
        nq = dev_ingress_queue_rcu(dev);
        if (nq)
-               q = qdisc_match_from_root(nq->qdisc_sleeping, handle);
+               q = qdisc_match_from_root(rcu_dereference(nq->qdisc_sleeping),
+                                         handle);
 out:
        return q;
 }
@@ -634,8 +635,13 @@ EXPORT_SYMBOL(qdisc_watchdog_init);
 void qdisc_watchdog_schedule_range_ns(struct qdisc_watchdog *wd, u64 expires,
                                      u64 delta_ns)
 {
-       if (test_bit(__QDISC_STATE_DEACTIVATED,
-                    &qdisc_root_sleeping(wd->qdisc)->state))
+       bool deactivated;
+
+       rcu_read_lock();
+       deactivated = test_bit(__QDISC_STATE_DEACTIVATED,
+                              &qdisc_root_sleeping(wd->qdisc)->state);
+       rcu_read_unlock();
+       if (deactivated)
                return;
 
        if (hrtimer_is_queued(&wd->timer)) {
@@ -1073,17 +1079,29 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
 
        if (parent == NULL) {
                unsigned int i, num_q, ingress;
+               struct netdev_queue *dev_queue;
 
                ingress = 0;
                num_q = dev->num_tx_queues;
                if ((q && q->flags & TCQ_F_INGRESS) ||
                    (new && new->flags & TCQ_F_INGRESS)) {
-                       num_q = 1;
                        ingress = 1;
-                       if (!dev_ingress_queue(dev)) {
+                       dev_queue = dev_ingress_queue(dev);
+                       if (!dev_queue) {
                                NL_SET_ERR_MSG(extack, "Device does not have an ingress queue");
                                return -ENOENT;
                        }
+
+                       q = rtnl_dereference(dev_queue->qdisc_sleeping);
+
+                       /* This is the counterpart of that qdisc_refcount_inc_nz() call in
+                        * __tcf_qdisc_find() for filter requests.
+                        */
+                       if (!qdisc_refcount_dec_if_one(q)) {
+                               NL_SET_ERR_MSG(extack,
+                                              "Current ingress or clsact Qdisc has ongoing filter requests");
+                               return -EBUSY;
+                       }
                }
 
                if (dev->flags & IFF_UP)
@@ -1094,18 +1112,26 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
                if (new && new->ops->attach && !ingress)
                        goto skip;
 
-               for (i = 0; i < num_q; i++) {
-                       struct netdev_queue *dev_queue = dev_ingress_queue(dev);
-
-                       if (!ingress)
+               if (!ingress) {
+                       for (i = 0; i < num_q; i++) {
                                dev_queue = netdev_get_tx_queue(dev, i);
+                               old = dev_graft_qdisc(dev_queue, new);
 
-                       old = dev_graft_qdisc(dev_queue, new);
-                       if (new && i > 0)
-                               qdisc_refcount_inc(new);
-
-                       if (!ingress)
+                               if (new && i > 0)
+                                       qdisc_refcount_inc(new);
                                qdisc_put(old);
+                       }
+               } else {
+                       old = dev_graft_qdisc(dev_queue, NULL);
+
+                       /* {ingress,clsact}_destroy() @old before grafting @new to avoid
+                        * unprotected concurrent accesses to net_device::miniq_{in,e}gress
+                        * pointer(s) in mini_qdisc_pair_swap().
+                        */
+                       qdisc_notify(net, skb, n, classid, old, new, extack);
+                       qdisc_destroy(old);
+
+                       dev_graft_qdisc(dev_queue, new);
                }
 
 skip:
@@ -1119,8 +1145,6 @@ skip:
 
                        if (new && new->ops->attach)
                                new->ops->attach(new);
-               } else {
-                       notify_and_destroy(net, skb, n, classid, old, new, extack);
                }
 
                if (dev->flags & IFF_UP)
@@ -1478,7 +1502,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
                                }
                                q = qdisc_leaf(p, clid);
                        } else if (dev_ingress_queue(dev)) {
-                               q = dev_ingress_queue(dev)->qdisc_sleeping;
+                               q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
                        }
                } else {
                        q = rtnl_dereference(dev->qdisc);
@@ -1564,7 +1588,7 @@ replay:
                                }
                                q = qdisc_leaf(p, clid);
                        } else if (dev_ingress_queue_create(dev)) {
-                               q = dev_ingress_queue(dev)->qdisc_sleeping;
+                               q = rtnl_dereference(dev_ingress_queue(dev)->qdisc_sleeping);
                        }
                } else {
                        q = rtnl_dereference(dev->qdisc);
@@ -1805,8 +1829,8 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
 
                dev_queue = dev_ingress_queue(dev);
                if (dev_queue &&
-                   tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb,
-                                      &q_idx, s_q_idx, false,
+                   tc_dump_qdisc_root(rtnl_dereference(dev_queue->qdisc_sleeping),
+                                      skb, cb, &q_idx, s_q_idx, false,
                                       tca[TCA_DUMP_INVISIBLE]) < 0)
                        goto done;
 
@@ -2249,8 +2273,8 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
 
        dev_queue = dev_ingress_queue(dev);
        if (dev_queue &&
-           tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb,
-                               &t, s_t, false) < 0)
+           tc_dump_tclass_root(rtnl_dereference(dev_queue->qdisc_sleeping),
+                               skb, tcm, cb, &t, s_t, false) < 0)
                goto done;
 
 done:
@@ -2302,7 +2326,9 @@ static struct pernet_operations psched_net_ops = {
        .exit = psched_net_exit,
 };
 
+#if IS_ENABLED(CONFIG_RETPOLINE)
 DEFINE_STATIC_KEY_FALSE(tc_skip_wrapper);
+#endif
 
 static int __init pktsched_init(void)
 {
index 6980796..591d87d 100644 (file)
@@ -201,6 +201,11 @@ out:
        return NET_XMIT_CN;
 }
 
+static struct netlink_range_validation fq_pie_q_range = {
+       .min = 1,
+       .max = 1 << 20,
+};
+
 static const struct nla_policy fq_pie_policy[TCA_FQ_PIE_MAX + 1] = {
        [TCA_FQ_PIE_LIMIT]              = {.type = NLA_U32},
        [TCA_FQ_PIE_FLOWS]              = {.type = NLA_U32},
@@ -208,7 +213,8 @@ static const struct nla_policy fq_pie_policy[TCA_FQ_PIE_MAX + 1] = {
        [TCA_FQ_PIE_TUPDATE]            = {.type = NLA_U32},
        [TCA_FQ_PIE_ALPHA]              = {.type = NLA_U32},
        [TCA_FQ_PIE_BETA]               = {.type = NLA_U32},
-       [TCA_FQ_PIE_QUANTUM]            = {.type = NLA_U32},
+       [TCA_FQ_PIE_QUANTUM]            =
+                       NLA_POLICY_FULL_RANGE(NLA_U32, &fq_pie_q_range),
        [TCA_FQ_PIE_MEMORY_LIMIT]       = {.type = NLA_U32},
        [TCA_FQ_PIE_ECN_PROB]           = {.type = NLA_U32},
        [TCA_FQ_PIE_ECN]                = {.type = NLA_U32},
@@ -373,6 +379,7 @@ static void fq_pie_timer(struct timer_list *t)
        spinlock_t *root_lock; /* to lock qdisc for probability calculations */
        u32 idx;
 
+       rcu_read_lock();
        root_lock = qdisc_lock(qdisc_root_sleeping(sch));
        spin_lock(root_lock);
 
@@ -385,6 +392,7 @@ static void fq_pie_timer(struct timer_list *t)
                mod_timer(&q->adapt_timer, jiffies + q->p_params.tupdate);
 
        spin_unlock(root_lock);
+       rcu_read_unlock();
 }
 
 static int fq_pie_init(struct Qdisc *sch, struct nlattr *opt,
index 37e41f9..5d7e23f 100644 (file)
@@ -648,7 +648,7 @@ struct Qdisc_ops noop_qdisc_ops __read_mostly = {
 
 static struct netdev_queue noop_netdev_queue = {
        RCU_POINTER_INITIALIZER(qdisc, &noop_qdisc),
-       .qdisc_sleeping =       &noop_qdisc,
+       RCU_POINTER_INITIALIZER(qdisc_sleeping, &noop_qdisc),
 };
 
 struct Qdisc noop_qdisc = {
@@ -1046,7 +1046,7 @@ static void qdisc_free_cb(struct rcu_head *head)
        qdisc_free(q);
 }
 
-static void qdisc_destroy(struct Qdisc *qdisc)
+static void __qdisc_destroy(struct Qdisc *qdisc)
 {
        const struct Qdisc_ops  *ops = qdisc->ops;
 
@@ -1070,6 +1070,14 @@ static void qdisc_destroy(struct Qdisc *qdisc)
        call_rcu(&qdisc->rcu, qdisc_free_cb);
 }
 
+void qdisc_destroy(struct Qdisc *qdisc)
+{
+       if (qdisc->flags & TCQ_F_BUILTIN)
+               return;
+
+       __qdisc_destroy(qdisc);
+}
+
 void qdisc_put(struct Qdisc *qdisc)
 {
        if (!qdisc)
@@ -1079,7 +1087,7 @@ void qdisc_put(struct Qdisc *qdisc)
            !refcount_dec_and_test(&qdisc->refcnt))
                return;
 
-       qdisc_destroy(qdisc);
+       __qdisc_destroy(qdisc);
 }
 EXPORT_SYMBOL(qdisc_put);
 
@@ -1094,7 +1102,7 @@ void qdisc_put_unlocked(struct Qdisc *qdisc)
            !refcount_dec_and_rtnl_lock(&qdisc->refcnt))
                return;
 
-       qdisc_destroy(qdisc);
+       __qdisc_destroy(qdisc);
        rtnl_unlock();
 }
 EXPORT_SYMBOL(qdisc_put_unlocked);
@@ -1103,7 +1111,7 @@ EXPORT_SYMBOL(qdisc_put_unlocked);
 struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
                              struct Qdisc *qdisc)
 {
-       struct Qdisc *oqdisc = dev_queue->qdisc_sleeping;
+       struct Qdisc *oqdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
        spinlock_t *root_lock;
 
        root_lock = qdisc_lock(oqdisc);
@@ -1112,7 +1120,7 @@ struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue,
        /* ... and graft new one */
        if (qdisc == NULL)
                qdisc = &noop_qdisc;
-       dev_queue->qdisc_sleeping = qdisc;
+       rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
        rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc);
 
        spin_unlock_bh(root_lock);
@@ -1125,12 +1133,12 @@ static void shutdown_scheduler_queue(struct net_device *dev,
                                     struct netdev_queue *dev_queue,
                                     void *_qdisc_default)
 {
-       struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
+       struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
        struct Qdisc *qdisc_default = _qdisc_default;
 
        if (qdisc) {
                rcu_assign_pointer(dev_queue->qdisc, qdisc_default);
-               dev_queue->qdisc_sleeping = qdisc_default;
+               rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc_default);
 
                qdisc_put(qdisc);
        }
@@ -1154,7 +1162,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
 
        if (!netif_is_multiqueue(dev))
                qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
-       dev_queue->qdisc_sleeping = qdisc;
+       rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
 }
 
 static void attach_default_qdiscs(struct net_device *dev)
@@ -1167,7 +1175,7 @@ static void attach_default_qdiscs(struct net_device *dev)
        if (!netif_is_multiqueue(dev) ||
            dev->priv_flags & IFF_NO_QUEUE) {
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
-               qdisc = txq->qdisc_sleeping;
+               qdisc = rtnl_dereference(txq->qdisc_sleeping);
                rcu_assign_pointer(dev->qdisc, qdisc);
                qdisc_refcount_inc(qdisc);
        } else {
@@ -1186,7 +1194,7 @@ static void attach_default_qdiscs(struct net_device *dev)
                netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
                dev->priv_flags |= IFF_NO_QUEUE;
                netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL);
-               qdisc = txq->qdisc_sleeping;
+               qdisc = rtnl_dereference(txq->qdisc_sleeping);
                rcu_assign_pointer(dev->qdisc, qdisc);
                qdisc_refcount_inc(qdisc);
                dev->priv_flags ^= IFF_NO_QUEUE;
@@ -1202,7 +1210,7 @@ static void transition_one_qdisc(struct net_device *dev,
                                 struct netdev_queue *dev_queue,
                                 void *_need_watchdog)
 {
-       struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping;
+       struct Qdisc *new_qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
        int *need_watchdog_p = _need_watchdog;
 
        if (!(new_qdisc->flags & TCQ_F_BUILTIN))
@@ -1272,7 +1280,7 @@ static void dev_reset_queue(struct net_device *dev,
        struct Qdisc *qdisc;
        bool nolock;
 
-       qdisc = dev_queue->qdisc_sleeping;
+       qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
        if (!qdisc)
                return;
 
@@ -1303,7 +1311,7 @@ static bool some_qdisc_is_busy(struct net_device *dev)
                int val;
 
                dev_queue = netdev_get_tx_queue(dev, i);
-               q = dev_queue->qdisc_sleeping;
+               q = rtnl_dereference(dev_queue->qdisc_sleeping);
 
                root_lock = qdisc_lock(q);
                spin_lock_bh(root_lock);
@@ -1379,7 +1387,7 @@ EXPORT_SYMBOL(dev_deactivate);
 static int qdisc_change_tx_queue_len(struct net_device *dev,
                                     struct netdev_queue *dev_queue)
 {
-       struct Qdisc *qdisc = dev_queue->qdisc_sleeping;
+       struct Qdisc *qdisc = rtnl_dereference(dev_queue->qdisc_sleeping);
        const struct Qdisc_ops *ops = qdisc->ops;
 
        if (ops->change_tx_queue_len)
@@ -1404,7 +1412,7 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
        unsigned int i;
 
        for (i = new_real_tx; i < dev->real_num_tx_queues; i++) {
-               qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
+               qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
                /* Only update the default qdiscs we created,
                 * qdiscs with handles are always hashed.
                 */
@@ -1412,7 +1420,7 @@ void mq_change_real_num_tx(struct Qdisc *sch, unsigned int new_real_tx)
                        qdisc_hash_del(qdisc);
        }
        for (i = dev->real_num_tx_queues; i < new_real_tx; i++) {
-               qdisc = netdev_get_tx_queue(dev, i)->qdisc_sleeping;
+               qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc_sleeping);
                if (qdisc != &noop_qdisc && !qdisc->handle)
                        qdisc_hash_add(qdisc, false);
        }
@@ -1449,7 +1457,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
        struct Qdisc *qdisc = _qdisc;
 
        rcu_assign_pointer(dev_queue->qdisc, qdisc);
-       dev_queue->qdisc_sleeping = qdisc;
+       rcu_assign_pointer(dev_queue->qdisc_sleeping, qdisc);
 }
 
 void dev_init_scheduler(struct net_device *dev)
index d0bc660..c860119 100644 (file)
@@ -141,7 +141,7 @@ static int mq_dump(struct Qdisc *sch, struct sk_buff *skb)
         * qdisc totals are added at end.
         */
        for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
-               qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
+               qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
                spin_lock_bh(qdisc_lock(qdisc));
 
                gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
@@ -202,7 +202,7 @@ static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl)
 {
        struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
 
-       return dev_queue->qdisc_sleeping;
+       return rtnl_dereference(dev_queue->qdisc_sleeping);
 }
 
 static unsigned long mq_find(struct Qdisc *sch, u32 classid)
@@ -221,7 +221,7 @@ static int mq_dump_class(struct Qdisc *sch, unsigned long cl,
 
        tcm->tcm_parent = TC_H_ROOT;
        tcm->tcm_handle |= TC_H_MIN(cl);
-       tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
+       tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
        return 0;
 }
 
@@ -230,7 +230,7 @@ static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl,
 {
        struct netdev_queue *dev_queue = mq_queue_get(sch, cl);
 
-       sch = dev_queue->qdisc_sleeping;
+       sch = rtnl_dereference(dev_queue->qdisc_sleeping);
        if (gnet_stats_copy_basic(d, sch->cpu_bstats, &sch->bstats, true) < 0 ||
            qdisc_qstats_copy(d, sch) < 0)
                return -1;
index dc5a0ff..ab69ff7 100644 (file)
@@ -557,7 +557,7 @@ static int mqprio_dump(struct Qdisc *sch, struct sk_buff *skb)
         * qdisc totals are added at end.
         */
        for (ntx = 0; ntx < dev->num_tx_queues; ntx++) {
-               qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping;
+               qdisc = rtnl_dereference(netdev_get_tx_queue(dev, ntx)->qdisc_sleeping);
                spin_lock_bh(qdisc_lock(qdisc));
 
                gnet_stats_add_basic(&sch->bstats, qdisc->cpu_bstats,
@@ -604,7 +604,7 @@ static struct Qdisc *mqprio_leaf(struct Qdisc *sch, unsigned long cl)
        if (!dev_queue)
                return NULL;
 
-       return dev_queue->qdisc_sleeping;
+       return rtnl_dereference(dev_queue->qdisc_sleeping);
 }
 
 static unsigned long mqprio_find(struct Qdisc *sch, u32 classid)
@@ -637,7 +637,7 @@ static int mqprio_dump_class(struct Qdisc *sch, unsigned long cl,
                tcm->tcm_parent = (tc < 0) ? 0 :
                        TC_H_MAKE(TC_H_MAJ(sch->handle),
                                  TC_H_MIN(tc + TC_H_MIN_PRIORITY));
-               tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
+               tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
        } else {
                tcm->tcm_parent = TC_H_ROOT;
                tcm->tcm_info = 0;
@@ -693,7 +693,7 @@ static int mqprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
        } else {
                struct netdev_queue *dev_queue = mqprio_queue_get(sch, cl);
 
-               sch = dev_queue->qdisc_sleeping;
+               sch = rtnl_dereference(dev_queue->qdisc_sleeping);
                if (gnet_stats_copy_basic(d, sch->cpu_bstats,
                                          &sch->bstats, true) < 0 ||
                    qdisc_qstats_copy(d, sch) < 0)
index 2152a56..2da6250 100644 (file)
@@ -421,8 +421,10 @@ static void pie_timer(struct timer_list *t)
 {
        struct pie_sched_data *q = from_timer(q, t, adapt_timer);
        struct Qdisc *sch = q->sch;
-       spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
+       spinlock_t *root_lock;
 
+       rcu_read_lock();
+       root_lock = qdisc_lock(qdisc_root_sleeping(sch));
        spin_lock(root_lock);
        pie_calculate_probability(&q->params, &q->vars, sch->qstats.backlog);
 
@@ -430,6 +432,7 @@ static void pie_timer(struct timer_list *t)
        if (q->params.tupdate)
                mod_timer(&q->adapt_timer, jiffies + q->params.tupdate);
        spin_unlock(root_lock);
+       rcu_read_unlock();
 }
 
 static int pie_init(struct Qdisc *sch, struct nlattr *opt,
index 9812932..16277b6 100644 (file)
@@ -321,12 +321,15 @@ static inline void red_adaptative_timer(struct timer_list *t)
 {
        struct red_sched_data *q = from_timer(q, t, adapt_timer);
        struct Qdisc *sch = q->sch;
-       spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
+       spinlock_t *root_lock;
 
+       rcu_read_lock();
+       root_lock = qdisc_lock(qdisc_root_sleeping(sch));
        spin_lock(root_lock);
        red_adaptative_algo(&q->parms, &q->vars);
        mod_timer(&q->adapt_timer, jiffies + HZ/2);
        spin_unlock(root_lock);
+       rcu_read_unlock();
 }
 
 static int red_init(struct Qdisc *sch, struct nlattr *opt,
index abd4363..66dcb18 100644 (file)
@@ -606,10 +606,12 @@ static void sfq_perturbation(struct timer_list *t)
 {
        struct sfq_sched_data *q = from_timer(q, t, perturb_timer);
        struct Qdisc *sch = q->sch;
-       spinlock_t *root_lock = qdisc_lock(qdisc_root_sleeping(sch));
+       spinlock_t *root_lock;
        siphash_key_t nkey;
 
        get_random_bytes(&nkey, sizeof(nkey));
+       rcu_read_lock();
+       root_lock = qdisc_lock(qdisc_root_sleeping(sch));
        spin_lock(root_lock);
        q->perturbation = nkey;
        if (!q->filter_list && q->tail)
@@ -618,6 +620,7 @@ static void sfq_perturbation(struct timer_list *t)
 
        if (q->perturb_period)
                mod_timer(&q->perturb_timer, jiffies + q->perturb_period);
+       rcu_read_unlock();
 }
 
 static int sfq_change(struct Qdisc *sch, struct nlattr *opt)
index 76db9a1..cf0e61e 100644 (file)
@@ -797,6 +797,9 @@ static struct sk_buff *taprio_dequeue_tc_priority(struct Qdisc *sch,
 
                        taprio_next_tc_txq(dev, tc, &q->cur_txq[tc]);
 
+                       if (q->cur_txq[tc] >= dev->num_tx_queues)
+                               q->cur_txq[tc] = first_txq;
+
                        if (skb)
                                return skb;
                } while (q->cur_txq[tc] != first_txq);
@@ -2358,7 +2361,7 @@ static struct Qdisc *taprio_leaf(struct Qdisc *sch, unsigned long cl)
        if (!dev_queue)
                return NULL;
 
-       return dev_queue->qdisc_sleeping;
+       return rtnl_dereference(dev_queue->qdisc_sleeping);
 }
 
 static unsigned long taprio_find(struct Qdisc *sch, u32 classid)
@@ -2377,7 +2380,7 @@ static int taprio_dump_class(struct Qdisc *sch, unsigned long cl,
 
        tcm->tcm_parent = TC_H_ROOT;
        tcm->tcm_handle |= TC_H_MIN(cl);
-       tcm->tcm_info = dev_queue->qdisc_sleeping->handle;
+       tcm->tcm_info = rtnl_dereference(dev_queue->qdisc_sleeping)->handle;
 
        return 0;
 }
@@ -2389,7 +2392,7 @@ static int taprio_dump_class_stats(struct Qdisc *sch, unsigned long cl,
 {
        struct netdev_queue *dev_queue = taprio_queue_get(sch, cl);
 
-       sch = dev_queue->qdisc_sleeping;
+       sch = rtnl_dereference(dev_queue->qdisc_sleeping);
        if (gnet_stats_copy_basic(d, NULL, &sch->bstats, true) < 0 ||
            qdisc_qstats_copy(d, sch) < 0)
                return -1;
index 16f9238..7721239 100644 (file)
@@ -297,7 +297,7 @@ restart:
                struct net_device *slave = qdisc_dev(q);
                struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
 
-               if (slave_txq->qdisc_sleeping != q)
+               if (rcu_access_pointer(slave_txq->qdisc_sleeping) != q)
                        continue;
                if (netif_xmit_stopped(netdev_get_tx_queue(slave, subq)) ||
                    !netif_running(slave)) {
index 7fbeb99..23d6633 100644 (file)
@@ -1250,7 +1250,10 @@ static int sctp_side_effects(enum sctp_event_type event_type,
        default:
                pr_err("impossible disposition %d in state %d, event_type %d, event_id %d\n",
                       status, state, event_type, subtype.chunk);
-               BUG();
+               error = status;
+               if (error >= 0)
+                       error = -EINVAL;
+               WARN_ON_ONCE(1);
                break;
        }
 
index 97f1155..08fdf12 100644 (file)
@@ -4482,7 +4482,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net,
                                    SCTP_AUTH_NEW_KEY, GFP_ATOMIC);
 
                if (!ev)
-                       return -ENOMEM;
+                       return SCTP_DISPOSITION_NOMEM;
 
                sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
                                SCTP_ULPEVENT(ev));
index 7a8d916..90f0b60 100644 (file)
@@ -851,6 +851,8 @@ static int smc_llc_add_link_cont(struct smc_link *link,
        addc_llc->num_rkeys = *num_rkeys_todo;
        n = *num_rkeys_todo;
        for (i = 0; i < min_t(u8, n, SMC_LLC_RKEYS_PER_CONT_MSG); i++) {
+               while (*buf_pos && !(*buf_pos)->used)
+                       *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos);
                if (!*buf_pos) {
                        addc_llc->num_rkeys = addc_llc->num_rkeys -
                                              *num_rkeys_todo;
@@ -867,8 +869,6 @@ static int smc_llc_add_link_cont(struct smc_link *link,
 
                (*num_rkeys_todo)--;
                *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos);
-               while (*buf_pos && !(*buf_pos)->used)
-                       *buf_pos = smc_llc_get_next_rmb(lgr, buf_lst, *buf_pos);
        }
        addc_llc->hd.common.llc_type = SMC_LLC_ADD_LINK_CONT;
        addc_llc->hd.length = sizeof(struct smc_llc_msg_add_link_cont);
index 5388140..cdcd273 100644 (file)
@@ -1258,7 +1258,7 @@ int tipc_nl_media_get(struct sk_buff *skb, struct genl_info *info)
        struct tipc_nl_msg msg;
        struct tipc_media *media;
        struct sk_buff *rep;
-       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+       struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1];
 
        if (!info->attrs[TIPC_NLA_MEDIA])
                return -EINVAL;
@@ -1307,7 +1307,7 @@ int __tipc_nl_media_set(struct sk_buff *skb, struct genl_info *info)
        int err;
        char *name;
        struct tipc_media *m;
-       struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
+       struct nlattr *attrs[TIPC_NLA_MEDIA_MAX + 1];
 
        if (!info->attrs[TIPC_NLA_MEDIA])
                return -EINVAL;
index 5b0c4d5..b3ec9ea 100644 (file)
@@ -368,12 +368,12 @@ static void cfg80211_sched_scan_stop_wk(struct work_struct *work)
        rdev = container_of(work, struct cfg80211_registered_device,
                           sched_scan_stop_wk);
 
-       rtnl_lock();
+       wiphy_lock(&rdev->wiphy);
        list_for_each_entry_safe(req, tmp, &rdev->sched_scan_req_list, list) {
                if (req->nl_owner_dead)
                        cfg80211_stop_sched_scan_req(rdev, req, false);
        }
-       rtnl_unlock();
+       wiphy_unlock(&rdev->wiphy);
 }
 
 static void cfg80211_propagate_radar_detect_wk(struct work_struct *work)
index d95f805..087d60c 100644 (file)
@@ -10723,6 +10723,8 @@ static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
                if (!info->attrs[NL80211_ATTR_MLD_ADDR])
                        return -EINVAL;
                req.ap_mld_addr = nla_data(info->attrs[NL80211_ATTR_MLD_ADDR]);
+               if (!is_valid_ether_addr(req.ap_mld_addr))
+                       return -EINVAL;
        }
 
        req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
index 2e497cf..69b5087 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * Portions of this file
  * Copyright(c) 2016-2017 Intel Deutschland GmbH
- * Copyright (C) 2018, 2021-2022 Intel Corporation
+ * Copyright (C) 2018, 2021-2023 Intel Corporation
  */
 #ifndef __CFG80211_RDEV_OPS
 #define __CFG80211_RDEV_OPS
@@ -1441,8 +1441,8 @@ rdev_del_intf_link(struct cfg80211_registered_device *rdev,
                   unsigned int link_id)
 {
        trace_rdev_del_intf_link(&rdev->wiphy, wdev, link_id);
-       if (rdev->ops->add_intf_link)
-               rdev->ops->add_intf_link(&rdev->wiphy, wdev, link_id);
+       if (rdev->ops->del_intf_link)
+               rdev->ops->del_intf_link(&rdev->wiphy, wdev, link_id);
        trace_rdev_return_void(&rdev->wiphy);
 }
 
index 0d40d6a..26f11e4 100644 (file)
@@ -2404,11 +2404,8 @@ static bool reg_wdev_chan_valid(struct wiphy *wiphy, struct wireless_dev *wdev)
                case NL80211_IFTYPE_P2P_GO:
                case NL80211_IFTYPE_ADHOC:
                case NL80211_IFTYPE_MESH_POINT:
-                       wiphy_lock(wiphy);
                        ret = cfg80211_reg_can_beacon_relax(wiphy, &chandef,
                                                            iftype);
-                       wiphy_unlock(wiphy);
-
                        if (!ret)
                                return ret;
                        break;
@@ -2440,11 +2437,11 @@ static void reg_leave_invalid_chans(struct wiphy *wiphy)
        struct wireless_dev *wdev;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
 
-       ASSERT_RTNL();
-
+       wiphy_lock(wiphy);
        list_for_each_entry(wdev, &rdev->wiphy.wdev_list, list)
                if (!reg_wdev_chan_valid(wiphy, wdev))
                        cfg80211_leave(rdev, wdev);
+       wiphy_unlock(wiphy);
 }
 
 static void reg_check_chans_work(struct work_struct *work)
index 3bc0c30..9755ef2 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright 2007-2009 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
  * Copyright 2017      Intel Deutschland GmbH
- * Copyright (C) 2018-2022 Intel Corporation
+ * Copyright (C) 2018-2023 Intel Corporation
  */
 #include <linux/export.h>
 #include <linux/bitops.h>
@@ -2558,6 +2558,13 @@ void cfg80211_remove_links(struct wireless_dev *wdev)
 {
        unsigned int link_id;
 
+       /*
+        * links are controlled by upper layers (userspace/cfg)
+        * only for AP mode, so only remove them here for AP
+        */
+       if (wdev->iftype != NL80211_IFTYPE_AP)
+               return;
+
        wdev_lock(wdev);
        if (wdev->valid_links) {
                for_each_valid_link(wdev, link_id)
index 07efb38..f2940b2 100644 (file)
@@ -37,6 +37,7 @@ struct seq_oss_midi {
        struct snd_midi_event *coder;   /* MIDI event coder */
        struct seq_oss_devinfo *devinfo;        /* assigned OSSseq device */
        snd_use_lock_t use_lock;
+       struct mutex open_mutex;
 };
 
 
@@ -172,6 +173,7 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
        mdev->flags = pinfo->capability;
        mdev->opened = 0;
        snd_use_lock_init(&mdev->use_lock);
+       mutex_init(&mdev->open_mutex);
 
        /* copy and truncate the name of synth device */
        strscpy(mdev->name, pinfo->name, sizeof(mdev->name));
@@ -322,15 +324,17 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
        int perm;
        struct seq_oss_midi *mdev;
        struct snd_seq_port_subscribe subs;
+       int err;
 
        mdev = get_mididev(dp, dev);
        if (!mdev)
                return -ENODEV;
 
+       mutex_lock(&mdev->open_mutex);
        /* already used? */
        if (mdev->opened && mdev->devinfo != dp) {
-               snd_use_lock_free(&mdev->use_lock);
-               return -EBUSY;
+               err = -EBUSY;
+               goto unlock;
        }
 
        perm = 0;
@@ -340,14 +344,14 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
                perm |= PERM_READ;
        perm &= mdev->flags;
        if (perm == 0) {
-               snd_use_lock_free(&mdev->use_lock);
-               return -ENXIO;
+               err = -ENXIO;
+               goto unlock;
        }
 
        /* already opened? */
        if ((mdev->opened & perm) == perm) {
-               snd_use_lock_free(&mdev->use_lock);
-               return 0;
+               err = 0;
+               goto unlock;
        }
 
        perm &= ~mdev->opened;
@@ -372,13 +376,17 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
        }
 
        if (! mdev->opened) {
-               snd_use_lock_free(&mdev->use_lock);
-               return -ENXIO;
+               err = -ENXIO;
+               goto unlock;
        }
 
        mdev->devinfo = dp;
+       err = 0;
+
+ unlock:
+       mutex_unlock(&mdev->open_mutex);
        snd_use_lock_free(&mdev->use_lock);
-       return 0;
+       return err;
 }
 
 /*
@@ -393,10 +401,9 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
        mdev = get_mididev(dp, dev);
        if (!mdev)
                return -ENODEV;
-       if (! mdev->opened || mdev->devinfo != dp) {
-               snd_use_lock_free(&mdev->use_lock);
-               return 0;
-       }
+       mutex_lock(&mdev->open_mutex);
+       if (!mdev->opened || mdev->devinfo != dp)
+               goto unlock;
 
        memset(&subs, 0, sizeof(subs));
        if (mdev->opened & PERM_WRITE) {
@@ -415,6 +422,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
        mdev->opened = 0;
        mdev->devinfo = NULL;
 
+ unlock:
+       mutex_unlock(&mdev->open_mutex);
        snd_use_lock_free(&mdev->use_lock);
        return 0;
 }
index 230f65a..388db5f 100644 (file)
@@ -892,10 +892,10 @@ int snd_gf1_pcm_new(struct snd_gus_card *gus, int pcm_dev, int control_index)
                kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control1, gus);
        else
                kctl = snd_ctl_new1(&snd_gf1_pcm_volume_control, gus);
+       kctl->id.index = control_index;
        err = snd_ctl_add(card, kctl);
        if (err < 0)
                return err;
-       kctl->id.index = control_index;
 
        return 0;
 }
index 727db6d..6d25c12 100644 (file)
@@ -2688,20 +2688,20 @@ static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device)
                }
                if (cm->can_ac3_hw) {
                        kctl = snd_ctl_new1(&snd_cmipci_spdif_default, cm);
+                       kctl->id.device = pcm_spdif_device;
                        err = snd_ctl_add(card, kctl);
                        if (err < 0)
                                return err;
-                       kctl->id.device = pcm_spdif_device;
                        kctl = snd_ctl_new1(&snd_cmipci_spdif_mask, cm);
+                       kctl->id.device = pcm_spdif_device;
                        err = snd_ctl_add(card, kctl);
                        if (err < 0)
                                return err;
-                       kctl->id.device = pcm_spdif_device;
                        kctl = snd_ctl_new1(&snd_cmipci_spdif_stream, cm);
+                       kctl->id.device = pcm_spdif_device;
                        err = snd_ctl_add(card, kctl);
                        if (err < 0)
                                return err;
-                       kctl->id.device = pcm_spdif_device;
                }
                if (cm->chip_version <= 37) {
                        sw = snd_cmipci_old_mixer_switches;
index 9f79c0a..bd19f92 100644 (file)
@@ -2458,10 +2458,14 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
                   type == HDA_PCM_TYPE_HDMI) {
                /* suppose a single SPDIF device */
                for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) {
+                       struct snd_ctl_elem_id id;
+
                        kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0);
                        if (!kctl)
                                break;
-                       kctl->id.index = spdif_index;
+                       id = kctl->id;
+                       id.index = spdif_index;
+                       snd_ctl_rename_id(codec->card, &kctl->id, &id);
                }
                bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI;
        }
index 7b5f194..308ec70 100644 (file)
@@ -9500,7 +9500,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8b8a, "HP", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b8b, "HP", ALC236_FIXUP_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b8d, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
        SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
        SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
@@ -9547,6 +9547,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
@@ -9565,6 +9566,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
        SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
        SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
+       SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC245_FIXUP_CS35L41_SPI_2),
        SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
@@ -9588,6 +9594,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC225_FIXUP_HEADSET_JACK),
        SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
        SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
        SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -9636,6 +9643,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
@@ -9807,6 +9815,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        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),
        SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
+       SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC225_FIXUP_HEADSET_JACK),
        SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
 
 #if 0
@@ -11694,6 +11703,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
        SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
        SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", 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),
@@ -11715,6 +11725,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
        SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
        SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
        SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
@@ -11729,6 +11740,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
        SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
        SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
+       SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
 
 #if 0
        /* Below is a quirk table taken from the old code.
index 24b9782..0278493 100644 (file)
@@ -1899,11 +1899,12 @@ static int aureon_add_controls(struct snd_ice1712 *ice)
                else {
                        for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) {
                                struct snd_kcontrol *kctl;
-                               err = snd_ctl_add(ice->card, (kctl = snd_ctl_new1(&cs8415_controls[i], ice)));
-                               if (err < 0)
-                                       return err;
+                               kctl = snd_ctl_new1(&cs8415_controls[i], ice);
                                if (i > 1)
                                        kctl->id.device = ice->pcm->device;
+                               err = snd_ctl_add(ice->card, kctl);
+                               if (err < 0)
+                                       return err;
                        }
                }
        }
index a5241a2..3b0c3e7 100644 (file)
@@ -2371,22 +2371,26 @@ int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice)
 
        if (snd_BUG_ON(!ice->pcm_pro))
                return -EIO;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice));
+       kctl = snd_ctl_new1(&snd_ice1712_spdif_default, ice);
+       kctl->id.device = ice->pcm_pro->device;
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
+       kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice);
        kctl->id.device = ice->pcm_pro->device;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskc, ice));
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
+       kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice);
        kctl->id.device = ice->pcm_pro->device;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_maskp, ice));
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
+       kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice);
        kctl->id.device = ice->pcm_pro->device;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_ice1712_spdif_stream, ice));
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = ice->pcm_pro->device;
        ice->spdif.stream_ctl = kctl;
        return 0;
 }
index 6fab2ad..1dc776a 100644 (file)
@@ -2392,23 +2392,27 @@ static int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice)
        if (err < 0)
                return err;
 
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice));
+       kctl = snd_ctl_new1(&snd_vt1724_spdif_default, ice);
+       kctl->id.device = ice->pcm->device;
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
+       kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice);
        kctl->id.device = ice->pcm->device;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskc, ice));
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
+       kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice);
        kctl->id.device = ice->pcm->device;
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_maskp, ice));
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = ice->pcm->device;
 #if 0 /* use default only */
-       err = snd_ctl_add(ice->card, kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice));
+       kctl = snd_ctl_new1(&snd_vt1724_spdif_stream, ice);
+       kctl->id.device = ice->pcm->device;
+       err = snd_ctl_add(ice->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = ice->pcm->device;
        ice->spdif.stream_ctl = kctl;
 #endif
        return 0;
index 6971eec..6b8d869 100644 (file)
@@ -1822,20 +1822,20 @@ int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch)
        if (snd_BUG_ON(!chip->pcm_spdif))
                return -ENXIO;
        kctl = snd_ctl_new1(&snd_ymfpci_spdif_default, chip);
+       kctl->id.device = chip->pcm_spdif->device;
        err = snd_ctl_add(chip->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = chip->pcm_spdif->device;
        kctl = snd_ctl_new1(&snd_ymfpci_spdif_mask, chip);
+       kctl->id.device = chip->pcm_spdif->device;
        err = snd_ctl_add(chip->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = chip->pcm_spdif->device;
        kctl = snd_ctl_new1(&snd_ymfpci_spdif_stream, chip);
+       kctl->id.device = chip->pcm_spdif->device;
        err = snd_ctl_add(chip->card, kctl);
        if (err < 0)
                return err;
-       kctl->id.device = chip->pcm_spdif->device;
        chip->spdif_pcm_ctl = kctl;
 
        /* direct recording source */
index afddb9a..b1337b9 100644 (file)
@@ -211,8 +211,7 @@ static int create_acp63_platform_devs(struct pci_dev *pci, struct acp63_dev_data
        case ACP63_PDM_DEV_MASK:
                adata->pdm_dev_index  = 0;
                acp63_fill_platform_dev_info(&pdevinfo[0], parent, NULL, "acp_ps_pdm_dma",
-                                            0, adata->res, 1, &adata->acp_lock,
-                                            sizeof(adata->acp_lock));
+                                            0, adata->res, 1, NULL, 0);
                acp63_fill_platform_dev_info(&pdevinfo[1], parent, NULL, "dmic-codec",
                                             0, NULL, 0, NULL, 0);
                acp63_fill_platform_dev_info(&pdevinfo[2], parent, NULL, "acp_ps_mach",
index 46b9132..3a83dc1 100644 (file)
@@ -361,12 +361,12 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct pdm_dev_data *adata;
+       struct acp63_dev_data *acp_data;
+       struct device *parent;
        int status;
 
-       if (!pdev->dev.platform_data) {
-               dev_err(&pdev->dev, "platform_data not retrieved\n");
-               return -ENODEV;
-       }
+       parent = pdev->dev.parent;
+       acp_data = dev_get_drvdata(parent);
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n");
@@ -382,7 +382,7 @@ static int acp63_pdm_audio_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        adata->capture_stream = NULL;
-       adata->acp_lock = pdev->dev.platform_data;
+       adata->acp_lock = &acp_data->acp_lock;
        dev_set_drvdata(&pdev->dev, adata);
        status = devm_snd_soc_register_component(&pdev->dev,
                                                 &acp63_pdm_component,
index 4406a5d..246299a 100644 (file)
@@ -175,6 +175,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
                .driver_data = &acp6x_card,
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "21EF"),
+               }
+       },
+       {
+               .driver_data = &acp6x_card,
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "21EM"),
                }
        },
index d1677d7..e0d2b9b 100644 (file)
@@ -704,9 +704,6 @@ static int cs35l56_sdw_dai_hw_free(struct snd_pcm_substream *substream,
 static int cs35l56_sdw_dai_set_stream(struct snd_soc_dai *dai,
                                      void *sdw_stream, int direction)
 {
-       if (!sdw_stream)
-               return 0;
-
        snd_soc_dai_dma_data_set(dai, direction, sdw_stream);
 
        return 0;
index dcce06b..e6b84e2 100644 (file)
@@ -211,7 +211,7 @@ static int max98363_io_init(struct sdw_slave *slave)
 }
 
 #define MAX98363_RATES SNDRV_PCM_RATE_8000_192000
-#define MAX98363_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
+#define MAX98363_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
 
 static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream,
                                      struct snd_pcm_hw_params *params,
@@ -246,7 +246,7 @@ static int max98363_sdw_dai_hw_params(struct snd_pcm_substream *substream,
        stream_config.frame_rate = params_rate(params);
        stream_config.bps = snd_pcm_format_width(params_format(params));
        stream_config.direction = direction;
-       stream_config.ch_count = params_channels(params);
+       stream_config.ch_count = 1;
 
        if (stream_config.ch_count > runtime->hw.channels_max) {
                stream_config.ch_count = runtime->hw.channels_max;
index 4f19fd9..5a4db89 100644 (file)
@@ -1903,6 +1903,30 @@ static const struct dmi_system_id nau8824_quirk_table[] = {
                },
                .driver_data = (void *)(NAU8824_MONO_SPEAKER),
        },
+       {
+               /* Positivo CW14Q01P */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+                       DMI_MATCH(DMI_BOARD_NAME, "CW14Q01P"),
+               },
+               .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+       },
+       {
+               /* Positivo K1424G */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+                       DMI_MATCH(DMI_BOARD_NAME, "K1424G"),
+               },
+               .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+       },
+       {
+               /* Positivo N14ZP74G */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Positivo Tecnologia SA"),
+                       DMI_MATCH(DMI_BOARD_NAME, "N14ZP74G"),
+               },
+               .driver_data = (void *)(NAU8824_JD_ACTIVE_HIGH),
+       },
        {}
 };
 
index 402286d..9c10200 100644 (file)
@@ -1190,7 +1190,6 @@ static const struct regmap_config wcd938x_regmap_config = {
        .readable_reg = wcd938x_readable_register,
        .writeable_reg = wcd938x_writeable_register,
        .volatile_reg = wcd938x_volatile_register,
-       .can_multi_write = true,
 };
 
 static const struct sdw_slave_ops wcd9380_slave_ops = {
index f709231..97f6873 100644 (file)
@@ -645,7 +645,6 @@ static struct regmap_config wsa881x_regmap_config = {
        .readable_reg = wsa881x_readable_register,
        .reg_format_endian = REGMAP_ENDIAN_NATIVE,
        .val_format_endian = REGMAP_ENDIAN_NATIVE,
-       .can_multi_write = true,
 };
 
 enum {
index c609cb6..e80b531 100644 (file)
@@ -946,7 +946,6 @@ static struct regmap_config wsa883x_regmap_config = {
        .writeable_reg = wsa883x_writeable_register,
        .reg_format_endian = REGMAP_ENDIAN_NATIVE,
        .val_format_endian = REGMAP_ENDIAN_NATIVE,
-       .can_multi_write = true,
        .use_single_read = true,
 };
 
index abdaffb..e3105d4 100644 (file)
@@ -491,14 +491,21 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
        regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK,
                           FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
 
-       if (savediv == 1)
+       if (savediv == 1) {
                regmap_update_bits(sai->regmap, reg,
                                   FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
                                   FSL_SAI_CR2_BYP);
-       else
+               if (fsl_sai_dir_is_synced(sai, adir))
+                       regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+                                          FSL_SAI_CR2_BCI, FSL_SAI_CR2_BCI);
+               else
+                       regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
+                                          FSL_SAI_CR2_BCI, 0);
+       } else {
                regmap_update_bits(sai->regmap, reg,
                                   FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
                                   savediv / 2 - 1);
+       }
 
        if (sai->soc_data->max_register >= FSL_SAI_MCTL) {
                /* SAI is in master mode at this point, so enable MCLK */
index 197748a..a53c4f0 100644 (file)
 
 /* SAI Transmit and Receive Configuration 2 Register */
 #define FSL_SAI_CR2_SYNC       BIT(30)
+#define FSL_SAI_CR2_BCI                BIT(28)
 #define FSL_SAI_CR2_MSEL_MASK  (0x3 << 26)
 #define FSL_SAI_CR2_MSEL_BUS   0
 #define FSL_SAI_CR2_MSEL_MCLK1 BIT(26)
index 467edd9..e5ff61c 100644 (file)
@@ -314,7 +314,7 @@ int asoc_simple_startup(struct snd_pcm_substream *substream)
                }
                ret = snd_pcm_hw_constraint_minmax(substream->runtime, SNDRV_PCM_HW_PARAM_RATE,
                        fixed_rate, fixed_rate);
-               if (ret)
+               if (ret < 0)
                        goto codec_err;
        }
 
index 6f044cc..5a5e4ec 100644 (file)
@@ -416,6 +416,7 @@ static int __simple_for_each_link(struct asoc_simple_priv *priv,
 
                        if (ret < 0) {
                                of_node_put(codec);
+                               of_node_put(plat);
                                of_node_put(np);
                                goto error;
                        }
index 743d6a1..0fb9751 100644 (file)
@@ -418,13 +418,6 @@ int mt8188_afe_init_clock(struct mtk_base_afe *afe)
        return 0;
 }
 
-void mt8188_afe_deinit_clock(void *priv)
-{
-       struct mtk_base_afe *afe = priv;
-
-       mt8188_audsys_clk_unregister(afe);
-}
-
 int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
 {
        int ret;
index 084fdfb..a4203a8 100644 (file)
@@ -100,7 +100,6 @@ int mt8188_afe_get_mclk_source_clk_id(int sel);
 int mt8188_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
 int mt8188_afe_get_default_mclk_source_by_rate(int rate);
 int mt8188_afe_init_clock(struct mtk_base_afe *afe);
-void mt8188_afe_deinit_clock(void *priv);
 int mt8188_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
 void mt8188_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
 int mt8188_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk,
index e5f9373..bcf7025 100644 (file)
@@ -3185,10 +3185,6 @@ static int mt8188_afe_pcm_dev_probe(struct platform_device *pdev)
        if (ret)
                return dev_err_probe(dev, ret, "init clock error");
 
-       ret = devm_add_action_or_reset(dev, mt8188_afe_deinit_clock, (void *)afe);
-       if (ret)
-               return ret;
-
        spin_lock_init(&afe_priv->afe_ctrl_lock);
 
        mutex_init(&afe->irq_alloc_lock);
index be1c53b..c796ad8 100644 (file)
@@ -138,6 +138,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
        GATE_AUD6(CLK_AUD_GASRC11, "aud_gasrc11", "top_asm_h", 11),
 };
 
+static void mt8188_audsys_clk_unregister(void *data)
+{
+       struct mtk_base_afe *afe = data;
+       struct mt8188_afe_private *afe_priv = afe->platform_priv;
+       struct clk *clk;
+       struct clk_lookup *cl;
+       int i;
+
+       if (!afe_priv)
+               return;
+
+       for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+               cl = afe_priv->lookup[i];
+               if (!cl)
+                       continue;
+
+               clk = cl->clk;
+               clk_unregister_gate(clk);
+
+               clkdev_drop(cl);
+       }
+}
+
 int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
 {
        struct mt8188_afe_private *afe_priv = afe->platform_priv;
@@ -179,27 +202,5 @@ int mt8188_audsys_clk_register(struct mtk_base_afe *afe)
                afe_priv->lookup[i] = cl;
        }
 
-       return 0;
-}
-
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
-       struct mt8188_afe_private *afe_priv = afe->platform_priv;
-       struct clk *clk;
-       struct clk_lookup *cl;
-       int i;
-
-       if (!afe_priv)
-               return;
-
-       for (i = 0; i < CLK_AUD_NR_CLK; i++) {
-               cl = afe_priv->lookup[i];
-               if (!cl)
-                       continue;
-
-               clk = cl->clk;
-               clk_unregister_gate(clk);
-
-               clkdev_drop(cl);
-       }
+       return devm_add_action_or_reset(afe->dev, mt8188_audsys_clk_unregister, afe);
 }
index 6c5f463..45b0948 100644 (file)
@@ -10,6 +10,5 @@
 #define _MT8188_AUDSYS_CLK_H_
 
 int mt8188_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8188_audsys_clk_unregister(struct mtk_base_afe *afe);
 
 #endif
index 9ca2cb8..f35318a 100644 (file)
@@ -410,11 +410,6 @@ int mt8195_afe_init_clock(struct mtk_base_afe *afe)
        return 0;
 }
 
-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe)
-{
-       mt8195_audsys_clk_unregister(afe);
-}
-
 int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk)
 {
        int ret;
index 40663e3..a08c0ee 100644 (file)
@@ -101,7 +101,6 @@ int mt8195_afe_get_mclk_source_clk_id(int sel);
 int mt8195_afe_get_mclk_source_rate(struct mtk_base_afe *afe, int apll);
 int mt8195_afe_get_default_mclk_source_by_rate(int rate);
 int mt8195_afe_init_clock(struct mtk_base_afe *afe);
-void mt8195_afe_deinit_clock(struct mtk_base_afe *afe);
 int mt8195_afe_enable_clk(struct mtk_base_afe *afe, struct clk *clk);
 void mt8195_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk);
 int mt8195_afe_prepare_clk(struct mtk_base_afe *afe, struct clk *clk);
index 9e45efe..03dabc0 100644 (file)
@@ -3255,15 +3255,11 @@ err_pm_put:
 
 static void mt8195_afe_pcm_dev_remove(struct platform_device *pdev)
 {
-       struct mtk_base_afe *afe = platform_get_drvdata(pdev);
-
        snd_soc_unregister_component(&pdev->dev);
 
        pm_runtime_disable(&pdev->dev);
        if (!pm_runtime_status_suspended(&pdev->dev))
                mt8195_afe_runtime_suspend(&pdev->dev);
-
-       mt8195_afe_deinit_clock(afe);
 }
 
 static const struct of_device_id mt8195_afe_pcm_dt_match[] = {
index e0670e0..38594bc 100644 (file)
@@ -148,6 +148,29 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = {
        GATE_AUD6(CLK_AUD_GASRC19, "aud_gasrc19", "top_asm_h", 19),
 };
 
+static void mt8195_audsys_clk_unregister(void *data)
+{
+       struct mtk_base_afe *afe = data;
+       struct mt8195_afe_private *afe_priv = afe->platform_priv;
+       struct clk *clk;
+       struct clk_lookup *cl;
+       int i;
+
+       if (!afe_priv)
+               return;
+
+       for (i = 0; i < CLK_AUD_NR_CLK; i++) {
+               cl = afe_priv->lookup[i];
+               if (!cl)
+                       continue;
+
+               clk = cl->clk;
+               clk_unregister_gate(clk);
+
+               clkdev_drop(cl);
+       }
+}
+
 int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
 {
        struct mt8195_afe_private *afe_priv = afe->platform_priv;
@@ -188,27 +211,5 @@ int mt8195_audsys_clk_register(struct mtk_base_afe *afe)
                afe_priv->lookup[i] = cl;
        }
 
-       return 0;
-}
-
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe)
-{
-       struct mt8195_afe_private *afe_priv = afe->platform_priv;
-       struct clk *clk;
-       struct clk_lookup *cl;
-       int i;
-
-       if (!afe_priv)
-               return;
-
-       for (i = 0; i < CLK_AUD_NR_CLK; i++) {
-               cl = afe_priv->lookup[i];
-               if (!cl)
-                       continue;
-
-               clk = cl->clk;
-               clk_unregister_gate(clk);
-
-               clkdev_drop(cl);
-       }
+       return devm_add_action_or_reset(afe->dev, mt8195_audsys_clk_unregister, afe);
 }
index 239d310..69db2dd 100644 (file)
@@ -10,6 +10,5 @@
 #define _MT8195_AUDSYS_CLK_H_
 
 int mt8195_audsys_clk_register(struct mtk_base_afe *afe);
-void mt8195_audsys_clk_unregister(struct mtk_base_afe *afe);
 
 #endif
index 468c8e7..0b69ceb 100644 (file)
@@ -117,6 +117,9 @@ int tegra_pcm_open(struct snd_soc_component *component,
                return ret;
        }
 
+       /* Set wait time to 500ms by default */
+       substream->wait_time = 500;
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(tegra_pcm_open);
index eec5232..08bf535 100644 (file)
@@ -650,6 +650,10 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
                goto unlock;
        }
 
+       ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0);
+       if (ret < 0)
+               goto unlock;
+
  again:
        if (subs->sync_endpoint) {
                ret = snd_usb_endpoint_prepare(chip, subs->sync_endpoint);
index 3ecd1ba..6cf55b7 100644 (file)
@@ -2191,6 +2191,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
                   QUIRK_FLAG_DSD_RAW),
        VENDOR_FLG(0x2ab6, /* T+A devices */
                   QUIRK_FLAG_DSD_RAW),
+       VENDOR_FLG(0x3336, /* HEM devices */
+                  QUIRK_FLAG_DSD_RAW),
        VENDOR_FLG(0x3353, /* Khadas devices */
                   QUIRK_FLAG_DSD_RAW),
        VENDOR_FLG(0x3842, /* EVGA */
index 1bb11a6..c994ff5 100644 (file)
@@ -1035,6 +1035,7 @@ enum bpf_attach_type {
        BPF_TRACE_KPROBE_MULTI,
        BPF_LSM_CGROUP,
        BPF_STRUCT_OPS,
+       BPF_NETFILTER,
        __MAX_BPF_ATTACH_TYPE
 };
 
index ad1ec89..a27f6e9 100644 (file)
@@ -117,6 +117,7 @@ static const char * const attach_type_name[] = {
        [BPF_PERF_EVENT]                = "perf_event",
        [BPF_TRACE_KPROBE_MULTI]        = "trace_kprobe_multi",
        [BPF_STRUCT_OPS]                = "struct_ops",
+       [BPF_NETFILTER]                 = "netfilter",
 };
 
 static const char * const link_type_name[] = {
@@ -8712,7 +8713,7 @@ static const struct bpf_sec_def section_defs[] = {
        SEC_DEF("struct_ops+",          STRUCT_OPS, 0, SEC_NONE),
        SEC_DEF("struct_ops.s+",        STRUCT_OPS, 0, SEC_SLEEPABLE),
        SEC_DEF("sk_lookup",            SK_LOOKUP, BPF_SK_LOOKUP, SEC_ATTACHABLE),
-       SEC_DEF("netfilter",            NETFILTER, 0, SEC_NONE),
+       SEC_DEF("netfilter",            NETFILTER, BPF_NETFILTER, SEC_NONE),
 };
 
 static size_t custom_sec_def_cnt;
index 6065f40..b7d4431 100644 (file)
@@ -180,7 +180,9 @@ static int probe_prog_load(enum bpf_prog_type prog_type,
        case BPF_PROG_TYPE_SK_REUSEPORT:
        case BPF_PROG_TYPE_FLOW_DISSECTOR:
        case BPF_PROG_TYPE_CGROUP_SYSCTL:
+               break;
        case BPF_PROG_TYPE_NETFILTER:
+               opts.expected_attach_type = BPF_NETFILTER;
                break;
        default:
                return -EOPNOTSUPP;
index caf32a9..7527f73 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
-CFLAGS += -I. -I../../include -g -Og -Wall -D_LGPL_SOURCE -fsanitize=address \
-         -fsanitize=undefined
+CFLAGS += -I. -I../../include -I../../../lib -g -Og -Wall \
+         -D_LGPL_SOURCE -fsanitize=address -fsanitize=undefined
 LDFLAGS += -fsanitize=address -fsanitize=undefined
 LDLIBS+= -lpthread -lurcu
 TARGETS = main idr-test multiorder xarray maple
@@ -49,6 +49,7 @@ $(OFILES): Makefile *.h */*.h generated/map-shift.h generated/bit-length.h \
        ../../../include/linux/xarray.h \
        ../../../include/linux/maple_tree.h \
        ../../../include/linux/radix-tree.h \
+       ../../../lib/radix-tree.h \
        ../../../include/linux/idr.h
 
 radix-tree.c: ../../../lib/radix-tree.c
index 3e390fe..b7eef32 100644 (file)
@@ -381,7 +381,7 @@ __format:
                goto __close;
        }
        if (rrate != rate) {
-               snprintf(msg, sizeof(msg), "rate mismatch %ld != %ld", rate, rrate);
+               snprintf(msg, sizeof(msg), "rate mismatch %ld != %d", rate, rrate);
                goto __close;
        }
        rperiod_size = period_size;
@@ -447,24 +447,24 @@ __format:
                        frames = snd_pcm_writei(handle, samples, rate);
                        if (frames < 0) {
                                snprintf(msg, sizeof(msg),
-                                        "Write failed: expected %d, wrote %li", rate, frames);
+                                        "Write failed: expected %ld, wrote %li", rate, frames);
                                goto __close;
                        }
                        if (frames < rate) {
                                snprintf(msg, sizeof(msg),
-                                        "expected %d, wrote %li", rate, frames);
+                                        "expected %ld, wrote %li", rate, frames);
                                goto __close;
                        }
                } else {
                        frames = snd_pcm_readi(handle, samples, rate);
                        if (frames < 0) {
                                snprintf(msg, sizeof(msg),
-                                        "expected %d, wrote %li", rate, frames);
+                                        "expected %ld, wrote %li", rate, frames);
                                goto __close;
                        }
                        if (frames < rate) {
                                snprintf(msg, sizeof(msg),
-                                        "expected %d, wrote %li", rate, frames);
+                                        "expected %ld, wrote %li", rate, frames);
                                goto __close;
                        }
                }
diff --git a/tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c b/tools/testing/selftests/bpf/prog_tests/inner_array_lookup.c
new file mode 100644 (file)
index 0000000..9ab4cd1
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <test_progs.h>
+
+#include "inner_array_lookup.skel.h"
+
+void test_inner_array_lookup(void)
+{
+       int map1_fd, err;
+       int key = 3;
+       int val = 1;
+       struct inner_array_lookup *skel;
+
+       skel = inner_array_lookup__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "open_load_skeleton"))
+               return;
+
+       err = inner_array_lookup__attach(skel);
+       if (!ASSERT_OK(err, "skeleton_attach"))
+               goto cleanup;
+
+       map1_fd = bpf_map__fd(skel->maps.inner_map1);
+       bpf_map_update_elem(map1_fd, &key, &val, 0);
+
+       /* Probe should have set the element at index 3 to 2 */
+       bpf_map_lookup_elem(map1_fd, &key, &val);
+       ASSERT_EQ(val, 2, "value_is_2");
+
+cleanup:
+       inner_array_lookup__destroy(skel);
+}
index 4512dd8..05d0e07 100644 (file)
@@ -209,7 +209,7 @@ static int getsetsockopt(void)
                        err, errno);
                goto err;
        }
-       ASSERT_EQ(optlen, 4, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
+       ASSERT_EQ(optlen, 8, "Unexpected NETLINK_LIST_MEMBERSHIPS value");
 
        free(big_buf);
        close(fd);
diff --git a/tools/testing/selftests/bpf/progs/inner_array_lookup.c b/tools/testing/selftests/bpf/progs/inner_array_lookup.c
new file mode 100644 (file)
index 0000000..c2c8f2f
--- /dev/null
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+struct inner_map {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __uint(max_entries, 5);
+       __type(key, int);
+       __type(value, int);
+} inner_map1 SEC(".maps");
+
+struct outer_map {
+       __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
+       __uint(max_entries, 3);
+       __type(key, int);
+       __array(values, struct inner_map);
+} outer_map1 SEC(".maps") = {
+       .values = {
+               [2] = &inner_map1,
+       },
+};
+
+SEC("raw_tp/sys_enter")
+int handle__sys_enter(void *ctx)
+{
+       int outer_key = 2, inner_key = 3;
+       int *val;
+       void *map;
+
+       map = bpf_map_lookup_elem(&outer_map1, &outer_key);
+       if (!map)
+               return 1;
+
+       val = bpf_map_lookup_elem(map, &inner_key);
+       if (!val)
+               return 1;
+
+       if (*val == 1)
+               *val = 2;
+
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";
index 80f06aa..f27a733 100644 (file)
@@ -8,8 +8,10 @@ diag_uid
 fin_ack_lat
 gro
 hwtstamp_config
+io_uring_zerocopy_tx
 ioam6_parser
 ip_defrag
+ip_local_port_range
 ipsec
 ipv6_flowlabel
 ipv6_flowlabel_mgr
@@ -26,6 +28,7 @@ reuseport_bpf_cpu
 reuseport_bpf_numa
 reuseport_dualstack
 rxtimestamp
+sctp_hello
 sk_bind_sendto_listen
 sk_connect_zero_addr
 socket
index 432fe84..48584a5 100755 (executable)
@@ -84,8 +84,9 @@ h2_destroy()
 
 router_rp1_200_create()
 {
-       ip link add name $rp1.200 up \
-               link $rp1 addrgenmode eui64 type vlan id 200
+       ip link add name $rp1.200 link $rp1 type vlan id 200
+       ip link set dev $rp1.200 addrgenmode eui64
+       ip link set dev $rp1.200 up
        ip address add dev $rp1.200 192.0.2.2/28
        ip address add dev $rp1.200 2001:db8:1::2/64
        ip stats set dev $rp1.200 l3_stats on
@@ -256,9 +257,11 @@ reapply_config()
 
        router_rp1_200_destroy
 
-       ip link add name $rp1.200 link $rp1 addrgenmode none type vlan id 200
+       ip link add name $rp1.200 link $rp1 type vlan id 200
+       ip link set dev $rp1.200 addrgenmode none
        ip stats set dev $rp1.200 l3_stats on
-       ip link set dev $rp1.200 up addrgenmode eui64
+       ip link set dev $rp1.200 addrgenmode eui64
+       ip link set dev $rp1.200 up
        ip address add dev $rp1.200 192.0.2.2/28
        ip address add dev $rp1.200 2001:db8:1::2/64
 }
index 38021a0..6032f9b 100644 (file)
@@ -1,3 +1,4 @@
+CONFIG_KALLSYMS=y
 CONFIG_MPTCP=y
 CONFIG_IPV6=y
 CONFIG_MPTCP_IPV6=y
index 4eacdb1..fa9e09a 100755 (executable)
@@ -55,16 +55,20 @@ __chk_nr()
 {
        local command="$1"
        local expected=$2
-       local msg nr
+       local msg="$3"
+       local skip="${4:-SKIP}"
+       local nr
 
-       shift 2
-       msg=$*
        nr=$(eval $command)
 
        printf "%-50s" "$msg"
        if [ $nr != $expected ]; then
-               echo "[ fail ] expected $expected found $nr"
-               ret=$test_cnt
+               if [ $nr = "$skip" ] && ! mptcp_lib_expect_all_features; then
+                       echo "[ skip ] Feature probably not supported"
+               else
+                       echo "[ fail ] expected $expected found $nr"
+                       ret=$test_cnt
+               fi
        else
                echo "[  ok  ]"
        fi
@@ -76,12 +80,12 @@ __chk_msk_nr()
        local condition=$1
        shift 1
 
-       __chk_nr "ss -inmHMN $ns | $condition" $*
+       __chk_nr "ss -inmHMN $ns | $condition" "$@"
 }
 
 chk_msk_nr()
 {
-       __chk_msk_nr "grep -c token:" $*
+       __chk_msk_nr "grep -c token:" "$@"
 }
 
 wait_msk_nr()
@@ -119,37 +123,26 @@ wait_msk_nr()
 
 chk_msk_fallback_nr()
 {
-               __chk_msk_nr "grep -c fallback" $*
+       __chk_msk_nr "grep -c fallback" "$@"
 }
 
 chk_msk_remote_key_nr()
 {
-               __chk_msk_nr "grep -c remote_key" $*
+       __chk_msk_nr "grep -c remote_key" "$@"
 }
 
 __chk_listen()
 {
        local filter="$1"
        local expected=$2
+       local msg="$3"
 
-       shift 2
-       msg=$*
-
-       nr=$(ss -N $ns -Ml "$filter" | grep -c LISTEN)
-       printf "%-50s" "$msg"
-
-       if [ $nr != $expected ]; then
-               echo "[ fail ] expected $expected found $nr"
-               ret=$test_cnt
-       else
-               echo "[  ok  ]"
-       fi
+       __chk_nr "ss -N $ns -Ml '$filter' | grep -c LISTEN" "$expected" "$msg" 0
 }
 
 chk_msk_listen()
 {
        lport=$1
-       local msg="check for listen socket"
 
        # destination port search should always return empty list
        __chk_listen "dport $lport" 0 "listen match for dport $lport"
@@ -167,10 +160,9 @@ chk_msk_listen()
 chk_msk_inuse()
 {
        local expected=$1
+       local msg="$2"
        local listen_nr
 
-       shift 1
-
        listen_nr=$(ss -N "${ns}" -Ml | grep -c LISTEN)
        expected=$((expected + listen_nr))
 
@@ -181,7 +173,7 @@ chk_msk_inuse()
                sleep 0.1
        done
 
-       __chk_nr get_msk_inuse $expected $*
+       __chk_nr get_msk_inuse $expected "$msg" 0
 }
 
 # $1: ns, $2: port
index c1f7bac..773dd77 100755 (executable)
@@ -144,6 +144,7 @@ cleanup()
 }
 
 mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
 
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
@@ -695,6 +696,15 @@ run_test_transparent()
                return 0
        fi
 
+       # IP(V6)_TRANSPARENT has been added after TOS support which came with
+       # the required infrastructure in MPTCP sockopt code. To support TOS, the
+       # following function has been exported (T). Not great but better than
+       # checking for a specific kernel version.
+       if ! mptcp_lib_kallsyms_has "T __ip_sock_set_tos$"; then
+               echo "INFO: ${msg} not supported by the kernel: SKIP"
+               return
+       fi
+
 ip netns exec "$listener_ns" nft -f /dev/stdin <<"EOF"
 flush ruleset
 table inet mangle {
@@ -767,6 +777,11 @@ run_tests_peekmode()
 
 run_tests_mptfo()
 {
+       if ! mptcp_lib_kallsyms_has "mptcp_fastopen_"; then
+               echo "INFO: TFO not supported by the kernel: SKIP"
+               return
+       fi
+
        echo "INFO: with MPTFO start"
        ip netns exec "$ns1" sysctl -q net.ipv4.tcp_fastopen=2
        ip netns exec "$ns2" sysctl -q net.ipv4.tcp_fastopen=1
@@ -787,6 +802,11 @@ run_tests_disconnect()
        local old_cin=$cin
        local old_sin=$sin
 
+       if ! mptcp_lib_kallsyms_has "mptcp_pm_data_reset$"; then
+               echo "INFO: Full disconnect not supported: SKIP"
+               return
+       fi
+
        cat $cin $cin $cin > "$cin".disconnect
 
        # force do_transfer to cope with the multiple tranmissions
index 96f6317..0ae8caf 100755 (executable)
@@ -25,6 +25,8 @@ capout=""
 ns1=""
 ns2=""
 ksft_skip=4
+iptables="iptables"
+ip6tables="ip6tables"
 timeout_poll=30
 timeout_test=$((timeout_poll * 2 + 1))
 capture=0
@@ -82,7 +84,7 @@ init_partial()
                ip netns add $netns || exit $ksft_skip
                ip -net $netns link set lo up
                ip netns exec $netns sysctl -q net.mptcp.enabled=1
-               ip netns exec $netns sysctl -q net.mptcp.pm_type=0
+               ip netns exec $netns sysctl -q net.mptcp.pm_type=0 2>/dev/null || true
                ip netns exec $netns sysctl -q net.ipv4.conf.all.rp_filter=0
                ip netns exec $netns sysctl -q net.ipv4.conf.default.rp_filter=0
                if [ $checksum -eq 1 ]; then
@@ -140,13 +142,18 @@ cleanup_partial()
 check_tools()
 {
        mptcp_lib_check_mptcp
+       mptcp_lib_check_kallsyms
 
        if ! ip -Version &> /dev/null; then
                echo "SKIP: Could not run test without ip tool"
                exit $ksft_skip
        fi
 
-       if ! iptables -V &> /dev/null; then
+       # Use the legacy version if available to support old kernel versions
+       if iptables-legacy -V &> /dev/null; then
+               iptables="iptables-legacy"
+               ip6tables="ip6tables-legacy"
+       elif ! iptables -V &> /dev/null; then
                echo "SKIP: Could not run all tests without iptables tool"
                exit $ksft_skip
        fi
@@ -185,6 +192,32 @@ cleanup()
        cleanup_partial
 }
 
+# $1: msg
+print_title()
+{
+       printf "%03u %-36s %s" "${TEST_COUNT}" "${TEST_NAME}" "${1}"
+}
+
+# [ $1: fail msg ]
+mark_as_skipped()
+{
+       local msg="${1:-"Feature not supported"}"
+
+       mptcp_lib_fail_if_expected_feature "${msg}"
+
+       print_title "[ skip ] ${msg}"
+       printf "\n"
+}
+
+# $@: condition
+continue_if()
+{
+       if ! "${@}"; then
+               mark_as_skipped
+               return 1
+       fi
+}
+
 skip_test()
 {
        if [ "${#only_tests_ids[@]}" -eq 0 ] && [ "${#only_tests_names[@]}" -eq 0 ]; then
@@ -228,6 +261,19 @@ reset()
        return 0
 }
 
+# $1: test name ; $2: counter to check
+reset_check_counter()
+{
+       reset "${1}" || return 1
+
+       local counter="${2}"
+
+       if ! nstat -asz "${counter}" | grep -wq "${counter}"; then
+               mark_as_skipped "counter '${counter}' is not available"
+               return 1
+       fi
+}
+
 # $1: test name
 reset_with_cookies()
 {
@@ -247,17 +293,21 @@ reset_with_add_addr_timeout()
 
        reset "${1}" || return 1
 
-       tables="iptables"
+       tables="${iptables}"
        if [ $ip -eq 6 ]; then
-               tables="ip6tables"
+               tables="${ip6tables}"
        fi
 
        ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
-       ip netns exec $ns2 $tables -A OUTPUT -p tcp \
-               -m tcp --tcp-option 30 \
-               -m bpf --bytecode \
-               "$CBPF_MPTCP_SUBOPTION_ADD_ADDR" \
-               -j DROP
+
+       if ! ip netns exec $ns2 $tables -A OUTPUT -p tcp \
+                       -m tcp --tcp-option 30 \
+                       -m bpf --bytecode \
+                       "$CBPF_MPTCP_SUBOPTION_ADD_ADDR" \
+                       -j DROP; then
+               mark_as_skipped "unable to set the 'add addr' rule"
+               return 1
+       fi
 }
 
 # $1: test name
@@ -301,22 +351,17 @@ reset_with_allow_join_id0()
 #     tc action pedit offset 162 out of bounds
 #
 # Netfilter is used to mark packets with enough data.
-reset_with_fail()
+setup_fail_rules()
 {
-       reset "${1}" || return 1
-
-       ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=1
-       ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=1
-
        check_invert=1
        validate_checksum=1
-       local i="$2"
-       local ip="${3:-4}"
+       local i="$1"
+       local ip="${2:-4}"
        local tables
 
-       tables="iptables"
+       tables="${iptables}"
        if [ $ip -eq 6 ]; then
-               tables="ip6tables"
+               tables="${ip6tables}"
        fi
 
        ip netns exec $ns2 $tables \
@@ -326,15 +371,32 @@ reset_with_fail()
                -p tcp \
                -m length --length 150:9999 \
                -m statistic --mode nth --packet 1 --every 99999 \
-               -j MARK --set-mark 42 || exit 1
+               -j MARK --set-mark 42 || return ${ksft_skip}
 
-       tc -n $ns2 qdisc add dev ns2eth$i clsact || exit 1
+       tc -n $ns2 qdisc add dev ns2eth$i clsact || return ${ksft_skip}
        tc -n $ns2 filter add dev ns2eth$i egress \
                protocol ip prio 1000 \
                handle 42 fw \
                action pedit munge offset 148 u8 invert \
                pipe csum tcp \
-               index 100 || exit 1
+               index 100 || return ${ksft_skip}
+}
+
+reset_with_fail()
+{
+       reset_check_counter "${1}" "MPTcpExtInfiniteMapTx" || return 1
+       shift
+
+       ip netns exec $ns1 sysctl -q net.mptcp.checksum_enabled=1
+       ip netns exec $ns2 sysctl -q net.mptcp.checksum_enabled=1
+
+       local rc=0
+       setup_fail_rules "${@}" || rc=$?
+
+       if [ ${rc} -eq ${ksft_skip} ]; then
+               mark_as_skipped "unable to set the 'fail' rules"
+               return 1
+       fi
 }
 
 reset_with_events()
@@ -349,6 +411,25 @@ reset_with_events()
        evts_ns2_pid=$!
 }
 
+reset_with_tcp_filter()
+{
+       reset "${1}" || return 1
+       shift
+
+       local ns="${!1}"
+       local src="${2}"
+       local target="${3}"
+
+       if ! ip netns exec "${ns}" ${iptables} \
+                       -A INPUT \
+                       -s "${src}" \
+                       -p tcp \
+                       -j "${target}"; then
+               mark_as_skipped "unable to set the filter rules"
+               return 1
+       fi
+}
+
 fail_test()
 {
        ret=1
@@ -467,11 +548,25 @@ wait_local_port_listen()
        done
 }
 
-rm_addr_count()
+# $1: ns ; $2: counter
+get_counter()
 {
-       local ns=${1}
+       local ns="${1}"
+       local counter="${2}"
+       local count
 
-       ip netns exec ${ns} nstat -as | grep MPTcpExtRmAddr | awk '{print $2}'
+       count=$(ip netns exec ${ns} nstat -asz "${counter}" | awk 'NR==1 {next} {print $2}')
+       if [ -z "${count}" ]; then
+               mptcp_lib_fail_if_expected_feature "${counter} counter"
+               return 1
+       fi
+
+       echo "${count}"
+}
+
+rm_addr_count()
+{
+       get_counter "${1}" "MPTcpExtRmAddr"
 }
 
 # $1: ns, $2: old rm_addr counter in $ns
@@ -494,11 +589,11 @@ wait_mpj()
        local ns="${1}"
        local cnt old_cnt
 
-       old_cnt=$(ip netns exec ${ns} nstat -as | grep MPJoinAckRx | awk '{print $2}')
+       old_cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx")
 
        local i
        for i in $(seq 10); do
-               cnt=$(ip netns exec ${ns} nstat -as | grep MPJoinAckRx | awk '{print $2}')
+               cnt=$(get_counter ${ns} "MPTcpExtMPJoinAckRx")
                [ "$cnt" = "${old_cnt}" ] || break
                sleep 0.1
        done
@@ -698,15 +793,6 @@ pm_nl_check_endpoint()
        fi
 }
 
-filter_tcp_from()
-{
-       local ns="${1}"
-       local src="${2}"
-       local target="${3}"
-
-       ip netns exec "${ns}" iptables -A INPUT -s "${src}" -p tcp -j "${target}"
-}
-
 do_transfer()
 {
        local listener_ns="$1"
@@ -862,7 +948,15 @@ do_transfer()
                                     sed -n 's/.*\(token:\)\([[:digit:]]*\).*$/\2/p;q')
                                ip netns exec ${listener_ns} ./pm_nl_ctl ann $addr token $tk id $id
                                sleep 1
+                               sp=$(grep "type:10" "$evts_ns1" |
+                                    sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+                               da=$(grep "type:10" "$evts_ns1" |
+                                    sed -n 's/.*\(daddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
+                               dp=$(grep "type:10" "$evts_ns1" |
+                                    sed -n 's/.*\(dport:\)\([[:digit:]]*\).*$/\2/p;q')
                                ip netns exec ${listener_ns} ./pm_nl_ctl rem token $tk id $id
+                               ip netns exec ${listener_ns} ./pm_nl_ctl dsf lip "::ffff:$addr" \
+                                                       lport $sp rip $da rport $dp token $tk
                        fi
 
                        counter=$((counter + 1))
@@ -928,6 +1022,7 @@ do_transfer()
                                sleep 1
                                sp=$(grep "type:10" "$evts_ns2" |
                                     sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+                               ip netns exec ${connector_ns} ./pm_nl_ctl rem token $tk id $id
                                ip netns exec ${connector_ns} ./pm_nl_ctl dsf lip $addr lport $sp \
                                                                        rip $da rport $dp token $tk
                        fi
@@ -1148,12 +1243,13 @@ chk_csum_nr()
        fi
 
        printf "%-${nr_blank}s %s" " " "sum"
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}')
-       [ -z "$count" ] && count=0
+       count=$(get_counter ${ns1} "MPTcpExtDataCsumErr")
        if [ "$count" != "$csum_ns1" ]; then
                extra_msg="$extra_msg ns1=$count"
        fi
-       if { [ "$count" != $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 0 ]; } ||
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif { [ "$count" != $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 0 ]; } ||
           { [ "$count" -lt $csum_ns1 ] && [ $allow_multi_errors_ns1 -eq 1 ]; }; then
                echo "[fail] got $count data checksum error[s] expected $csum_ns1"
                fail_test
@@ -1162,12 +1258,13 @@ chk_csum_nr()
                echo -n "[ ok ]"
        fi
        echo -n " - csum  "
-       count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtDataCsumErr | awk '{print $2}')
-       [ -z "$count" ] && count=0
+       count=$(get_counter ${ns2} "MPTcpExtDataCsumErr")
        if [ "$count" != "$csum_ns2" ]; then
                extra_msg="$extra_msg ns2=$count"
        fi
-       if { [ "$count" != $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 0 ]; } ||
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif { [ "$count" != $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 0 ]; } ||
           { [ "$count" -lt $csum_ns2 ] && [ $allow_multi_errors_ns2 -eq 1 ]; }; then
                echo "[fail] got $count data checksum error[s] expected $csum_ns2"
                fail_test
@@ -1209,12 +1306,13 @@ chk_fail_nr()
        fi
 
        printf "%-${nr_blank}s %s" " " "ftx"
-       count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFailTx | awk '{print $2}')
-       [ -z "$count" ] && count=0
+       count=$(get_counter ${ns_tx} "MPTcpExtMPFailTx")
        if [ "$count" != "$fail_tx" ]; then
                extra_msg="$extra_msg,tx=$count"
        fi
-       if { [ "$count" != "$fail_tx" ] && [ $allow_tx_lost -eq 0 ]; } ||
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif { [ "$count" != "$fail_tx" ] && [ $allow_tx_lost -eq 0 ]; } ||
           { [ "$count" -gt "$fail_tx" ] && [ $allow_tx_lost -eq 1 ]; }; then
                echo "[fail] got $count MP_FAIL[s] TX expected $fail_tx"
                fail_test
@@ -1224,12 +1322,13 @@ chk_fail_nr()
        fi
 
        echo -n " - failrx"
-       count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFailRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
+       count=$(get_counter ${ns_rx} "MPTcpExtMPFailRx")
        if [ "$count" != "$fail_rx" ]; then
                extra_msg="$extra_msg,rx=$count"
        fi
-       if { [ "$count" != "$fail_rx" ] && [ $allow_rx_lost -eq 0 ]; } ||
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif { [ "$count" != "$fail_rx" ] && [ $allow_rx_lost -eq 0 ]; } ||
           { [ "$count" -gt "$fail_rx" ] && [ $allow_rx_lost -eq 1 ]; }; then
                echo "[fail] got $count MP_FAIL[s] RX expected $fail_rx"
                fail_test
@@ -1261,10 +1360,11 @@ chk_fclose_nr()
        fi
 
        printf "%-${nr_blank}s %s" " " "ctx"
-       count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPFastcloseTx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       [ "$count" != "$fclose_tx" ] && extra_msg="$extra_msg,tx=$count"
-       if [ "$count" != "$fclose_tx" ]; then
+       count=$(get_counter ${ns_tx} "MPTcpExtMPFastcloseTx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$fclose_tx" ]; then
+               extra_msg="$extra_msg,tx=$count"
                echo "[fail] got $count MP_FASTCLOSE[s] TX expected $fclose_tx"
                fail_test
                dump_stats=1
@@ -1273,10 +1373,11 @@ chk_fclose_nr()
        fi
 
        echo -n " - fclzrx"
-       count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPFastcloseRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       [ "$count" != "$fclose_rx" ] && extra_msg="$extra_msg,rx=$count"
-       if [ "$count" != "$fclose_rx" ]; then
+       count=$(get_counter ${ns_rx} "MPTcpExtMPFastcloseRx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$fclose_rx" ]; then
+               extra_msg="$extra_msg,rx=$count"
                echo "[fail] got $count MP_FASTCLOSE[s] RX expected $fclose_rx"
                fail_test
                dump_stats=1
@@ -1307,9 +1408,10 @@ chk_rst_nr()
        fi
 
        printf "%-${nr_blank}s %s" " " "rtx"
-       count=$(ip netns exec $ns_tx nstat -as | grep MPTcpExtMPRstTx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ $count -lt $rst_tx ]; then
+       count=$(get_counter ${ns_tx} "MPTcpExtMPRstTx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ $count -lt $rst_tx ]; then
                echo "[fail] got $count MP_RST[s] TX expected $rst_tx"
                fail_test
                dump_stats=1
@@ -1318,9 +1420,10 @@ chk_rst_nr()
        fi
 
        echo -n " - rstrx "
-       count=$(ip netns exec $ns_rx nstat -as | grep MPTcpExtMPRstRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" -lt "$rst_rx" ]; then
+       count=$(get_counter ${ns_rx} "MPTcpExtMPRstRx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" -lt "$rst_rx" ]; then
                echo "[fail] got $count MP_RST[s] RX expected $rst_rx"
                fail_test
                dump_stats=1
@@ -1341,9 +1444,10 @@ chk_infi_nr()
        local dump_stats
 
        printf "%-${nr_blank}s %s" " " "itx"
-       count=$(ip netns exec $ns2 nstat -as | grep InfiniteMapTx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$infi_tx" ]; then
+       count=$(get_counter ${ns2} "MPTcpExtInfiniteMapTx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$infi_tx" ]; then
                echo "[fail] got $count infinite map[s] TX expected $infi_tx"
                fail_test
                dump_stats=1
@@ -1352,9 +1456,10 @@ chk_infi_nr()
        fi
 
        echo -n " - infirx"
-       count=$(ip netns exec $ns1 nstat -as | grep InfiniteMapRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$infi_rx" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtInfiniteMapRx")
+       if [ -z "$count" ]; then
+               echo "[skip]"
+       elif [ "$count" != "$infi_rx" ]; then
                echo "[fail] got $count infinite map[s] RX expected $infi_rx"
                fail_test
                dump_stats=1
@@ -1386,9 +1491,10 @@ chk_join_nr()
        fi
 
        printf "%03u %-36s %s" "${TEST_COUNT}" "${title}" "syn"
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinSynRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$syn_nr" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtMPJoinSynRx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$syn_nr" ]; then
                echo "[fail] got $count JOIN[s] syn expected $syn_nr"
                fail_test
                dump_stats=1
@@ -1398,9 +1504,10 @@ chk_join_nr()
 
        echo -n " - synack"
        with_cookie=$(ip netns exec $ns2 sysctl -n net.ipv4.tcp_syncookies)
-       count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinSynAckRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$syn_ack_nr" ]; then
+       count=$(get_counter ${ns2} "MPTcpExtMPJoinSynAckRx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$syn_ack_nr" ]; then
                # simult connections exceeding the limit with cookie enabled could go up to
                # synack validation as the conn limit can be enforced reliably only after
                # the subflow creation
@@ -1416,9 +1523,10 @@ chk_join_nr()
        fi
 
        echo -n " - ack"
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinAckRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$ack_nr" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtMPJoinAckRx")
+       if [ -z "$count" ]; then
+               echo "[skip]"
+       elif [ "$count" != "$ack_nr" ]; then
                echo "[fail] got $count JOIN[s] ack expected $ack_nr"
                fail_test
                dump_stats=1
@@ -1450,12 +1558,12 @@ chk_stale_nr()
        local recover_nr
 
        printf "%-${nr_blank}s %-18s" " " "stale"
-       stale_nr=$(ip netns exec $ns nstat -as | grep MPTcpExtSubflowStale | awk '{print $2}')
-       [ -z "$stale_nr" ] && stale_nr=0
-       recover_nr=$(ip netns exec $ns nstat -as | grep MPTcpExtSubflowRecover | awk '{print $2}')
-       [ -z "$recover_nr" ] && recover_nr=0
 
-       if [ $stale_nr -lt $stale_min ] ||
+       stale_nr=$(get_counter ${ns} "MPTcpExtSubflowStale")
+       recover_nr=$(get_counter ${ns} "MPTcpExtSubflowRecover")
+       if [ -z "$stale_nr" ] || [ -z "$recover_nr" ]; then
+               echo "[skip]"
+       elif [ $stale_nr -lt $stale_min ] ||
           { [ $stale_max -gt 0 ] && [ $stale_nr -gt $stale_max ]; } ||
           [ $((stale_nr - recover_nr)) -ne $stale_delta ]; then
                echo "[fail] got $stale_nr stale[s] $recover_nr recover[s], " \
@@ -1491,12 +1599,12 @@ chk_add_nr()
        timeout=$(ip netns exec $ns1 sysctl -n net.mptcp.add_addr_timeout)
 
        printf "%-${nr_blank}s %s" " " "add"
-       count=$(ip netns exec $ns2 nstat -as MPTcpExtAddAddr | grep MPTcpExtAddAddr | awk '{print $2}')
-       [ -z "$count" ] && count=0
-
+       count=$(get_counter ${ns2} "MPTcpExtAddAddr")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
        # if the test configured a short timeout tolerate greater then expected
        # add addrs options, due to retransmissions
-       if [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then
+       elif [ "$count" != "$add_nr" ] && { [ "$timeout" -gt 1 ] || [ "$count" -lt "$add_nr" ]; }; then
                echo "[fail] got $count ADD_ADDR[s] expected $add_nr"
                fail_test
                dump_stats=1
@@ -1505,9 +1613,10 @@ chk_add_nr()
        fi
 
        echo -n " - echo  "
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtEchoAdd | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$echo_nr" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtEchoAdd")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$echo_nr" ]; then
                echo "[fail] got $count ADD_ADDR echo[s] expected $echo_nr"
                fail_test
                dump_stats=1
@@ -1517,9 +1626,10 @@ chk_add_nr()
 
        if [ $port_nr -gt 0 ]; then
                echo -n " - pt "
-               count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtPortAdd | awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$port_nr" ]; then
+               count=$(get_counter ${ns2} "MPTcpExtPortAdd")
+               if [ -z "$count" ]; then
+                       echo "[skip]"
+               elif [ "$count" != "$port_nr" ]; then
                        echo "[fail] got $count ADD_ADDR[s] with a port-number expected $port_nr"
                        fail_test
                        dump_stats=1
@@ -1528,10 +1638,10 @@ chk_add_nr()
                fi
 
                printf "%-${nr_blank}s %s" " " "syn"
-               count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortSynRx |
-                       awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$syn_nr" ]; then
+               count=$(get_counter ${ns1} "MPTcpExtMPJoinPortSynRx")
+               if [ -z "$count" ]; then
+                       echo -n "[skip]"
+               elif [ "$count" != "$syn_nr" ]; then
                        echo "[fail] got $count JOIN[s] syn with a different \
                                port-number expected $syn_nr"
                        fail_test
@@ -1541,10 +1651,10 @@ chk_add_nr()
                fi
 
                echo -n " - synack"
-               count=$(ip netns exec $ns2 nstat -as | grep MPTcpExtMPJoinPortSynAckRx |
-                       awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$syn_ack_nr" ]; then
+               count=$(get_counter ${ns2} "MPTcpExtMPJoinPortSynAckRx")
+               if [ -z "$count" ]; then
+                       echo -n "[skip]"
+               elif [ "$count" != "$syn_ack_nr" ]; then
                        echo "[fail] got $count JOIN[s] synack with a different \
                                port-number expected $syn_ack_nr"
                        fail_test
@@ -1554,10 +1664,10 @@ chk_add_nr()
                fi
 
                echo -n " - ack"
-               count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPJoinPortAckRx |
-                       awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$ack_nr" ]; then
+               count=$(get_counter ${ns1} "MPTcpExtMPJoinPortAckRx")
+               if [ -z "$count" ]; then
+                       echo "[skip]"
+               elif [ "$count" != "$ack_nr" ]; then
                        echo "[fail] got $count JOIN[s] ack with a different \
                                port-number expected $ack_nr"
                        fail_test
@@ -1567,10 +1677,10 @@ chk_add_nr()
                fi
 
                printf "%-${nr_blank}s %s" " " "syn"
-               count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortSynRx |
-                       awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$mis_syn_nr" ]; then
+               count=$(get_counter ${ns1} "MPTcpExtMismatchPortSynRx")
+               if [ -z "$count" ]; then
+                       echo -n "[skip]"
+               elif [ "$count" != "$mis_syn_nr" ]; then
                        echo "[fail] got $count JOIN[s] syn with a mismatched \
                                port-number expected $mis_syn_nr"
                        fail_test
@@ -1580,10 +1690,10 @@ chk_add_nr()
                fi
 
                echo -n " - ack   "
-               count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMismatchPortAckRx |
-                       awk '{print $2}')
-               [ -z "$count" ] && count=0
-               if [ "$count" != "$mis_ack_nr" ]; then
+               count=$(get_counter ${ns1} "MPTcpExtMismatchPortAckRx")
+               if [ -z "$count" ]; then
+                       echo "[skip]"
+               elif [ "$count" != "$mis_ack_nr" ]; then
                        echo "[fail] got $count JOIN[s] ack with a mismatched \
                                port-number expected $mis_ack_nr"
                        fail_test
@@ -1627,9 +1737,10 @@ chk_rm_nr()
        fi
 
        printf "%-${nr_blank}s %s" " " "rm "
-       count=$(ip netns exec $addr_ns nstat -as | grep MPTcpExtRmAddr | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$rm_addr_nr" ]; then
+       count=$(get_counter ${addr_ns} "MPTcpExtRmAddr")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$rm_addr_nr" ]; then
                echo "[fail] got $count RM_ADDR[s] expected $rm_addr_nr"
                fail_test
                dump_stats=1
@@ -1638,29 +1749,27 @@ chk_rm_nr()
        fi
 
        echo -n " - rmsf  "
-       count=$(ip netns exec $subflow_ns nstat -as | grep MPTcpExtRmSubflow | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ -n "$simult" ]; then
+       count=$(get_counter ${subflow_ns} "MPTcpExtRmSubflow")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ -n "$simult" ]; then
                local cnt suffix
 
-               cnt=$(ip netns exec $addr_ns nstat -as | grep MPTcpExtRmSubflow | awk '{print $2}')
+               cnt=$(get_counter ${addr_ns} "MPTcpExtRmSubflow")
 
                # in case of simult flush, the subflow removal count on each side is
                # unreliable
-               [ -z "$cnt" ] && cnt=0
                count=$((count + cnt))
                [ "$count" != "$rm_subflow_nr" ] && suffix="$count in [$rm_subflow_nr:$((rm_subflow_nr*2))]"
                if [ $count -ge "$rm_subflow_nr" ] && \
                   [ "$count" -le "$((rm_subflow_nr *2 ))" ]; then
-                       echo "[ ok ] $suffix"
+                       echo -n "[ ok ] $suffix"
                else
                        echo "[fail] got $count RM_SUBFLOW[s] expected in range [$rm_subflow_nr:$((rm_subflow_nr*2))]"
                        fail_test
                        dump_stats=1
                fi
-               return
-       fi
-       if [ "$count" != "$rm_subflow_nr" ]; then
+       elif [ "$count" != "$rm_subflow_nr" ]; then
                echo "[fail] got $count RM_SUBFLOW[s] expected $rm_subflow_nr"
                fail_test
                dump_stats=1
@@ -1681,9 +1790,10 @@ chk_prio_nr()
        local dump_stats
 
        printf "%-${nr_blank}s %s" " " "ptx"
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioTx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$mp_prio_nr_tx" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtMPPrioTx")
+       if [ -z "$count" ]; then
+               echo -n "[skip]"
+       elif [ "$count" != "$mp_prio_nr_tx" ]; then
                echo "[fail] got $count MP_PRIO[s] TX expected $mp_prio_nr_tx"
                fail_test
                dump_stats=1
@@ -1692,9 +1802,10 @@ chk_prio_nr()
        fi
 
        echo -n " - prx   "
-       count=$(ip netns exec $ns1 nstat -as | grep MPTcpExtMPPrioRx | awk '{print $2}')
-       [ -z "$count" ] && count=0
-       if [ "$count" != "$mp_prio_nr_rx" ]; then
+       count=$(get_counter ${ns1} "MPTcpExtMPPrioRx")
+       if [ -z "$count" ]; then
+               echo "[skip]"
+       elif [ "$count" != "$mp_prio_nr_rx" ]; then
                echo "[fail] got $count MP_PRIO[s] RX expected $mp_prio_nr_rx"
                fail_test
                dump_stats=1
@@ -1810,7 +1921,7 @@ wait_attempt_fail()
        while [ $time -lt $timeout_ms ]; do
                local cnt
 
-               cnt=$(ip netns exec $ns nstat -as TcpAttemptFails | grep TcpAttemptFails | awk '{print $2}')
+               cnt=$(get_counter ${ns} "TcpAttemptFails")
 
                [ "$cnt" = 1 ] && return 1
                time=$((time + 100))
@@ -1903,23 +2014,23 @@ subflows_error_tests()
        fi
 
        # multiple subflows, with subflow creation error
-       if reset "multi subflows, with failing subflow"; then
+       if reset_with_tcp_filter "multi subflows, with failing subflow" ns1 10.0.3.2 REJECT &&
+          continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
                pm_nl_set_limits $ns1 0 2
                pm_nl_set_limits $ns2 0 2
                pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
                pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
-               filter_tcp_from $ns1 10.0.3.2 REJECT
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
                chk_join_nr 1 1 1
        fi
 
        # multiple subflows, with subflow timeout on MPJ
-       if reset "multi subflows, with subflow timeout"; then
+       if reset_with_tcp_filter "multi subflows, with subflow timeout" ns1 10.0.3.2 DROP &&
+          continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
                pm_nl_set_limits $ns1 0 2
                pm_nl_set_limits $ns2 0 2
                pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
                pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow
-               filter_tcp_from $ns1 10.0.3.2 DROP
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
                chk_join_nr 1 1 1
        fi
@@ -1927,11 +2038,11 @@ subflows_error_tests()
        # multiple subflows, check that the endpoint corresponding to
        # closed subflow (due to reset) is not reused if additional
        # subflows are added later
-       if reset "multi subflows, fair usage on close"; then
+       if reset_with_tcp_filter "multi subflows, fair usage on close" ns1 10.0.3.2 REJECT &&
+          continue_if mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_set_limits $ns2 0 1
                pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow
-               filter_tcp_from $ns1 10.0.3.2 REJECT
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow &
 
                # mpj subflow will be in TW after the reset
@@ -2031,11 +2142,18 @@ signal_address_tests()
                # the peer could possibly miss some addr notification, allow retransmission
                ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=1
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
-               chk_join_nr 3 3 3
 
-               # the server will not signal the address terminating
-               # the MPC subflow
-               chk_add_nr 3 3
+               # It is not directly linked to the commit introducing this
+               # symbol but for the parent one which is linked anyway.
+               if ! mptcp_lib_kallsyms_has "mptcp_pm_subflow_check_next$"; then
+                       chk_join_nr 3 3 2
+                       chk_add_nr 4 4
+               else
+                       chk_join_nr 3 3 3
+                       # the server will not signal the address terminating
+                       # the MPC subflow
+                       chk_add_nr 3 3
+               fi
        fi
 }
 
@@ -2276,7 +2394,12 @@ remove_tests()
                pm_nl_add_endpoint $ns2 10.0.4.2 flags subflow
                run_tests $ns1 $ns2 10.0.1.1 0 -8 -8 slow
                chk_join_nr 3 3 3
-               chk_rm_nr 0 3 simult
+
+               if mptcp_lib_kversion_ge 5.18; then
+                       chk_rm_nr 0 3 simult
+               else
+                       chk_rm_nr 3 3
+               fi
        fi
 
        # addresses flush
@@ -2514,7 +2637,8 @@ v4mapped_tests()
 
 mixed_tests()
 {
-       if reset "IPv4 sockets do not use IPv6 addresses"; then
+       if reset "IPv4 sockets do not use IPv6 addresses" &&
+          continue_if mptcp_lib_kversion_ge 6.3; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_set_limits $ns2 1 1
                pm_nl_add_endpoint $ns1 dead:beef:2::1 flags signal
@@ -2523,7 +2647,8 @@ mixed_tests()
        fi
 
        # Need an IPv6 mptcp socket to allow subflows of both families
-       if reset "simult IPv4 and IPv6 subflows"; then
+       if reset "simult IPv4 and IPv6 subflows" &&
+          continue_if mptcp_lib_kversion_ge 6.3; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_set_limits $ns2 1 1
                pm_nl_add_endpoint $ns1 10.0.1.1 flags signal
@@ -2532,7 +2657,8 @@ mixed_tests()
        fi
 
        # cross families subflows will not be created even in fullmesh mode
-       if reset "simult IPv4 and IPv6 subflows, fullmesh 1x1"; then
+       if reset "simult IPv4 and IPv6 subflows, fullmesh 1x1" &&
+          continue_if mptcp_lib_kversion_ge 6.3; then
                pm_nl_set_limits $ns1 0 4
                pm_nl_set_limits $ns2 1 4
                pm_nl_add_endpoint $ns2 dead:beef:2::2 flags subflow,fullmesh
@@ -2543,7 +2669,8 @@ mixed_tests()
 
        # fullmesh still tries to create all the possibly subflows with
        # matching family
-       if reset "simult IPv4 and IPv6 subflows, fullmesh 2x2"; then
+       if reset "simult IPv4 and IPv6 subflows, fullmesh 2x2" &&
+          continue_if mptcp_lib_kversion_ge 6.3; then
                pm_nl_set_limits $ns1 0 4
                pm_nl_set_limits $ns2 2 4
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
@@ -2556,7 +2683,8 @@ mixed_tests()
 backup_tests()
 {
        # single subflow, backup
-       if reset "single subflow, backup"; then
+       if reset "single subflow, backup" &&
+          continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_set_limits $ns2 0 1
                pm_nl_add_endpoint $ns2 10.0.3.2 flags subflow,backup
@@ -2566,7 +2694,8 @@ backup_tests()
        fi
 
        # single address, backup
-       if reset "single address, backup"; then
+       if reset "single address, backup" &&
+          continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
                pm_nl_set_limits $ns2 1 1
@@ -2577,7 +2706,8 @@ backup_tests()
        fi
 
        # single address with port, backup
-       if reset "single address with port, backup"; then
+       if reset "single address with port, backup" &&
+          continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
                pm_nl_set_limits $ns1 0 1
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal port 10100
                pm_nl_set_limits $ns2 1 1
@@ -2587,14 +2717,16 @@ backup_tests()
                chk_prio_nr 1 1
        fi
 
-       if reset "mpc backup"; then
+       if reset "mpc backup" &&
+          continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
                pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
                chk_join_nr 0 0 0
                chk_prio_nr 0 1
        fi
 
-       if reset "mpc backup both sides"; then
+       if reset "mpc backup both sides" &&
+          continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
                pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow,backup
                pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow,backup
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow
@@ -2602,14 +2734,16 @@ backup_tests()
                chk_prio_nr 1 1
        fi
 
-       if reset "mpc switch to backup"; then
+       if reset "mpc switch to backup" &&
+          continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
                pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup
                chk_join_nr 0 0 0
                chk_prio_nr 0 1
        fi
 
-       if reset "mpc switch to backup both sides"; then
+       if reset "mpc switch to backup both sides" &&
+          continue_if mptcp_lib_kallsyms_doesnt_have "mptcp_subflow_send_ack$"; then
                pm_nl_add_endpoint $ns1 10.0.1.1 flags subflow
                pm_nl_add_endpoint $ns2 10.0.1.2 flags subflow
                run_tests $ns1 $ns2 10.0.1.1 0 0 0 slow backup
@@ -2635,38 +2769,41 @@ verify_listener_events()
        local family
        local saddr
        local sport
+       local name
 
        if [ $e_type = $LISTENER_CREATED ]; then
-               stdbuf -o0 -e0 printf "\t\t\t\t\t CREATE_LISTENER %s:%s"\
-                       $e_saddr $e_sport
+               name="LISTENER_CREATED"
        elif [ $e_type = $LISTENER_CLOSED ]; then
-               stdbuf -o0 -e0 printf "\t\t\t\t\t CLOSE_LISTENER %s:%s "\
-                       $e_saddr $e_sport
+               name="LISTENER_CLOSED"
+       else
+               name="$e_type"
        fi
 
-       type=$(grep "type:$e_type," $evt |
-              sed --unbuffered -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q')
-       family=$(grep "type:$e_type," $evt |
-                sed --unbuffered -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q')
-       sport=$(grep "type:$e_type," $evt |
-               sed --unbuffered -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
+       printf "%-${nr_blank}s %s %s:%s " " " "$name" "$e_saddr" "$e_sport"
+
+       if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
+               printf "[skip]: event not supported\n"
+               return
+       fi
+
+       type=$(grep "type:$e_type," $evt | sed -n 's/.*\(type:\)\([[:digit:]]*\).*$/\2/p;q')
+       family=$(grep "type:$e_type," $evt | sed -n 's/.*\(family:\)\([[:digit:]]*\).*$/\2/p;q')
+       sport=$(grep "type:$e_type," $evt | sed -n 's/.*\(sport:\)\([[:digit:]]*\).*$/\2/p;q')
        if [ $family ] && [ $family = $AF_INET6 ]; then
-               saddr=$(grep "type:$e_type," $evt |
-                       sed --unbuffered -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
+               saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr6:\)\([0-9a-f:.]*\).*$/\2/p;q')
        else
-               saddr=$(grep "type:$e_type," $evt |
-                       sed --unbuffered -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q')
+               saddr=$(grep "type:$e_type," $evt | sed -n 's/.*\(saddr4:\)\([0-9.]*\).*$/\2/p;q')
        fi
 
        if [ $type ] && [ $type = $e_type ] &&
           [ $family ] && [ $family = $e_family ] &&
           [ $saddr ] && [ $saddr = $e_saddr ] &&
           [ $sport ] && [ $sport = $e_sport ]; then
-               stdbuf -o0 -e0 printf "[ ok ]\n"
+               echo "[ ok ]"
                return 0
        fi
        fail_test
-       stdbuf -o0 -e0 printf "[fail]\n"
+       echo "[fail]"
 }
 
 add_addr_ports_tests()
@@ -2972,7 +3109,8 @@ fullmesh_tests()
        fi
 
        # set fullmesh flag
-       if reset "set fullmesh flag test"; then
+       if reset "set fullmesh flag test" &&
+          continue_if mptcp_lib_kversion_ge 5.18; then
                pm_nl_set_limits $ns1 4 4
                pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow
                pm_nl_set_limits $ns2 4 4
@@ -2982,7 +3120,8 @@ fullmesh_tests()
        fi
 
        # set nofullmesh flag
-       if reset "set nofullmesh flag test"; then
+       if reset "set nofullmesh flag test" &&
+          continue_if mptcp_lib_kversion_ge 5.18; then
                pm_nl_set_limits $ns1 4 4
                pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow,fullmesh
                pm_nl_set_limits $ns2 4 4
@@ -2992,7 +3131,8 @@ fullmesh_tests()
        fi
 
        # set backup,fullmesh flags
-       if reset "set backup,fullmesh flags test"; then
+       if reset "set backup,fullmesh flags test" &&
+          continue_if mptcp_lib_kversion_ge 5.18; then
                pm_nl_set_limits $ns1 4 4
                pm_nl_add_endpoint $ns1 10.0.2.1 flags subflow
                pm_nl_set_limits $ns2 4 4
@@ -3003,7 +3143,8 @@ fullmesh_tests()
        fi
 
        # set nobackup,nofullmesh flags
-       if reset "set nobackup,nofullmesh flags test"; then
+       if reset "set nobackup,nofullmesh flags test" &&
+          continue_if mptcp_lib_kversion_ge 5.18; then
                pm_nl_set_limits $ns1 4 4
                pm_nl_set_limits $ns2 4 4
                pm_nl_add_endpoint $ns2 10.0.2.2 flags subflow,backup,fullmesh
@@ -3016,14 +3157,14 @@ fullmesh_tests()
 
 fastclose_tests()
 {
-       if reset "fastclose test"; then
+       if reset_check_counter "fastclose test" "MPTcpExtMPFastcloseTx"; then
                run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_client
                chk_join_nr 0 0 0
                chk_fclose_nr 1 1
                chk_rst_nr 1 1 invert
        fi
 
-       if reset "fastclose server test"; then
+       if reset_check_counter "fastclose server test" "MPTcpExtMPFastcloseRx"; then
                run_tests $ns1 $ns2 10.0.1.1 1024 0 fastclose_server
                chk_join_nr 0 0 0
                chk_fclose_nr 1 1 invert
@@ -3061,7 +3202,8 @@ fail_tests()
 userspace_tests()
 {
        # userspace pm type prevents add_addr
-       if reset "userspace pm type prevents add_addr"; then
+       if reset "userspace pm type prevents add_addr" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
                pm_nl_set_limits $ns1 0 2
                pm_nl_set_limits $ns2 0 2
@@ -3072,7 +3214,8 @@ userspace_tests()
        fi
 
        # userspace pm type does not echo add_addr without daemon
-       if reset "userspace pm no echo w/o daemon"; then
+       if reset "userspace pm no echo w/o daemon" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns2
                pm_nl_set_limits $ns1 0 2
                pm_nl_set_limits $ns2 0 2
@@ -3083,7 +3226,8 @@ userspace_tests()
        fi
 
        # userspace pm type rejects join
-       if reset "userspace pm type rejects join"; then
+       if reset "userspace pm type rejects join" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
                pm_nl_set_limits $ns1 1 1
                pm_nl_set_limits $ns2 1 1
@@ -3093,7 +3237,8 @@ userspace_tests()
        fi
 
        # userspace pm type does not send join
-       if reset "userspace pm type does not send join"; then
+       if reset "userspace pm type does not send join" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns2
                pm_nl_set_limits $ns1 1 1
                pm_nl_set_limits $ns2 1 1
@@ -3103,7 +3248,8 @@ userspace_tests()
        fi
 
        # userspace pm type prevents mp_prio
-       if reset "userspace pm type prevents mp_prio"; then
+       if reset "userspace pm type prevents mp_prio" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
                pm_nl_set_limits $ns1 1 1
                pm_nl_set_limits $ns2 1 1
@@ -3114,7 +3260,8 @@ userspace_tests()
        fi
 
        # userspace pm type prevents rm_addr
-       if reset "userspace pm type prevents rm_addr"; then
+       if reset "userspace pm type prevents rm_addr" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
                set_userspace_pm $ns2
                pm_nl_set_limits $ns1 0 1
@@ -3126,7 +3273,8 @@ userspace_tests()
        fi
 
        # userspace pm add & remove address
-       if reset_with_events "userspace pm add & remove address"; then
+       if reset_with_events "userspace pm add & remove address" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns1
                pm_nl_set_limits $ns2 1 1
                run_tests $ns1 $ns2 10.0.1.1 0 userspace_1 0 slow
@@ -3137,20 +3285,23 @@ userspace_tests()
        fi
 
        # userspace pm create destroy subflow
-       if reset_with_events "userspace pm create destroy subflow"; then
+       if reset_with_events "userspace pm create destroy subflow" &&
+          continue_if mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
                set_userspace_pm $ns2
                pm_nl_set_limits $ns1 0 1
                run_tests $ns1 $ns2 10.0.1.1 0 0 userspace_1 slow
                chk_join_nr 1 1 1
-               chk_rm_nr 0 1
+               chk_rm_nr 1 1
                kill_events_pids
        fi
 }
 
 endpoint_tests()
 {
+       # subflow_rebuild_header is needed to support the implicit flag
        # userspace pm type prevents add_addr
-       if reset "implicit EP"; then
+       if reset "implicit EP" &&
+          mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
                pm_nl_set_limits $ns1 2 2
                pm_nl_set_limits $ns2 2 2
                pm_nl_add_endpoint $ns1 10.0.2.1 flags signal
@@ -3170,7 +3321,8 @@ endpoint_tests()
                kill_tests_wait
        fi
 
-       if reset "delete and re-add"; then
+       if reset "delete and re-add" &&
+          mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then
                pm_nl_set_limits $ns1 1 1
                pm_nl_set_limits $ns2 1 1
                pm_nl_add_endpoint $ns2 10.0.2.2 id 2 dev ns2eth2 flags subflow
index 3286536..f32045b 100644 (file)
@@ -38,3 +38,67 @@ mptcp_lib_check_mptcp() {
                exit ${KSFT_SKIP}
        fi
 }
+
+mptcp_lib_check_kallsyms() {
+       if ! mptcp_lib_has_file "/proc/kallsyms"; then
+               echo "SKIP: CONFIG_KALLSYMS is missing"
+               exit ${KSFT_SKIP}
+       fi
+}
+
+# Internal: use mptcp_lib_kallsyms_has() instead
+__mptcp_lib_kallsyms_has() {
+       local sym="${1}"
+
+       mptcp_lib_check_kallsyms
+
+       grep -q " ${sym}" /proc/kallsyms
+}
+
+# $1: part of a symbol to look at, add '$' at the end for full name
+mptcp_lib_kallsyms_has() {
+       local sym="${1}"
+
+       if __mptcp_lib_kallsyms_has "${sym}"; then
+               return 0
+       fi
+
+       mptcp_lib_fail_if_expected_feature "${sym} symbol not found"
+}
+
+# $1: part of a symbol to look at, add '$' at the end for full name
+mptcp_lib_kallsyms_doesnt_have() {
+       local sym="${1}"
+
+       if ! __mptcp_lib_kallsyms_has "${sym}"; then
+               return 0
+       fi
+
+       mptcp_lib_fail_if_expected_feature "${sym} symbol has been found"
+}
+
+# !!!AVOID USING THIS!!!
+# Features might not land in the expected version and features can be backported
+#
+# $1: kernel version, e.g. 6.3
+mptcp_lib_kversion_ge() {
+       local exp_maj="${1%.*}"
+       local exp_min="${1#*.}"
+       local v maj min
+
+       # If the kernel has backported features, set this env var to 1:
+       if [ "${SELFTESTS_MPTCP_LIB_NO_KVERSION_CHECK:-}" = "1" ]; then
+               return 0
+       fi
+
+       v=$(uname -r | cut -d'.' -f1,2)
+       maj=${v%.*}
+       min=${v#*.}
+
+       if   [ "${maj}" -gt "${exp_maj}" ] ||
+          { [ "${maj}" -eq "${exp_maj}" ] && [ "${min}" -ge "${exp_min}" ]; }; then
+               return 0
+       fi
+
+       mptcp_lib_fail_if_expected_feature "kernel version ${1} lower than ${v}"
+}
index ae61f39..b35148e 100644 (file)
@@ -87,6 +87,10 @@ struct so_state {
        uint64_t tcpi_rcv_delta;
 };
 
+#ifndef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
 static void die_perror(const char *msg)
 {
        perror(msg);
@@ -349,13 +353,14 @@ static void do_getsockopt_tcp_info(struct so_state *s, int fd, size_t r, size_t
                        xerror("getsockopt MPTCP_TCPINFO (tries %d, %m)");
 
                assert(olen <= sizeof(ti));
-               assert(ti.d.size_user == ti.d.size_kernel);
-               assert(ti.d.size_user == sizeof(struct tcp_info));
+               assert(ti.d.size_kernel > 0);
+               assert(ti.d.size_user ==
+                      MIN(ti.d.size_kernel, sizeof(struct tcp_info)));
                assert(ti.d.num_subflows == 1);
 
                assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
                olen -= sizeof(struct mptcp_subflow_data);
-               assert(olen == sizeof(struct tcp_info));
+               assert(olen == ti.d.size_user);
 
                if (ti.ti[0].tcpi_bytes_sent == w &&
                    ti.ti[0].tcpi_bytes_received == r)
@@ -401,13 +406,14 @@ static void do_getsockopt_subflow_addrs(int fd)
                die_perror("getsockopt MPTCP_SUBFLOW_ADDRS");
 
        assert(olen <= sizeof(addrs));
-       assert(addrs.d.size_user == addrs.d.size_kernel);
-       assert(addrs.d.size_user == sizeof(struct mptcp_subflow_addrs));
+       assert(addrs.d.size_kernel > 0);
+       assert(addrs.d.size_user ==
+              MIN(addrs.d.size_kernel, sizeof(struct mptcp_subflow_addrs)));
        assert(addrs.d.num_subflows == 1);
 
        assert(olen > (socklen_t)sizeof(struct mptcp_subflow_data));
        olen -= sizeof(struct mptcp_subflow_data);
-       assert(olen == sizeof(struct mptcp_subflow_addrs));
+       assert(olen == addrs.d.size_user);
 
        llen = sizeof(local);
        ret = getsockname(fd, (struct sockaddr *)&local, &llen);
index ff5adbb..f295a37 100755 (executable)
@@ -87,6 +87,7 @@ cleanup()
 }
 
 mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
 
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
@@ -186,9 +187,14 @@ do_transfer()
                local_addr="0.0.0.0"
        fi
 
+       cmsg="TIMESTAMPNS"
+       if mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
+               cmsg+=",TCPINQ"
+       fi
+
        timeout ${timeout_test} \
                ip netns exec ${listener_ns} \
-                       $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c TIMESTAMPNS,TCPINQ \
+                       $mptcp_connect -t ${timeout_poll} -l -M 1 -p $port -s ${srv_proto} -c "${cmsg}" \
                                ${local_addr} < "$sin" > "$sout" &
        local spid=$!
 
@@ -196,7 +202,7 @@ do_transfer()
 
        timeout ${timeout_test} \
                ip netns exec ${connector_ns} \
-                       $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c TIMESTAMPNS,TCPINQ \
+                       $mptcp_connect -t ${timeout_poll} -M 2 -p $port -s ${cl_proto} -c "${cmsg}" \
                                $connect_addr < "$cin" > "$cout" &
 
        local cpid=$!
@@ -253,6 +259,11 @@ do_mptcp_sockopt_tests()
 {
        local lret=0
 
+       if ! mptcp_lib_kallsyms_has "mptcp_diag_fill_info$"; then
+               echo "INFO: MPTCP sockopt not supported: SKIP"
+               return
+       fi
+
        ip netns exec "$ns_sbox" ./mptcp_sockopt
        lret=$?
 
@@ -307,6 +318,11 @@ do_tcpinq_tests()
 {
        local lret=0
 
+       if ! mptcp_lib_kallsyms_has "mptcp_ioctl$"; then
+               echo "INFO: TCP_INQ not supported: SKIP"
+               return
+       fi
+
        local args
        for args in "-t tcp" "-r tcp"; do
                do_tcpinq_test $args
index 32f7533..d02e0d6 100755 (executable)
@@ -73,8 +73,12 @@ check()
 }
 
 check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "defaults addr list"
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
+
+default_limits="$(ip netns exec $ns1 ./pm_nl_ctl limits)"
+if mptcp_lib_expect_all_features; then
+       check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
 subflows 2" "defaults limits"
+fi
 
 ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.1
 ip netns exec $ns1 ./pm_nl_ctl add 10.0.1.2 flags subflow dev lo
@@ -121,12 +125,10 @@ ip netns exec $ns1 ./pm_nl_ctl flush
 check "ip netns exec $ns1 ./pm_nl_ctl dump" "" "flush addrs"
 
 ip netns exec $ns1 ./pm_nl_ctl limits 9 1
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
-subflows 2" "rcv addrs above hard limit"
+check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "rcv addrs above hard limit"
 
 ip netns exec $ns1 ./pm_nl_ctl limits 1 9
-check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 0
-subflows 2" "subflows above hard limit"
+check "ip netns exec $ns1 ./pm_nl_ctl limits" "$default_limits" "subflows above hard limit"
 
 ip netns exec $ns1 ./pm_nl_ctl limits 8 8
 check "ip netns exec $ns1 ./pm_nl_ctl limits" "accept 8
@@ -176,14 +178,19 @@ subflow,backup 10.0.1.1" "set flags (backup)"
 ip netns exec $ns1 ./pm_nl_ctl set 10.0.1.1 flags nobackup
 check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow 10.0.1.1" "          (nobackup)"
+
+# fullmesh support has been added later
 ip netns exec $ns1 ./pm_nl_ctl set id 1 flags fullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+if ip netns exec $ns1 ./pm_nl_ctl dump | grep -q "fullmesh" ||
+   mptcp_lib_expect_all_features; then
+       check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow,fullmesh 10.0.1.1" "          (fullmesh)"
-ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+       ip netns exec $ns1 ./pm_nl_ctl set id 1 flags nofullmesh
+       check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow 10.0.1.1" "          (nofullmesh)"
-ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
-check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
+       ip netns exec $ns1 ./pm_nl_ctl set id 1 flags backup,fullmesh
+       check "ip netns exec $ns1 ./pm_nl_ctl dump" "id 1 flags \
 subflow,backup,fullmesh 10.0.1.1" "          (backup,fullmesh)"
+fi
 
 exit $ret
index 8092399..98d9e4d 100755 (executable)
@@ -4,11 +4,17 @@
 . "$(dirname "${0}")/mptcp_lib.sh"
 
 mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
+if ! mptcp_lib_has_file '/proc/sys/net/mptcp/pm_type'; then
+       echo "userspace pm tests are not supported by the kernel: SKIP"
+       exit ${KSFT_SKIP}
+fi
 
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Cannot not run test without ip tool"
-       exit 1
+       exit ${KSFT_SKIP}
 fi
 
 ANNOUNCED=6        # MPTCP_EVENT_ANNOUNCED
@@ -909,6 +915,11 @@ test_listener()
 {
        print_title "Listener tests"
 
+       if ! mptcp_lib_kallsyms_has "mptcp_event_pm_listener$"; then
+               stdbuf -o0 -e0 printf "LISTENER events                                            \t[SKIP] Not supported\n"
+               return
+       fi
+
        # Capture events on the network namespace running the client
        :>$client_evts
 
index 198ad5f..cfa9562 100644 (file)
@@ -502,11 +502,11 @@ int main(int argc, char *argv[])
                        interval = t2 - t1;
                        offset = (t2 + t1) / 2 - tp;
 
-                       printf("system time: %lld.%u\n",
+                       printf("system time: %lld.%09u\n",
                                (pct+2*i)->sec, (pct+2*i)->nsec);
-                       printf("phc    time: %lld.%u\n",
+                       printf("phc    time: %lld.%09u\n",
                                (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
-                       printf("system time: %lld.%u\n",
+                       printf("system time: %lld.%09u\n",
                                (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
                        printf("system/phc clock time offset is %" PRId64 " ns\n"
                               "system     clock time delay  is %" PRId64 " ns\n",
index 4638c63..6e73b09 100644 (file)
@@ -6,20 +6,18 @@ CONFIG_NF_CONNTRACK_MARK=y
 CONFIG_NF_CONNTRACK_ZONES=y
 CONFIG_NF_CONNTRACK_LABELS=y
 CONFIG_NF_NAT=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
 
 CONFIG_NET_SCHED=y
 
 #
 # Queueing/Scheduling
 #
-CONFIG_NET_SCH_ATM=m
 CONFIG_NET_SCH_CAKE=m
-CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_CBS=m
 CONFIG_NET_SCH_CHOKE=m
 CONFIG_NET_SCH_CODEL=m
 CONFIG_NET_SCH_DRR=m
-CONFIG_NET_SCH_DSMARK=m
 CONFIG_NET_SCH_ETF=m
 CONFIG_NET_SCH_FQ=m
 CONFIG_NET_SCH_FQ_CODEL=m
@@ -57,8 +55,6 @@ CONFIG_NET_CLS_FLOW=m
 CONFIG_NET_CLS_FLOWER=m
 CONFIG_NET_CLS_MATCHALL=m
 CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_TCINDEX=m
 CONFIG_NET_EMATCH=y
 CONFIG_NET_EMATCH_STACK=32
 CONFIG_NET_EMATCH_CMP=m
index ba2f5e7..e21c7f2 100644 (file)
         "setup": [
             "$IP link add dev $DUMMY type dummy || /bin/true"
         ],
-        "cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfb db 10",
+        "cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfb db 100",
         "expExitCode": "0",
         "verifyCmd": "$TC qdisc show dev $DUMMY",
-        "matchPattern": "qdisc sfb 1: root refcnt [0-9]+ rehash 600s db 10ms",
+        "matchPattern": "qdisc sfb 1: root refcnt [0-9]+ rehash 600s db 100ms",
         "matchCount": "1",
         "teardown": [
             "$TC qdisc del dev $DUMMY handle 1: root",
index afb0cd8..eb357bd 100755 (executable)
@@ -2,5 +2,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 modprobe netdevsim
+modprobe sch_teql
 ./tdc.py -c actions --nobuildebpf
 ./tdc.py -c qdisc
index 8879a7b..d6979a4 100644 (file)
 
 #include "../kselftest_harness.h"
 
-const char *dyn_file = "/sys/kernel/tracing/dynamic_events";
-const char *clear = "!u:__test_event";
+const char *abi_file = "/sys/kernel/tracing/user_events_data";
+const char *enable_file = "/sys/kernel/tracing/events/user_events/__test_event/enable";
 
-static int Append(const char *value)
+static bool wait_for_delete(void)
 {
-       int fd = open(dyn_file, O_RDWR | O_APPEND);
-       int ret = write(fd, value, strlen(value));
+       int i;
+
+       for (i = 0; i < 1000; ++i) {
+               int fd = open(enable_file, O_RDONLY);
+
+               if (fd == -1)
+                       return true;
+
+               close(fd);
+               usleep(1000);
+       }
+
+       return false;
+}
+
+static int reg_event(int fd, int *check, int bit, const char *value)
+{
+       struct user_reg reg = {0};
+
+       reg.size = sizeof(reg);
+       reg.name_args = (__u64)value;
+       reg.enable_bit = bit;
+       reg.enable_addr = (__u64)check;
+       reg.enable_size = sizeof(*check);
+
+       if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
+               return -1;
+
+       return 0;
+}
+
+static int unreg_event(int fd, int *check, int bit)
+{
+       struct user_unreg unreg = {0};
+
+       unreg.size = sizeof(unreg);
+       unreg.disable_bit = bit;
+       unreg.disable_addr = (__u64)check;
+
+       return ioctl(fd, DIAG_IOCSUNREG, &unreg);
+}
+
+static int parse(int *check, const char *value)
+{
+       int fd = open(abi_file, O_RDWR);
+       int ret;
+
+       if (fd == -1)
+               return -1;
+
+       /* Until we have persist flags via dynamic events, use the base name */
+       if (value[0] != 'u' || value[1] != ':') {
+               close(fd);
+               return -1;
+       }
+
+       ret = reg_event(fd, check, 31, value + 2);
+
+       if (ret != -1) {
+               if (unreg_event(fd, check, 31) == -1)
+                       printf("WARN: Couldn't unreg event\n");
+       }
 
        close(fd);
+
        return ret;
 }
 
-#define CLEAR() \
+static int check_match(int *check, const char *first, const char *second, bool *match)
+{
+       int fd = open(abi_file, O_RDWR);
+       int ret = -1;
+
+       if (fd == -1)
+               return -1;
+
+       if (reg_event(fd, check, 31, first) == -1)
+               goto cleanup;
+
+       if (reg_event(fd, check, 30, second) == -1) {
+               if (errno == EADDRINUSE) {
+                       /* Name is in use, with different fields */
+                       *match = false;
+                       ret = 0;
+               }
+
+               goto cleanup;
+       }
+
+       *match = true;
+       ret = 0;
+cleanup:
+       unreg_event(fd, check, 31);
+       unreg_event(fd, check, 30);
+
+       close(fd);
+
+       wait_for_delete();
+
+       return ret;
+}
+
+#define TEST_MATCH(x, y) \
 do { \
-       int ret = Append(clear); \
-       if (ret == -1) \
-               ASSERT_EQ(ENOENT, errno); \
+       bool match; \
+       ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
+       ASSERT_EQ(true, match); \
 } while (0)
 
-#define TEST_PARSE(x) \
+#define TEST_NMATCH(x, y) \
 do { \
-       ASSERT_NE(-1, Append(x)); \
-       CLEAR(); \
+       bool match; \
+       ASSERT_NE(-1, check_match(&self->check, x, y, &match)); \
+       ASSERT_EQ(false, match); \
 } while (0)
 
-#define TEST_NPARSE(x) ASSERT_EQ(-1, Append(x))
+#define TEST_PARSE(x) ASSERT_NE(-1, parse(&self->check, x))
+
+#define TEST_NPARSE(x) ASSERT_EQ(-1, parse(&self->check, x))
 
 FIXTURE(user) {
+       int check;
 };
 
 FIXTURE_SETUP(user) {
-       CLEAR();
 }
 
 FIXTURE_TEARDOWN(user) {
-       CLEAR();
+       wait_for_delete();
 }
 
 TEST_F(user, basic_types) {
@@ -95,33 +193,30 @@ TEST_F(user, size_types) {
        TEST_NPARSE("u:__test_event char a 20");
 }
 
-TEST_F(user, flags) {
-       /* Should work */
-       TEST_PARSE("u:__test_event:BPF_ITER u32 a");
-       /* Forward compat */
-       TEST_PARSE("u:__test_event:BPF_ITER,FLAG_FUTURE u32 a");
-}
-
 TEST_F(user, matching) {
-       /* Register */
-       ASSERT_NE(-1, Append("u:__test_event struct custom a 20"));
-       /* Should not match */
-       TEST_NPARSE("!u:__test_event struct custom b");
-       /* Should match */
-       TEST_PARSE("!u:__test_event struct custom a");
-       /* Multi field reg */
-       ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b"));
-       /* Non matching cases */
-       TEST_NPARSE("!u:__test_event u32 a");
-       TEST_NPARSE("!u:__test_event u32 b");
-       TEST_NPARSE("!u:__test_event u32 a; u32 ");
-       TEST_NPARSE("!u:__test_event u32 a; u32 a");
-       /* Matching case */
-       TEST_PARSE("!u:__test_event u32 a; u32 b");
-       /* Register */
-       ASSERT_NE(-1, Append("u:__test_event u32 a; u32 b"));
-       /* Ensure trailing semi-colon case */
-       TEST_PARSE("!u:__test_event u32 a; u32 b;");
+       /* Single name matches */
+       TEST_MATCH("__test_event u32 a",
+                  "__test_event u32 a");
+
+       /* Multiple names match */
+       TEST_MATCH("__test_event u32 a; u32 b",
+                  "__test_event u32 a; u32 b");
+
+       /* Multiple names match with dangling ; */
+       TEST_MATCH("__test_event u32 a; u32 b",
+                  "__test_event u32 a; u32 b;");
+
+       /* Single name doesn't match */
+       TEST_NMATCH("__test_event u32 a",
+                   "__test_event u32 b");
+
+       /* Multiple names don't match */
+       TEST_NMATCH("__test_event u32 a; u32 b",
+                   "__test_event u32 b; u32 a");
+
+       /* Types don't match */
+       TEST_NMATCH("__test_event u64 a; u64 b",
+                   "__test_event u32 a; u32 b");
 }
 
 int main(int argc, char **argv)
index 7c99cef..eb6904d 100644 (file)
@@ -102,30 +102,56 @@ err:
        return -1;
 }
 
+static bool wait_for_delete(void)
+{
+       int i;
+
+       for (i = 0; i < 1000; ++i) {
+               int fd = open(enable_file, O_RDONLY);
+
+               if (fd == -1)
+                       return true;
+
+               close(fd);
+               usleep(1000);
+       }
+
+       return false;
+}
+
 static int clear(int *check)
 {
        struct user_unreg unreg = {0};
+       int fd;
 
        unreg.size = sizeof(unreg);
        unreg.disable_bit = 31;
        unreg.disable_addr = (__u64)check;
 
-       int fd = open(data_file, O_RDWR);
+       fd = open(data_file, O_RDWR);
 
        if (fd == -1)
                return -1;
 
        if (ioctl(fd, DIAG_IOCSUNREG, &unreg) == -1)
                if (errno != ENOENT)
-                       return -1;
-
-       if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
-               if (errno != ENOENT)
-                       return -1;
+                       goto fail;
+
+       if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1) {
+               if (errno == EBUSY) {
+                       if (!wait_for_delete())
+                               goto fail;
+               } else if (errno != ENOENT)
+                       goto fail;
+       }
 
        close(fd);
 
        return 0;
+fail:
+       close(fd);
+
+       return -1;
 }
 
 static int check_print_fmt(const char *event, const char *expected, int *check)
@@ -155,9 +181,8 @@ static int check_print_fmt(const char *event, const char *expected, int *check)
        /* Register should work */
        ret = ioctl(fd, DIAG_IOCSREG, &reg);
 
-       close(fd);
-
        if (ret != 0) {
+               close(fd);
                printf("Reg failed in fmt\n");
                return ret;
        }
@@ -165,6 +190,8 @@ static int check_print_fmt(const char *event, const char *expected, int *check)
        /* Ensure correct print_fmt */
        ret = get_print_fmt(print_fmt, sizeof(print_fmt));
 
+       close(fd);
+
        if (ret != 0)
                return ret;
 
@@ -228,6 +255,12 @@ TEST_F(user, register_events) {
        ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
        ASSERT_EQ(0, reg.write_index);
 
+       /* Multiple registers to same name but different args should fail */
+       reg.enable_bit = 29;
+       reg.name_args = (__u64)"__test_event u32 field1;";
+       ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+       ASSERT_EQ(EADDRINUSE, errno);
+
        /* Ensure disabled */
        self->enable_fd = open(enable_file, O_RDWR);
        ASSERT_NE(-1, self->enable_fd);
@@ -250,10 +283,10 @@ TEST_F(user, register_events) {
        unreg.disable_bit = 30;
        ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSUNREG, &unreg));
 
-       /* Delete should work only after close and unregister */
+       /* Delete should have been auto-done after close and unregister */
        close(self->data_fd);
-       self->data_fd = open(data_file, O_RDWR);
-       ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event"));
+
+       ASSERT_EQ(true, wait_for_delete());
 }
 
 TEST_F(user, write_events) {
@@ -310,6 +343,39 @@ TEST_F(user, write_events) {
        ASSERT_EQ(EINVAL, errno);
 }
 
+TEST_F(user, write_empty_events) {
+       struct user_reg reg = {0};
+       struct iovec io[1];
+       int before = 0, after = 0;
+
+       reg.size = sizeof(reg);
+       reg.name_args = (__u64)"__test_event";
+       reg.enable_bit = 31;
+       reg.enable_addr = (__u64)&self->check;
+       reg.enable_size = sizeof(self->check);
+
+       io[0].iov_base = &reg.write_index;
+       io[0].iov_len = sizeof(reg.write_index);
+
+       /* Register should work */
+       ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+       ASSERT_EQ(0, reg.write_index);
+       ASSERT_EQ(0, self->check);
+
+       /* Enable event */
+       self->enable_fd = open(enable_file, O_RDWR);
+       ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
+
+       /* Event should now be enabled */
+       ASSERT_EQ(1 << reg.enable_bit, self->check);
+
+       /* Write should make it out to ftrace buffers */
+       before = trace_bytes();
+       ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 1));
+       after = trace_bytes();
+       ASSERT_GT(after, before);
+}
+
 TEST_F(user, write_fault) {
        struct user_reg reg = {0};
        struct iovec io[2];
index a070258..8b09be5 100644 (file)
@@ -81,6 +81,32 @@ static int get_offset(void)
        return offset;
 }
 
+static int clear(int *check)
+{
+       struct user_unreg unreg = {0};
+
+       unreg.size = sizeof(unreg);
+       unreg.disable_bit = 31;
+       unreg.disable_addr = (__u64)check;
+
+       int fd = open(data_file, O_RDWR);
+
+       if (fd == -1)
+               return -1;
+
+       if (ioctl(fd, DIAG_IOCSUNREG, &unreg) == -1)
+               if (errno != ENOENT)
+                       return -1;
+
+       if (ioctl(fd, DIAG_IOCSDEL, "__test_event") == -1)
+               if (errno != ENOENT)
+                       return -1;
+
+       close(fd);
+
+       return 0;
+}
+
 FIXTURE(user) {
        int data_fd;
        int check;
@@ -93,6 +119,9 @@ FIXTURE_SETUP(user) {
 
 FIXTURE_TEARDOWN(user) {
        close(self->data_fd);
+
+       if (clear(&self->check) != 0)
+               printf("WARNING: Clear didn't work!\n");
 }
 
 TEST_F(user, perf_write) {
@@ -160,6 +189,59 @@ TEST_F(user, perf_write) {
        ASSERT_EQ(0, self->check);
 }
 
+TEST_F(user, perf_empty_events) {
+       struct perf_event_attr pe = {0};
+       struct user_reg reg = {0};
+       struct perf_event_mmap_page *perf_page;
+       int page_size = sysconf(_SC_PAGESIZE);
+       int id, fd;
+       __u32 *val;
+
+       reg.size = sizeof(reg);
+       reg.name_args = (__u64)"__test_event";
+       reg.enable_bit = 31;
+       reg.enable_addr = (__u64)&self->check;
+       reg.enable_size = sizeof(self->check);
+
+       /* Register should work */
+       ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
+       ASSERT_EQ(0, reg.write_index);
+       ASSERT_EQ(0, self->check);
+
+       /* Id should be there */
+       id = get_id();
+       ASSERT_NE(-1, id);
+
+       pe.type = PERF_TYPE_TRACEPOINT;
+       pe.size = sizeof(pe);
+       pe.config = id;
+       pe.sample_type = PERF_SAMPLE_RAW;
+       pe.sample_period = 1;
+       pe.wakeup_events = 1;
+
+       /* Tracepoint attach should work */
+       fd = perf_event_open(&pe, 0, -1, -1, 0);
+       ASSERT_NE(-1, fd);
+
+       perf_page = mmap(NULL, page_size * 2, PROT_READ, MAP_SHARED, fd, 0);
+       ASSERT_NE(MAP_FAILED, perf_page);
+
+       /* Status should be updated */
+       ASSERT_EQ(1 << reg.enable_bit, self->check);
+
+       /* Ensure write shows up at correct offset */
+       ASSERT_NE(-1, write(self->data_fd, &reg.write_index,
+                                       sizeof(reg.write_index)));
+       val = (void *)(((char *)perf_page) + perf_page->data_offset);
+       ASSERT_EQ(PERF_RECORD_SAMPLE, *val);
+
+       munmap(perf_page, page_size * 2);
+       close(fd);
+
+       /* Status should be updated */
+       ASSERT_EQ(0, self->check);
+}
+
 int main(int argc, char **argv)
 {
        return test_harness_run(argc, argv);
diff --git a/tools/virtio/ringtest/.gitignore b/tools/virtio/ringtest/.gitignore
new file mode 100644 (file)
index 0000000..100b9e3
--- /dev/null
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+/noring
+/ptr_ring
+/ring
+/virtio_ring_0_9
+/virtio_ring_inorder
+/virtio_ring_poll
index b68920d..d18dd31 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef MAIN_H
 #define MAIN_H
 
+#include <assert.h>
 #include <stdbool.h>
 
 extern int param;
@@ -95,6 +96,8 @@ extern unsigned ring_size;
 #define cpu_relax() asm ("rep; nop" ::: "memory")
 #elif defined(__s390x__)
 #define cpu_relax() barrier()
+#elif defined(__aarch64__)
+#define cpu_relax() asm ("yield" ::: "memory")
 #else
 #define cpu_relax() assert(0)
 #endif
@@ -112,6 +115,8 @@ static inline void busy_wait(void)
 
 #if defined(__x86_64__) || defined(__i386__)
 #define smp_mb()     asm volatile("lock; addl $0,-132(%%rsp)" ::: "memory", "cc")
+#elif defined(__aarch64__)
+#define smp_mb()     asm volatile("dmb ish" ::: "memory")
 #else
 /*
  * Not using __ATOMIC_SEQ_CST since gcc docs say they are only synchronized
@@ -136,10 +141,16 @@ static inline void busy_wait(void)
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__s390x__)
 #define smp_wmb() barrier()
+#elif defined(__aarch64__)
+#define smp_wmb() asm volatile("dmb ishst" ::: "memory")
 #else
 #define smp_wmb() smp_release()
 #endif
 
+#ifndef __always_inline
+#define __always_inline inline __attribute__((always_inline))
+#endif
+
 static __always_inline
 void __read_once_size(const volatile void *p, void *res, int size)
 {
index 4fb9368..0127ff0 100644 (file)
@@ -95,7 +95,7 @@ Run
 
 1) Enable ftrace in the guest
  <Example>
-       # echo 1 > /sys/kernel/debug/tracing/events/sched/enable
+       # echo 1 > /sys/kernel/tracing/events/sched/enable
 
 2) Run trace agent in the guest
  This agent must be operated as root.
index cdfe77c..7e2d9bb 100644 (file)
@@ -18,8 +18,9 @@
 #define PIPE_DEF_BUFS          16
 #define PIPE_MIN_SIZE          (PAGE_SIZE*PIPE_DEF_BUFS)
 #define PIPE_MAX_SIZE          (1024*1024)
-#define READ_PATH_FMT  \
-               "/sys/kernel/debug/tracing/per_cpu/cpu%d/trace_pipe_raw"
+#define TRACEFS                "/sys/kernel/tracing"
+#define DEBUGFS                "/sys/kernel/debug/tracing"
+#define READ_PATH_FMT          "%s/per_cpu/cpu%d/trace_pipe_raw"
 #define WRITE_PATH_FMT         "/dev/virtio-ports/trace-path-cpu%d"
 #define CTL_PATH               "/dev/virtio-ports/agent-ctl-path"
 
@@ -120,9 +121,12 @@ static const char *make_path(int cpu_num, bool this_is_write_path)
        if (this_is_write_path)
                /* write(output) path */
                ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
-       else
+       else {
                /* read(input) path */
-               ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, cpu_num);
+               ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, TRACEFS, cpu_num);
+               if (ret > 0 && access(buf, F_OK) != 0)
+                       ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, DEBUGFS, cpu_num);
+       }
 
        if (ret <= 0) {
                pr_err("Failed to generate %s path(CPU#%d):%d\n",