Merge tag 'mm-hotfixes-stable-2023-06-20-12-31' of git://git.kernel.org/pub/scm/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Jun 2023 00:20:22 +0000 (17:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 21 Jun 2023 00:20:22 +0000 (17:20 -0700)
Pull hotfixes from Andrew Morton:
 "19 hotfixes.  8 of these are cc:stable.

  This includes a wholesale reversion of the post-6.4 series 'make slab
  shrink lockless'. After input from Dave Chinner it has been decided
  that we should go a different way [1]"

Link: https://lkml.kernel.org/r/ZH6K0McWBeCjaf16@dread.disaster.area
* tag 'mm-hotfixes-stable-2023-06-20-12-31' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  selftests/mm: fix cross compilation with LLVM
  mailmap: add entries for Ben Dooks
  nilfs2: prevent general protection fault in nilfs_clear_dirty_page()
  Revert "mm: vmscan: make global slab shrink lockless"
  Revert "mm: vmscan: make memcg slab shrink lockless"
  Revert "mm: vmscan: add shrinker_srcu_generation"
  Revert "mm: shrinkers: make count and scan in shrinker debugfs lockless"
  Revert "mm: vmscan: hold write lock to reparent shrinker nr_deferred"
  Revert "mm: vmscan: remove shrinker_rwsem from synchronize_shrinkers()"
  Revert "mm: shrinkers: convert shrinker_rwsem to mutex"
  nilfs2: fix buffer corruption due to concurrent device reads
  scripts/gdb: fix SB_* constants parsing
  scripts: fix the gfp flags header path in gfp-translate
  udmabuf: revert 'Add support for mapping hugepages (v4)'
  mm/khugepaged: fix iteration in collapse_file
  memfd: check for non-NULL file_seals in memfd_create() syscall
  mm/vmalloc: do not output a spurious warning when huge vmalloc() fails
  mm/mprotect: fix do_mprotect_pkey() limit check
  writeback: fix dereferencing NULL mapping->host on writeback_page_template

832 files changed:
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/fpga/lattice,sysconfig.yaml
Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml
Documentation/devicetree/bindings/i3c/silvaco,i3c-master.yaml
Documentation/devicetree/bindings/iio/adc/nxp,imx8qxp-adc.yaml
Documentation/devicetree/bindings/iio/adc/renesas,rcar-gyroadc.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/bindings/serial/8250_omap.yaml
Documentation/devicetree/bindings/usb/snps,dwc3.yaml
Documentation/devicetree/usage-model.rst
Documentation/mm/page_table_check.rst
Documentation/netlink/specs/ethtool.yaml
Documentation/networking/device_drivers/ethernet/mellanox/mlx5/devlink.rst
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/include/asm/kvm_pgtable.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kvm/hyp/include/hyp/switch.h
arch/arm64/kvm/hyp/nvhe/mem_protect.c
arch/arm64/kvm/hyp/nvhe/switch.c
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/hyp/vhe/switch.c
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/sys_regs.c
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-its.c
arch/arm64/kvm/vgic/vgic-kvm-device.c
arch/arm64/kvm/vgic/vgic-mmio-v3.c
arch/arm64/kvm/vgic/vgic-mmio.c
arch/arm64/kvm/vgic/vgic-v2.c
arch/arm64/kvm/vgic/vgic-v3.c
arch/arm64/kvm/vgic/vgic-v4.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/crypto/Makefile
arch/powerpc/crypto/aes-gcm-p10-glue.c
arch/powerpc/crypto/aesp10-ppc.pl [moved from arch/powerpc/crypto/aesp8-ppc.pl with 99% similarity]
arch/powerpc/crypto/ghashp10-ppc.pl [moved from arch/powerpc/crypto/ghashp8-ppc.pl with 97% similarity]
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/xmon/xmon.c
arch/riscv/Kconfig
arch/riscv/errata/Makefile
arch/riscv/include/asm/hugetlb.h
arch/riscv/include/asm/kfence.h
arch/riscv/include/asm/perf_event.h
arch/riscv/include/asm/pgtable.h
arch/riscv/kernel/Makefile
arch/riscv/mm/hugetlbpage.c
arch/riscv/mm/init.c
arch/s390/purgatory/Makefile
arch/x86/hyperv/hv_init.c
arch/x86/hyperv/hv_vtl.c
arch/x86/include/asm/fpu/sched.h
arch/x86/kernel/fpu/context.h
arch/x86/kernel/fpu/core.c
arch/x86/kernel/head_64.S
arch/x86/kvm/lapic.c
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/svm/svm.c
arch/x86/kvm/x86.c
block/blk-cgroup.c
block/blk-mq.c
block/blk-settings.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/acpica/achware.h
drivers/acpi/apei/apei-internal.h
drivers/acpi/apei/bert.c
drivers/acpi/sleep.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/base/cacheinfo.c
drivers/base/firmware_loader/main.c
drivers/base/regmap/Kconfig
drivers/base/regmap/regcache-maple.c
drivers/base/regmap/regcache.c
drivers/base/regmap/regmap-sdw.c
drivers/base/regmap/regmap.c
drivers/block/null_blk/main.c
drivers/block/rbd.c
drivers/bluetooth/hci_qca.c
drivers/char/tpm/tpm_tis_core.h
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/firmware/efi/libstub/Makefile.zboot
drivers/firmware/efi/libstub/efistub.h
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_gmc.c
drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.c
drivers/gpu/drm/amd/amdgpu/amdgpu_jpeg.h
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_vcn.c
drivers/gpu/drm/amd/amdgpu/amdgpu_vcn.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/jpeg_v2_5.c
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.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/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.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/legacy-dpm/si_dpm.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/vangogh_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu12/renoir_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/amd/pm/swsmu/smu13/smu_v13_0_4_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_5_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/yellow_carp_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/i915/i915_perf.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-google-hammer.c
drivers/hid/hid-ids.h
drivers/hid/hid-logitech-hidpp.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.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/iio/accel/kionix-kx022a.c
drivers/iio/accel/st_accel_core.c
drivers/iio/adc/ad4130.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/ad_sigma_delta.c
drivers/iio/adc/imx93_adc.c
drivers/iio/adc/mt6370-adc.c
drivers/iio/adc/mxs-lradc-adc.c
drivers/iio/adc/palmas_gpadc.c
drivers/iio/adc/stm32-adc.c
drivers/iio/addac/ad74413r.c
drivers/iio/dac/Makefile
drivers/iio/dac/mcp4725.c
drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
drivers/iio/industrialio-gts-helper.c
drivers/iio/light/rohm-bu27034.c
drivers/iio/light/vcnl4035.c
drivers/iio/magnetometer/tmag5273.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/bnxt_re/qplib_fp.c
drivers/infiniband/hw/bnxt_re/qplib_res.c
drivers/infiniband/hw/bnxt_re/qplib_sp.c
drivers/infiniband/hw/efa/efa_verbs.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.c
drivers/infiniband/hw/hns/hns_roce_hw_v2.h
drivers/infiniband/hw/hns/hns_roce_mr.c
drivers/infiniband/hw/irdma/verbs.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_comp.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_recv.c
drivers/infiniband/sw/rxe/rxe_req.c
drivers/infiniband/sw/rxe/rxe_resp.c
drivers/infiniband/sw/rxe/rxe_verbs.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/iommu/Kconfig
drivers/iommu/amd/amd_iommu.h
drivers/iommu/amd/init.c
drivers/iommu/amd/iommu.c
drivers/iommu/mtk_iommu.c
drivers/iommu/rockchip-iommu.c
drivers/irqchip/irq-gic-common.c
drivers/leds/rgb/leds-qcom-lpg.c
drivers/mailbox/mailbox-test.c
drivers/md/dm-ioctl.c
drivers/md/dm-thin-metadata.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/raid5.c
drivers/media/cec/core/cec-adap.c
drivers/media/cec/core/cec-core.c
drivers/media/cec/core/cec-priv.h
drivers/media/dvb-core/dvb_frontend.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
drivers/media/platform/qcom/camss/camss-video.c
drivers/media/platform/verisilicon/hantro_v4l2.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/v4l2-core/v4l2-mc.c
drivers/misc/eeprom/Kconfig
drivers/misc/fastrpc.c
drivers/mmc/core/pwrseq_sd8787.c
drivers/mmc/host/vub300.c
drivers/mtd/mtdchar.c
drivers/mtd/nand/raw/ingenic/ingenic_ecc.h
drivers/mtd/nand/raw/marvell_nand.c
drivers/mtd/spi-nor/core.c
drivers/mtd/spi-nor/spansion.c
drivers/net/dsa/lan9303-core.c
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/dsa/ocelot/felix_vsc9959.c
drivers/net/dsa/qca/Kconfig
drivers/net/ethernet/amd/pds_core/dev.c
drivers/net/ethernet/amd/xgbe/xgbe-mdio.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/ice/ice_txrx.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/diag/fw_tracer.c
drivers/net/ethernet/mellanox/mlx5/core/en.h
drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c
drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc/act/act.h
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.c
drivers/net/ethernet/mellanox/mlx5/core/en/tc_tun_encap.h
drivers/net/ethernet/mellanox/mlx5/core/en_common.c
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/en_rep.c
drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/main.c
drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
drivers/net/ethernet/mellanox/mlx5/core/mr.c
drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
drivers/net/ethernet/mellanox/mlx5/core/sf/dev/driver.c
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_ptrn.c
drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c
drivers/net/ethernet/microsoft/mana/mana_en.c
drivers/net/ethernet/microsoft/mana/mana_ethtool.c
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/sfc/tc.c
drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ipa/ipa_endpoint.c
drivers/net/ipvlan/ipvlan_l3s.c
drivers/net/macsec.c
drivers/net/phy/mxl-gpy.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/nfc/nfcsim.c
drivers/nvme/host/constants.c
drivers/nvme/host/core.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/nvme.h
drivers/nvme/target/passthru.c
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/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_inline.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/stex.c
drivers/scsi/storvsc_drv.c
drivers/soc/fsl/qe/Kconfig
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/media/atomisp/i2c/atomisp-ov2680.c
drivers/staging/media/imx/imx8mq-mipi-csi2.c
drivers/staging/octeon/TODO
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
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/8250/8250_tegra.c
drivers/tty/serial/Kconfig
drivers/tty/serial/cpm_uart/cpm_uart.h
drivers/tty/serial/fsl_lpuart.c
drivers/tty/serial/lantiq.c
drivers/usb/cdns3/cdns3-gadget.c
drivers/usb/core/buffer.c
drivers/usb/core/devio.c
drivers/usb/dwc3/core.c
drivers/usb/dwc3/dwc3-qcom.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/function/f_fs.c
drivers/usb/gadget/udc/amd5536udc_pci.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/tipd/core.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
drivers/video/fbdev/arcfb.c
drivers/video/fbdev/au1100fb.c
drivers/video/fbdev/au1200fb.c
drivers/video/fbdev/broadsheetfb.c
drivers/video/fbdev/bw2.c
drivers/video/fbdev/core/bitblit.c
drivers/video/fbdev/imsttfb.c
drivers/video/fbdev/matrox/matroxfb_maven.c
drivers/video/fbdev/ssd1307fb.c
fs/afs/dir.c
fs/afs/vl_probe.c
fs/afs/write.c
fs/btrfs/bio.c
fs/btrfs/disk-io.c
fs/btrfs/inode.c
fs/btrfs/scrub.c
fs/btrfs/super.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/ceph/caps.c
fs/ceph/snap.c
fs/coredump.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/fsync.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/super.c
fs/ext4/xattr.c
fs/gfs2/file.c
fs/nfsd/nfsctl.c
fs/nfsd/vfs.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/ioctl.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/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/acpixf.h
include/dt-bindings/power/qcom-rpmpd.h
include/linux/cper.h
include/linux/cpuhotplug.h
include/linux/efi.h
include/linux/firewire.h
include/linux/iio/iio-gts-helper.h
include/linux/libata.h
include/linux/mlx5/driver.h
include/linux/netdevice.h
include/linux/notifier.h
include/linux/page-flags.h
include/linux/pe.h
include/linux/sched/task.h
include/linux/sched/vhost_task.h
include/linux/soc/qcom/llcc-qcom.h
include/linux/sunrpc/svcsock.h
include/linux/surface_aggregator/device.h
include/linux/usb/hcd.h
include/media/dvb_frontend.h
include/media/v4l2-subdev.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/mana/mana.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/net/tcp.h
include/rdma/ib_addr.h
include/target/iscsi/iscsi_target_core.h
include/uapi/linux/bpf.h
include/uapi/linux/ethtool_netlink.h
io_uring/epoll.c
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/exit.c
kernel/fork.c
kernel/module/decompress.c
kernel/module/main.c
kernel/signal.c
kernel/trace/bpf_trace.c
kernel/trace/trace_events_user.c
kernel/trace/trace_output.c
kernel/trace/trace_probe.h
kernel/vhost_task.c
lib/cpu_rmap.c
lib/test_firmware.c
mm/Kconfig.debug
mm/mmap.c
mm/page_table_check.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/rtnetlink.c
net/core/skmsg.c
net/core/sock.c
net/dccp/proto.c
net/handshake/handshake.h
net/handshake/request.c
net/ipv4/af_inet.c
net/ipv4/inet_connection_sock.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_offload.c
net/ipv4/tcp_timer.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.c
net/mptcp/protocol.h
net/mptcp/subflow.c
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/netlink/af_netlink.c
net/netrom/nr_subr.c
net/openvswitch/datapath.c
net/openvswitch/vport.c
net/packet/af_packet.c
net/packet/diag.c
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/local_event.c
net/sched/act_ct.c
net/sched/act_pedit.c
net/sched/act_police.c
net/sched/cls_api.c
net/sched/cls_flower.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_ingress.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/sunrpc/svcsock.c
net/tipc/bearer.c
net/tls/tls_strp.c
net/tls/tls_sw.c
net/wireless/core.c
net/wireless/nl80211.c
net/wireless/rdev-ops.h
net/wireless/reg.c
net/wireless/util.c
security/selinux/Makefile
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/linux/coresight-pmu.h
tools/include/uapi/linux/bpf.h
tools/include/uapi/linux/in.h
tools/lib/bpf/libbpf.c
tools/lib/bpf/libbpf_probes.c
tools/net/ynl/lib/ynl.py
tools/perf/Makefile.config
tools/perf/Makefile.perf
tools/perf/arch/arm/util/pmu.c
tools/perf/builtin-ftrace.c
tools/perf/util/Build
tools/perf/util/bpf_skel/sample_filter.bpf.c
tools/perf/util/cs-etm.h
tools/perf/util/evsel.c
tools/perf/util/evsel.h
tools/perf/util/symbol-elf.c
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/ftrace/test.d/filter/event-filter-function.tc
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.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/Makefile
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 [new file with mode: 0644]
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/simult_flows.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 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 4fb05eb..164331e 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Lattice Slave SPI sysCONFIG FPGA manager
 
 maintainers:
-  - Ivan Bornyakov <i.bornyakov@metrotek.ru>
+  - Vladimir Georgiev <v.georgiev@metrotek.ru>
 
 description: |
   Lattice sysCONFIG port, which is used for FPGA configuration, among others,
index 527532f..a157eec 100644 (file)
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Microchip Polarfire FPGA manager.
 
 maintainers:
-  - Ivan Bornyakov <i.bornyakov@metrotek.ru>
+  - Vladimir Georgiev <v.georgiev@metrotek.ru>
 
 description:
   Device Tree Bindings for Microchip Polarfire FPGA Manager using slave SPI to
index 62f3ca6..32c821f 100644 (file)
@@ -44,7 +44,7 @@ required:
   - clock-names
   - clocks
 
-additionalProperties: true
+unevaluatedProperties: false
 
 examples:
   - |
index 63369ba..0a192ca 100644 (file)
@@ -39,6 +39,12 @@ properties:
   power-domains:
     maxItems: 1
 
+  vref-supply:
+    description: |
+      External ADC reference voltage supply on VREFH pad. If VERID[MVI] is
+      set, there are additional, internal reference voltages selectable.
+      VREFH1 is always from VREFH pad.
+
   "#io-channel-cells":
     const: 1
 
@@ -72,6 +78,7 @@ examples:
             assigned-clocks = <&clk IMX_SC_R_ADC_0>;
             assigned-clock-rates = <24000000>;
             power-domains = <&pd IMX_SC_R_ADC_0>;
+            vref-supply = <&reg_1v8>;
             #io-channel-cells = <1>;
         };
     };
index 1c7aee5..36dff32 100644 (file)
@@ -90,7 +90,7 @@ patternProperties:
             of the MAX chips to the GyroADC, while MISO line of each Maxim
             ADC connects to a shared input pin of the GyroADC.
         enum:
-          - adi,7476
+          - adi,ad7476
           - fujitsu,mb88101a
           - maxim,max1162
           - maxim,max11100
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 eb3488d..6a7be42 100644 (file)
@@ -70,6 +70,7 @@ properties:
   dsr-gpios: true
   rng-gpios: true
   dcd-gpios: true
+  rs485-rts-active-high: true
   rts-gpio: true
   power-domains: true
   clock-frequency: true
index 50edc4d..4f76259 100644 (file)
@@ -287,7 +287,7 @@ properties:
     description:
       High-Speed PHY interface selection between UTMI+ and ULPI when the
       DWC_USB3_HSPHY_INTERFACE has value 3.
-    $ref: /schemas/types.yaml#/definitions/uint8
+    $ref: /schemas/types.yaml#/definitions/string
     enum: [utmi, ulpi]
 
   snps,quirk-frame-length-adjustment:
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 cfd8f41..c12838c 100644 (file)
@@ -52,3 +52,22 @@ Build kernel with:
 
 Optionally, build kernel with PAGE_TABLE_CHECK_ENFORCED in order to have page
 table support without extra kernel parameter.
+
+Implementation notes
+====================
+
+We specifically decided not to use VMA information in order to avoid relying on
+MM states (except for limited "struct page" info). The page table check is a
+separate from Linux-MM state machine that verifies that the user accessible
+pages are not falsely shared.
+
+PAGE_TABLE_CHECK depends on EXCLUSIVE_SYSTEM_RAM. The reason is that without
+EXCLUSIVE_SYSTEM_RAM, users are allowed to map arbitrary physical memory
+regions into the userspace via /dev/mem. At the same time, pages may change
+their properties (e.g., from anonymous pages to named pages) while they are
+still being mapped in the userspace, leading to "corruption" detected by the
+page table check.
+
+Even with EXCLUSIVE_SYSTEM_RAM, I/O pages may be still allowed to be mapped via
+/dev/mem. However, these pages are always considered as named pages, so they
+won't break the logic used in the page table check.
index 129f413..4846345 100644 (file)
@@ -61,22 +61,6 @@ attribute-sets:
         nested-attributes: bitset-bits
 
   -
-    name: u64-array
-    attributes:
-      -
-        name: u64
-        type: nest
-        multi-attr: true
-        nested-attributes: u64
-  -
-    name: s32-array
-    attributes:
-      -
-        name: s32
-        type: nest
-        multi-attr: true
-        nested-attributes: s32
-  -
     name: string
     attributes:
       -
@@ -239,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
@@ -310,7 +294,7 @@ attribute-sets:
         name: master-slave-state
         type: u8
       -
-        name: master-slave-lanes
+        name: lanes
         type: u32
       -
         name: rate-matching
@@ -338,7 +322,7 @@ attribute-sets:
         name: ext-substate
         type: u8
       -
-        name: down-cnt
+        name: ext-down-cnt
         type: u32
   -
     name: debug
@@ -593,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
@@ -602,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
@@ -611,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:
@@ -634,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:
@@ -705,16 +689,16 @@ attribute-sets:
         type: u8
       -
         name: corrected
-        type: nest
-        nested-attributes: u64-array
+        type: binary
+        sub-type: u64
       -
         name: uncorr
-        type: nest
-        nested-attributes: u64-array
+        type: binary
+        sub-type: u64
       -
         name: corr-bits
-        type: nest
-        nested-attributes: u64-array
+        type: binary
+        sub-type: u64
   -
     name: fec
     attributes:
@@ -792,7 +776,7 @@ attribute-sets:
         name: hist-bkt-hi
         type: u32
       -
-        name: hist-bkt-val
+        name: hist-val
         type: u64
   -
     name: stats
@@ -827,8 +811,8 @@ attribute-sets:
         type: u32
       -
         name: index
-        type: nest
-        nested-attributes: s32-array
+        type: binary
+        sub-type: s32
   -
     name: module
     attributes:
@@ -981,7 +965,7 @@ operations:
             - duplex
             - master-slave-cfg
             - master-slave-state
-            - master-slave-lanes
+            - lanes
             - rate-matching
       dump: *linkmodes-get-op
     -
@@ -1015,7 +999,7 @@ operations:
             - sqi-max
             - ext-state
             - ext-substate
-            - down-cnt
+            - ext-down-cnt
       dump: *linkstate-get-op
     -
       name: debug-get
@@ -1367,7 +1351,7 @@ operations:
         reply:
           attributes:
             - header
-            - cable-test-nft-nest
+            - cable-test-ntf-nest
     -
       name: cable-test-tdr-act
       doc: Cable test TDR.
@@ -1555,7 +1539,7 @@ operations:
             - hkey
       dump: *rss-get-op
     -
-      name: plca-get
+      name: plca-get-cfg
       doc: Get PLCA params.
 
       attribute-set: plca
@@ -1577,7 +1561,7 @@ operations:
             - burst-tmr
       dump: *plca-get-op
     -
-      name: plca-set
+      name: plca-set-cfg
       doc: Set PLCA params.
 
       attribute-set: plca
@@ -1601,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 3a7a714..3354ca3 100644 (file)
@@ -40,6 +40,7 @@ flow_steering_mode: Device flow steering mode
 ---------------------------------------------
 The flow steering mode parameter controls the flow steering mode of the driver.
 Two modes are supported:
+
 1. 'dmfs' - Device managed flow steering.
 2. 'smfs' - Software/Driver managed flow steering.
 
@@ -99,6 +100,7 @@ between representors and stacked devices.
 By default metadata is enabled on the supported devices in E-switch.
 Metadata is applicable only for E-switch in switchdev mode and
 users may disable it when NONE of the below use cases will be in use:
+
 1. HCA is in Dual/multi-port RoCE mode.
 2. VF/SF representor bonding (Usually used for Live migration)
 3. Stacked devices
@@ -180,7 +182,8 @@ User commands examples:
 
     $ devlink health diagnose pci/0000:82:00.0 reporter tx
 
-NOTE: This command has valid output only when interface is up, otherwise the command has empty output.
+.. note::
+   This command has valid output only when interface is up, otherwise the command has empty output.
 
 - Show number of tx errors indicated, number of recover flows ended successfully,
   is autorecover enabled and graceful period from last recover::
@@ -232,8 +235,9 @@ User commands examples:
 
     $ devlink health dump show pci/0000:82:00.0 reporter fw
 
-NOTE: This command can run only on the PF which has fw tracer ownership,
-running it on other PF or any VF will return "Operation not permitted".
+.. note::
+   This command can run only on the PF which has fw tracer ownership,
+   running it on other PF or any VF will return "Operation not permitted".
 
 fw fatal reporter
 -----------------
@@ -256,7 +260,8 @@ User commands examples:
 
     $ devlink health dump show pci/0000:82:00.1 reporter fw_fatal
 
-NOTE: This command can run only on PF.
+.. note::
+   This command can run only on PF.
 
 vnic reporter
 -------------
@@ -265,28 +270,37 @@ It is responsible for querying the vnic diagnostic counters from fw and displayi
 them in realtime.
 
 Description of the vnic counters:
-total_q_under_processor_handle: number of queues in an error state due to
-an async error or errored command.
-send_queue_priority_update_flow: number of QP/SQ priority/SL update
-events.
-cq_overrun: number of times CQ entered an error state due to an
-overflow.
-async_eq_overrun: number of times an EQ mapped to async events was
-overrun.
-comp_eq_overrun: number of times an EQ mapped to completion events was
-overrun.
-quota_exceeded_command: number of commands issued and failed due to quota
-exceeded.
-invalid_command: number of commands issued and failed dues to any reason
-other than quota exceeded.
-nic_receive_steering_discard: number of packets that completed RX flow
-steering but were discarded due to a mismatch in flow table.
+
+- total_q_under_processor_handle
+        number of queues in an error state due to
+        an async error or errored command.
+- send_queue_priority_update_flow
+        number of QP/SQ priority/SL update events.
+- cq_overrun
+        number of times CQ entered an error state due to an overflow.
+- async_eq_overrun
+        number of times an EQ mapped to async events was overrun.
+        comp_eq_overrun number of times an EQ mapped to completion events was
+        overrun.
+- quota_exceeded_command
+        number of commands issued and failed due to quota exceeded.
+- invalid_command
+        number of commands issued and failed dues to any reason other than quota
+        exceeded.
+- nic_receive_steering_discard
+        number of packets that completed RX flow
+        steering but were discarded due to a mismatch in flow table.
 
 User commands examples:
-- Diagnose PF/VF vnic counters
+
+- Diagnose PF/VF vnic counters::
+
         $ devlink health diagnose pci/0000:82:00.1 reporter vnic
+
 - Diagnose representor vnic counters (performed by supplying devlink port of the
-  representor, which can be obtained via devlink port command)
+  representor, which can be obtained via devlink port command)::
+
         $ devlink health diagnose pci/0000:82:00.1/65537 reporter vnic
 
-NOTE: This command can run over all interfaces such as PF/VF and representor ports.
+.. note::
+   This command can run over all interfaces such as PF/VF and representor ports.
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 250518f..ad32db6 100644 (file)
@@ -956,7 +956,8 @@ F:  Documentation/networking/device_drivers/ethernet/amazon/ena.rst
 F:     drivers/net/ethernet/amazon/
 
 AMAZON RDMA EFA DRIVER
-M:     Gal Pressman <galpress@amazon.com>
+M:     Michael Margolin <mrgolin@amazon.com>
+R:     Gal Pressman <gal.pressman@linux.dev>
 R:     Yossi Leybovich <sleybo@amazon.com>
 L:     linux-rdma@vger.kernel.org
 S:     Supported
@@ -1600,7 +1601,7 @@ F:        drivers/media/i2c/ar0521.c
 
 ARASAN NAND CONTROLLER DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
-M:     Naga Sureshkumar Relli <nagasure@xilinx.com>
+R:     Michal Simek <michal.simek@amd.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/mtd/arasan,nand-controller.yaml
@@ -1763,7 +1764,7 @@ F:        include/linux/amba/mmci.h
 
 ARM PRIMECELL PL35X NAND CONTROLLER DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
-M:     Naga Sureshkumar Relli <nagasure@xilinx.com>
+R:     Michal Simek <michal.simek@amd.com>
 L:     linux-mtd@lists.infradead.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/mtd/arm,pl353-nand-r2p1.yaml
@@ -1771,7 +1772,7 @@ F:        drivers/mtd/nand/raw/pl35x-nand-controller.c
 
 ARM PRIMECELL PL35X SMC DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
-M:     Naga Sureshkumar Relli <nagasure@xilinx.com>
+R:     Michal Simek <michal.simek@amd.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     Documentation/devicetree/bindings/memory-controllers/arm,pl35x-smc.yaml
@@ -5138,7 +5139,7 @@ X:        drivers/clk/clkdev.c
 
 COMMON INTERNET FILE SYSTEM CLIENT (CIFS and SMB3)
 M:     Steve French <sfrench@samba.org>
-R:     Paulo Alcantara <pc@cjr.nz> (DFS, global name space)
+R:     Paulo Alcantara <pc@manguebit.com> (DFS, global name space)
 R:     Ronnie Sahlberg <lsahlber@redhat.com> (directory leases, sparse files)
 R:     Shyam Prasad N <sprasad@microsoft.com> (multichannel)
 R:     Tom Talpey <tom@talpey.com> (RDMA, smbdirect)
@@ -5727,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
@@ -8790,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
@@ -9343,7 +9353,7 @@ F:        include/linux/hisi_acc_qm.h
 
 HISILICON ROCE DRIVER
 M:     Haoyue Xu <xuhaoyue1@hisilicon.com>
-M:     Wenpeng Liang <liangwenpeng@huawei.com>
+M:     Junxian Huang <huangjunxian6@hisilicon.com>
 L:     linux-rdma@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
@@ -9686,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
@@ -10114,7 +10125,7 @@ S:      Maintained
 F:     Documentation/process/kernel-docs.rst
 
 INDUSTRY PACK SUBSYSTEM (IPACK)
-M:     Samuel Iglesias Gonsalvez <siglesias@igalia.com>
+M:     Vaibhav Gupta <vaibhavgupta40@gmail.com>
 M:     Jens Taprogge <jens.taprogge@taprogge.org>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     industrypack-devel@lists.sourceforge.net
@@ -13836,7 +13847,7 @@ F:      drivers/tty/serial/8250/8250_pci1xxxx.c
 
 MICROCHIP POLARFIRE FPGA DRIVERS
 M:     Conor Dooley <conor.dooley@microchip.com>
-R:     Ivan Bornyakov <i.bornyakov@metrotek.ru>
+R:     Vladimir Georgiev <v.georgiev@metrotek.ru>
 L:     linux-fpga@vger.kernel.org
 S:     Supported
 F:     Documentation/devicetree/bindings/fpga/microchip,mpf-spi-fpga-mgr.yaml
@@ -17816,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/
@@ -18037,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
@@ -18378,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
@@ -19121,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 836643e..b68b43c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 4
 SUBLEVEL = 0
-EXTRAVERSION = -rc4
+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 dc3c072..93bd097 100644 (file)
@@ -632,9 +632,9 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size);
  *
  * The walker will walk the page-table entries corresponding to the input
  * address range specified, visiting entries according to the walker flags.
- * Invalid entries are treated as leaf entries. Leaf entries are reloaded
- * after invoking the walker callback, allowing the walker to descend into
- * a newly installed table.
+ * Invalid entries are treated as leaf entries. The visited page table entry is
+ * reloaded after invoking the walker callback, allowing the walker to descend
+ * into a newly installed table.
  *
  * Returning a negative error code from the walker callback function will
  * terminate the walk immediately with the same error code.
index e72d9aa..eefd712 100644 (file)
 #define SB_BARRIER_INSN                        __SYS_BARRIER_INSN(0, 7, 31)
 
 #define SYS_DC_ISW                     sys_insn(1, 0, 7, 6, 2)
+#define SYS_DC_IGSW                    sys_insn(1, 0, 7, 6, 4)
+#define SYS_DC_IGDSW                   sys_insn(1, 0, 7, 6, 6)
 #define SYS_DC_CSW                     sys_insn(1, 0, 7, 10, 2)
+#define SYS_DC_CGSW                    sys_insn(1, 0, 7, 10, 4)
+#define SYS_DC_CGDSW                   sys_insn(1, 0, 7, 10, 6)
 #define SYS_DC_CISW                    sys_insn(1, 0, 7, 14, 2)
+#define SYS_DC_CIGSW                   sys_insn(1, 0, 7, 14, 4)
+#define SYS_DC_CIGDSW                  sys_insn(1, 0, 7, 14, 6)
 
 /*
  * Automatically generated definitions for system registers, the
index e78a08a..5c15c58 100644 (file)
@@ -412,17 +412,21 @@ static bool kvm_hyp_handle_cp15_32(struct kvm_vcpu *vcpu, u64 *exit_code)
        return false;
 }
 
-static bool kvm_hyp_handle_iabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
+static bool kvm_hyp_handle_memory_fault(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
        if (!__populate_fault_info(vcpu))
                return true;
 
        return false;
 }
+static bool kvm_hyp_handle_iabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
+       __alias(kvm_hyp_handle_memory_fault);
+static bool kvm_hyp_handle_watchpt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
+       __alias(kvm_hyp_handle_memory_fault);
 
 static bool kvm_hyp_handle_dabt_low(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-       if (!__populate_fault_info(vcpu))
+       if (kvm_hyp_handle_memory_fault(vcpu, exit_code))
                return true;
 
        if (static_branch_unlikely(&vgic_v2_cpuif_trap)) {
index 2e9ec4a..a8813b2 100644 (file)
@@ -575,7 +575,7 @@ struct pkvm_mem_donation {
 
 struct check_walk_data {
        enum pkvm_page_state    desired;
-       enum pkvm_page_state    (*get_page_state)(kvm_pte_t pte);
+       enum pkvm_page_state    (*get_page_state)(kvm_pte_t pte, u64 addr);
 };
 
 static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx,
@@ -583,10 +583,7 @@ static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx,
 {
        struct check_walk_data *d = ctx->arg;
 
-       if (kvm_pte_valid(ctx->old) && !addr_is_allowed_memory(kvm_pte_to_phys(ctx->old)))
-               return -EINVAL;
-
-       return d->get_page_state(ctx->old) == d->desired ? 0 : -EPERM;
+       return d->get_page_state(ctx->old, ctx->addr) == d->desired ? 0 : -EPERM;
 }
 
 static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size,
@@ -601,8 +598,11 @@ static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size,
        return kvm_pgtable_walk(pgt, addr, size, &walker);
 }
 
-static enum pkvm_page_state host_get_page_state(kvm_pte_t pte)
+static enum pkvm_page_state host_get_page_state(kvm_pte_t pte, u64 addr)
 {
+       if (!addr_is_allowed_memory(addr))
+               return PKVM_NOPAGE;
+
        if (!kvm_pte_valid(pte) && pte)
                return PKVM_NOPAGE;
 
@@ -709,7 +709,7 @@ static int host_complete_donation(u64 addr, const struct pkvm_mem_transition *tx
        return host_stage2_set_owner_locked(addr, size, host_id);
 }
 
-static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte)
+static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte, u64 addr)
 {
        if (!kvm_pte_valid(pte))
                return PKVM_NOPAGE;
index 71fa16a..7779149 100644 (file)
@@ -186,6 +186,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
        [ESR_ELx_EC_FP_ASIMD]           = kvm_hyp_handle_fpsimd,
        [ESR_ELx_EC_IABT_LOW]           = kvm_hyp_handle_iabt_low,
        [ESR_ELx_EC_DABT_LOW]           = kvm_hyp_handle_dabt_low,
+       [ESR_ELx_EC_WATCHPT_LOW]        = kvm_hyp_handle_watchpt_low,
        [ESR_ELx_EC_PAC]                = kvm_hyp_handle_ptrauth,
 };
 
@@ -196,6 +197,7 @@ static const exit_handler_fn pvm_exit_handlers[] = {
        [ESR_ELx_EC_FP_ASIMD]           = kvm_hyp_handle_fpsimd,
        [ESR_ELx_EC_IABT_LOW]           = kvm_hyp_handle_iabt_low,
        [ESR_ELx_EC_DABT_LOW]           = kvm_hyp_handle_dabt_low,
+       [ESR_ELx_EC_WATCHPT_LOW]        = kvm_hyp_handle_watchpt_low,
        [ESR_ELx_EC_PAC]                = kvm_hyp_handle_ptrauth,
 };
 
index 5282cb9..95dae02 100644 (file)
@@ -209,14 +209,26 @@ static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
                .flags  = flags,
        };
        int ret = 0;
+       bool reload = false;
        kvm_pteref_t childp;
        bool table = kvm_pte_table(ctx.old, level);
 
-       if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE))
+       if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE)) {
                ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_TABLE_PRE);
+               reload = true;
+       }
 
        if (!table && (ctx.flags & KVM_PGTABLE_WALK_LEAF)) {
                ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_LEAF);
+               reload = true;
+       }
+
+       /*
+        * Reload the page table after invoking the walker callback for leaf
+        * entries or after pre-order traversal, to allow the walker to descend
+        * into a newly installed or replaced table.
+        */
+       if (reload) {
                ctx.old = READ_ONCE(*ptep);
                table = kvm_pte_table(ctx.old, level);
        }
@@ -1320,4 +1332,7 @@ void kvm_pgtable_stage2_free_removed(struct kvm_pgtable_mm_ops *mm_ops, void *pg
        };
 
        WARN_ON(__kvm_pgtable_walk(&data, mm_ops, ptep, level + 1));
+
+       WARN_ON(mm_ops->page_count(pgtable) != 1);
+       mm_ops->put_page(pgtable);
 }
index 3d868e8..7a1aa51 100644 (file)
@@ -110,6 +110,7 @@ static const exit_handler_fn hyp_exit_handlers[] = {
        [ESR_ELx_EC_FP_ASIMD]           = kvm_hyp_handle_fpsimd,
        [ESR_ELx_EC_IABT_LOW]           = kvm_hyp_handle_iabt_low,
        [ESR_ELx_EC_DABT_LOW]           = kvm_hyp_handle_dabt_low,
+       [ESR_ELx_EC_WATCHPT_LOW]        = kvm_hyp_handle_watchpt_low,
        [ESR_ELx_EC_PAC]                = kvm_hyp_handle_ptrauth,
 };
 
index 45727d5..491ca7e 100644 (file)
@@ -694,45 +694,23 @@ out_unlock:
 
 static struct arm_pmu *kvm_pmu_probe_armpmu(void)
 {
-       struct perf_event_attr attr = { };
-       struct perf_event *event;
-       struct arm_pmu *pmu = NULL;
-
-       /*
-        * Create a dummy event that only counts user cycles. As we'll never
-        * leave this function with the event being live, it will never
-        * count anything. But it allows us to probe some of the PMU
-        * details. Yes, this is terrible.
-        */
-       attr.type = PERF_TYPE_RAW;
-       attr.size = sizeof(attr);
-       attr.pinned = 1;
-       attr.disabled = 0;
-       attr.exclude_user = 0;
-       attr.exclude_kernel = 1;
-       attr.exclude_hv = 1;
-       attr.exclude_host = 1;
-       attr.config = ARMV8_PMUV3_PERFCTR_CPU_CYCLES;
-       attr.sample_period = GENMASK(63, 0);
+       struct arm_pmu *tmp, *pmu = NULL;
+       struct arm_pmu_entry *entry;
+       int cpu;
 
-       event = perf_event_create_kernel_counter(&attr, -1, current,
-                                                kvm_pmu_perf_overflow, &attr);
+       mutex_lock(&arm_pmus_lock);
 
-       if (IS_ERR(event)) {
-               pr_err_once("kvm: pmu event creation failed %ld\n",
-                           PTR_ERR(event));
-               return NULL;
-       }
+       cpu = smp_processor_id();
+       list_for_each_entry(entry, &arm_pmus, entry) {
+               tmp = entry->arm_pmu;
 
-       if (event->pmu) {
-               pmu = to_arm_pmu(event->pmu);
-               if (pmu->pmuver == ID_AA64DFR0_EL1_PMUVer_NI ||
-                   pmu->pmuver == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
-                       pmu = NULL;
+               if (cpumask_test_cpu(cpu, &tmp->supported_cpus)) {
+                       pmu = tmp;
+                       break;
+               }
        }
 
-       perf_event_disable(event);
-       perf_event_release_kernel(event);
+       mutex_unlock(&arm_pmus_lock);
 
        return pmu;
 }
@@ -912,7 +890,17 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
                return -EBUSY;
 
        if (!kvm->arch.arm_pmu) {
-               /* No PMU set, get the default one */
+               /*
+                * No PMU set, get the default one.
+                *
+                * The observant among you will notice that the supported_cpus
+                * mask does not get updated for the default PMU even though it
+                * is quite possible the selected instance supports only a
+                * subset of cores in the system. This is intentional, and
+                * upholds the preexisting behavior on heterogeneous systems
+                * where vCPUs can be scheduled on any core but the guest
+                * counters could stop working.
+                */
                kvm->arch.arm_pmu = kvm_pmu_probe_armpmu();
                if (!kvm->arch.arm_pmu)
                        return -ENODEV;
index 71b1209..753aa74 100644 (file)
@@ -211,6 +211,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
        return true;
 }
 
+static bool access_dcgsw(struct kvm_vcpu *vcpu,
+                        struct sys_reg_params *p,
+                        const struct sys_reg_desc *r)
+{
+       if (!kvm_has_mte(vcpu->kvm)) {
+               kvm_inject_undefined(vcpu);
+               return false;
+       }
+
+       /* Treat MTE S/W ops as we treat the classic ones: with contempt */
+       return access_dcsw(vcpu, p, r);
+}
+
 static void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift)
 {
        switch (r->aarch32_map) {
@@ -1756,8 +1769,14 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
  */
 static const struct sys_reg_desc sys_reg_descs[] = {
        { SYS_DESC(SYS_DC_ISW), access_dcsw },
+       { SYS_DESC(SYS_DC_IGSW), access_dcgsw },
+       { SYS_DESC(SYS_DC_IGDSW), access_dcgsw },
        { SYS_DESC(SYS_DC_CSW), access_dcsw },
+       { SYS_DESC(SYS_DC_CGSW), access_dcgsw },
+       { SYS_DESC(SYS_DC_CGDSW), access_dcgsw },
        { SYS_DESC(SYS_DC_CISW), access_dcsw },
+       { SYS_DESC(SYS_DC_CIGSW), access_dcgsw },
+       { SYS_DESC(SYS_DC_CIGDSW), access_dcgsw },
 
        DBG_BCR_BVR_WCR_WVR_EL1(0),
        DBG_BCR_BVR_WCR_WVR_EL1(1),
index 9d42c7c..6eafc2c 100644 (file)
@@ -235,9 +235,9 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
         * KVM io device for the redistributor that belongs to this VCPU.
         */
        if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
-               mutex_lock(&vcpu->kvm->arch.config_lock);
+               mutex_lock(&vcpu->kvm->slots_lock);
                ret = vgic_register_redist_iodev(vcpu);
-               mutex_unlock(&vcpu->kvm->arch.config_lock);
+               mutex_unlock(&vcpu->kvm->slots_lock);
        }
        return ret;
 }
@@ -406,7 +406,7 @@ void kvm_vgic_destroy(struct kvm *kvm)
 
 /**
  * vgic_lazy_init: Lazy init is only allowed if the GIC exposed to the guest
- * is a GICv2. A GICv3 must be explicitly initialized by the guest using the
+ * is a GICv2. A GICv3 must be explicitly initialized by userspace using the
  * KVM_DEV_ARM_VGIC_GRP_CTRL KVM_DEVICE group.
  * @kvm: kvm struct pointer
  */
@@ -446,11 +446,13 @@ int vgic_lazy_init(struct kvm *kvm)
 int kvm_vgic_map_resources(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
+       gpa_t dist_base;
        int ret = 0;
 
        if (likely(vgic_ready(kvm)))
                return 0;
 
+       mutex_lock(&kvm->slots_lock);
        mutex_lock(&kvm->arch.config_lock);
        if (vgic_ready(kvm))
                goto out;
@@ -463,13 +465,26 @@ int kvm_vgic_map_resources(struct kvm *kvm)
        else
                ret = vgic_v3_map_resources(kvm);
 
-       if (ret)
+       if (ret) {
                __kvm_vgic_destroy(kvm);
-       else
-               dist->ready = true;
+               goto out;
+       }
+       dist->ready = true;
+       dist_base = dist->vgic_dist_base;
+       mutex_unlock(&kvm->arch.config_lock);
+
+       ret = vgic_register_dist_iodev(kvm, dist_base,
+                                      kvm_vgic_global_state.type);
+       if (ret) {
+               kvm_err("Unable to register VGIC dist MMIO regions\n");
+               kvm_vgic_destroy(kvm);
+       }
+       mutex_unlock(&kvm->slots_lock);
+       return ret;
 
 out:
        mutex_unlock(&kvm->arch.config_lock);
+       mutex_unlock(&kvm->slots_lock);
        return ret;
 }
 
index 750e51e..5fe2365 100644 (file)
@@ -1936,6 +1936,7 @@ void vgic_lpi_translation_cache_destroy(struct kvm *kvm)
 
 static int vgic_its_create(struct kvm_device *dev, u32 type)
 {
+       int ret;
        struct vgic_its *its;
 
        if (type != KVM_DEV_TYPE_ARM_VGIC_ITS)
@@ -1945,9 +1946,12 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
        if (!its)
                return -ENOMEM;
 
+       mutex_lock(&dev->kvm->arch.config_lock);
+
        if (vgic_initialized(dev->kvm)) {
-               int ret = vgic_v4_init(dev->kvm);
+               ret = vgic_v4_init(dev->kvm);
                if (ret < 0) {
+                       mutex_unlock(&dev->kvm->arch.config_lock);
                        kfree(its);
                        return ret;
                }
@@ -1960,12 +1964,10 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
 
        /* Yep, even more trickery for lock ordering... */
 #ifdef CONFIG_LOCKDEP
-       mutex_lock(&dev->kvm->arch.config_lock);
        mutex_lock(&its->cmd_lock);
        mutex_lock(&its->its_lock);
        mutex_unlock(&its->its_lock);
        mutex_unlock(&its->cmd_lock);
-       mutex_unlock(&dev->kvm->arch.config_lock);
 #endif
 
        its->vgic_its_base = VGIC_ADDR_UNDEF;
@@ -1986,7 +1988,11 @@ static int vgic_its_create(struct kvm_device *dev, u32 type)
 
        dev->private = its;
 
-       return vgic_its_set_abi(its, NR_ITS_ABIS - 1);
+       ret = vgic_its_set_abi(its, NR_ITS_ABIS - 1);
+
+       mutex_unlock(&dev->kvm->arch.config_lock);
+
+       return ret;
 }
 
 static void vgic_its_destroy(struct kvm_device *kvm_dev)
index 35cfa26..212b73a 100644 (file)
@@ -102,7 +102,11 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri
                if (get_user(addr, uaddr))
                        return -EFAULT;
 
-       mutex_lock(&kvm->arch.config_lock);
+       /*
+        * Since we can't hold config_lock while registering the redistributor
+        * iodevs, take the slots_lock immediately.
+        */
+       mutex_lock(&kvm->slots_lock);
        switch (attr->attr) {
        case KVM_VGIC_V2_ADDR_TYPE_DIST:
                r = vgic_check_type(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
@@ -182,6 +186,7 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri
        if (r)
                goto out;
 
+       mutex_lock(&kvm->arch.config_lock);
        if (write) {
                r = vgic_check_iorange(kvm, *addr_ptr, addr, alignment, size);
                if (!r)
@@ -189,9 +194,10 @@ static int kvm_vgic_addr(struct kvm *kvm, struct kvm_device_attr *attr, bool wri
        } else {
                addr = *addr_ptr;
        }
+       mutex_unlock(&kvm->arch.config_lock);
 
 out:
-       mutex_unlock(&kvm->arch.config_lock);
+       mutex_unlock(&kvm->slots_lock);
 
        if (!r && !write)
                r =  put_user(addr, uaddr);
index 472b18a..188d218 100644 (file)
@@ -769,10 +769,13 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
        struct vgic_io_device *rd_dev = &vcpu->arch.vgic_cpu.rd_iodev;
        struct vgic_redist_region *rdreg;
        gpa_t rd_base;
-       int ret;
+       int ret = 0;
+
+       lockdep_assert_held(&kvm->slots_lock);
+       mutex_lock(&kvm->arch.config_lock);
 
        if (!IS_VGIC_ADDR_UNDEF(vgic_cpu->rd_iodev.base_addr))
-               return 0;
+               goto out_unlock;
 
        /*
         * We may be creating VCPUs before having set the base address for the
@@ -782,10 +785,12 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
         */
        rdreg = vgic_v3_rdist_free_slot(&vgic->rd_regions);
        if (!rdreg)
-               return 0;
+               goto out_unlock;
 
-       if (!vgic_v3_check_base(kvm))
-               return -EINVAL;
+       if (!vgic_v3_check_base(kvm)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
        vgic_cpu->rdreg = rdreg;
        vgic_cpu->rdreg_index = rdreg->free_index;
@@ -799,16 +804,20 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
        rd_dev->nr_regions = ARRAY_SIZE(vgic_v3_rd_registers);
        rd_dev->redist_vcpu = vcpu;
 
-       mutex_lock(&kvm->slots_lock);
+       mutex_unlock(&kvm->arch.config_lock);
+
        ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, rd_base,
                                      2 * SZ_64K, &rd_dev->dev);
-       mutex_unlock(&kvm->slots_lock);
-
        if (ret)
                return ret;
 
+       /* Protected by slots_lock */
        rdreg->free_index++;
        return 0;
+
+out_unlock:
+       mutex_unlock(&kvm->arch.config_lock);
+       return ret;
 }
 
 static void vgic_unregister_redist_iodev(struct kvm_vcpu *vcpu)
@@ -834,12 +843,10 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm)
                /* The current c failed, so iterate over the previous ones. */
                int i;
 
-               mutex_lock(&kvm->slots_lock);
                for (i = 0; i < c; i++) {
                        vcpu = kvm_get_vcpu(kvm, i);
                        vgic_unregister_redist_iodev(vcpu);
                }
-               mutex_unlock(&kvm->slots_lock);
        }
 
        return ret;
@@ -938,7 +945,9 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
 {
        int ret;
 
+       mutex_lock(&kvm->arch.config_lock);
        ret = vgic_v3_alloc_redist_region(kvm, index, addr, count);
+       mutex_unlock(&kvm->arch.config_lock);
        if (ret)
                return ret;
 
@@ -950,8 +959,10 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
        if (ret) {
                struct vgic_redist_region *rdreg;
 
+               mutex_lock(&kvm->arch.config_lock);
                rdreg = vgic_v3_rdist_region_from_index(kvm, index);
                vgic_v3_free_redist_region(rdreg);
+               mutex_unlock(&kvm->arch.config_lock);
                return ret;
        }
 
index 1939c94..ff558c0 100644 (file)
@@ -1096,7 +1096,6 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
                             enum vgic_type type)
 {
        struct vgic_io_device *io_device = &kvm->arch.vgic.dist_iodev;
-       int ret = 0;
        unsigned int len;
 
        switch (type) {
@@ -1114,10 +1113,6 @@ int vgic_register_dist_iodev(struct kvm *kvm, gpa_t dist_base_address,
        io_device->iodev_type = IODEV_DIST;
        io_device->redist_vcpu = NULL;
 
-       mutex_lock(&kvm->slots_lock);
-       ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
-                                     len, &io_device->dev);
-       mutex_unlock(&kvm->slots_lock);
-
-       return ret;
+       return kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, dist_base_address,
+                                      len, &io_device->dev);
 }
index 6456483..7e9cdb7 100644 (file)
@@ -312,12 +312,6 @@ int vgic_v2_map_resources(struct kvm *kvm)
                return ret;
        }
 
-       ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V2);
-       if (ret) {
-               kvm_err("Unable to register VGIC MMIO regions\n");
-               return ret;
-       }
-
        if (!static_branch_unlikely(&vgic_v2_cpuif_trap)) {
                ret = kvm_phys_addr_ioremap(kvm, dist->vgic_cpu_base,
                                            kvm_vgic_global_state.vcpu_base,
index 93a47a5..c3b8e13 100644 (file)
@@ -539,7 +539,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
        struct kvm_vcpu *vcpu;
-       int ret = 0;
        unsigned long c;
 
        kvm_for_each_vcpu(c, vcpu, kvm) {
@@ -569,12 +568,6 @@ int vgic_v3_map_resources(struct kvm *kvm)
                return -EBUSY;
        }
 
-       ret = vgic_register_dist_iodev(kvm, dist->vgic_dist_base, VGIC_V3);
-       if (ret) {
-               kvm_err("Unable to register VGICv3 dist MMIO regions\n");
-               return ret;
-       }
-
        if (kvm_vgic_global_state.has_gicv4_1)
                vgic_v4_configure_vsgis(kvm);
 
index 3bb0034..c1c28fe 100644 (file)
@@ -184,13 +184,14 @@ static void vgic_v4_disable_vsgis(struct kvm_vcpu *vcpu)
        }
 }
 
-/* Must be called with the kvm lock held */
 void vgic_v4_configure_vsgis(struct kvm *kvm)
 {
        struct vgic_dist *dist = &kvm->arch.vgic;
        struct kvm_vcpu *vcpu;
        unsigned long i;
 
+       lockdep_assert_held(&kvm->arch.config_lock);
+
        kvm_arm_halt_guest(kvm);
 
        kvm_for_each_vcpu(i, vcpu, kvm) {
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 05c7486..7b4f516 100644 (file)
@@ -22,15 +22,15 @@ sha1-ppc-spe-y := sha1-spe-asm.o sha1-spe-glue.o
 sha256-ppc-spe-y := sha256-spe-asm.o sha256-spe-glue.o
 crc32c-vpmsum-y := crc32c-vpmsum_asm.o crc32c-vpmsum_glue.o
 crct10dif-vpmsum-y := crct10dif-vpmsum_asm.o crct10dif-vpmsum_glue.o
-aes-gcm-p10-crypto-y := aes-gcm-p10-glue.o aes-gcm-p10.o ghashp8-ppc.o aesp8-ppc.o
+aes-gcm-p10-crypto-y := aes-gcm-p10-glue.o aes-gcm-p10.o ghashp10-ppc.o aesp10-ppc.o
 
 quiet_cmd_perl = PERL    $@
       cmd_perl = $(PERL) $< $(if $(CONFIG_CPU_LITTLE_ENDIAN), linux-ppc64le, linux-ppc64) > $@
 
-targets += aesp8-ppc.S ghashp8-ppc.S
+targets += aesp10-ppc.S ghashp10-ppc.S
 
-$(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE
+$(obj)/aesp10-ppc.S $(obj)/ghashp10-ppc.S: $(obj)/%.S: $(src)/%.pl FORCE
        $(call if_changed,perl)
 
-OBJECT_FILES_NON_STANDARD_aesp8-ppc.o := y
-OBJECT_FILES_NON_STANDARD_ghashp8-ppc.o := y
+OBJECT_FILES_NON_STANDARD_aesp10-ppc.o := y
+OBJECT_FILES_NON_STANDARD_ghashp10-ppc.o := y
index bd3475f..4b6e899 100644 (file)
@@ -30,15 +30,15 @@ MODULE_AUTHOR("Danny Tsen <dtsen@linux.ibm.com");
 MODULE_LICENSE("GPL v2");
 MODULE_ALIAS_CRYPTO("aes");
 
-asmlinkage int aes_p8_set_encrypt_key(const u8 *userKey, const int bits,
+asmlinkage int aes_p10_set_encrypt_key(const u8 *userKey, const int bits,
                                      void *key);
-asmlinkage void aes_p8_encrypt(const u8 *in, u8 *out, const void *key);
+asmlinkage void aes_p10_encrypt(const u8 *in, u8 *out, const void *key);
 asmlinkage void aes_p10_gcm_encrypt(u8 *in, u8 *out, size_t len,
                                    void *rkey, u8 *iv, void *Xi);
 asmlinkage void aes_p10_gcm_decrypt(u8 *in, u8 *out, size_t len,
                                    void *rkey, u8 *iv, void *Xi);
 asmlinkage void gcm_init_htable(unsigned char htable[256], unsigned char Xi[16]);
-asmlinkage void gcm_ghash_p8(unsigned char *Xi, unsigned char *Htable,
+asmlinkage void gcm_ghash_p10(unsigned char *Xi, unsigned char *Htable,
                unsigned char *aad, unsigned int alen);
 
 struct aes_key {
@@ -93,7 +93,7 @@ static void set_aad(struct gcm_ctx *gctx, struct Hash_ctx *hash,
        gctx->aadLen = alen;
        i = alen & ~0xf;
        if (i) {
-               gcm_ghash_p8(nXi, hash->Htable+32, aad, i);
+               gcm_ghash_p10(nXi, hash->Htable+32, aad, i);
                aad += i;
                alen -= i;
        }
@@ -102,7 +102,7 @@ static void set_aad(struct gcm_ctx *gctx, struct Hash_ctx *hash,
                        nXi[i] ^= aad[i];
 
                memset(gctx->aad_hash, 0, 16);
-               gcm_ghash_p8(gctx->aad_hash, hash->Htable+32, nXi, 16);
+               gcm_ghash_p10(gctx->aad_hash, hash->Htable+32, nXi, 16);
        } else {
                memcpy(gctx->aad_hash, nXi, 16);
        }
@@ -115,7 +115,7 @@ static void gcmp10_init(struct gcm_ctx *gctx, u8 *iv, unsigned char *rdkey,
 {
        __be32 counter = cpu_to_be32(1);
 
-       aes_p8_encrypt(hash->H, hash->H, rdkey);
+       aes_p10_encrypt(hash->H, hash->H, rdkey);
        set_subkey(hash->H);
        gcm_init_htable(hash->Htable+32, hash->H);
 
@@ -126,7 +126,7 @@ static void gcmp10_init(struct gcm_ctx *gctx, u8 *iv, unsigned char *rdkey,
        /*
         * Encrypt counter vector as iv tag and increment counter.
         */
-       aes_p8_encrypt(iv, gctx->ivtag, rdkey);
+       aes_p10_encrypt(iv, gctx->ivtag, rdkey);
 
        counter = cpu_to_be32(2);
        *((__be32 *)(iv+12)) = counter;
@@ -160,7 +160,7 @@ static void finish_tag(struct gcm_ctx *gctx, struct Hash_ctx *hash, int len)
        /*
         * hash (AAD len and len)
         */
-       gcm_ghash_p8(hash->Htable, hash->Htable+32, aclen, 16);
+       gcm_ghash_p10(hash->Htable, hash->Htable+32, aclen, 16);
 
        for (i = 0; i < 16; i++)
                hash->Htable[i] ^= gctx->ivtag[i];
@@ -192,7 +192,7 @@ static int p10_aes_gcm_setkey(struct crypto_aead *aead, const u8 *key,
        int ret;
 
        vsx_begin();
-       ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
+       ret = aes_p10_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
        vsx_end();
 
        return ret ? -EINVAL : 0;
similarity index 99%
rename from arch/powerpc/crypto/aesp8-ppc.pl
rename to arch/powerpc/crypto/aesp10-ppc.pl
index 1f22aec..2c06ce2 100644 (file)
@@ -110,7 +110,7 @@ die "can't locate ppc-xlate.pl";
 open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!";
 
 $FRAME=8*$SIZE_T;
-$prefix="aes_p8";
+$prefix="aes_p10";
 
 $sp="r1";
 $vrsave="r12";
similarity index 97%
rename from arch/powerpc/crypto/ghashp8-ppc.pl
rename to arch/powerpc/crypto/ghashp10-ppc.pl
index b56603b..27a6b0b 100644 (file)
@@ -64,7 +64,7 @@ $code=<<___;
 
 .text
 
-.globl .gcm_init_p8
+.globl .gcm_init_p10
        lis             r0,0xfff0
        li              r8,0x10
        mfspr           $vrsave,256
@@ -110,7 +110,7 @@ $code=<<___;
        .long           0
        .byte           0,12,0x14,0,0,0,2,0
        .long           0
-.size  .gcm_init_p8,.-.gcm_init_p8
+.size  .gcm_init_p10,.-.gcm_init_p10
 
 .globl .gcm_init_htable
        lis             r0,0xfff0
@@ -237,7 +237,7 @@ $code=<<___;
        .long           0
 .size  .gcm_init_htable,.-.gcm_init_htable
 
-.globl .gcm_gmult_p8
+.globl .gcm_gmult_p10
        lis             r0,0xfff8
        li              r8,0x10
        mfspr           $vrsave,256
@@ -283,9 +283,9 @@ $code=<<___;
        .long           0
        .byte           0,12,0x14,0,0,0,2,0
        .long           0
-.size  .gcm_gmult_p8,.-.gcm_gmult_p8
+.size  .gcm_gmult_p10,.-.gcm_gmult_p10
 
-.globl .gcm_ghash_p8
+.globl .gcm_ghash_p10
        lis             r0,0xfff8
        li              r8,0x10
        mfspr           $vrsave,256
@@ -350,7 +350,7 @@ Loop:
        .long           0
        .byte           0,12,0x14,0,0,0,4,0
        .long           0
-.size  .gcm_ghash_p8,.-.gcm_ghash_p8
+.size  .gcm_ghash_p10,.-.gcm_ghash_p10
 
 .asciz  "GHASH for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>"
 .align  2
index 918f511..d59e8a9 100644 (file)
@@ -317,13 +317,22 @@ static void tce_free_pSeriesLP(unsigned long liobn, long tcenum, long tceshift,
 static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages)
 {
        u64 rc;
+       long rpages = npages;
+       unsigned long limit;
 
        if (!firmware_has_feature(FW_FEATURE_STUFF_TCE))
                return tce_free_pSeriesLP(tbl->it_index, tcenum,
                                          tbl->it_page_shift, npages);
 
-       rc = plpar_tce_stuff((u64)tbl->it_index,
-                            (u64)tcenum << tbl->it_page_shift, 0, npages);
+       do {
+               limit = min_t(unsigned long, rpages, 512);
+
+               rc = plpar_tce_stuff((u64)tbl->it_index,
+                                    (u64)tcenum << tbl->it_page_shift, 0, limit);
+
+               rpages -= limit;
+               tcenum += limit;
+       } while (rpages > 0 && !rc);
 
        if (rc && printk_ratelimit()) {
                printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
index 728d3c2..70c4c59 100644 (file)
@@ -88,7 +88,7 @@ static unsigned long ndump = 64;
 static unsigned long nidump = 16;
 static unsigned long ncsum = 4096;
 static int termch;
-static char tmpstr[128];
+static char tmpstr[KSYM_NAME_LEN];
 static int tracing_enabled;
 
 static long bus_error_jmp[JMP_BUF_LEN];
index 348c0fa..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
@@ -799,8 +800,11 @@ menu "Power management options"
 
 source "kernel/power/Kconfig"
 
+# Hibernation is only possible on systems where the SBI implementation has
+# marked its reserved memory as not accessible from, or does not run
+# from the same memory as, Linux
 config ARCH_HIBERNATION_POSSIBLE
-       def_bool y
+       def_bool NONPORTABLE
 
 config ARCH_HIBERNATION_HEADER
        def_bool HIBERNATION
index a105596..7b2637c 100644 (file)
@@ -1,2 +1,6 @@
+ifdef CONFIG_RELOCATABLE
+KBUILD_CFLAGS += -fno-pie
+endif
+
 obj-$(CONFIG_ERRATA_SIFIVE) += sifive/
 obj-$(CONFIG_ERRATA_THEAD) += thead/
index fe6f230..ce1ebda 100644 (file)
@@ -36,6 +36,9 @@ int huge_ptep_set_access_flags(struct vm_area_struct *vma,
                               unsigned long addr, pte_t *ptep,
                               pte_t pte, int dirty);
 
+#define __HAVE_ARCH_HUGE_PTEP_GET
+pte_t huge_ptep_get(pte_t *ptep);
+
 pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags);
 #define arch_make_huge_pte arch_make_huge_pte
 
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 d42c901..665bbc9 100644 (file)
 
 #include <linux/perf_event.h>
 #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs
+
+#define perf_arch_fetch_caller_regs(regs, __ip) { \
+       (regs)->epc = (__ip); \
+       (regs)->s0 = (unsigned long) __builtin_frame_address(0); \
+       (regs)->sp = current_stack_pointer; \
+       (regs)->status = SR_PP; \
+}
 #endif /* _ASM_RISCV_PERF_EVENT_H */
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 fbdccc2..153864e 100644 (file)
@@ -23,6 +23,10 @@ ifdef CONFIG_FTRACE
 CFLAGS_REMOVE_alternative.o = $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_cpufeature.o = $(CC_FLAGS_FTRACE)
 endif
+ifdef CONFIG_RELOCATABLE
+CFLAGS_alternative.o += -fno-pie
+CFLAGS_cpufeature.o += -fno-pie
+endif
 ifdef CONFIG_KASAN
 KASAN_SANITIZE_alternative.o := n
 KASAN_SANITIZE_cpufeature.o := n
index a163a3e..e0ef56d 100644 (file)
@@ -3,6 +3,30 @@
 #include <linux/err.h>
 
 #ifdef CONFIG_RISCV_ISA_SVNAPOT
+pte_t huge_ptep_get(pte_t *ptep)
+{
+       unsigned long pte_num;
+       int i;
+       pte_t orig_pte = ptep_get(ptep);
+
+       if (!pte_present(orig_pte) || !pte_napot(orig_pte))
+               return orig_pte;
+
+       pte_num = napot_pte_num(napot_cont_order(orig_pte));
+
+       for (i = 0; i < pte_num; i++, ptep++) {
+               pte_t pte = ptep_get(ptep);
+
+               if (pte_dirty(pte))
+                       orig_pte = pte_mkdirty(orig_pte);
+
+               if (pte_young(pte))
+                       orig_pte = pte_mkyoung(orig_pte);
+       }
+
+       return orig_pte;
+}
+
 pte_t *huge_pte_alloc(struct mm_struct *mm,
                      struct vm_area_struct *vma,
                      unsigned long addr,
@@ -218,6 +242,7 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
 {
        pte_t pte = ptep_get(ptep);
        unsigned long order;
+       pte_t orig_pte;
        int i, pte_num;
 
        if (!pte_napot(pte)) {
@@ -228,9 +253,12 @@ void huge_ptep_set_wrprotect(struct mm_struct *mm,
        order = napot_cont_order(pte);
        pte_num = napot_pte_num(order);
        ptep = huge_pte_offset(mm, addr, napot_cont_size(order));
+       orig_pte = get_clear_contig_flush(mm, addr, ptep, pte_num);
+
+       orig_pte = pte_wrprotect(orig_pte);
 
        for (i = 0; i < pte_num; i++, addr += PAGE_SIZE, ptep++)
-               ptep_set_wrprotect(mm, addr, ptep);
+               set_pte_at(mm, addr, ptep, orig_pte);
 }
 
 pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
index 747e5b1..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;
@@ -922,9 +924,9 @@ static void __init create_kernel_page_table(pgd_t *pgdir, bool early)
 static void __init create_fdt_early_page_table(uintptr_t fix_fdt_va,
                                               uintptr_t dtb_pa)
 {
+#ifndef CONFIG_BUILTIN_DTB
        uintptr_t pa = dtb_pa & ~(PMD_SIZE - 1);
 
-#ifndef CONFIG_BUILTIN_DTB
        /* Make sure the fdt fixmap address is always aligned on PMD size */
        BUILD_BUG_ON(FIX_FDT % (PMD_SIZE / 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 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 c2d6cd7..78fcde7 100644 (file)
@@ -39,7 +39,7 @@ extern void fpu_flush_thread(void);
 static inline void switch_fpu_prepare(struct fpu *old_fpu, int cpu)
 {
        if (cpu_feature_enabled(X86_FEATURE_FPU) &&
-           !(current->flags & (PF_KTHREAD | PF_IO_WORKER))) {
+           !(current->flags & (PF_KTHREAD | PF_USER_WORKER))) {
                save_fpregs_to_fpstate(old_fpu);
                /*
                 * The save operation preserved register state, so the
index 9fcfa5c..af5cbdd 100644 (file)
@@ -57,7 +57,7 @@ static inline void fpregs_restore_userregs(void)
        struct fpu *fpu = &current->thread.fpu;
        int cpu = smp_processor_id();
 
-       if (WARN_ON_ONCE(current->flags & (PF_KTHREAD | PF_IO_WORKER)))
+       if (WARN_ON_ONCE(current->flags & (PF_KTHREAD | PF_USER_WORKER)))
                return;
 
        if (!fpregs_state_valid(fpu, cpu)) {
index caf3348..1015af1 100644 (file)
@@ -426,7 +426,7 @@ void kernel_fpu_begin_mask(unsigned int kfpu_mask)
 
        this_cpu_write(in_kernel_fpu, true);
 
-       if (!(current->flags & (PF_KTHREAD | PF_IO_WORKER)) &&
+       if (!(current->flags & (PF_KTHREAD | PF_USER_WORKER)) &&
            !test_thread_flag(TIF_NEED_FPU_LOAD)) {
                set_thread_flag(TIF_NEED_FPU_LOAD);
                save_fpregs_to_fpstate(&current->thread.fpu);
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 e542cf2..3c300a1 100644 (file)
@@ -229,6 +229,23 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
        u32 physical_id;
 
        /*
+        * For simplicity, KVM always allocates enough space for all possible
+        * xAPIC IDs.  Yell, but don't kill the VM, as KVM can continue on
+        * without the optimized map.
+        */
+       if (WARN_ON_ONCE(xapic_id > new->max_apic_id))
+               return -EINVAL;
+
+       /*
+        * Bail if a vCPU was added and/or enabled its APIC between allocating
+        * the map and doing the actual calculations for the map.  Note, KVM
+        * hardcodes the x2APIC ID to vcpu_id, i.e. there's no TOCTOU bug if
+        * the compiler decides to reload x2apic_id after this check.
+        */
+       if (x2apic_id > new->max_apic_id)
+               return -E2BIG;
+
+       /*
         * Deliberately truncate the vCPU ID when detecting a mismatched APIC
         * ID to avoid false positives if the vCPU ID, i.e. x2APIC ID, is a
         * 32-bit value.  Any unwanted aliasing due to truncation results will
@@ -253,8 +270,7 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
         */
        if (vcpu->kvm->arch.x2apic_format) {
                /* See also kvm_apic_match_physical_addr(). */
-               if ((apic_x2apic_mode(apic) || x2apic_id > 0xff) &&
-                       x2apic_id <= new->max_apic_id)
+               if (apic_x2apic_mode(apic) || x2apic_id > 0xff)
                        new->phys_map[x2apic_id] = apic;
 
                if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])
index c8961f4..6eaa3d6 100644 (file)
@@ -7091,7 +7091,10 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm)
                 */
                slot = NULL;
                if (atomic_read(&kvm->nr_memslots_dirty_logging)) {
-                       slot = gfn_to_memslot(kvm, sp->gfn);
+                       struct kvm_memslots *slots;
+
+                       slots = kvm_memslots_for_spte_role(kvm, sp->role);
+                       slot = __gfn_to_memslot(slots, sp->gfn);
                        WARN_ON_ONCE(!slot);
                }
 
index ca32389..54089f9 100644 (file)
@@ -3510,7 +3510,7 @@ static bool svm_is_vnmi_pending(struct kvm_vcpu *vcpu)
        if (!is_vnmi_enabled(svm))
                return false;
 
-       return !!(svm->vmcb->control.int_ctl & V_NMI_BLOCKING_MASK);
+       return !!(svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK);
 }
 
 static bool svm_set_vnmi_pending(struct kvm_vcpu *vcpu)
index c0778ca..04b57a3 100644 (file)
@@ -10758,6 +10758,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
                        exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED;
                        break;
                }
+
+               /* Note, VM-Exits that go down the "slow" path are accounted below. */
+               ++vcpu->stat.exits;
        }
 
        /*
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 896b465..4dd5905 100644 (file)
@@ -915,6 +915,7 @@ static bool disk_has_partitions(struct gendisk *disk)
 void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 {
        struct request_queue *q = disk->queue;
+       unsigned int old_model = q->limits.zoned;
 
        switch (model) {
        case BLK_ZONED_HM:
@@ -952,7 +953,7 @@ void disk_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
                 */
                blk_queue_zone_write_granularity(q,
                                                queue_logical_block_size(q));
-       } else {
+       } else if (old_model != BLK_ZONED_NONE) {
                disk_clear_zone_settings(disk);
        }
 }
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 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 1d6ef96..67c2c3b 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef APEI_INTERNAL_H
 #define APEI_INTERNAL_H
 
-#include <linux/cper.h>
 #include <linux/acpi.h>
 
 struct apei_exec_context;
@@ -130,10 +129,5 @@ static inline u32 cper_estatus_len(struct acpi_hest_generic_status *estatus)
                return sizeof(*estatus) + estatus->data_length;
 }
 
-void cper_estatus_print(const char *pfx,
-                       const struct acpi_hest_generic_status *estatus);
-int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus);
-int cper_estatus_check(const struct acpi_hest_generic_status *estatus);
-
 int apei_osc_setup(void);
 #endif
index c23eb75..7514e38 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/acpi.h>
+#include <linux/cper.h>
 #include <linux/io.h>
 
 #include "apei-internal.h"
index 72470b9..f32570f 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();
 
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 7bb12de..551077c 100644 (file)
@@ -2694,18 +2694,36 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc)
        return 0;
 }
 
-static struct ata_device *ata_find_dev(struct ata_port *ap, int devno)
+static struct ata_device *ata_find_dev(struct ata_port *ap, unsigned int devno)
 {
-       if (!sata_pmp_attached(ap)) {
-               if (likely(devno >= 0 &&
-                          devno < ata_link_max_devices(&ap->link)))
+       /*
+        * For the non-PMP case, ata_link_max_devices() returns 1 (SATA case),
+        * or 2 (IDE master + slave case). However, the former case includes
+        * libsas hosted devices which are numbered per scsi host, leading
+        * to devno potentially being larger than 0 but with each struct
+        * ata_device having its own struct ata_port and struct ata_link.
+        * To accommodate these, ignore devno and always use device number 0.
+        */
+       if (likely(!sata_pmp_attached(ap))) {
+               int link_max_devices = ata_link_max_devices(&ap->link);
+
+               if (link_max_devices == 1)
+                       return &ap->link.device[0];
+
+               if (devno < link_max_devices)
                        return &ap->link.device[devno];
-       } else {
-               if (likely(devno >= 0 &&
-                          devno < ap->nr_pmp_links))
-                       return &ap->pmp_link[devno].device[0];
+
+               return NULL;
        }
 
+       /*
+        * For PMP-attached devices, the device number corresponds to C
+        * (channel) of SCSI [H:C:I:L], indicating the port pmp link
+        * for the device.
+        */
+       if (devno < ap->nr_pmp_links)
+               return &ap->pmp_link[devno].device[0];
+
        return NULL;
 }
 
@@ -4579,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);
@@ -4596,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);
@@ -4605,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 bba3482..cbae8be 100644 (file)
@@ -388,6 +388,16 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
                                continue;/* skip if itself or no cacheinfo */
                        for (sib_index = 0; sib_index < cache_leaves(i); sib_index++) {
                                sib_leaf = per_cpu_cacheinfo_idx(i, sib_index);
+
+                               /*
+                                * Comparing cache IDs only makes sense if the leaves
+                                * belong to the same cache level of same type. Skip
+                                * the check if level and type do not match.
+                                */
+                               if (sib_leaf->level != this_leaf->level ||
+                                   sib_leaf->type != this_leaf->type)
+                                       continue;
+
                                if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
                                        cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map);
                                        cpumask_set_cpu(i, &this_leaf->shared_cpu_map);
@@ -400,11 +410,14 @@ static int cache_shared_cpu_map_setup(unsigned int cpu)
                        coherency_max_size = this_leaf->coherency_line_size;
        }
 
+       /* shared_cpu_map is now populated for the cpu */
+       this_cpu_ci->cpu_map_populated = true;
        return 0;
 }
 
 static void cache_shared_cpu_map_remove(unsigned int cpu)
 {
+       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
        struct cacheinfo *this_leaf, *sib_leaf;
        unsigned int sibling, index, sib_index;
 
@@ -419,6 +432,16 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
 
                        for (sib_index = 0; sib_index < cache_leaves(sibling); sib_index++) {
                                sib_leaf = per_cpu_cacheinfo_idx(sibling, sib_index);
+
+                               /*
+                                * Comparing cache IDs only makes sense if the leaves
+                                * belong to the same cache level of same type. Skip
+                                * the check if level and type do not match.
+                                */
+                               if (sib_leaf->level != this_leaf->level ||
+                                   sib_leaf->type != this_leaf->type)
+                                       continue;
+
                                if (cache_leaves_are_shared(this_leaf, sib_leaf)) {
                                        cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map);
                                        cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map);
@@ -427,6 +450,9 @@ static void cache_shared_cpu_map_remove(unsigned int cpu)
                        }
                }
        }
+
+       /* cpu is no longer populated in the shared map */
+       this_cpu_ci->cpu_map_populated = false;
 }
 
 static void free_cache_attributes(unsigned int cpu)
index 9d79d5a..b58c42f 100644 (file)
@@ -812,7 +812,7 @@ static void fw_log_firmware_info(const struct firmware *fw, const char *name, st
        char *outbuf;
 
        alg = crypto_alloc_shash("sha256", 0, 0);
-       if (!alg)
+       if (IS_ERR(alg))
                return;
 
        sha256buf = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
index 33a8366..0db2021 100644 (file)
@@ -4,16 +4,23 @@
 # subsystems should select the appropriate symbols.
 
 config REGMAP
+       bool "Register Map support" if KUNIT_ALL_TESTS
        default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SOUNDWIRE || REGMAP_SOUNDWIRE_MBQ || REGMAP_SCCB || REGMAP_I3C || REGMAP_SPI_AVMM || REGMAP_MDIO || REGMAP_FSI)
        select IRQ_DOMAIN if REGMAP_IRQ
        select MDIO_BUS if REGMAP_MDIO
-       bool
+       help
+         Enable support for the Register Map (regmap) access API.
+
+         Usually, this option is automatically selected when needed.
+         However, you may want to enable it manually for running the regmap
+         KUnit tests.
+
+         If unsure, say N.
 
 config REGMAP_KUNIT
        tristate "KUnit tests for regmap"
-       depends on KUNIT
+       depends on KUNIT && REGMAP
        default KUNIT_ALL_TESTS
-       select REGMAP
        select REGMAP_RAM
 
 config REGMAP_AC97
index 9b1b559..c2e3a0f 100644 (file)
@@ -203,15 +203,18 @@ static int regcache_maple_sync(struct regmap *map, unsigned int min,
 
        mas_for_each(&mas, entry, max) {
                for (r = max(mas.index, lmin); r <= min(mas.last, lmax); r++) {
+                       mas_pause(&mas);
+                       rcu_read_unlock();
                        ret = regcache_sync_val(map, r, entry[r - mas.index]);
                        if (ret != 0)
                                goto out;
+                       rcu_read_lock();
                }
        }
 
-out:
        rcu_read_unlock();
 
+out:
        map->cache_bypass = false;
 
        return ret;
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 09899ae..159c0b7 100644 (file)
@@ -59,6 +59,10 @@ static int regmap_sdw_config_check(const struct regmap_config *config)
        if (config->pad_bits != 0)
                return -ENOTSUPP;
 
+       /* Only bulk writes are supported not multi-register writes */
+       if (config->can_multi_write)
+               return -ENOTSUPP;
+
        return 0;
 }
 
index db7851f..fa2d3fb 100644 (file)
@@ -2082,6 +2082,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
        size_t val_count = val_len / val_bytes;
        size_t chunk_count, chunk_bytes;
        size_t chunk_regs = val_count;
+       size_t max_data = map->max_raw_write - map->format.reg_bytes -
+                       map->format.pad_bytes;
        int ret, i;
 
        if (!val_count)
@@ -2089,8 +2091,8 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
 
        if (map->use_single_write)
                chunk_regs = 1;
-       else if (map->max_raw_write && val_len > map->max_raw_write)
-               chunk_regs = map->max_raw_write / val_bytes;
+       else if (map->max_raw_write && val_len > max_data)
+               chunk_regs = max_data / val_bytes;
 
        chunk_count = val_count / chunk_regs;
        chunk_bytes = chunk_regs * val_bytes;
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 e978f45..610bfad 100644 (file)
@@ -84,10 +84,10 @@ enum tis_defaults {
 #define ILB_REMAP_SIZE                 0x100
 
 enum tpm_tis_flags {
-       TPM_TIS_ITPM_WORKAROUND         = BIT(0),
-       TPM_TIS_INVALID_STATUS          = BIT(1),
-       TPM_TIS_DEFAULT_CANCELLATION    = BIT(2),
-       TPM_TIS_IRQ_TESTED              = BIT(3),
+       TPM_TIS_ITPM_WORKAROUND         = 0,
+       TPM_TIS_INVALID_STATUS          = 1,
+       TPM_TIS_DEFAULT_CANCELLATION    = 2,
+       TPM_TIS_IRQ_TESTED              = 3,
 };
 
 struct tpm_tis_data {
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 89ef820..2c48962 100644 (file)
@@ -32,7 +32,8 @@ zboot-size-len-$(CONFIG_KERNEL_GZIP)   := 0
 $(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
        $(call if_changed,$(zboot-method-y))
 
-OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
+# avoid eager evaluation to prevent references to non-existent build artifacts
+OBJCOPYFLAGS_vmlinuz.o = -I binary -O $(EFI_ZBOOT_BFD_TARGET) $(EFI_ZBOOT_OBJCOPY_FLAGS) \
                          --rename-section .data=.gzdata,load,alloc,readonly,contents
 $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
        $(call if_changed,objcopy)
index 67d5a20..54a2822 100644 (file)
@@ -1133,4 +1133,7 @@ const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
 void efi_remap_image(unsigned long image_base, unsigned alloc_size,
                     unsigned long code_size);
 
+asmlinkage efi_status_t __efiapi
+efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab);
+
 #endif
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 4e25317..95b0f98 100644 (file)
@@ -593,6 +593,8 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
        case IP_VERSION(9, 3, 0):
        /* GC 10.3.7 */
        case IP_VERSION(10, 3, 7):
+       /* GC 11.0.1 */
+       case IP_VERSION(11, 0, 1):
                if (amdgpu_tmz == 0) {
                        adev->gmc.tmz_enabled = false;
                        dev_info(adev->dev,
@@ -616,7 +618,6 @@ void amdgpu_gmc_tmz_set(struct amdgpu_device *adev)
        case IP_VERSION(10, 3, 1):
        /* YELLOW_CARP*/
        case IP_VERSION(10, 3, 3):
-       case IP_VERSION(11, 0, 1):
        case IP_VERSION(11, 0, 4):
                /* Don't enable it by default yet.
                 */
index b07c000..4fa019c 100644 (file)
@@ -241,6 +241,31 @@ int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+int amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
+{
+       int r, i;
+
+       r = amdgpu_ras_block_late_init(adev, ras_block);
+       if (r)
+               return r;
+
+       if (amdgpu_ras_is_supported(adev, ras_block->block)) {
+               for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
+                       if (adev->jpeg.harvest_config & (1 << i))
+                               continue;
+
+                       r = amdgpu_irq_get(adev, &adev->jpeg.inst[i].ras_poison_irq, 0);
+                       if (r)
+                               goto late_fini;
+               }
+       }
+       return 0;
+
+late_fini:
+       amdgpu_ras_block_late_fini(adev, ras_block);
+       return r;
+}
+
 int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev)
 {
        int err;
@@ -262,7 +287,7 @@ int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev)
        adev->jpeg.ras_if = &ras->ras_block.ras_comm;
 
        if (!ras->ras_block.ras_late_init)
-               ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
+               ras->ras_block.ras_late_init = amdgpu_jpeg_ras_late_init;
 
        return 0;
 }
index 0ca76f0..1471a1e 100644 (file)
@@ -38,6 +38,7 @@ struct amdgpu_jpeg_reg{
 struct amdgpu_jpeg_inst {
        struct amdgpu_ring ring_dec;
        struct amdgpu_irq_src irq;
+       struct amdgpu_irq_src ras_poison_irq;
        struct amdgpu_jpeg_reg external;
 };
 
@@ -72,6 +73,8 @@ int amdgpu_jpeg_dec_ring_test_ib(struct amdgpu_ring *ring, long timeout);
 int amdgpu_jpeg_process_poison_irq(struct amdgpu_device *adev,
                                struct amdgpu_irq_src *source,
                                struct amdgpu_iv_entry *entry);
+int amdgpu_jpeg_ras_late_init(struct amdgpu_device *adev,
+                               struct ras_common_if *ras_block);
 int amdgpu_jpeg_ras_sw_init(struct amdgpu_device *adev);
 
 #endif /*__AMDGPU_JPEG_H__*/
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 e63fcc5..2d94f1b 100644 (file)
@@ -1181,6 +1181,31 @@ int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
        return 0;
 }
 
+int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev, struct ras_common_if *ras_block)
+{
+       int r, i;
+
+       r = amdgpu_ras_block_late_init(adev, ras_block);
+       if (r)
+               return r;
+
+       if (amdgpu_ras_is_supported(adev, ras_block->block)) {
+               for (i = 0; i < adev->vcn.num_vcn_inst; i++) {
+                       if (adev->vcn.harvest_config & (1 << i))
+                               continue;
+
+                       r = amdgpu_irq_get(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
+                       if (r)
+                               goto late_fini;
+               }
+       }
+       return 0;
+
+late_fini:
+       amdgpu_ras_block_late_fini(adev, ras_block);
+       return r;
+}
+
 int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev)
 {
        int err;
@@ -1202,7 +1227,7 @@ int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev)
        adev->vcn.ras_if = &ras->ras_block.ras_comm;
 
        if (!ras->ras_block.ras_late_init)
-               ras->ras_block.ras_late_init = amdgpu_ras_block_late_init;
+               ras->ras_block.ras_late_init = amdgpu_vcn_ras_late_init;
 
        return 0;
 }
index c730949..f1397ef 100644 (file)
@@ -234,6 +234,7 @@ struct amdgpu_vcn_inst {
        struct amdgpu_ring      ring_enc[AMDGPU_VCN_MAX_ENC_RINGS];
        atomic_t                sched_score;
        struct amdgpu_irq_src   irq;
+       struct amdgpu_irq_src   ras_poison_irq;
        struct amdgpu_vcn_reg   external;
        struct amdgpu_bo        *dpg_sram_bo;
        struct dpg_pause_state  pause_state;
@@ -400,6 +401,8 @@ void amdgpu_debugfs_vcn_fwlog_init(struct amdgpu_device *adev,
 int amdgpu_vcn_process_poison_irq(struct amdgpu_device *adev,
                        struct amdgpu_irq_src *source,
                        struct amdgpu_iv_entry *entry);
+int amdgpu_vcn_ras_late_init(struct amdgpu_device *adev,
+                       struct ras_common_if *ras_block);
 int amdgpu_vcn_ras_sw_init(struct amdgpu_device *adev);
 
 #endif
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 b040f51..73e0dc5 100644 (file)
@@ -102,13 +102,13 @@ static int jpeg_v2_5_sw_init(void *handle)
 
                /* JPEG DJPEG POISON EVENT */
                r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_jpeg[i],
-                       VCN_2_6__SRCID_DJPEG0_POISON, &adev->jpeg.inst[i].irq);
+                       VCN_2_6__SRCID_DJPEG0_POISON, &adev->jpeg.inst[i].ras_poison_irq);
                if (r)
                        return r;
 
                /* JPEG EJPEG POISON EVENT */
                r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_jpeg[i],
-                       VCN_2_6__SRCID_EJPEG0_POISON, &adev->jpeg.inst[i].irq);
+                       VCN_2_6__SRCID_EJPEG0_POISON, &adev->jpeg.inst[i].ras_poison_irq);
                if (r)
                        return r;
        }
@@ -221,6 +221,9 @@ static int jpeg_v2_5_hw_fini(void *handle)
                if (adev->jpeg.cur_state != AMD_PG_STATE_GATE &&
                      RREG32_SOC15(JPEG, i, mmUVD_JRBC_STATUS))
                        jpeg_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+
+               if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
+                       amdgpu_irq_put(adev, &adev->jpeg.inst[i].ras_poison_irq, 0);
        }
 
        return 0;
@@ -569,6 +572,14 @@ static int jpeg_v2_5_set_interrupt_state(struct amdgpu_device *adev,
        return 0;
 }
 
+static int jpeg_v2_6_set_ras_interrupt_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *source,
+                                       unsigned int type,
+                                       enum amdgpu_interrupt_state state)
+{
+       return 0;
+}
+
 static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev,
                                      struct amdgpu_irq_src *source,
                                      struct amdgpu_iv_entry *entry)
@@ -593,10 +604,6 @@ static int jpeg_v2_5_process_interrupt(struct amdgpu_device *adev,
        case VCN_2_0__SRCID__JPEG_DECODE:
                amdgpu_fence_process(&adev->jpeg.inst[ip_instance].ring_dec);
                break;
-       case VCN_2_6__SRCID_DJPEG0_POISON:
-       case VCN_2_6__SRCID_EJPEG0_POISON:
-               amdgpu_jpeg_process_poison_irq(adev, source, entry);
-               break;
        default:
                DRM_ERROR("Unhandled interrupt: %d %d\n",
                          entry->src_id, entry->src_data[0]);
@@ -725,6 +732,11 @@ static const struct amdgpu_irq_src_funcs jpeg_v2_5_irq_funcs = {
        .process = jpeg_v2_5_process_interrupt,
 };
 
+static const struct amdgpu_irq_src_funcs jpeg_v2_6_ras_irq_funcs = {
+       .set = jpeg_v2_6_set_ras_interrupt_state,
+       .process = amdgpu_jpeg_process_poison_irq,
+};
+
 static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev)
 {
        int i;
@@ -735,6 +747,9 @@ static void jpeg_v2_5_set_irq_funcs(struct amdgpu_device *adev)
 
                adev->jpeg.inst[i].irq.num_types = 1;
                adev->jpeg.inst[i].irq.funcs = &jpeg_v2_5_irq_funcs;
+
+               adev->jpeg.inst[i].ras_poison_irq.num_types = 1;
+               adev->jpeg.inst[i].ras_poison_irq.funcs = &jpeg_v2_6_ras_irq_funcs;
        }
 }
 
@@ -800,6 +815,7 @@ const struct amdgpu_ras_block_hw_ops jpeg_v2_6_ras_hw_ops = {
 static struct amdgpu_jpeg_ras jpeg_v2_6_ras = {
        .ras_block = {
                .hw_ops = &jpeg_v2_6_ras_hw_ops,
+               .ras_late_init = amdgpu_jpeg_ras_late_init,
        },
 };
 
index 77e1e64..a3d83c9 100644 (file)
@@ -87,13 +87,13 @@ static int jpeg_v4_0_sw_init(void *handle)
 
        /* JPEG DJPEG POISON EVENT */
        r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
-                       VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->irq);
+                       VCN_4_0__SRCID_DJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
        if (r)
                return r;
 
        /* JPEG EJPEG POISON EVENT */
        r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_VCN,
-                       VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->irq);
+                       VCN_4_0__SRCID_EJPEG0_POISON, &adev->jpeg.inst->ras_poison_irq);
        if (r)
                return r;
 
@@ -202,7 +202,8 @@ static int jpeg_v4_0_hw_fini(void *handle)
                        RREG32_SOC15(JPEG, 0, regUVD_JRBC_STATUS))
                        jpeg_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
        }
-       amdgpu_irq_put(adev, &adev->jpeg.inst->irq, 0);
+       if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__JPEG))
+               amdgpu_irq_put(adev, &adev->jpeg.inst->ras_poison_irq, 0);
 
        return 0;
 }
@@ -670,6 +671,14 @@ static int jpeg_v4_0_set_interrupt_state(struct amdgpu_device *adev,
        return 0;
 }
 
+static int jpeg_v4_0_set_ras_interrupt_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *source,
+                                       unsigned int type,
+                                       enum amdgpu_interrupt_state state)
+{
+       return 0;
+}
+
 static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev,
                                      struct amdgpu_irq_src *source,
                                      struct amdgpu_iv_entry *entry)
@@ -680,10 +689,6 @@ static int jpeg_v4_0_process_interrupt(struct amdgpu_device *adev,
        case VCN_4_0__SRCID__JPEG_DECODE:
                amdgpu_fence_process(&adev->jpeg.inst->ring_dec);
                break;
-       case VCN_4_0__SRCID_DJPEG0_POISON:
-       case VCN_4_0__SRCID_EJPEG0_POISON:
-               amdgpu_jpeg_process_poison_irq(adev, source, entry);
-               break;
        default:
                DRM_DEV_ERROR(adev->dev, "Unhandled interrupt: %d %d\n",
                          entry->src_id, entry->src_data[0]);
@@ -753,10 +758,18 @@ static const struct amdgpu_irq_src_funcs jpeg_v4_0_irq_funcs = {
        .process = jpeg_v4_0_process_interrupt,
 };
 
+static const struct amdgpu_irq_src_funcs jpeg_v4_0_ras_irq_funcs = {
+       .set = jpeg_v4_0_set_ras_interrupt_state,
+       .process = amdgpu_jpeg_process_poison_irq,
+};
+
 static void jpeg_v4_0_set_irq_funcs(struct amdgpu_device *adev)
 {
        adev->jpeg.inst->irq.num_types = 1;
        adev->jpeg.inst->irq.funcs = &jpeg_v4_0_irq_funcs;
+
+       adev->jpeg.inst->ras_poison_irq.num_types = 1;
+       adev->jpeg.inst->ras_poison_irq.funcs = &jpeg_v4_0_ras_irq_funcs;
 }
 
 const struct amdgpu_ip_block_version jpeg_v4_0_ip_block = {
@@ -811,6 +824,7 @@ const struct amdgpu_ras_block_hw_ops jpeg_v4_0_ras_hw_ops = {
 static struct amdgpu_jpeg_ras jpeg_v4_0_ras = {
        .ras_block = {
                .hw_ops = &jpeg_v4_0_ras_hw_ops,
+               .ras_late_init = amdgpu_jpeg_ras_late_init,
        },
 };
 
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 ab0b45d..515681c 100644 (file)
@@ -143,7 +143,7 @@ static int vcn_v2_5_sw_init(void *handle)
 
                /* VCN POISON TRAP */
                r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[j],
-                       VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].irq);
+                       VCN_2_6__SRCID_UVD_POISON, &adev->vcn.inst[j].ras_poison_irq);
                if (r)
                        return r;
        }
@@ -354,6 +354,9 @@ static int vcn_v2_5_hw_fini(void *handle)
                    (adev->vcn.cur_state != AMD_PG_STATE_GATE &&
                     RREG32_SOC15(VCN, i, mmUVD_STATUS)))
                        vcn_v2_5_set_powergating_state(adev, AMD_PG_STATE_GATE);
+
+               if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+                       amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
        }
 
        return 0;
@@ -1807,6 +1810,14 @@ static int vcn_v2_5_set_interrupt_state(struct amdgpu_device *adev,
        return 0;
 }
 
+static int vcn_v2_6_set_ras_interrupt_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *source,
+                                       unsigned int type,
+                                       enum amdgpu_interrupt_state state)
+{
+       return 0;
+}
+
 static int vcn_v2_5_process_interrupt(struct amdgpu_device *adev,
                                      struct amdgpu_irq_src *source,
                                      struct amdgpu_iv_entry *entry)
@@ -1837,9 +1848,6 @@ static int vcn_v2_5_process_interrupt(struct amdgpu_device *adev,
        case VCN_2_0__SRCID__UVD_ENC_LOW_LATENCY:
                amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[1]);
                break;
-       case VCN_2_6__SRCID_UVD_POISON:
-               amdgpu_vcn_process_poison_irq(adev, source, entry);
-               break;
        default:
                DRM_ERROR("Unhandled interrupt: %d %d\n",
                          entry->src_id, entry->src_data[0]);
@@ -1854,6 +1862,11 @@ static const struct amdgpu_irq_src_funcs vcn_v2_5_irq_funcs = {
        .process = vcn_v2_5_process_interrupt,
 };
 
+static const struct amdgpu_irq_src_funcs vcn_v2_6_ras_irq_funcs = {
+       .set = vcn_v2_6_set_ras_interrupt_state,
+       .process = amdgpu_vcn_process_poison_irq,
+};
+
 static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev)
 {
        int i;
@@ -1863,6 +1876,9 @@ static void vcn_v2_5_set_irq_funcs(struct amdgpu_device *adev)
                        continue;
                adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1;
                adev->vcn.inst[i].irq.funcs = &vcn_v2_5_irq_funcs;
+
+               adev->vcn.inst[i].ras_poison_irq.num_types = adev->vcn.num_enc_rings + 1;
+               adev->vcn.inst[i].ras_poison_irq.funcs = &vcn_v2_6_ras_irq_funcs;
        }
 }
 
@@ -1965,6 +1981,7 @@ const struct amdgpu_ras_block_hw_ops vcn_v2_6_ras_hw_ops = {
 static struct amdgpu_vcn_ras vcn_v2_6_ras = {
        .ras_block = {
                .hw_ops = &vcn_v2_6_ras_hw_ops,
+               .ras_late_init = amdgpu_vcn_ras_late_init,
        },
 };
 
index bf06740..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],
@@ -139,7 +143,7 @@ static int vcn_v4_0_sw_init(void *handle)
 
                /* VCN POISON TRAP */
                r = amdgpu_irq_add_id(adev, amdgpu_ih_clientid_vcns[i],
-                               VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].irq);
+                               VCN_4_0__SRCID_UVD_POISON, &adev->vcn.inst[i].ras_poison_irq);
                if (r)
                        return r;
 
@@ -305,8 +309,8 @@ static int vcn_v4_0_hw_fini(void *handle)
                         vcn_v4_0_set_powergating_state(adev, AMD_PG_STATE_GATE);
                        }
                }
-
-               amdgpu_irq_put(adev, &adev->vcn.inst[i].irq, 0);
+               if (amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__VCN))
+                       amdgpu_irq_put(adev, &adev->vcn.inst[i].ras_poison_irq, 0);
        }
 
        return 0;
@@ -1976,6 +1980,24 @@ static int vcn_v4_0_set_interrupt_state(struct amdgpu_device *adev, struct amdgp
 }
 
 /**
+ * vcn_v4_0_set_ras_interrupt_state - set VCN block RAS interrupt state
+ *
+ * @adev: amdgpu_device pointer
+ * @source: interrupt sources
+ * @type: interrupt types
+ * @state: interrupt states
+ *
+ * Set VCN block RAS interrupt state
+ */
+static int vcn_v4_0_set_ras_interrupt_state(struct amdgpu_device *adev,
+       struct amdgpu_irq_src *source,
+       unsigned int type,
+       enum amdgpu_interrupt_state state)
+{
+       return 0;
+}
+
+/**
  * vcn_v4_0_process_interrupt - process VCN block interrupt
  *
  * @adev: amdgpu_device pointer
@@ -2007,9 +2029,6 @@ static int vcn_v4_0_process_interrupt(struct amdgpu_device *adev, struct amdgpu_
        case VCN_4_0__SRCID__UVD_ENC_GENERAL_PURPOSE:
                amdgpu_fence_process(&adev->vcn.inst[ip_instance].ring_enc[0]);
                break;
-       case VCN_4_0__SRCID_UVD_POISON:
-               amdgpu_vcn_process_poison_irq(adev, source, entry);
-               break;
        default:
                DRM_ERROR("Unhandled interrupt: %d %d\n",
                          entry->src_id, entry->src_data[0]);
@@ -2024,6 +2043,11 @@ static const struct amdgpu_irq_src_funcs vcn_v4_0_irq_funcs = {
        .process = vcn_v4_0_process_interrupt,
 };
 
+static const struct amdgpu_irq_src_funcs vcn_v4_0_ras_irq_funcs = {
+       .set = vcn_v4_0_set_ras_interrupt_state,
+       .process = amdgpu_vcn_process_poison_irq,
+};
+
 /**
  * vcn_v4_0_set_irq_funcs - set VCN block interrupt irq functions
  *
@@ -2041,6 +2065,9 @@ static void vcn_v4_0_set_irq_funcs(struct amdgpu_device *adev)
 
                adev->vcn.inst[i].irq.num_types = adev->vcn.num_enc_rings + 1;
                adev->vcn.inst[i].irq.funcs = &vcn_v4_0_irq_funcs;
+
+               adev->vcn.inst[i].ras_poison_irq.num_types = adev->vcn.num_enc_rings + 1;
+               adev->vcn.inst[i].ras_poison_irq.funcs = &vcn_v4_0_ras_irq_funcs;
        }
 }
 
@@ -2114,6 +2141,7 @@ const struct amdgpu_ras_block_hw_ops vcn_v4_0_ras_hw_ops = {
 static struct amdgpu_vcn_ras vcn_v4_0_ras = {
        .ras_block = {
                .hw_ops = &vcn_v4_0_ras_hw_ops,
+               .ras_late_init = amdgpu_vcn_ras_late_init,
        },
 };
 
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 422fbf7..5403e93 100644 (file)
@@ -2113,15 +2113,6 @@ void dcn20_optimize_bandwidth(
        if (hubbub->funcs->program_compbuf_size)
                hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
 
-       if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching) {
-               dc_dmub_srv_p_state_delegate(dc,
-                       true, context);
-               context->bw_ctx.bw.dcn.clk.p_state_change_support = true;
-               dc->clk_mgr->clks.fw_based_mclk_switching = true;
-       } else {
-               dc->clk_mgr->clks.fw_based_mclk_switching = false;
-       }
-
        dc->clk_mgr->funcs->update_clocks(
                        dc->clk_mgr,
                        context,
index 8263a07..32121db 100644 (file)
@@ -983,36 +983,13 @@ void dcn30_set_disp_pattern_generator(const struct dc *dc,
 }
 
 void dcn30_prepare_bandwidth(struct dc *dc,
-       struct dc_state *context)
+                            struct dc_state *context)
 {
-       bool p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support;
-       /* Any transition into an FPO config should disable MCLK switching first to avoid
-        * driver and FW P-State synchronization issues.
-        */
-       if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) {
-               dc->optimized_required = true;
-               context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
-       }
-
        if (dc->clk_mgr->dc_mode_softmax_enabled)
                if (dc->clk_mgr->clks.dramclk_khz <= dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000 &&
                                context->bw_ctx.bw.dcn.clk.dramclk_khz > dc->clk_mgr->bw_params->dc_mode_softmax_memclk * 1000)
                        dc->clk_mgr->funcs->set_max_memclk(dc->clk_mgr, dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz);
 
        dcn20_prepare_bandwidth(dc, context);
-       /*
-        * enabled -> enabled: do not disable
-        * enabled -> disabled: disable
-        * disabled -> enabled: don't care
-        * disabled -> disabled: don't care
-        */
-       if (!context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching)
-               dc_dmub_srv_p_state_delegate(dc, false, context);
-
-       if (context->bw_ctx.bw.dcn.clk.fw_based_mclk_switching || dc->clk_mgr->clks.fw_based_mclk_switching) {
-               /* After disabling P-State, restore the original value to ensure we get the correct P-State
-                * on the next optimize. */
-               context->bw_ctx.bw.dcn.clk.p_state_change_support = p_state_change_support;
-       }
 }
 
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 d6d9e3b..02e69cc 100644 (file)
@@ -6925,23 +6925,6 @@ static int si_dpm_enable(struct amdgpu_device *adev)
        return 0;
 }
 
-static int si_set_temperature_range(struct amdgpu_device *adev)
-{
-       int ret;
-
-       ret = si_thermal_enable_alert(adev, false);
-       if (ret)
-               return ret;
-       ret = si_thermal_set_temperature_range(adev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-       if (ret)
-               return ret;
-       ret = si_thermal_enable_alert(adev, true);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-
 static void si_dpm_disable(struct amdgpu_device *adev)
 {
        struct rv7xx_power_info *pi = rv770_get_pi(adev);
@@ -7626,18 +7609,6 @@ static int si_dpm_process_interrupt(struct amdgpu_device *adev,
 
 static int si_dpm_late_init(void *handle)
 {
-       int ret;
-       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
-
-       if (!adev->pm.dpm_enabled)
-               return 0;
-
-       ret = si_set_temperature_range(adev);
-       if (ret)
-               return ret;
-#if 0 //TODO ?
-       si_dpm_powergate_uvd(adev, true);
-#endif
        return 0;
 }
 
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 7433dca..067b4e0 100644 (file)
@@ -582,7 +582,7 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
        SmuMetrics_legacy_t metrics;
        struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0;
        bool cur_value_match_level = false;
 
@@ -656,7 +656,8 @@ static int vangogh_print_legacy_clk_levels(struct smu_context *smu,
        case SMU_MCLK:
        case SMU_FCLK:
                for (i = 0; i < count; i++) {
-                       ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = vangogh_get_dpm_clk_limited(smu, clk_type, idx, &value);
                        if (ret)
                                return ret;
                        if (!value)
@@ -683,7 +684,7 @@ static int vangogh_print_clk_levels(struct smu_context *smu,
        DpmClocks_t *clk_table = smu->smu_table.clocks_table;
        SmuMetrics_t metrics;
        struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0;
        bool cur_value_match_level = false;
        uint32_t min, max;
@@ -765,7 +766,8 @@ static int vangogh_print_clk_levels(struct smu_context *smu,
        case SMU_MCLK:
        case SMU_FCLK:
                for (i = 0; i < count; i++) {
-                       ret = vangogh_get_dpm_clk_limited(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = vangogh_get_dpm_clk_limited(smu, clk_type, idx, &value);
                        if (ret)
                                return ret;
                        if (!value)
index 5cdc071..8a8ba25 100644 (file)
@@ -494,7 +494,7 @@ static int renoir_set_fine_grain_gfx_freq_parameters(struct smu_context *smu)
 static int renoir_print_clk_levels(struct smu_context *smu,
                        enum smu_clk_type clk_type, char *buf)
 {
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0;
        SmuMetrics_t metrics;
        struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm);
@@ -594,7 +594,8 @@ static int renoir_print_clk_levels(struct smu_context *smu,
        case SMU_VCLK:
        case SMU_DCLK:
                for (i = 0; i < count; i++) {
-                       ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = renoir_get_dpm_clk_limited(smu, clk_type, idx, &value);
                        if (ret)
                                return ret;
                        if (!value)
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 8fa9a36..6d9760e 100644 (file)
@@ -478,7 +478,7 @@ static int smu_v13_0_4_get_dpm_level_count(struct smu_context *smu,
 static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
                                        enum smu_clk_type clk_type, char *buf)
 {
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0;
        uint32_t min, max;
 
@@ -512,7 +512,8 @@ static int smu_v13_0_4_print_clk_levels(struct smu_context *smu,
                        break;
 
                for (i = 0; i < count; i++) {
-                       ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = smu_v13_0_4_get_dpm_freq_by_index(smu, clk_type, idx, &value);
                        if (ret)
                                break;
 
index 6644596..0081fa6 100644 (file)
@@ -866,7 +866,7 @@ out:
 static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
                                enum smu_clk_type clk_type, char *buf)
 {
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0;
        uint32_t min = 0, max = 0;
 
@@ -898,7 +898,8 @@ static int smu_v13_0_5_print_clk_levels(struct smu_context *smu,
                        goto print_clk_out;
 
                for (i = 0; i < count; i++) {
-                       ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = smu_v13_0_5_get_dpm_freq_by_index(smu, clk_type, idx, &value);
                        if (ret)
                                goto print_clk_out;
 
index 04e56b0..798f36c 100644 (file)
@@ -1000,7 +1000,7 @@ out:
 static int yellow_carp_print_clk_levels(struct smu_context *smu,
                                enum smu_clk_type clk_type, char *buf)
 {
-       int i, size = 0, ret = 0;
+       int i, idx, size = 0, ret = 0;
        uint32_t cur_value = 0, value = 0, count = 0;
        uint32_t min, max;
 
@@ -1033,7 +1033,8 @@ static int yellow_carp_print_clk_levels(struct smu_context *smu,
                        goto print_clk_out;
 
                for (i = 0; i < count; i++) {
-                       ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, i, &value);
+                       idx = (clk_type == SMU_FCLK || clk_type == SMU_MCLK) ? (count - i - 1) : i;
+                       ret = yellow_carp_get_dpm_freq_by_index(smu, clk_type, idx, &value);
                        if (ret)
                                goto print_clk_out;
 
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 050b8ae..3035cba 100644 (file)
@@ -877,12 +877,17 @@ static int gen8_append_oa_reports(struct i915_perf_stream *stream,
                        stream->oa_buffer.last_ctx_id = ctx_id;
                }
 
-               /*
-                * Clear out the report id and timestamp as a means to detect unlanded
-                * reports.
-                */
-               oa_report_id_clear(stream, report32);
-               oa_timestamp_clear(stream, report32);
+               if (is_power_of_2(report_size)) {
+                       /*
+                        * Clear out the report id and timestamp as a means
+                        * to detect unlanded reports.
+                        */
+                       oa_report_id_clear(stream, report32);
+                       oa_timestamp_clear(stream, report32);
+               } else {
+                       /* Zero out the entire report */
+                       memset(report32, 0, report_size);
+               }
        }
 
        if (start_offset != *offset) {
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 7ae5f27..c6bdb9c 100644 (file)
@@ -587,6 +587,8 @@ static const struct hid_device_id hammer_devices[] = {
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
+                    USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_JEWEL) },
+       { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) },
        { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
                     USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MASTERBALL) },
index d79e946..5d29aba 100644 (file)
 #define USB_DEVICE_ID_GOOGLE_MOONBALL  0x5044
 #define USB_DEVICE_ID_GOOGLE_DON       0x5050
 #define USB_DEVICE_ID_GOOGLE_EEL       0x5057
+#define USB_DEVICE_ID_GOOGLE_JEWEL     0x5061
 
 #define USB_VENDOR_ID_GOTOP            0x08f2
 #define USB_DEVICE_ID_SUPER_Q2         0x007f
index 0fcfd85..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,13 +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;
+                       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 ||
@@ -329,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 8214896..76e5353 100644 (file)
@@ -2224,7 +2224,9 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
                } else if (strstr(product_name, "Wacom") ||
                           strstr(product_name, "wacom") ||
                           strstr(product_name, "WACOM")) {
-                       strscpy(name, product_name, sizeof(name));
+                       if (strscpy(name, product_name, sizeof(name)) < 0) {
+                               hid_warn(wacom->hdev, "String overflow while assembling device name");
+                       }
                } else {
                        snprintf(name, sizeof(name), "Wacom %s", product_name);
                }
@@ -2242,7 +2244,9 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
                if (name[strlen(name)-1] == ' ')
                        name[strlen(name)-1] = '\0';
        } else {
-               strscpy(name, features->name, sizeof(name));
+               if (strscpy(name, features->name, sizeof(name)) < 0) {
+                       hid_warn(wacom->hdev, "String overflow while assembling device name");
+               }
        }
 
        snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s%s",
@@ -2410,8 +2414,13 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless)
                goto fail_quirks;
        }
 
-       if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR)
+       if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) {
                error = hid_hw_open(hdev);
+               if (error) {
+                       hid_err(hdev, "hw open failed\n");
+                       goto fail_quirks;
+               }
+       }
 
        wacom_set_shared_values(wacom_wac);
        devres_close_group(&hdev->dev, wacom);
@@ -2500,8 +2509,10 @@ static void wacom_wireless_work(struct work_struct *work)
                                goto fail;
                }
 
-               strscpy(wacom_wac->name, wacom_wac1->name,
-                       sizeof(wacom_wac->name));
+               if (strscpy(wacom_wac->name, wacom_wac1->name,
+                       sizeof(wacom_wac->name)) < 0) {
+                       hid_warn(wacom->hdev, "String overflow while assembling device name");
+               }
        }
 
        return;
index dc0f7d9..2ccf838 100644 (file)
@@ -831,7 +831,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
        /* Enter report */
        if ((data[1] & 0xfc) == 0xc0) {
                /* serial number of the tool */
-               wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+               wacom->serial[idx] = ((__u64)(data[3] & 0x0f) << 28) +
                        (data[4] << 20) + (data[5] << 12) +
                        (data[6] << 4) + (data[7] >> 4);
 
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 f98393d..b8636fa 100644 (file)
@@ -1048,7 +1048,7 @@ int kx022a_probe_internal(struct device *dev)
                data->ien_reg = KX022A_REG_INC4;
        } else {
                irq = fwnode_irq_get_byname(fwnode, "INT2");
-               if (irq <= 0)
+               if (irq < 0)
                        return dev_err_probe(dev, irq, "No suitable IRQ\n");
 
                data->inc_reg = KX022A_REG_INC5;
index 5f7d81b..282e539 100644 (file)
@@ -1291,12 +1291,12 @@ static int apply_acpi_orientation(struct iio_dev *indio_dev)
 
        adev = ACPI_COMPANION(indio_dev->dev.parent);
        if (!adev)
-               return 0;
+               return -ENXIO;
 
        /* Read _ONT data, which should be a package of 6 integers. */
        status = acpi_evaluate_object(adev->handle, "_ONT", NULL, &buffer);
        if (status == AE_NOT_FOUND) {
-               return 0;
+               return -ENXIO;
        } else if (ACPI_FAILURE(status)) {
                dev_warn(&indio_dev->dev, "failed to execute _ONT: %d\n",
                         status);
index 3839434..5a5dd5e 100644 (file)
@@ -1817,6 +1817,11 @@ static const struct clk_ops ad4130_int_clk_ops = {
        .unprepare = ad4130_int_clk_unprepare,
 };
 
+static void ad4130_clk_del_provider(void *of_node)
+{
+       of_clk_del_provider(of_node);
+}
+
 static int ad4130_setup_int_clk(struct ad4130_state *st)
 {
        struct device *dev = &st->spi->dev;
@@ -1824,6 +1829,7 @@ static int ad4130_setup_int_clk(struct ad4130_state *st)
        struct clk_init_data init;
        const char *clk_name;
        struct clk *clk;
+       int ret;
 
        if (st->int_pin_sel == AD4130_INT_PIN_CLK ||
            st->mclk_sel != AD4130_MCLK_76_8KHZ)
@@ -1843,7 +1849,11 @@ static int ad4130_setup_int_clk(struct ad4130_state *st)
        if (IS_ERR(clk))
                return PTR_ERR(clk);
 
-       return of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+       ret = of_clk_add_provider(of_node, of_clk_src_simple_get, clk);
+       if (ret)
+               return ret;
+
+       return devm_add_action_or_reset(dev, ad4130_clk_del_provider, of_node);
 }
 
 static int ad4130_setup(struct iio_dev *indio_dev)
index 55a6ab5..99bb604 100644 (file)
@@ -897,10 +897,6 @@ static const struct iio_info ad7195_info = {
        __AD719x_CHANNEL(_si, _channel1, -1, _address, NULL, IIO_VOLTAGE, \
                BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
 
-#define AD719x_SHORTED_CHANNEL(_si, _channel1, _address) \
-       __AD719x_CHANNEL(_si, _channel1, -1, _address, "shorted", IIO_VOLTAGE, \
-               BIT(IIO_CHAN_INFO_SCALE), ad7192_calibsys_ext_info)
-
 #define AD719x_TEMP_CHANNEL(_si, _address) \
        __AD719x_CHANNEL(_si, 0, -1, _address, NULL, IIO_TEMP, 0, NULL)
 
@@ -908,7 +904,7 @@ static const struct iio_chan_spec ad7192_channels[] = {
        AD719x_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M),
        AD719x_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M),
        AD719x_TEMP_CHANNEL(2, AD7192_CH_TEMP),
-       AD719x_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M),
+       AD719x_DIFF_CHANNEL(3, 2, 2, AD7192_CH_AIN2P_AIN2M),
        AD719x_CHANNEL(4, 1, AD7192_CH_AIN1),
        AD719x_CHANNEL(5, 2, AD7192_CH_AIN2),
        AD719x_CHANNEL(6, 3, AD7192_CH_AIN3),
@@ -922,7 +918,7 @@ static const struct iio_chan_spec ad7193_channels[] = {
        AD719x_DIFF_CHANNEL(2, 5, 6, AD7193_CH_AIN5P_AIN6M),
        AD719x_DIFF_CHANNEL(3, 7, 8, AD7193_CH_AIN7P_AIN8M),
        AD719x_TEMP_CHANNEL(4, AD7193_CH_TEMP),
-       AD719x_SHORTED_CHANNEL(5, 2, AD7193_CH_AIN2P_AIN2M),
+       AD719x_DIFF_CHANNEL(5, 2, 2, AD7193_CH_AIN2P_AIN2M),
        AD719x_CHANNEL(6, 1, AD7193_CH_AIN1),
        AD719x_CHANNEL(7, 2, AD7193_CH_AIN2),
        AD719x_CHANNEL(8, 3, AD7193_CH_AIN3),
index d8570f6..7e21928 100644 (file)
@@ -584,6 +584,10 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
        init_completion(&sigma_delta->completion);
 
        sigma_delta->irq_dis = true;
+
+       /* the IRQ core clears IRQ_DISABLE_UNLAZY flag when freeing an IRQ */
+       irq_set_status_flags(sigma_delta->spi->irq, IRQ_DISABLE_UNLAZY);
+
        ret = devm_request_irq(dev, sigma_delta->spi->irq,
                               ad_sd_data_rdy_trig_poll,
                               sigma_delta->info->irq_flags | IRQF_NO_AUTOEN,
index a775d2e..dce9ec9 100644 (file)
@@ -236,8 +236,7 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev,
 {
        struct imx93_adc *adc = iio_priv(indio_dev);
        struct device *dev = adc->dev;
-       long ret;
-       u32 vref_uv;
+       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
@@ -253,10 +252,10 @@ static int imx93_adc_read_raw(struct iio_dev *indio_dev,
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
-               ret = vref_uv = regulator_get_voltage(adc->vref);
+               ret = regulator_get_voltage(adc->vref);
                if (ret < 0)
                        return ret;
-               *val = vref_uv / 1000;
+               *val = ret / 1000;
                *val2 = 12;
                return IIO_VAL_FRACTIONAL_LOG2;
 
index bc62e5a..0bc1121 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <dt-bindings/iio/adc/mediatek,mt6370_adc.h>
 
+#define MT6370_REG_DEV_INFO            0x100
 #define MT6370_REG_CHG_CTRL3           0x113
 #define MT6370_REG_CHG_CTRL7           0x117
 #define MT6370_REG_CHG_ADC             0x121
@@ -27,6 +28,7 @@
 #define MT6370_ADC_START_MASK          BIT(0)
 #define MT6370_ADC_IN_SEL_MASK         GENMASK(7, 4)
 #define MT6370_AICR_ICHG_MASK          GENMASK(7, 2)
+#define MT6370_VENID_MASK              GENMASK(7, 4)
 
 #define MT6370_AICR_100_mA             0x0
 #define MT6370_AICR_150_mA             0x1
 #define ADC_CONV_TIME_MS               35
 #define ADC_CONV_POLLING_TIME_US       1000
 
+#define MT6370_VID_RT5081              0x8
+#define MT6370_VID_RT5081A             0xA
+#define MT6370_VID_MT6370              0xE
+
 struct mt6370_adc_data {
        struct device *dev;
        struct regmap *regmap;
@@ -55,6 +61,7 @@ struct mt6370_adc_data {
         * from being read at the same time.
         */
        struct mutex adc_lock;
+       unsigned int vid;
 };
 
 static int mt6370_adc_read_channel(struct mt6370_adc_data *priv, int chan,
@@ -98,6 +105,30 @@ adc_unlock:
        return ret;
 }
 
+static int mt6370_adc_get_ibus_scale(struct mt6370_adc_data *priv)
+{
+       switch (priv->vid) {
+       case MT6370_VID_RT5081:
+       case MT6370_VID_RT5081A:
+       case MT6370_VID_MT6370:
+               return 3350;
+       default:
+               return 3875;
+       }
+}
+
+static int mt6370_adc_get_ibat_scale(struct mt6370_adc_data *priv)
+{
+       switch (priv->vid) {
+       case MT6370_VID_RT5081:
+       case MT6370_VID_RT5081A:
+       case MT6370_VID_MT6370:
+               return 2680;
+       default:
+               return 3870;
+       }
+}
+
 static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
                                 int chan, int *val1, int *val2)
 {
@@ -123,7 +154,7 @@ static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
                case MT6370_AICR_250_mA:
                case MT6370_AICR_300_mA:
                case MT6370_AICR_350_mA:
-                       *val1 = 3350;
+                       *val1 = mt6370_adc_get_ibus_scale(priv);
                        break;
                default:
                        *val1 = 5000;
@@ -150,7 +181,7 @@ static int mt6370_adc_read_scale(struct mt6370_adc_data *priv,
                case MT6370_ICHG_600_mA:
                case MT6370_ICHG_700_mA:
                case MT6370_ICHG_800_mA:
-                       *val1 = 2680;
+                       *val1 = mt6370_adc_get_ibat_scale(priv);
                        break;
                default:
                        *val1 = 5000;
@@ -251,6 +282,20 @@ static const struct iio_chan_spec mt6370_adc_channels[] = {
        MT6370_ADC_CHAN(TEMP_JC, IIO_TEMP, 12, BIT(IIO_CHAN_INFO_OFFSET)),
 };
 
+static int mt6370_get_vendor_info(struct mt6370_adc_data *priv)
+{
+       unsigned int dev_info;
+       int ret;
+
+       ret = regmap_read(priv->regmap, MT6370_REG_DEV_INFO, &dev_info);
+       if (ret)
+               return ret;
+
+       priv->vid = FIELD_GET(MT6370_VENID_MASK, dev_info);
+
+       return 0;
+}
+
 static int mt6370_adc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -272,6 +317,10 @@ static int mt6370_adc_probe(struct platform_device *pdev)
        priv->regmap = regmap;
        mutex_init(&priv->adc_lock);
 
+       ret = mt6370_get_vendor_info(priv);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to get vid\n");
+
        ret = regmap_write(priv->regmap, MT6370_REG_CHG_ADC, 0);
        if (ret)
                return dev_err_probe(dev, ret, "Failed to reset ADC\n");
index bca79a9..a50f391 100644 (file)
@@ -757,13 +757,13 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
 
        ret = mxs_lradc_adc_trigger_init(iio);
        if (ret)
-               goto err_trig;
+               return ret;
 
        ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
                                         &mxs_lradc_adc_trigger_handler,
                                         &mxs_lradc_adc_buffer_ops);
        if (ret)
-               return ret;
+               goto err_trig;
 
        adc->vref_mv = mxs_lradc_adc_vref_mv[lradc->soc];
 
@@ -801,9 +801,9 @@ static int mxs_lradc_adc_probe(struct platform_device *pdev)
 
 err_dev:
        mxs_lradc_adc_hw_stop(adc);
-       mxs_lradc_adc_trigger_remove(iio);
-err_trig:
        iio_triggered_buffer_cleanup(iio);
+err_trig:
+       mxs_lradc_adc_trigger_remove(iio);
        return ret;
 }
 
@@ -814,8 +814,8 @@ static int mxs_lradc_adc_remove(struct platform_device *pdev)
 
        iio_device_unregister(iio);
        mxs_lradc_adc_hw_stop(adc);
-       mxs_lradc_adc_trigger_remove(iio);
        iio_triggered_buffer_cleanup(iio);
+       mxs_lradc_adc_trigger_remove(iio);
 
        return 0;
 }
index c1c4392..7dfc9c9 100644 (file)
@@ -547,7 +547,7 @@ static int palmas_gpadc_read_raw(struct iio_dev *indio_dev,
        int adc_chan = chan->channel;
        int ret = 0;
 
-       if (adc_chan > PALMAS_ADC_CH_MAX)
+       if (adc_chan >= PALMAS_ADC_CH_MAX)
                return -EINVAL;
 
        mutex_lock(&adc->lock);
@@ -595,7 +595,7 @@ static int palmas_gpadc_read_event_config(struct iio_dev *indio_dev,
        int adc_chan = chan->channel;
        int ret = 0;
 
-       if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
+       if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
                return -EINVAL;
 
        mutex_lock(&adc->lock);
@@ -684,7 +684,7 @@ static int palmas_gpadc_write_event_config(struct iio_dev *indio_dev,
        int adc_chan = chan->channel;
        int ret;
 
-       if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
+       if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
                return -EINVAL;
 
        mutex_lock(&adc->lock);
@@ -710,7 +710,7 @@ static int palmas_gpadc_read_event_value(struct iio_dev *indio_dev,
        int adc_chan = chan->channel;
        int ret;
 
-       if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
+       if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
                return -EINVAL;
 
        mutex_lock(&adc->lock);
@@ -744,7 +744,7 @@ static int palmas_gpadc_write_event_value(struct iio_dev *indio_dev,
        int old;
        int ret;
 
-       if (adc_chan > PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
+       if (adc_chan >= PALMAS_ADC_CH_MAX || type != IIO_EV_TYPE_THRESH)
                return -EINVAL;
 
        mutex_lock(&adc->lock);
index 1aadb2a..bd7e240 100644 (file)
@@ -2006,16 +2006,15 @@ static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm
         * to get the *real* number of channels.
         */
        ret = device_property_count_u32(dev, "st,adc-diff-channels");
-       if (ret < 0)
-               return ret;
-
-       ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32));
-       if (ret > adc_info->max_channels) {
-               dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
-               return -EINVAL;
-       } else if (ret > 0) {
-               adc->num_diff = ret;
-               num_channels += ret;
+       if (ret > 0) {
+               ret /= (int)(sizeof(struct stm32_adc_diff_channel) / sizeof(u32));
+               if (ret > adc_info->max_channels) {
+                       dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
+                       return -EINVAL;
+               } else if (ret > 0) {
+                       adc->num_diff = ret;
+                       num_channels += ret;
+               }
        }
 
        /* Optional sample time is provided either for each, or all channels */
@@ -2037,6 +2036,7 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
        struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
        struct device *dev = &indio_dev->dev;
        u32 num_diff = adc->num_diff;
+       int num_se = nchans - num_diff;
        int size = num_diff * sizeof(*diff) / sizeof(u32);
        int scan_index = 0, ret, i, c;
        u32 smp = 0, smps[STM32_ADC_CH_MAX], chans[STM32_ADC_CH_MAX];
@@ -2063,29 +2063,32 @@ static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
                        scan_index++;
                }
        }
-
-       ret = device_property_read_u32_array(dev, "st,adc-channels", chans,
-                                            nchans);
-       if (ret)
-               return ret;
-
-       for (c = 0; c < nchans; c++) {
-               if (chans[c] >= adc_info->max_channels) {
-                       dev_err(&indio_dev->dev, "Invalid channel %d\n",
-                               chans[c]);
-                       return -EINVAL;
+       if (num_se > 0) {
+               ret = device_property_read_u32_array(dev, "st,adc-channels", chans, num_se);
+               if (ret) {
+                       dev_err(&indio_dev->dev, "Failed to get st,adc-channels %d\n", ret);
+                       return ret;
                }
 
-               /* Channel can't be configured both as single-ended & diff */
-               for (i = 0; i < num_diff; i++) {
-                       if (chans[c] == diff[i].vinp) {
-                               dev_err(&indio_dev->dev, "channel %d misconfigured\n",  chans[c]);
+               for (c = 0; c < num_se; c++) {
+                       if (chans[c] >= adc_info->max_channels) {
+                               dev_err(&indio_dev->dev, "Invalid channel %d\n",
+                                       chans[c]);
                                return -EINVAL;
                        }
+
+                       /* Channel can't be configured both as single-ended & diff */
+                       for (i = 0; i < num_diff; i++) {
+                               if (chans[c] == diff[i].vinp) {
+                                       dev_err(&indio_dev->dev, "channel %d misconfigured\n",
+                                               chans[c]);
+                                       return -EINVAL;
+                               }
+                       }
+                       stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
+                                               chans[c], 0, scan_index, false);
+                       scan_index++;
                }
-               stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
-                                       chans[c], 0, scan_index, false);
-               scan_index++;
        }
 
        if (adc->nsmps > 0) {
@@ -2306,7 +2309,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping)
 
        if (legacy)
                ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels,
-                                                num_channels);
+                                                timestamping ? num_channels - 1 : num_channels);
        else
                ret = stm32_adc_generic_chan_init(indio_dev, adc, channels);
        if (ret < 0)
index 07e9f6a..e3366cf 100644 (file)
@@ -1007,7 +1007,7 @@ static int ad74413r_read_raw(struct iio_dev *indio_dev,
 
                ret = ad74413r_get_single_adc_result(indio_dev, chan->channel,
                                                     val);
-               if (ret)
+               if (ret < 0)
                        return ret;
 
                ad74413r_adc_to_resistance_result(*val, val);
index 6c74fea..addd97a 100644 (file)
@@ -17,7 +17,7 @@ obj-$(CONFIG_AD5592R_BASE) += ad5592r-base.o
 obj-$(CONFIG_AD5592R) += ad5592r.o
 obj-$(CONFIG_AD5593R) += ad5593r.o
 obj-$(CONFIG_AD5755) += ad5755.o
-obj-$(CONFIG_AD5755) += ad5758.o
+obj-$(CONFIG_AD5758) += ad5758.o
 obj-$(CONFIG_AD5761) += ad5761.o
 obj-$(CONFIG_AD5764) += ad5764.o
 obj-$(CONFIG_AD5766) += ad5766.o
index 46bf758..3f5661a 100644 (file)
@@ -47,12 +47,18 @@ static int mcp4725_suspend(struct device *dev)
        struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
                to_i2c_client(dev)));
        u8 outbuf[2];
+       int ret;
 
        outbuf[0] = (data->powerdown_mode + 1) << 4;
        outbuf[1] = 0;
        data->powerdown = true;
 
-       return i2c_master_send(data->client, outbuf, 2);
+       ret = i2c_master_send(data->client, outbuf, 2);
+       if (ret < 0)
+               return ret;
+       else if (ret != 2)
+               return -EIO;
+       return 0;
 }
 
 static int mcp4725_resume(struct device *dev)
@@ -60,13 +66,19 @@ static int mcp4725_resume(struct device *dev)
        struct mcp4725_data *data = iio_priv(i2c_get_clientdata(
                to_i2c_client(dev)));
        u8 outbuf[2];
+       int ret;
 
        /* restore previous DAC value */
        outbuf[0] = (data->dac_value >> 8) & 0xf;
        outbuf[1] = data->dac_value & 0xff;
        data->powerdown = false;
 
-       return i2c_master_send(data->client, outbuf, 2);
+       ret = i2c_master_send(data->client, outbuf, 2);
+       if (ret < 0)
+               return ret;
+       else if (ret != 2)
+               return -EIO;
+       return 0;
 }
 static DEFINE_SIMPLE_DEV_PM_OPS(mcp4725_pm_ops, mcp4725_suspend,
                                mcp4725_resume);
index 99576b2..32d7f83 100644 (file)
@@ -275,9 +275,14 @@ static int inv_icm42600_buffer_preenable(struct iio_dev *indio_dev)
 {
        struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev);
        struct device *dev = regmap_get_device(st->map);
+       struct inv_icm42600_timestamp *ts = iio_priv(indio_dev);
 
        pm_runtime_get_sync(dev);
 
+       mutex_lock(&st->lock);
+       inv_icm42600_timestamp_reset(ts);
+       mutex_unlock(&st->lock);
+
        return 0;
 }
 
@@ -375,7 +380,6 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
        struct device *dev = regmap_get_device(st->map);
        unsigned int sensor;
        unsigned int *watermark;
-       struct inv_icm42600_timestamp *ts;
        struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT;
        unsigned int sleep_temp = 0;
        unsigned int sleep_sensor = 0;
@@ -385,11 +389,9 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
        if (indio_dev == st->indio_gyro) {
                sensor = INV_ICM42600_SENSOR_GYRO;
                watermark = &st->fifo.watermark.gyro;
-               ts = iio_priv(st->indio_gyro);
        } else if (indio_dev == st->indio_accel) {
                sensor = INV_ICM42600_SENSOR_ACCEL;
                watermark = &st->fifo.watermark.accel;
-               ts = iio_priv(st->indio_accel);
        } else {
                return -EINVAL;
        }
@@ -417,8 +419,6 @@ static int inv_icm42600_buffer_postdisable(struct iio_dev *indio_dev)
        if (!st->fifo.on)
                ret = inv_icm42600_set_temp_conf(st, false, &sleep_temp);
 
-       inv_icm42600_timestamp_reset(ts);
-
 out_unlock:
        mutex_unlock(&st->lock);
 
index 8bb6897..7653261 100644 (file)
@@ -337,6 +337,17 @@ free_gains:
        return ret;
 }
 
+static void iio_gts_us_to_int_micro(int *time_us, int *int_micro_times,
+                                   int num_times)
+{
+       int i;
+
+       for (i = 0; i < num_times; i++) {
+               int_micro_times[i * 2] = time_us[i] / 1000000;
+               int_micro_times[i * 2 + 1] = time_us[i] % 1000000;
+       }
+}
+
 /**
  * iio_gts_build_avail_time_table - build table of available integration times
  * @gts:       Gain time scale descriptor
@@ -351,7 +362,7 @@ free_gains:
  */
 static int iio_gts_build_avail_time_table(struct iio_gts *gts)
 {
-       int *times, i, j, idx = 0;
+       int *times, i, j, idx = 0, *int_micro_times;
 
        if (!gts->num_itime)
                return 0;
@@ -378,13 +389,24 @@ static int iio_gts_build_avail_time_table(struct iio_gts *gts)
                        }
                }
        }
-       gts->avail_time_tables = times;
-       /*
-        * This is just to survive a unlikely corner-case where times in the
-        * given time table were not unique. Else we could just trust the
-        * gts->num_itime.
-        */
-       gts->num_avail_time_tables = idx;
+
+       /* create a list of times formatted as list of IIO_VAL_INT_PLUS_MICRO */
+       int_micro_times = kcalloc(idx, sizeof(int) * 2, GFP_KERNEL);
+       if (int_micro_times) {
+               /*
+                * This is just to survive a unlikely corner-case where times in
+                * the given time table were not unique. Else we could just
+                * trust the gts->num_itime.
+                */
+               gts->num_avail_time_tables = idx;
+               iio_gts_us_to_int_micro(times, int_micro_times, idx);
+       }
+
+       gts->avail_time_tables = int_micro_times;
+       kfree(times);
+
+       if (!int_micro_times)
+               return -ENOMEM;
 
        return 0;
 }
@@ -683,8 +705,8 @@ int iio_gts_avail_times(struct iio_gts *gts,  const int **vals, int *type,
                return -EINVAL;
 
        *vals = gts->avail_time_tables;
-       *type = IIO_VAL_INT;
-       *length = gts->num_avail_time_tables;
+       *type = IIO_VAL_INT_PLUS_MICRO;
+       *length = gts->num_avail_time_tables * 2;
 
        return IIO_AVAIL_LIST;
 }
index e486dcf..f85194f 100644 (file)
@@ -231,6 +231,9 @@ struct bu27034_result {
 
 static const struct regmap_range bu27034_volatile_ranges[] = {
        {
+               .range_min = BU27034_REG_SYSTEM_CONTROL,
+               .range_max = BU27034_REG_SYSTEM_CONTROL,
+       }, {
                .range_min = BU27034_REG_MODE_CONTROL4,
                .range_max = BU27034_REG_MODE_CONTROL4,
        }, {
@@ -1167,11 +1170,12 @@ static int bu27034_read_raw(struct iio_dev *idev,
 
        switch (mask) {
        case IIO_CHAN_INFO_INT_TIME:
-               *val = bu27034_get_int_time(data);
-               if (*val < 0)
-                       return *val;
+               *val = 0;
+               *val2 = bu27034_get_int_time(data);
+               if (*val2 < 0)
+                       return *val2;
 
-               return IIO_VAL_INT;
+               return IIO_VAL_INT_PLUS_MICRO;
 
        case IIO_CHAN_INFO_SCALE:
                return bu27034_get_scale(data, chan->channel, val, val2);
@@ -1229,7 +1233,10 @@ static int bu27034_write_raw(struct iio_dev *idev,
                ret = bu27034_set_scale(data, chan->channel, val, val2);
                break;
        case IIO_CHAN_INFO_INT_TIME:
-               ret = bu27034_try_set_int_time(data, val);
+               if (!val)
+                       ret = bu27034_try_set_int_time(data, val2);
+               else
+                       ret = -EINVAL;
                break;
        default:
                ret = -EINVAL;
@@ -1268,12 +1275,19 @@ static int bu27034_chip_init(struct bu27034_data *data)
        int ret, sel;
 
        /* Reset */
-       ret = regmap_update_bits(data->regmap, BU27034_REG_SYSTEM_CONTROL,
+       ret = regmap_write_bits(data->regmap, BU27034_REG_SYSTEM_CONTROL,
                           BU27034_MASK_SW_RESET, BU27034_MASK_SW_RESET);
        if (ret)
                return dev_err_probe(data->dev, ret, "Sensor reset failed\n");
 
        msleep(1);
+
+       ret = regmap_reinit_cache(data->regmap, &bu27034_regmap);
+       if (ret) {
+               dev_err(data->dev, "Failed to reinit reg cache\n");
+               return ret;
+       }
+
        /*
         * Read integration time here to ensure it is in regmap cache. We do
         * this to speed-up the int-time acquisition in the start of the buffer
index 14e2933..94f5d61 100644 (file)
@@ -8,6 +8,7 @@
  * TODO: Proximity
  */
 #include <linux/bitops.h>
+#include <linux/bitfield.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/pm_runtime.h>
@@ -42,6 +43,7 @@
 #define VCNL4035_ALS_PERS_MASK         GENMASK(3, 2)
 #define VCNL4035_INT_ALS_IF_H_MASK     BIT(12)
 #define VCNL4035_INT_ALS_IF_L_MASK     BIT(13)
+#define VCNL4035_DEV_ID_MASK           GENMASK(7, 0)
 
 /* Default values */
 #define VCNL4035_MODE_ALS_ENABLE       BIT(0)
@@ -413,6 +415,7 @@ static int vcnl4035_init(struct vcnl4035_data *data)
                return ret;
        }
 
+       id = FIELD_GET(VCNL4035_DEV_ID_MASK, id);
        if (id != VCNL4035_DEV_ID_VAL) {
                dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
                        id, VCNL4035_DEV_ID_VAL);
index 28bb7ef..e155a75 100644 (file)
@@ -296,12 +296,13 @@ static int tmag5273_read_raw(struct iio_dev *indio_dev,
                        return ret;
 
                ret = tmag5273_get_measure(data, &t, &x, &y, &z, &angle, &magnitude);
-               if (ret)
-                       return ret;
 
                pm_runtime_mark_last_busy(data->dev);
                pm_runtime_put_autosuspend(data->dev);
 
+               if (ret)
+                       return ret;
+
                switch (chan->address) {
                case TEMPERATURE:
                        *val = t;
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 e86afec..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,
@@ -3341,9 +3342,7 @@ static int bnxt_re_process_raw_qp_pkt_rx(struct bnxt_re_qp *gsi_qp,
        udwr.remote_qkey = gsi_sqp->qplib_qp.qkey;
 
        /* post data received  in the send queue */
-       rc = bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr);
-
-       return 0;
+       return bnxt_re_post_send_shadow_qp(rdev, gsi_sqp, swr);
 }
 
 static void bnxt_re_process_res_rawqp1_wc(struct ib_wc *wc,
index b9e2f89..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) ?
@@ -1336,6 +1334,10 @@ static void bnxt_re_setup_cc(struct bnxt_re_dev *rdev, bool enable)
 {
        struct bnxt_qplib_cc_param cc_param = {};
 
+       /* Do not enable congestion control on VFs */
+       if (rdev->is_virtfn)
+               return;
+
        /* Currently enabling only for GenP5 adapters */
        if (!bnxt_qplib_is_chip_gen_p5(rdev->chip_ctx))
                return;
index f139d4c..8974f62 100644 (file)
@@ -2056,6 +2056,12 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
        u32 pg_sz_lvl;
        int rc;
 
+       if (!cq->dpi) {
+               dev_err(&rcfw->pdev->dev,
+                       "FP: CREATE_CQ failed due to NULL DPI\n");
+               return -EINVAL;
+       }
+
        hwq_attr.res = res;
        hwq_attr.depth = cq->max_wqe;
        hwq_attr.stride = sizeof(struct cq_base);
@@ -2069,11 +2075,6 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
                                 CMDQ_BASE_OPCODE_CREATE_CQ,
                                 sizeof(req));
 
-       if (!cq->dpi) {
-               dev_err(&rcfw->pdev->dev,
-                       "FP: CREATE_CQ failed due to NULL DPI\n");
-               return -EINVAL;
-       }
        req.dpi = cpu_to_le32(cq->dpi->dpi);
        req.cq_handle = cpu_to_le64(cq->cq_handle);
        req.cq_size = cpu_to_le32(cq->hwq.max_elements);
index 126d4f2..81b0c5e 100644 (file)
@@ -215,17 +215,9 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq,
                        return -EINVAL;
                hwq_attr->sginfo->npages = npages;
        } else {
-               unsigned long sginfo_num_pages = ib_umem_num_dma_blocks(
-                       hwq_attr->sginfo->umem, hwq_attr->sginfo->pgsize);
-
+               npages = ib_umem_num_dma_blocks(hwq_attr->sginfo->umem,
+                                               hwq_attr->sginfo->pgsize);
                hwq->is_user = true;
-               npages = sginfo_num_pages;
-               npages = (npages * PAGE_SIZE) /
-                         BIT_ULL(hwq_attr->sginfo->pgshft);
-               if ((sginfo_num_pages * PAGE_SIZE) %
-                    BIT_ULL(hwq_attr->sginfo->pgshft))
-                       if (!npages)
-                               npages++;
        }
 
        if (npages == MAX_PBL_LVL_0_PGS && !hwq_attr->sginfo->nopte) {
index 1714a1e..b967a17 100644 (file)
@@ -617,16 +617,15 @@ int bnxt_qplib_reg_mr(struct bnxt_qplib_res *res, struct bnxt_qplib_mrw *mr,
                /* Free the hwq if it already exist, must be a rereg */
                if (mr->hwq.max_elements)
                        bnxt_qplib_free_hwq(res, &mr->hwq);
-               /* Use system PAGE_SIZE */
                hwq_attr.res = res;
                hwq_attr.depth = pages;
-               hwq_attr.stride = buf_pg_size;
+               hwq_attr.stride = sizeof(dma_addr_t);
                hwq_attr.type = HWQ_TYPE_MR;
                hwq_attr.sginfo = &sginfo;
                hwq_attr.sginfo->umem = umem;
                hwq_attr.sginfo->npages = pages;
-               hwq_attr.sginfo->pgsize = PAGE_SIZE;
-               hwq_attr.sginfo->pgshft = PAGE_SHIFT;
+               hwq_attr.sginfo->pgsize = buf_pg_size;
+               hwq_attr.sginfo->pgshft = ilog2(buf_pg_size);
                rc = bnxt_qplib_alloc_init_hwq(&mr->hwq, &hwq_attr);
                if (rc) {
                        dev_err(&res->pdev->dev,
index 8eca6c1..2a195c4 100644 (file)
@@ -1403,7 +1403,7 @@ static int pbl_continuous_initialize(struct efa_dev *dev,
  */
 static int pbl_indirect_initialize(struct efa_dev *dev, struct pbl_context *pbl)
 {
-       u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, PAGE_SIZE);
+       u32 size_in_pages = DIV_ROUND_UP(pbl->pbl_buf_size_in_bytes, EFA_CHUNK_PAYLOAD_SIZE);
        struct scatterlist *sgl;
        int sg_dma_cnt, err;
 
index 84f1167..d4c6b9b 100644 (file)
@@ -4583,11 +4583,9 @@ static int modify_qp_init_to_rtr(struct ib_qp *ibqp,
        mtu = ib_mtu_enum_to_int(ib_mtu);
        if (WARN_ON(mtu <= 0))
                return -EINVAL;
-#define MAX_LP_MSG_LEN 16384
-       /* MTU * (2 ^ LP_PKTN_INI) shouldn't be bigger than 16KB */
-       lp_pktn_ini = ilog2(MAX_LP_MSG_LEN / mtu);
-       if (WARN_ON(lp_pktn_ini >= 0xF))
-               return -EINVAL;
+#define MIN_LP_MSG_LEN 1024
+       /* mtu * (2 ^ lp_pktn_ini) should be in the range of 1024 to mtu */
+       lp_pktn_ini = ilog2(max(mtu, MIN_LP_MSG_LEN) / mtu);
 
        if (attr_mask & IB_QP_PATH_MTU) {
                hr_reg_write(context, QPC_MTU, ib_mtu);
@@ -5012,7 +5010,6 @@ static int hns_roce_v2_set_abs_fields(struct ib_qp *ibqp,
 static bool check_qp_timeout_cfg_range(struct hns_roce_dev *hr_dev, u8 *timeout)
 {
 #define QP_ACK_TIMEOUT_MAX_HIP08 20
-#define QP_ACK_TIMEOUT_OFFSET 10
 #define QP_ACK_TIMEOUT_MAX 31
 
        if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08) {
@@ -5021,7 +5018,7 @@ static bool check_qp_timeout_cfg_range(struct hns_roce_dev *hr_dev, u8 *timeout)
                                   "local ACK timeout shall be 0 to 20.\n");
                        return false;
                }
-               *timeout += QP_ACK_TIMEOUT_OFFSET;
+               *timeout += HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08;
        } else if (hr_dev->pci_dev->revision > PCI_REVISION_ID_HIP08) {
                if (*timeout > QP_ACK_TIMEOUT_MAX) {
                        ibdev_warn(&hr_dev->ib_dev,
@@ -5307,6 +5304,18 @@ out:
        return ret;
 }
 
+static u8 get_qp_timeout_attr(struct hns_roce_dev *hr_dev,
+                             struct hns_roce_v2_qp_context *context)
+{
+       u8 timeout;
+
+       timeout = (u8)hr_reg_read(context, QPC_AT);
+       if (hr_dev->pci_dev->revision == PCI_REVISION_ID_HIP08)
+               timeout -= HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08;
+
+       return timeout;
+}
+
 static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
                                int qp_attr_mask,
                                struct ib_qp_init_attr *qp_init_attr)
@@ -5384,7 +5393,7 @@ static int hns_roce_v2_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr,
        qp_attr->max_dest_rd_atomic = 1 << hr_reg_read(&context, QPC_RR_MAX);
 
        qp_attr->min_rnr_timer = (u8)hr_reg_read(&context, QPC_MIN_RNR_TIME);
-       qp_attr->timeout = (u8)hr_reg_read(&context, QPC_AT);
+       qp_attr->timeout = get_qp_timeout_attr(hr_dev, &context);
        qp_attr->retry_cnt = hr_reg_read(&context, QPC_RETRY_NUM_INIT);
        qp_attr->rnr_retry = hr_reg_read(&context, QPC_RNR_NUM_INIT);
 
index 1b44d24..7033eae 100644 (file)
@@ -44,6 +44,8 @@
 #define HNS_ROCE_V2_MAX_XRCD_NUM               0x1000000
 #define HNS_ROCE_V2_RSV_XRCD_NUM               0
 
+#define HNS_ROCE_V2_QP_ACK_TIMEOUT_OFS_HIP08    10
+
 #define HNS_ROCE_V3_SCCC_SZ                    64
 #define HNS_ROCE_V3_GMV_ENTRY_SZ               32
 
index 37a5cf6..1437649 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <linux/vmalloc.h>
 #include <rdma/ib_umem.h>
+#include <linux/math.h>
 #include "hns_roce_device.h"
 #include "hns_roce_cmd.h"
 #include "hns_roce_hem.h"
@@ -909,6 +910,44 @@ static int mtr_init_buf_cfg(struct hns_roce_dev *hr_dev,
        return page_cnt;
 }
 
+static u64 cal_pages_per_l1ba(unsigned int ba_per_bt, unsigned int hopnum)
+{
+       return int_pow(ba_per_bt, hopnum - 1);
+}
+
+static unsigned int cal_best_bt_pg_sz(struct hns_roce_dev *hr_dev,
+                                     struct hns_roce_mtr *mtr,
+                                     unsigned int pg_shift)
+{
+       unsigned long cap = hr_dev->caps.page_size_cap;
+       struct hns_roce_buf_region *re;
+       unsigned int pgs_per_l1ba;
+       unsigned int ba_per_bt;
+       unsigned int ba_num;
+       int i;
+
+       for_each_set_bit_from(pg_shift, &cap, sizeof(cap) * BITS_PER_BYTE) {
+               if (!(BIT(pg_shift) & cap))
+                       continue;
+
+               ba_per_bt = BIT(pg_shift) / BA_BYTE_LEN;
+               ba_num = 0;
+               for (i = 0; i < mtr->hem_cfg.region_count; i++) {
+                       re = &mtr->hem_cfg.region[i];
+                       if (re->hopnum == 0)
+                               continue;
+
+                       pgs_per_l1ba = cal_pages_per_l1ba(ba_per_bt, re->hopnum);
+                       ba_num += DIV_ROUND_UP(re->count, pgs_per_l1ba);
+               }
+
+               if (ba_num <= ba_per_bt)
+                       return pg_shift;
+       }
+
+       return 0;
+}
+
 static int mtr_alloc_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
                         unsigned int ba_page_shift)
 {
@@ -917,6 +956,10 @@ static int mtr_alloc_mtt(struct hns_roce_dev *hr_dev, struct hns_roce_mtr *mtr,
 
        hns_roce_hem_list_init(&mtr->hem_list);
        if (!cfg->is_direct) {
+               ba_page_shift = cal_best_bt_pg_sz(hr_dev, mtr, ba_page_shift);
+               if (!ba_page_shift)
+                       return -ERANGE;
+
                ret = hns_roce_hem_list_request(hr_dev, &mtr->hem_list,
                                                cfg->region, cfg->region_count,
                                                ba_page_shift);
index ab5cdf7..eaa12c1 100644 (file)
@@ -522,11 +522,6 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
        if (!iwqp->user_mode)
                cancel_delayed_work_sync(&iwqp->dwork_flush);
 
-       irdma_qp_rem_ref(&iwqp->ibqp);
-       wait_for_completion(&iwqp->free_qp);
-       irdma_free_lsmm_rsrc(iwqp);
-       irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
-
        if (!iwqp->user_mode) {
                if (iwqp->iwscq) {
                        irdma_clean_cqes(iwqp, iwqp->iwscq);
@@ -534,6 +529,12 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
                                irdma_clean_cqes(iwqp, iwqp->iwrcq);
                }
        }
+
+       irdma_qp_rem_ref(&iwqp->ibqp);
+       wait_for_completion(&iwqp->free_qp);
+       irdma_free_lsmm_rsrc(iwqp);
+       irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp);
+
        irdma_remove_push_mmap_entries(iwqp);
        irdma_free_qp_rsrc(iwqp);
 
@@ -3291,6 +3292,7 @@ static int irdma_post_send(struct ib_qp *ibqp,
                        break;
                case IB_WR_LOCAL_INV:
                        info.op_type = IRDMA_OP_TYPE_INV_STAG;
+                       info.local_fence = info.read_fence;
                        info.op.inv_local_stag.target_stag = ib_wr->ex.invalidate_rkey;
                        err = irdma_uk_stag_local_invalidate(ukqp, &info, true);
                        break;
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 db18ace..f46c5a5 100644 (file)
@@ -115,15 +115,16 @@ static enum ib_wc_opcode wr_to_wc_opcode(enum ib_wr_opcode opcode)
 void retransmit_timer(struct timer_list *t)
 {
        struct rxe_qp *qp = from_timer(qp, t, retrans_timer);
+       unsigned long flags;
 
        rxe_dbg_qp(qp, "retransmit timer fired\n");
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp->valid) {
                qp->comp.timeout = 1;
                rxe_sched_task(&qp->comp.task);
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 void rxe_comp_queue_pkt(struct rxe_qp *qp, struct sk_buff *skb)
@@ -481,11 +482,13 @@ static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe)
 
 static void comp_check_sq_drain_done(struct rxe_qp *qp)
 {
-       spin_lock_bh(&qp->state_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (unlikely(qp_state(qp) == IB_QPS_SQD)) {
                if (qp->attr.sq_draining && qp->comp.psn == qp->req.psn) {
                        qp->attr.sq_draining = 0;
-                       spin_unlock_bh(&qp->state_lock);
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
 
                        if (qp->ibqp.event_handler) {
                                struct ib_event ev;
@@ -499,7 +502,7 @@ static void comp_check_sq_drain_done(struct rxe_qp *qp)
                        return;
                }
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 static inline enum comp_state complete_ack(struct rxe_qp *qp,
@@ -625,13 +628,15 @@ static void free_pkt(struct rxe_pkt_info *pkt)
  */
 static void reset_retry_timer(struct rxe_qp *qp)
 {
+       unsigned long flags;
+
        if (qp_type(qp) == IB_QPT_RC && qp->qp_timeout_jiffies) {
-               spin_lock_bh(&qp->state_lock);
+               spin_lock_irqsave(&qp->state_lock, flags);
                if (qp_state(qp) >= IB_QPS_RTS &&
                    psn_compare(qp->req.psn, qp->comp.psn) > 0)
                        mod_timer(&qp->retrans_timer,
                                  jiffies + qp->qp_timeout_jiffies);
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
        }
 }
 
@@ -643,18 +648,19 @@ int rxe_completer(struct rxe_qp *qp)
        struct rxe_pkt_info *pkt = NULL;
        enum comp_state state;
        int ret;
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (!qp->valid || qp_state(qp) == IB_QPS_ERR ||
                          qp_state(qp) == IB_QPS_RESET) {
                bool notify = qp->valid && (qp_state(qp) == IB_QPS_ERR);
 
                drain_resp_pkts(qp);
                flush_send_queue(qp, notify);
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                goto exit;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        if (qp->comp.timeout) {
                qp->comp.timeout_retry = 1;
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 2bc7361..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;
@@ -412,15 +418,16 @@ int rxe_xmit_packet(struct rxe_qp *qp, struct rxe_pkt_info *pkt,
        int err;
        int is_request = pkt->mask & RXE_REQ_MASK;
        struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if ((is_request && (qp_state(qp) < IB_QPS_RTS)) ||
            (!is_request && (qp_state(qp) < IB_QPS_RTR))) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                rxe_dbg_qp(qp, "Packet dropped. QP is not in ready state\n");
                goto drop;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        rxe_icrc_generate(skb, pkt);
 
index c5451a4..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;
@@ -300,6 +299,7 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
        struct rxe_cq *rcq = to_rcq(init->recv_cq);
        struct rxe_cq *scq = to_rcq(init->send_cq);
        struct rxe_srq *srq = init->srq ? to_rsrq(init->srq) : NULL;
+       unsigned long flags;
 
        rxe_get(pd);
        rxe_get(rcq);
@@ -325,10 +325,10 @@ int rxe_qp_from_init(struct rxe_dev *rxe, struct rxe_qp *qp, struct rxe_pd *pd,
        if (err)
                goto err2;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        qp->attr.qp_state = IB_QPS_RESET;
        qp->valid = 1;
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        return 0;
 
@@ -492,24 +492,28 @@ static void rxe_qp_reset(struct rxe_qp *qp)
 /* move the qp to the error state */
 void rxe_qp_error(struct rxe_qp *qp)
 {
-       spin_lock_bh(&qp->state_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->state_lock, flags);
        qp->attr.qp_state = IB_QPS_ERR;
 
        /* drain work and packet queues */
        rxe_sched_task(&qp->resp.task);
        rxe_sched_task(&qp->comp.task);
        rxe_sched_task(&qp->req.task);
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 static void rxe_qp_sqd(struct rxe_qp *qp, struct ib_qp_attr *attr,
                       int mask)
 {
-       spin_lock_bh(&qp->state_lock);
+       unsigned long flags;
+
+       spin_lock_irqsave(&qp->state_lock, flags);
        qp->attr.sq_draining = 1;
        rxe_sched_task(&qp->comp.task);
        rxe_sched_task(&qp->req.task);
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 /* caller should hold qp->state_lock */
@@ -555,14 +559,16 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
                qp->attr.cur_qp_state = attr->qp_state;
 
        if (mask & IB_QP_STATE) {
-               spin_lock_bh(&qp->state_lock);
+               unsigned long flags;
+
+               spin_lock_irqsave(&qp->state_lock, flags);
                err = __qp_chk_state(qp, attr, mask);
                if (!err) {
                        qp->attr.qp_state = attr->qp_state;
                        rxe_dbg_qp(qp, "state -> %s\n",
                                        qps2str[attr->qp_state]);
                }
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
 
                if (err)
                        return err;
@@ -688,6 +694,8 @@ int rxe_qp_from_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask,
 /* called by the query qp verb */
 int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask)
 {
+       unsigned long flags;
+
        *attr = qp->attr;
 
        attr->rq_psn                            = qp->resp.psn;
@@ -708,12 +716,13 @@ int rxe_qp_to_attr(struct rxe_qp *qp, struct ib_qp_attr *attr, int mask)
        /* Applications that get this state typically spin on it.
         * Yield the processor
         */
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp->attr.sq_draining) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                cond_resched();
+       } else {
+               spin_unlock_irqrestore(&qp->state_lock, flags);
        }
-       spin_unlock_bh(&qp->state_lock);
 
        return 0;
 }
@@ -736,10 +745,11 @@ int rxe_qp_chk_destroy(struct rxe_qp *qp)
 static void rxe_qp_do_cleanup(struct work_struct *work)
 {
        struct rxe_qp *qp = container_of(work, typeof(*qp), cleanup_work.work);
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        qp->valid = 0;
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
        qp->qp_timeout_jiffies = 0;
 
        if (qp_type(qp) == IB_QPT_RC) {
index 2f953cc..5861e42 100644 (file)
@@ -14,6 +14,7 @@ static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
                            struct rxe_qp *qp)
 {
        unsigned int pkt_type;
+       unsigned long flags;
 
        if (unlikely(!qp->valid))
                return -EINVAL;
@@ -38,19 +39,19 @@ static int check_type_state(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
                return -EINVAL;
        }
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (pkt->mask & RXE_REQ_MASK) {
                if (unlikely(qp_state(qp) < IB_QPS_RTR)) {
-                       spin_unlock_bh(&qp->state_lock);
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
                        return -EINVAL;
                }
        } else {
                if (unlikely(qp_state(qp) < IB_QPS_RTS)) {
-                       spin_unlock_bh(&qp->state_lock);
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
                        return -EINVAL;
                }
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        return 0;
 }
index 65134a9..5fe7cba 100644 (file)
@@ -99,17 +99,18 @@ static void req_retry(struct rxe_qp *qp)
 void rnr_nak_timer(struct timer_list *t)
 {
        struct rxe_qp *qp = from_timer(qp, t, rnr_nak_timer);
+       unsigned long flags;
 
        rxe_dbg_qp(qp, "nak timer fired\n");
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp->valid) {
                /* request a send queue retry */
                qp->req.need_retry = 1;
                qp->req.wait_for_rnr_timer = 0;
                rxe_sched_task(&qp->req.task);
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 static void req_check_sq_drain_done(struct rxe_qp *qp)
@@ -118,8 +119,9 @@ static void req_check_sq_drain_done(struct rxe_qp *qp)
        unsigned int index;
        unsigned int cons;
        struct rxe_send_wqe *wqe;
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp_state(qp) == IB_QPS_SQD) {
                q = qp->sq.queue;
                index = qp->req.wqe_index;
@@ -140,7 +142,7 @@ static void req_check_sq_drain_done(struct rxe_qp *qp)
                                break;
 
                        qp->attr.sq_draining = 0;
-                       spin_unlock_bh(&qp->state_lock);
+                       spin_unlock_irqrestore(&qp->state_lock, flags);
 
                        if (qp->ibqp.event_handler) {
                                struct ib_event ev;
@@ -154,7 +156,7 @@ static void req_check_sq_drain_done(struct rxe_qp *qp)
                        return;
                } while (0);
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 }
 
 static struct rxe_send_wqe *__req_next_wqe(struct rxe_qp *qp)
@@ -173,6 +175,7 @@ static struct rxe_send_wqe *__req_next_wqe(struct rxe_qp *qp)
 static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
 {
        struct rxe_send_wqe *wqe;
+       unsigned long flags;
 
        req_check_sq_drain_done(qp);
 
@@ -180,13 +183,13 @@ static struct rxe_send_wqe *req_next_wqe(struct rxe_qp *qp)
        if (wqe == NULL)
                return NULL;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (unlikely((qp_state(qp) == IB_QPS_SQD) &&
                     (wqe->state != wqe_state_processing))) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                return NULL;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        wqe->mask = wr_opcode_mask(wqe->wr.opcode, qp);
        return wqe;
@@ -676,16 +679,17 @@ int rxe_requester(struct rxe_qp *qp)
        struct rxe_queue *q = qp->sq.queue;
        struct rxe_ah *ah;
        struct rxe_av *av;
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (unlikely(!qp->valid)) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                goto exit;
        }
 
        if (unlikely(qp_state(qp) == IB_QPS_ERR)) {
                wqe = __req_next_wqe(qp);
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                if (wqe)
                        goto err;
                else
@@ -700,10 +704,10 @@ int rxe_requester(struct rxe_qp *qp)
                qp->req.wait_psn = 0;
                qp->req.need_retry = 0;
                qp->req.wait_for_rnr_timer = 0;
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                goto exit;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        /* we come here if the retransmit timer has fired
         * or if the rnr timer has fired. If the retransmit
index 68f6cd1..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) {
@@ -1047,6 +1048,7 @@ static enum resp_states do_complete(struct rxe_qp *qp,
        struct ib_uverbs_wc *uwc = &cqe.uibwc;
        struct rxe_recv_wqe *wqe = qp->resp.wqe;
        struct rxe_dev *rxe = to_rdev(qp->ibqp.device);
+       unsigned long flags;
 
        if (!wqe)
                goto finish;
@@ -1137,12 +1139,12 @@ static enum resp_states do_complete(struct rxe_qp *qp,
                return RESPST_ERR_CQ_OVERFLOW;
 
 finish:
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (unlikely(qp_state(qp) == IB_QPS_ERR)) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                return RESPST_CHK_RESOURCE;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        if (unlikely(!pkt))
                return RESPST_DONE;
@@ -1468,18 +1470,19 @@ int rxe_responder(struct rxe_qp *qp)
        enum resp_states state;
        struct rxe_pkt_info *pkt = NULL;
        int ret;
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (!qp->valid || qp_state(qp) == IB_QPS_ERR ||
                          qp_state(qp) == IB_QPS_RESET) {
                bool notify = qp->valid && (qp_state(qp) == IB_QPS_ERR);
 
                drain_req_pkts(qp);
                flush_recv_queue(qp, notify);
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                goto exit;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED;
 
index dea605b..4d8f6b8 100644 (file)
@@ -904,10 +904,10 @@ static int rxe_post_send_kernel(struct rxe_qp *qp,
        if (!err)
                rxe_sched_task(&qp->req.task);
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp_state(qp) == IB_QPS_ERR)
                rxe_sched_task(&qp->comp.task);
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        return err;
 }
@@ -917,22 +917,23 @@ static int rxe_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
 {
        struct rxe_qp *qp = to_rqp(ibqp);
        int err;
+       unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        /* caller has already called destroy_qp */
        if (WARN_ON_ONCE(!qp->valid)) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                rxe_err_qp(qp, "qp has been destroyed");
                return -EINVAL;
        }
 
        if (unlikely(qp_state(qp) < IB_QPS_RTS)) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                *bad_wr = wr;
                rxe_err_qp(qp, "qp not ready to send");
                return -EINVAL;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        if (qp->is_user) {
                /* Utilize process context to do protocol processing */
@@ -1008,22 +1009,22 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
        struct rxe_rq *rq = &qp->rq;
        unsigned long flags;
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        /* caller has already called destroy_qp */
        if (WARN_ON_ONCE(!qp->valid)) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                rxe_err_qp(qp, "qp has been destroyed");
                return -EINVAL;
        }
 
        /* see C10-97.2.1 */
        if (unlikely((qp_state(qp) < IB_QPS_INIT))) {
-               spin_unlock_bh(&qp->state_lock);
+               spin_unlock_irqrestore(&qp->state_lock, flags);
                *bad_wr = wr;
                rxe_dbg_qp(qp, "qp not ready to post recv");
                return -EINVAL;
        }
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        if (unlikely(qp->srq)) {
                *bad_wr = wr;
@@ -1044,10 +1045,10 @@ static int rxe_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
 
        spin_unlock_irqrestore(&rq->producer_lock, flags);
 
-       spin_lock_bh(&qp->state_lock);
+       spin_lock_irqsave(&qp->state_lock, flags);
        if (qp_state(qp) == IB_QPS_ERR)
                rxe_sched_task(&qp->resp.task);
-       spin_unlock_bh(&qp->state_lock);
+       spin_unlock_irqrestore(&qp->state_lock, flags);
 
        return err;
 }
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 6de9007..4d80060 100644 (file)
@@ -282,6 +282,7 @@ config EXYNOS_IOMMU_DEBUG
 config IPMMU_VMSA
        bool "Renesas VMSA-compatible IPMMU"
        depends on ARCH_RENESAS || COMPILE_TEST
+       depends on ARM || ARM64 || COMPILE_TEST
        depends on !GENERIC_ATOMIC64    # for IOMMU_IO_PGTABLE_LPAE
        select IOMMU_API
        select IOMMU_IO_PGTABLE_LPAE
index e98f20a..9beeceb 100644 (file)
@@ -15,9 +15,7 @@ extern irqreturn_t amd_iommu_int_thread(int irq, void *data);
 extern irqreturn_t amd_iommu_int_handler(int irq, void *data);
 extern void amd_iommu_apply_erratum_63(struct amd_iommu *iommu, u16 devid);
 extern void amd_iommu_restart_event_logging(struct amd_iommu *iommu);
-extern int amd_iommu_init_devices(void);
-extern void amd_iommu_uninit_devices(void);
-extern void amd_iommu_init_notifier(void);
+extern void amd_iommu_restart_ga_log(struct amd_iommu *iommu);
 extern void amd_iommu_set_rlookup_table(struct amd_iommu *iommu, u16 devid);
 
 #ifdef CONFIG_AMD_IOMMU_DEBUGFS
index 329a406..c2d80a4 100644 (file)
@@ -759,6 +759,30 @@ void amd_iommu_restart_event_logging(struct amd_iommu *iommu)
 }
 
 /*
+ * This function restarts event logging in case the IOMMU experienced
+ * an GA log overflow.
+ */
+void amd_iommu_restart_ga_log(struct amd_iommu *iommu)
+{
+       u32 status;
+
+       status = readl(iommu->mmio_base + MMIO_STATUS_OFFSET);
+       if (status & MMIO_STATUS_GALOG_RUN_MASK)
+               return;
+
+       pr_info_ratelimited("IOMMU GA Log restarting\n");
+
+       iommu_feature_disable(iommu, CONTROL_GALOG_EN);
+       iommu_feature_disable(iommu, CONTROL_GAINT_EN);
+
+       writel(MMIO_STATUS_GALOG_OVERFLOW_MASK,
+              iommu->mmio_base + MMIO_STATUS_OFFSET);
+
+       iommu_feature_enable(iommu, CONTROL_GAINT_EN);
+       iommu_feature_enable(iommu, CONTROL_GALOG_EN);
+}
+
+/*
  * This function resets the command buffer if the IOMMU stopped fetching
  * commands from it.
  */
index 4a31464..dc1ec68 100644 (file)
@@ -845,6 +845,7 @@ amd_iommu_set_pci_msi_domain(struct device *dev, struct amd_iommu *iommu) { }
        (MMIO_STATUS_EVT_OVERFLOW_INT_MASK | \
         MMIO_STATUS_EVT_INT_MASK | \
         MMIO_STATUS_PPR_INT_MASK | \
+        MMIO_STATUS_GALOG_OVERFLOW_MASK | \
         MMIO_STATUS_GALOG_INT_MASK)
 
 irqreturn_t amd_iommu_int_thread(int irq, void *data)
@@ -868,10 +869,16 @@ irqreturn_t amd_iommu_int_thread(int irq, void *data)
                }
 
 #ifdef CONFIG_IRQ_REMAP
-               if (status & MMIO_STATUS_GALOG_INT_MASK) {
+               if (status & (MMIO_STATUS_GALOG_INT_MASK |
+                             MMIO_STATUS_GALOG_OVERFLOW_MASK)) {
                        pr_devel("Processing IOMMU GA Log\n");
                        iommu_poll_ga_log(iommu);
                }
+
+               if (status & MMIO_STATUS_GALOG_OVERFLOW_MASK) {
+                       pr_info_ratelimited("IOMMU GA Log overflow\n");
+                       amd_iommu_restart_ga_log(iommu);
+               }
 #endif
 
                if (status & MMIO_STATUS_EVT_OVERFLOW_INT_MASK) {
@@ -2067,7 +2074,7 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
 {
        struct io_pgtable_ops *pgtbl_ops;
        struct protection_domain *domain;
-       int pgtable = amd_iommu_pgtable;
+       int pgtable;
        int mode = DEFAULT_PGTABLE_LEVEL;
        int ret;
 
@@ -2084,6 +2091,10 @@ static struct protection_domain *protection_domain_alloc(unsigned int type)
                mode = PAGE_MODE_NONE;
        } else if (type == IOMMU_DOMAIN_UNMANAGED) {
                pgtable = AMD_IOMMU_V1;
+       } else if (type == IOMMU_DOMAIN_DMA || type == IOMMU_DOMAIN_DMA_FQ) {
+               pgtable = amd_iommu_pgtable;
+       } else {
+               return NULL;
        }
 
        switch (pgtable) {
@@ -2118,6 +2129,15 @@ out_err:
        return NULL;
 }
 
+static inline u64 dma_max_address(void)
+{
+       if (amd_iommu_pgtable == AMD_IOMMU_V1)
+               return ~0ULL;
+
+       /* V2 with 4/5 level page table */
+       return ((1ULL << PM_LEVEL_SHIFT(amd_iommu_gpt_level)) - 1);
+}
+
 static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
 {
        struct protection_domain *domain;
@@ -2134,7 +2154,7 @@ static struct iommu_domain *amd_iommu_domain_alloc(unsigned type)
                return NULL;
 
        domain->domain.geometry.aperture_start = 0;
-       domain->domain.geometry.aperture_end   = ~0ULL;
+       domain->domain.geometry.aperture_end   = dma_max_address();
        domain->domain.geometry.force_aperture = true;
 
        return &domain->domain;
@@ -2387,7 +2407,7 @@ static void amd_iommu_iotlb_sync(struct iommu_domain *domain,
        unsigned long flags;
 
        spin_lock_irqsave(&dom->lock, flags);
-       domain_flush_pages(dom, gather->start, gather->end - gather->start, 1);
+       domain_flush_pages(dom, gather->start, gather->end - gather->start + 1, 1);
        amd_iommu_domain_flush_complete(dom);
        spin_unlock_irqrestore(&dom->lock, flags);
 }
@@ -3493,8 +3513,7 @@ int amd_iommu_activate_guest_mode(void *data)
        struct irte_ga *entry = (struct irte_ga *) ir_data->entry;
        u64 valid;
 
-       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) ||
-           !entry || entry->lo.fields_vapic.guest_mode)
+       if (!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir) || !entry)
                return 0;
 
        valid = entry->lo.fields_vapic.valid;
index aecc7d1..e93906d 100644 (file)
@@ -781,7 +781,8 @@ static void mtk_iommu_flush_iotlb_all(struct iommu_domain *domain)
 {
        struct mtk_iommu_domain *dom = to_mtk_domain(domain);
 
-       mtk_iommu_tlb_flush_all(dom->bank->parent_data);
+       if (dom->bank)
+               mtk_iommu_tlb_flush_all(dom->bank->parent_data);
 }
 
 static void mtk_iommu_iotlb_sync(struct iommu_domain *domain,
index ea5a308..4054030 100644 (file)
@@ -1335,20 +1335,22 @@ static int rk_iommu_probe(struct platform_device *pdev)
        for (i = 0; i < iommu->num_irq; i++) {
                int irq = platform_get_irq(pdev, i);
 
-               if (irq < 0)
-                       return irq;
+               if (irq < 0) {
+                       err = irq;
+                       goto err_pm_disable;
+               }
 
                err = devm_request_irq(iommu->dev, irq, rk_iommu_irq,
                                       IRQF_SHARED, dev_name(dev), iommu);
-               if (err) {
-                       pm_runtime_disable(dev);
-                       goto err_remove_sysfs;
-               }
+               if (err)
+                       goto err_pm_disable;
        }
 
        dma_set_mask_and_coherent(dev, rk_ops->dma_bit_mask);
 
        return 0;
+err_pm_disable:
+       pm_runtime_disable(dev);
 err_remove_sysfs:
        iommu_device_sysfs_remove(&iommu->iommu);
 err_put_group:
index de47b51..afd6a18 100644 (file)
@@ -16,6 +16,8 @@ void gic_enable_of_quirks(const struct device_node *np,
                          const struct gic_quirk *quirks, void *data)
 {
        for (; quirks->desc; quirks++) {
+               if (!quirks->compatible && !quirks->property)
+                       continue;
                if (quirks->compatible &&
                    !of_device_is_compatible(np, quirks->compatible))
                        continue;
index 55a0372..1c84981 100644 (file)
@@ -312,14 +312,14 @@ static int lpg_calc_freq(struct lpg_channel *chan, uint64_t period)
                max_res = LPG_RESOLUTION_9BIT;
        }
 
-       min_period = (u64)NSEC_PER_SEC *
-                       div64_u64((1 << pwm_resolution_arr[0]), clk_rate_arr[clk_len - 1]);
+       min_period = div64_u64((u64)NSEC_PER_SEC * (1 << pwm_resolution_arr[0]),
+                              clk_rate_arr[clk_len - 1]);
        if (period <= min_period)
                return -EINVAL;
 
        /* Limit period to largest possible value, to avoid overflows */
-       max_period = (u64)NSEC_PER_SEC * max_res * LPG_MAX_PREDIV *
-                       div64_u64((1 << LPG_MAX_M), 1024);
+       max_period = div64_u64((u64)NSEC_PER_SEC * max_res * LPG_MAX_PREDIV * (1 << LPG_MAX_M),
+                              1024);
        if (period > max_period)
                period = max_period;
 
index c4a705c..fc6a12a 100644 (file)
@@ -98,6 +98,7 @@ static ssize_t mbox_test_message_write(struct file *filp,
                                       size_t count, loff_t *ppos)
 {
        struct mbox_test_device *tdev = filp->private_data;
+       char *message;
        void *data;
        int ret;
 
@@ -113,12 +114,13 @@ static ssize_t mbox_test_message_write(struct file *filp,
                return -EINVAL;
        }
 
-       mutex_lock(&tdev->mutex);
-
-       tdev->message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
-       if (!tdev->message)
+       message = kzalloc(MBOX_MAX_MSG_LEN, GFP_KERNEL);
+       if (!message)
                return -ENOMEM;
 
+       mutex_lock(&tdev->mutex);
+
+       tdev->message = message;
        ret = copy_from_user(tdev->message, userbuf, count);
        if (ret) {
                ret = -EFAULT;
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 fd464fb..9dd0409 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 4739ed8..9ea285f 100644 (file)
@@ -5516,7 +5516,7 @@ static int raid5_read_one_chunk(struct mddev *mddev, struct bio *raid_bio)
 
        sector = raid5_compute_sector(conf, raid_bio->bi_iter.bi_sector, 0,
                                      &dd_idx, NULL);
-       end_sector = bio_end_sector(raid_bio);
+       end_sector = sector + bio_sectors(raid_bio);
 
        rcu_read_lock();
        if (r5c_big_stripe_cached(conf, sector))
index 769ea6b..241b162 100644 (file)
@@ -1091,7 +1091,8 @@ void cec_received_msg_ts(struct cec_adapter *adap,
        mutex_lock(&adap->lock);
        dprintk(2, "%s: %*ph\n", __func__, msg->len, msg->msg);
 
-       adap->last_initiator = 0xff;
+       if (!adap->transmit_in_progress)
+               adap->last_initiator = 0xff;
 
        /* Check if this message was for us (directed or broadcast). */
        if (!cec_msg_is_broadcast(msg)) {
@@ -1585,7 +1586,7 @@ static void cec_claim_log_addrs(struct cec_adapter *adap, bool block)
  *
  * This function is called with adap->lock held.
  */
-static int cec_adap_enable(struct cec_adapter *adap)
+int cec_adap_enable(struct cec_adapter *adap)
 {
        bool enable;
        int ret = 0;
@@ -1595,6 +1596,9 @@ static int cec_adap_enable(struct cec_adapter *adap)
        if (adap->needs_hpd)
                enable = enable && adap->phys_addr != CEC_PHYS_ADDR_INVALID;
 
+       if (adap->devnode.unregistered)
+               enable = false;
+
        if (enable == adap->is_enabled)
                return 0;
 
index af358e9..7e153c5 100644 (file)
@@ -191,6 +191,8 @@ static void cec_devnode_unregister(struct cec_adapter *adap)
        mutex_lock(&adap->lock);
        __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false);
        __cec_s_log_addrs(adap, NULL, false);
+       // Disable the adapter (since adap->devnode.unregistered is true)
+       cec_adap_enable(adap);
        mutex_unlock(&adap->lock);
 
        cdev_device_del(&devnode->cdev, &devnode->dev);
index b78df93..ed1f8c6 100644 (file)
@@ -47,6 +47,7 @@ int cec_monitor_pin_cnt_inc(struct cec_adapter *adap);
 void cec_monitor_pin_cnt_dec(struct cec_adapter *adap);
 int cec_adap_status(struct seq_file *file, void *priv);
 int cec_thread_func(void *_adap);
+int cec_adap_enable(struct cec_adapter *adap);
 void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block);
 int __cec_s_log_addrs(struct cec_adapter *adap,
                      struct cec_log_addrs *log_addrs, bool block);
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 2999155..0fbd030 100644 (file)
@@ -584,6 +584,9 @@ static void mtk_init_vdec_params(struct mtk_vcodec_ctx *ctx)
 
        if (!(ctx->dev->dec_capability & VCODEC_CAPABILITY_4K_DISABLED)) {
                for (i = 0; i < num_supported_formats; i++) {
+                       if (mtk_video_formats[i].type != MTK_FMT_DEC)
+                               continue;
+
                        mtk_video_formats[i].frmsize.max_width =
                                VCODEC_DEC_4K_CODED_WIDTH;
                        mtk_video_formats[i].frmsize.max_height =
index 898f321..8640db3 100644 (file)
@@ -353,7 +353,6 @@ static int video_get_subdev_format(struct camss_video *video,
        if (subdev == NULL)
                return -EPIPE;
 
-       memset(&fmt, 0, sizeof(fmt));
        fmt.pad = pad;
 
        ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
index 8355185..61cfaaf 100644 (file)
@@ -397,10 +397,12 @@ hantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth)
        if (!raw_vpu_fmt)
                return -EINVAL;
 
-       if (ctx->is_encoder)
+       if (ctx->is_encoder) {
                encoded_fmt = &ctx->dst_fmt;
-       else
+               ctx->vpu_src_fmt = raw_vpu_fmt;
+       } else {
                encoded_fmt = &ctx->src_fmt;
+       }
 
        hantro_reset_fmt(&raw_fmt, raw_vpu_fmt);
        raw_fmt.width = encoded_fmt->width;
index 7aefa76..d631ce4 100644 (file)
@@ -251,14 +251,17 @@ static int uvc_parse_format(struct uvc_device *dev,
                /* Find the format descriptor from its GUID. */
                fmtdesc = uvc_format_by_guid(&buffer[5]);
 
-               if (fmtdesc != NULL) {
-                       format->fcc = fmtdesc->fcc;
-               } else {
+               if (!fmtdesc) {
+                       /*
+                        * Unknown video formats are not fatal errors, the
+                        * caller will skip this descriptor.
+                        */
                        dev_info(&streaming->intf->dev,
                                 "Unknown video format %pUl\n", &buffer[5]);
-                       format->fcc = 0;
+                       return 0;
                }
 
+               format->fcc = fmtdesc->fcc;
                format->bpp = buffer[21];
 
                /*
@@ -675,7 +678,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
        interval = (u32 *)&frame[nframes];
 
        streaming->format = format;
-       streaming->nformats = nformats;
+       streaming->nformats = 0;
 
        /* Parse the format descriptors. */
        while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
@@ -689,7 +692,10 @@ static int uvc_parse_streaming(struct uvc_device *dev,
                                &interval, buffer, buflen);
                        if (ret < 0)
                                goto error;
+                       if (!ret)
+                               break;
 
+                       streaming->nformats++;
                        frame += format->nframes;
                        format++;
 
index bf0c181..22fe08f 100644 (file)
@@ -314,8 +314,7 @@ int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd,
 {
        struct fwnode_handle *endpoint;
 
-       if (!(sink->flags & MEDIA_PAD_FL_SINK) ||
-           !is_media_entity_v4l2_subdev(sink->entity))
+       if (!(sink->flags & MEDIA_PAD_FL_SINK))
                return -EINVAL;
 
        fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) {
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 f484669..30d4d04 100644 (file)
@@ -316,12 +316,14 @@ static void fastrpc_free_map(struct kref *ref)
        if (map->table) {
                if (map->attr & FASTRPC_ATTR_SECUREMAP) {
                        struct qcom_scm_vmperm perm;
+                       int vmid = map->fl->cctx->vmperms[0].vmid;
+                       u64 src_perms = BIT(QCOM_SCM_VMID_HLOS) | BIT(vmid);
                        int err = 0;
 
                        perm.vmid = QCOM_SCM_VMID_HLOS;
                        perm.perm = QCOM_SCM_PERM_RWX;
                        err = qcom_scm_assign_mem(map->phys, map->size,
-                               &map->fl->cctx->perms, &perm, 1);
+                               &src_perms, &perm, 1);
                        if (err) {
                                dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d",
                                                map->phys, map->size, err);
@@ -787,8 +789,12 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
                goto map_err;
        }
 
-       map->phys = sg_dma_address(map->table->sgl);
-       map->phys += ((u64)fl->sctx->sid << 32);
+       if (attr & FASTRPC_ATTR_SECUREMAP) {
+               map->phys = sg_phys(map->table->sgl);
+       } else {
+               map->phys = sg_dma_address(map->table->sgl);
+               map->phys += ((u64)fl->sctx->sid << 32);
+       }
        map->size = len;
        map->va = sg_virt(map->table->sgl);
        map->len = len;
@@ -798,9 +804,15 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd,
                 * If subsystem VMIDs are defined in DTSI, then do
                 * hyp_assign from HLOS to those VM(s)
                 */
+               u64 src_perms = BIT(QCOM_SCM_VMID_HLOS);
+               struct qcom_scm_vmperm dst_perms[2] = {0};
+
+               dst_perms[0].vmid = QCOM_SCM_VMID_HLOS;
+               dst_perms[0].perm = QCOM_SCM_PERM_RW;
+               dst_perms[1].vmid = fl->cctx->vmperms[0].vmid;
+               dst_perms[1].perm = QCOM_SCM_PERM_RWX;
                map->attr = attr;
-               err = qcom_scm_assign_mem(map->phys, (u64)map->size, &fl->cctx->perms,
-                               fl->cctx->vmperms, fl->cctx->vmcount);
+               err = qcom_scm_assign_mem(map->phys, (u64)map->size, &src_perms, dst_perms, 2);
                if (err) {
                        dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d",
                                        map->phys, map->size, err);
@@ -1892,7 +1904,7 @@ static int fastrpc_req_mmap(struct fastrpc_user *fl, char __user *argp)
        req.vaddrout = rsp_msg.vaddr;
 
        /* Add memory to static PD pool, protection thru hypervisor */
-       if (req.flags != ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
+       if (req.flags == ADSP_MMAP_REMOTE_HEAP_ADDR && fl->cctx->vmcount) {
                struct qcom_scm_vmperm perm;
 
                perm.vmid = QCOM_SCM_VMID_HLOS;
@@ -2337,8 +2349,10 @@ static void fastrpc_notify_users(struct fastrpc_user *user)
        struct fastrpc_invoke_ctx *ctx;
 
        spin_lock(&user->lock);
-       list_for_each_entry(ctx, &user->pending, node)
+       list_for_each_entry(ctx, &user->pending, node) {
+               ctx->retval = -EPIPE;
                complete(&ctx->work);
+       }
        spin_unlock(&user->lock);
 }
 
@@ -2349,7 +2363,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
        struct fastrpc_user *user;
        unsigned long flags;
 
+       /* No invocations past this point */
        spin_lock_irqsave(&cctx->lock, flags);
+       cctx->rpdev = NULL;
        list_for_each_entry(user, &cctx->users, user)
                fastrpc_notify_users(user);
        spin_unlock_irqrestore(&cctx->lock, flags);
@@ -2368,7 +2384,6 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev)
 
        of_platform_depopulate(&rpdev->dev);
 
-       cctx->rpdev = NULL;
        fastrpc_channel_ctx_put(cctx);
 }
 
index 2e120ad..0c5f5e3 100644 (file)
@@ -28,7 +28,6 @@ struct mmc_pwrseq_sd8787 {
        struct mmc_pwrseq pwrseq;
        struct gpio_desc *reset_gpio;
        struct gpio_desc *pwrdn_gpio;
-       u32 reset_pwrdwn_delay_ms;
 };
 
 #define to_pwrseq_sd8787(p) container_of(p, struct mmc_pwrseq_sd8787, pwrseq)
@@ -39,7 +38,7 @@ static void mmc_pwrseq_sd8787_pre_power_on(struct mmc_host *host)
 
        gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
 
-       msleep(pwrseq->reset_pwrdwn_delay_ms);
+       msleep(300);
        gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
 }
 
@@ -51,17 +50,37 @@ static void mmc_pwrseq_sd8787_power_off(struct mmc_host *host)
        gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
 }
 
+static void mmc_pwrseq_wilc1000_pre_power_on(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       /* The pwrdn_gpio is really CHIP_EN, reset_gpio is RESETN */
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 1);
+       msleep(5);
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 1);
+}
+
+static void mmc_pwrseq_wilc1000_power_off(struct mmc_host *host)
+{
+       struct mmc_pwrseq_sd8787 *pwrseq = to_pwrseq_sd8787(host->pwrseq);
+
+       gpiod_set_value_cansleep(pwrseq->reset_gpio, 0);
+       gpiod_set_value_cansleep(pwrseq->pwrdn_gpio, 0);
+}
+
 static const struct mmc_pwrseq_ops mmc_pwrseq_sd8787_ops = {
        .pre_power_on = mmc_pwrseq_sd8787_pre_power_on,
        .power_off = mmc_pwrseq_sd8787_power_off,
 };
 
-static const u32 sd8787_delay_ms = 300;
-static const u32 wilc1000_delay_ms = 5;
+static const struct mmc_pwrseq_ops mmc_pwrseq_wilc1000_ops = {
+       .pre_power_on = mmc_pwrseq_wilc1000_pre_power_on,
+       .power_off = mmc_pwrseq_wilc1000_power_off,
+};
 
 static const struct of_device_id mmc_pwrseq_sd8787_of_match[] = {
-       { .compatible = "mmc-pwrseq-sd8787", .data = &sd8787_delay_ms },
-       { .compatible = "mmc-pwrseq-wilc1000", .data = &wilc1000_delay_ms },
+       { .compatible = "mmc-pwrseq-sd8787", .data = &mmc_pwrseq_sd8787_ops },
+       { .compatible = "mmc-pwrseq-wilc1000", .data = &mmc_pwrseq_wilc1000_ops },
        {/* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, mmc_pwrseq_sd8787_of_match);
@@ -77,7 +96,6 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        match = of_match_node(mmc_pwrseq_sd8787_of_match, pdev->dev.of_node);
-       pwrseq->reset_pwrdwn_delay_ms = *(u32 *)match->data;
 
        pwrseq->pwrdn_gpio = devm_gpiod_get(dev, "powerdown", GPIOD_OUT_LOW);
        if (IS_ERR(pwrseq->pwrdn_gpio))
@@ -88,7 +106,7 @@ static int mmc_pwrseq_sd8787_probe(struct platform_device *pdev)
                return PTR_ERR(pwrseq->reset_gpio);
 
        pwrseq->pwrseq.dev = dev;
-       pwrseq->pwrseq.ops = &mmc_pwrseq_sd8787_ops;
+       pwrseq->pwrseq.ops = match->data;
        pwrseq->pwrseq.owner = THIS_MODULE;
        platform_set_drvdata(pdev, pwrseq);
 
index e4c4bfa..9ec593d 100644 (file)
@@ -1713,6 +1713,9 @@ static void construct_request_response(struct vub300_mmc_host *vub300,
        int bytes = 3 & less_cmd;
        int words = less_cmd >> 2;
        u8 *r = vub300->resp.response.command_response;
+
+       if (!resp_len)
+               return;
        if (bytes == 3) {
                cmd->resp[words] = (r[1 + (words << 2)] << 24)
                        | (r[2 + (words << 2)] << 16)
index 01f1c67..8dc4f5c 100644 (file)
@@ -590,8 +590,8 @@ static void adjust_oob_length(struct mtd_info *mtd, uint64_t start,
                            (end_page - start_page + 1) * oob_per_page);
 }
 
-static int mtdchar_write_ioctl(struct mtd_info *mtd,
-               struct mtd_write_req __user *argp)
+static noinline_for_stack int
+mtdchar_write_ioctl(struct mtd_info *mtd, struct mtd_write_req __user *argp)
 {
        struct mtd_info *master = mtd_get_master(mtd);
        struct mtd_write_req req;
@@ -688,8 +688,8 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
        return ret;
 }
 
-static int mtdchar_read_ioctl(struct mtd_info *mtd,
-               struct mtd_read_req __user *argp)
+static noinline_for_stack int
+mtdchar_read_ioctl(struct mtd_info *mtd, struct mtd_read_req __user *argp)
 {
        struct mtd_info *master = mtd_get_master(mtd);
        struct mtd_read_req req;
index 2cda439..017868f 100644 (file)
@@ -36,25 +36,25 @@ int ingenic_ecc_correct(struct ingenic_ecc *ecc,
 void ingenic_ecc_release(struct ingenic_ecc *ecc);
 struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np);
 #else /* CONFIG_MTD_NAND_INGENIC_ECC */
-int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
+static inline int ingenic_ecc_calculate(struct ingenic_ecc *ecc,
                          struct ingenic_ecc_params *params,
                          const u8 *buf, u8 *ecc_code)
 {
        return -ENODEV;
 }
 
-int ingenic_ecc_correct(struct ingenic_ecc *ecc,
+static inline int ingenic_ecc_correct(struct ingenic_ecc *ecc,
                        struct ingenic_ecc_params *params, u8 *buf,
                        u8 *ecc_code)
 {
        return -ENODEV;
 }
 
-void ingenic_ecc_release(struct ingenic_ecc *ecc)
+static inline void ingenic_ecc_release(struct ingenic_ecc *ecc)
 {
 }
 
-struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
+static inline struct ingenic_ecc *of_ingenic_ecc_get(struct device_node *np)
 {
        return ERR_PTR(-ENODEV);
 }
index afb4245..30c15e4 100644 (file)
@@ -2457,6 +2457,12 @@ static int marvell_nfc_setup_interface(struct nand_chip *chip, int chipnr,
                        NDTR1_WAIT_MODE;
        }
 
+       /*
+        * Reset nfc->selected_chip so the next command will cause the timing
+        * registers to be updated in marvell_nfc_select_target().
+        */
+       nfc->selected_chip = NULL;
+
        return 0;
 }
 
@@ -2894,10 +2900,6 @@ static int marvell_nfc_init(struct marvell_nfc *nfc)
                regmap_update_bits(sysctrl_base, GENCONF_CLK_GATING_CTRL,
                                   GENCONF_CLK_GATING_CTRL_ND_GATE,
                                   GENCONF_CLK_GATING_CTRL_ND_GATE);
-
-               regmap_update_bits(sysctrl_base, GENCONF_ND_CLK_CTRL,
-                                  GENCONF_ND_CLK_CTRL_EN,
-                                  GENCONF_ND_CLK_CTRL_EN);
        }
 
        /* Configure the DMA if appropriate */
index 0bb0ad1..5f29fac 100644 (file)
@@ -2018,6 +2018,7 @@ static const struct spi_nor_manufacturer *manufacturers[] = {
 
 static const struct flash_info spi_nor_generic_flash = {
        .name = "spi-nor-generic",
+       .n_banks = 1,
        /*
         * JESD216 rev A doesn't specify the page size, therefore we need a
         * sane default.
@@ -2921,7 +2922,8 @@ static void spi_nor_late_init_params(struct spi_nor *nor)
        if (nor->flags & SNOR_F_HAS_LOCK && !nor->params->locking_ops)
                spi_nor_init_default_locking_ops(nor);
 
-       nor->params->bank_size = div64_u64(nor->params->size, nor->info->n_banks);
+       if (nor->info->n_banks > 1)
+               params->bank_size = div64_u64(params->size, nor->info->n_banks);
 }
 
 /**
@@ -2987,6 +2989,7 @@ static void spi_nor_init_default_params(struct spi_nor *nor)
        /* Set SPI NOR sizes. */
        params->writesize = 1;
        params->size = (u64)info->sector_size * info->n_sectors;
+       params->bank_size = params->size;
        params->page_size = info->page_size;
 
        if (!(info->flags & SPI_NOR_NO_FR)) {
index 15f9a80..36876aa 100644 (file)
@@ -361,7 +361,7 @@ static int cypress_nor_determine_addr_mode_by_sr1(struct spi_nor *nor,
  */
 static int cypress_nor_set_addr_mode_nbytes(struct spi_nor *nor)
 {
-       struct spi_mem_op op;
+       struct spi_mem_op op = {};
        u8 addr_mode;
        int ret;
 
@@ -492,7 +492,7 @@ s25fs256t_post_bfpt_fixup(struct spi_nor *nor,
                          const struct sfdp_parameter_header *bfpt_header,
                          const struct sfdp_bfpt *bfpt)
 {
-       struct spi_mem_op op;
+       struct spi_mem_op op = {};
        int ret;
 
        ret = cypress_nor_set_addr_mode_nbytes(nor);
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 64a2f2f..08a46ff 100644 (file)
@@ -7170,7 +7170,7 @@ static int mv88e6xxx_probe(struct mdio_device *mdiodev)
                goto out;
        }
        if (chip->reset)
-               usleep_range(1000, 2000);
+               usleep_range(10000, 20000);
 
        /* Detect if the device is configured in single chip addressing mode,
         * otherwise continue with address specific smi init/detection.
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 33a9574..32d2c6f 100644 (file)
@@ -1329,7 +1329,7 @@ static enum xgbe_mode xgbe_phy_status_aneg(struct xgbe_prv_data *pdata)
        return pdata->phy_if.phy_impl.an_outcome(pdata);
 }
 
-static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
+static bool xgbe_phy_status_result(struct xgbe_prv_data *pdata)
 {
        struct ethtool_link_ksettings *lks = &pdata->phy.lks;
        enum xgbe_mode mode;
@@ -1367,8 +1367,13 @@ static void xgbe_phy_status_result(struct xgbe_prv_data *pdata)
 
        pdata->phy.duplex = DUPLEX_FULL;
 
-       if (xgbe_set_mode(pdata, mode) && pdata->an_again)
+       if (!xgbe_set_mode(pdata, mode))
+               return false;
+
+       if (pdata->an_again)
                xgbe_phy_reconfig_aneg(pdata);
+
+       return true;
 }
 
 static void xgbe_phy_status(struct xgbe_prv_data *pdata)
@@ -1398,7 +1403,8 @@ static void xgbe_phy_status(struct xgbe_prv_data *pdata)
                        return;
                }
 
-               xgbe_phy_status_result(pdata);
+               if (xgbe_phy_status_result(pdata))
+                       return;
 
                if (test_bit(XGBE_LINK_INIT, &pdata->dev_state))
                        clear_bit(XGBE_LINK_INIT, &pdata->dev_state);
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 059bd91..52d0a12 100644 (file)
@@ -1152,11 +1152,11 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget)
        unsigned int total_rx_bytes = 0, total_rx_pkts = 0;
        unsigned int offset = rx_ring->rx_offset;
        struct xdp_buff *xdp = &rx_ring->xdp;
+       u32 cached_ntc = rx_ring->first_desc;
        struct ice_tx_ring *xdp_ring = NULL;
        struct bpf_prog *xdp_prog = NULL;
        u32 ntc = rx_ring->next_to_clean;
        u32 cnt = rx_ring->count;
-       u32 cached_ntc = ntc;
        u32 xdp_xmit = 0;
        u32 cached_ntu;
        bool failure;
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 f404978..7c0f2ad 100644 (file)
@@ -490,7 +490,7 @@ static void poll_trace(struct mlx5_fw_tracer *tracer,
                                (u64)timestamp_low;
                break;
        default:
-               if (tracer_event->event_id >= tracer->str_db.first_string_trace ||
+               if (tracer_event->event_id >= tracer->str_db.first_string_trace &&
                    tracer_event->event_id <= tracer->str_db.first_string_trace +
                                              tracer->str_db.num_string_trace) {
                        tracer_event->type = TRACER_EVENT_TYPE_STRING;
index b8987a4..8e999f2 100644 (file)
@@ -327,6 +327,7 @@ struct mlx5e_params {
        unsigned int sw_mtu;
        int hard_mtu;
        bool ptp_rx;
+       __be32 terminate_lkey_be;
 };
 
 static inline u8 mlx5e_get_dcb_num_tc(struct mlx5e_params *params)
index 7ac1ad9..7e8e96c 100644 (file)
@@ -51,7 +51,7 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
        if (err)
                goto out;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]);
                port_buffer->buffer[i].lossy =
                        MLX5_GET(bufferx_reg, buffer, lossy);
@@ -73,14 +73,24 @@ int mlx5e_port_query_buffer(struct mlx5e_priv *priv,
                          port_buffer->buffer[i].lossy);
        }
 
-       port_buffer->headroom_size = total_used;
+       port_buffer->internal_buffers_size = 0;
+       for (i = MLX5E_MAX_NETWORK_BUFFER; i < MLX5E_TOTAL_BUFFERS; i++) {
+               buffer = MLX5_ADDR_OF(pbmc_reg, out, buffer[i]);
+               port_buffer->internal_buffers_size +=
+                       MLX5_GET(bufferx_reg, buffer, size) * port_buff_cell_sz;
+       }
+
        port_buffer->port_buffer_size =
                MLX5_GET(pbmc_reg, out, port_buffer_size) * port_buff_cell_sz;
-       port_buffer->spare_buffer_size =
-               port_buffer->port_buffer_size - total_used;
-
-       mlx5e_dbg(HW, priv, "total buffer size=%d, spare buffer size=%d\n",
-                 port_buffer->port_buffer_size,
+       port_buffer->headroom_size = total_used;
+       port_buffer->spare_buffer_size = port_buffer->port_buffer_size -
+                                        port_buffer->internal_buffers_size -
+                                        port_buffer->headroom_size;
+
+       mlx5e_dbg(HW, priv,
+                 "total buffer size=%u, headroom buffer size=%u, internal buffers size=%u, spare buffer size=%u\n",
+                 port_buffer->port_buffer_size, port_buffer->headroom_size,
+                 port_buffer->internal_buffers_size,
                  port_buffer->spare_buffer_size);
 out:
        kfree(out);
@@ -206,11 +216,11 @@ static int port_update_pool_cfg(struct mlx5_core_dev *mdev,
        if (!MLX5_CAP_GEN(mdev, sbcam_reg))
                return 0;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++)
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++)
                lossless_buff_count += ((port_buffer->buffer[i].size) &&
                                       (!(port_buffer->buffer[i].lossy)));
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                p = select_sbcm_params(&port_buffer->buffer[i], lossless_buff_count);
                err = mlx5e_port_set_sbcm(mdev, 0, i,
                                          MLX5_INGRESS_DIR,
@@ -293,7 +303,7 @@ static int port_set_buffer(struct mlx5e_priv *priv,
        if (err)
                goto out;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                void *buffer = MLX5_ADDR_OF(pbmc_reg, in, buffer[i]);
                u64 size = port_buffer->buffer[i].size;
                u64 xoff = port_buffer->buffer[i].xoff;
@@ -351,7 +361,7 @@ static int update_xoff_threshold(struct mlx5e_port_buffer *port_buffer,
 {
        int i;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                if (port_buffer->buffer[i].lossy) {
                        port_buffer->buffer[i].xoff = 0;
                        port_buffer->buffer[i].xon  = 0;
@@ -408,7 +418,7 @@ static int update_buffer_lossy(struct mlx5_core_dev *mdev,
        int err;
        int i;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                prio_count = 0;
                lossy_count = 0;
 
@@ -432,11 +442,11 @@ static int update_buffer_lossy(struct mlx5_core_dev *mdev,
        }
 
        if (changed) {
-               err = port_update_pool_cfg(mdev, port_buffer);
+               err = update_xoff_threshold(port_buffer, xoff, max_mtu, port_buff_cell_sz);
                if (err)
                        return err;
 
-               err = update_xoff_threshold(port_buffer, xoff, max_mtu, port_buff_cell_sz);
+               err = port_update_pool_cfg(mdev, port_buffer);
                if (err)
                        return err;
 
@@ -515,7 +525,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
 
        if (change & MLX5E_PORT_BUFFER_PRIO2BUFFER) {
                update_prio2buffer = true;
-               for (i = 0; i < MLX5E_MAX_BUFFER; i++)
+               for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++)
                        mlx5e_dbg(HW, priv, "%s: requested to map prio[%d] to buffer %d\n",
                                  __func__, i, prio2buffer[i]);
 
@@ -530,7 +540,7 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
        }
 
        if (change & MLX5E_PORT_BUFFER_SIZE) {
-               for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+               for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                        mlx5e_dbg(HW, priv, "%s: buffer[%d]=%d\n", __func__, i, buffer_size[i]);
                        if (!port_buffer.buffer[i].lossy && !buffer_size[i]) {
                                mlx5e_dbg(HW, priv, "%s: lossless buffer[%d] size cannot be zero\n",
@@ -544,7 +554,9 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
 
                mlx5e_dbg(HW, priv, "%s: total buffer requested=%d\n", __func__, total_used);
 
-               if (total_used > port_buffer.port_buffer_size)
+               if (total_used > port_buffer.headroom_size &&
+                   (total_used - port_buffer.headroom_size) >
+                           port_buffer.spare_buffer_size)
                        return -EINVAL;
 
                update_buffer = true;
index a6ef118..f4a19ff 100644 (file)
@@ -35,7 +35,8 @@
 #include "en.h"
 #include "port.h"
 
-#define MLX5E_MAX_BUFFER 8
+#define MLX5E_MAX_NETWORK_BUFFER 8
+#define MLX5E_TOTAL_BUFFERS 10
 #define MLX5E_DEFAULT_CABLE_LEN 7 /* 7 meters */
 
 #define MLX5_BUFFER_SUPPORTED(mdev) (MLX5_CAP_GEN(mdev, pcam_reg) && \
@@ -60,8 +61,9 @@ struct mlx5e_bufferx_reg {
 struct mlx5e_port_buffer {
        u32                       port_buffer_size;
        u32                       spare_buffer_size;
-       u32                       headroom_size;
-       struct mlx5e_bufferx_reg  buffer[MLX5E_MAX_BUFFER];
+       u32                       headroom_size;          /* Buffers 0-7 */
+       u32                       internal_buffers_size;  /* Buffers 8-9 */
+       struct mlx5e_bufferx_reg  buffer[MLX5E_MAX_NETWORK_BUFFER];
 };
 
 int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv,
index fc923a9..0380a04 100644 (file)
@@ -84,7 +84,7 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state,
 
 int
 mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state,
-                       struct flow_action *flow_action,
+                       struct flow_action *flow_action, int from, int to,
                        struct mlx5_flow_attr *attr,
                        enum mlx5_flow_namespace_type ns_type)
 {
@@ -96,6 +96,11 @@ mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state,
        priv = parse_state->flow->priv;
 
        flow_action_for_each(i, act, flow_action) {
+               if (i < from)
+                       continue;
+               else if (i > to)
+                       break;
+
                tc_act = mlx5e_tc_act_get(act->id, ns_type);
                if (!tc_act || !tc_act->post_parse)
                        continue;
index 0e6e187..d6c12d0 100644 (file)
@@ -112,7 +112,7 @@ mlx5e_tc_act_init_parse_state(struct mlx5e_tc_act_parse_state *parse_state,
 
 int
 mlx5e_tc_act_post_parse(struct mlx5e_tc_act_parse_state *parse_state,
-                       struct flow_action *flow_action,
+                       struct flow_action *flow_action, int from, int to,
                        struct mlx5_flow_attr *attr,
                        enum mlx5_flow_namespace_type ns_type);
 
index 6a052c6..f0c3464 100644 (file)
@@ -492,6 +492,19 @@ void mlx5e_encap_put(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
        mlx5e_encap_dealloc(priv, e);
 }
 
+static void mlx5e_encap_put_locked(struct mlx5e_priv *priv, struct mlx5e_encap_entry *e)
+{
+       struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
+
+       lockdep_assert_held(&esw->offloads.encap_tbl_lock);
+
+       if (!refcount_dec_and_test(&e->refcnt))
+               return;
+       list_del(&e->route_list);
+       hash_del_rcu(&e->encap_hlist);
+       mlx5e_encap_dealloc(priv, e);
+}
+
 static void mlx5e_decap_put(struct mlx5e_priv *priv, struct mlx5e_decap_entry *d)
 {
        struct mlx5_eswitch *esw = priv->mdev->priv.eswitch;
@@ -816,6 +829,8 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
        uintptr_t hash_key;
        int err = 0;
 
+       lockdep_assert_held(&esw->offloads.encap_tbl_lock);
+
        parse_attr = attr->parse_attr;
        tun_info = parse_attr->tun_info[out_index];
        mpls_info = &parse_attr->mpls_info[out_index];
@@ -829,7 +844,6 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
 
        hash_key = hash_encap_info(&key);
 
-       mutex_lock(&esw->offloads.encap_tbl_lock);
        e = mlx5e_encap_get(priv, &key, hash_key);
 
        /* must verify if encap is valid or not */
@@ -840,15 +854,6 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
                        goto out_err;
                }
 
-               mutex_unlock(&esw->offloads.encap_tbl_lock);
-               wait_for_completion(&e->res_ready);
-
-               /* Protect against concurrent neigh update. */
-               mutex_lock(&esw->offloads.encap_tbl_lock);
-               if (e->compl_result < 0) {
-                       err = -EREMOTEIO;
-                       goto out_err;
-               }
                goto attach_flow;
        }
 
@@ -877,15 +882,12 @@ int mlx5e_attach_encap(struct mlx5e_priv *priv,
        INIT_LIST_HEAD(&e->flows);
        hash_add_rcu(esw->offloads.encap_tbl, &e->encap_hlist, hash_key);
        tbl_time_before = mlx5e_route_tbl_get_last_update(priv);
-       mutex_unlock(&esw->offloads.encap_tbl_lock);
 
        if (family == AF_INET)
                err = mlx5e_tc_tun_create_header_ipv4(priv, mirred_dev, e);
        else if (family == AF_INET6)
                err = mlx5e_tc_tun_create_header_ipv6(priv, mirred_dev, e);
 
-       /* Protect against concurrent neigh update. */
-       mutex_lock(&esw->offloads.encap_tbl_lock);
        complete_all(&e->res_ready);
        if (err) {
                e->compl_result = err;
@@ -920,18 +922,15 @@ attach_flow:
        } else {
                flow_flag_set(flow, SLOW);
        }
-       mutex_unlock(&esw->offloads.encap_tbl_lock);
 
        return err;
 
 out_err:
-       mutex_unlock(&esw->offloads.encap_tbl_lock);
        if (e)
-               mlx5e_encap_put(priv, e);
+               mlx5e_encap_put_locked(priv, e);
        return err;
 
 out_err_init:
-       mutex_unlock(&esw->offloads.encap_tbl_lock);
        kfree(tun_info);
        kfree(e);
        return err;
@@ -1016,6 +1015,93 @@ out_err:
        return err;
 }
 
+int mlx5e_tc_tun_encap_dests_set(struct mlx5e_priv *priv,
+                                struct mlx5e_tc_flow *flow,
+                                struct mlx5_flow_attr *attr,
+                                struct netlink_ext_ack *extack,
+                                bool *vf_tun)
+{
+       struct mlx5e_tc_flow_parse_attr *parse_attr;
+       struct mlx5_esw_flow_attr *esw_attr;
+       struct net_device *encap_dev = NULL;
+       struct mlx5e_rep_priv *rpriv;
+       struct mlx5e_priv *out_priv;
+       struct mlx5_eswitch *esw;
+       int out_index;
+       int err = 0;
+
+       if (!mlx5e_is_eswitch_flow(flow))
+               return 0;
+
+       parse_attr = attr->parse_attr;
+       esw_attr = attr->esw_attr;
+       *vf_tun = false;
+
+       esw = priv->mdev->priv.eswitch;
+       mutex_lock(&esw->offloads.encap_tbl_lock);
+       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
+               struct net_device *out_dev;
+               int mirred_ifindex;
+
+               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
+                       continue;
+
+               mirred_ifindex = parse_attr->mirred_ifindex[out_index];
+               out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex);
+               if (!out_dev) {
+                       NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found");
+                       err = -ENODEV;
+                       goto out;
+               }
+               err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index,
+                                        extack, &encap_dev);
+               dev_put(out_dev);
+               if (err)
+                       goto out;
+
+               if (esw_attr->dests[out_index].flags &
+                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
+                   !esw_attr->dest_int_port)
+                       *vf_tun = true;
+
+               out_priv = netdev_priv(encap_dev);
+               rpriv = out_priv->ppriv;
+               esw_attr->dests[out_index].rep = rpriv->rep;
+               esw_attr->dests[out_index].mdev = out_priv->mdev;
+       }
+
+       if (*vf_tun && esw_attr->out_count > 1) {
+               NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported");
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+out:
+       mutex_unlock(&esw->offloads.encap_tbl_lock);
+       return err;
+}
+
+void mlx5e_tc_tun_encap_dests_unset(struct mlx5e_priv *priv,
+                                   struct mlx5e_tc_flow *flow,
+                                   struct mlx5_flow_attr *attr)
+{
+       struct mlx5_esw_flow_attr *esw_attr;
+       int out_index;
+
+       if (!mlx5e_is_eswitch_flow(flow))
+               return;
+
+       esw_attr = attr->esw_attr;
+
+       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
+               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
+                       continue;
+
+               mlx5e_detach_encap(flow->priv, flow, attr, out_index);
+               kfree(attr->parse_attr->tun_info[out_index]);
+       }
+}
+
 static int cmp_route_info(struct mlx5e_route_key *a,
                          struct mlx5e_route_key *b)
 {
index 8ad273d..5d7d676 100644 (file)
@@ -30,6 +30,15 @@ int mlx5e_attach_decap_route(struct mlx5e_priv *priv,
 void mlx5e_detach_decap_route(struct mlx5e_priv *priv,
                              struct mlx5e_tc_flow *flow);
 
+int mlx5e_tc_tun_encap_dests_set(struct mlx5e_priv *priv,
+                                struct mlx5e_tc_flow *flow,
+                                struct mlx5_flow_attr *attr,
+                                struct netlink_ext_ack *extack,
+                                bool *vf_tun);
+void mlx5e_tc_tun_encap_dests_unset(struct mlx5e_priv *priv,
+                                   struct mlx5e_tc_flow *flow,
+                                   struct mlx5_flow_attr *attr);
+
 struct ip_tunnel_info *mlx5e_dup_tun_info(const struct ip_tunnel_info *tun_info);
 
 int mlx5e_tc_set_attr_rx_tun(struct mlx5e_tc_flow *flow,
index 1f90594..41c396e 100644 (file)
@@ -150,10 +150,8 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb,
 
        inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
        in = kvzalloc(inlen, GFP_KERNEL);
-       if (!in) {
-               err = -ENOMEM;
-               goto out;
-       }
+       if (!in)
+               return -ENOMEM;
 
        if (enable_uc_lb)
                lb_flags = MLX5_TIRC_SELF_LB_BLOCK_BLOCK_UNICAST;
@@ -171,14 +169,13 @@ int mlx5e_refresh_tirs(struct mlx5e_priv *priv, bool enable_uc_lb,
                tirn = tir->tirn;
                err = mlx5_core_modify_tir(mdev, tirn, in);
                if (err)
-                       goto out;
+                       break;
        }
+       mutex_unlock(&mdev->mlx5e_res.hw_objs.td.list_lock);
 
-out:
        kvfree(in);
        if (err)
                netdev_err(priv->netdev, "refresh tir(0x%x) failed, %d\n", tirn, err);
-       mutex_unlock(&mdev->mlx5e_res.hw_objs.td.list_lock);
 
        return err;
 }
index 89de92d..ebee52a 100644 (file)
@@ -926,9 +926,10 @@ static int mlx5e_dcbnl_getbuffer(struct net_device *dev,
        if (err)
                return err;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++)
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++)
                dcb_buffer->buffer_size[i] = port_buffer.buffer[i].size;
-       dcb_buffer->total_size = port_buffer.port_buffer_size;
+       dcb_buffer->total_size = port_buffer.port_buffer_size -
+                                port_buffer.internal_buffers_size;
 
        return 0;
 }
@@ -970,7 +971,7 @@ static int mlx5e_dcbnl_setbuffer(struct net_device *dev,
        if (err)
                return err;
 
-       for (i = 0; i < MLX5E_MAX_BUFFER; i++) {
+       for (i = 0; i < MLX5E_MAX_NETWORK_BUFFER; i++) {
                if (port_buffer.buffer[i].size != dcb_buffer->buffer_size[i]) {
                        changed |= MLX5E_PORT_BUFFER_SIZE;
                        buffer_size = dcb_buffer->buffer_size;
index 2944691..a7c526e 100644 (file)
@@ -727,26 +727,6 @@ static void mlx5e_rq_free_shampo(struct mlx5e_rq *rq)
        mlx5e_rq_shampo_hd_free(rq);
 }
 
-static __be32 mlx5e_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev)
-{
-       u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {};
-       u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {};
-       int res;
-
-       if (!MLX5_CAP_GEN(dev, terminate_scatter_list_mkey))
-               return MLX5_TERMINATE_SCATTER_LIST_LKEY;
-
-       MLX5_SET(query_special_contexts_in, in, opcode,
-                MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
-       res = mlx5_cmd_exec_inout(dev, query_special_contexts, in, out);
-       if (res)
-               return MLX5_TERMINATE_SCATTER_LIST_LKEY;
-
-       res = MLX5_GET(query_special_contexts_out, out,
-                      terminate_scatter_list_mkey);
-       return cpu_to_be32(res);
-}
-
 static int mlx5e_alloc_rq(struct mlx5e_params *params,
                          struct mlx5e_xsk_param *xsk,
                          struct mlx5e_rq_param *rqp,
@@ -908,7 +888,7 @@ static int mlx5e_alloc_rq(struct mlx5e_params *params,
                        /* check if num_frags is not a pow of two */
                        if (rq->wqe.info.num_frags < (1 << rq->wqe.info.log_num_frags)) {
                                wqe->data[f].byte_count = 0;
-                               wqe->data[f].lkey = mlx5e_get_terminate_scatter_list_mkey(mdev);
+                               wqe->data[f].lkey = params->terminate_lkey_be;
                                wqe->data[f].addr = 0;
                        }
                }
@@ -5007,6 +4987,8 @@ void mlx5e_build_nic_params(struct mlx5e_priv *priv, struct mlx5e_xsk *xsk, u16
        /* RQ */
        mlx5e_build_rq_params(mdev, params);
 
+       params->terminate_lkey_be = mlx5_core_get_terminate_scatter_list_mkey(mdev);
+
        params->packet_merge.timeout = mlx5e_choose_lro_timeout(mdev, MLX5E_DEFAULT_LRO_TIMEOUT);
 
        /* CQ moderation params */
@@ -5279,12 +5261,16 @@ static int mlx5e_nic_init(struct mlx5_core_dev *mdev,
 
        mlx5e_timestamp_init(priv);
 
+       priv->dfs_root = debugfs_create_dir("nic",
+                                           mlx5_debugfs_get_dev_root(mdev));
+
        fs = mlx5e_fs_init(priv->profile, mdev,
                           !test_bit(MLX5E_STATE_DESTROYING, &priv->state),
                           priv->dfs_root);
        if (!fs) {
                err = -ENOMEM;
                mlx5_core_err(mdev, "FS initialization failed, %d\n", err);
+               debugfs_remove_recursive(priv->dfs_root);
                return err;
        }
        priv->fs = fs;
@@ -5305,6 +5291,7 @@ static void mlx5e_nic_cleanup(struct mlx5e_priv *priv)
        mlx5e_health_destroy_reporters(priv);
        mlx5e_ktls_cleanup(priv);
        mlx5e_fs_cleanup(priv->fs);
+       debugfs_remove_recursive(priv->dfs_root);
        priv->fs = NULL;
 }
 
@@ -5851,8 +5838,8 @@ void mlx5e_detach_netdev(struct mlx5e_priv *priv)
 }
 
 static int
-mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mdev,
-                           const struct mlx5e_profile *new_profile, void *new_ppriv)
+mlx5e_netdev_init_profile(struct net_device *netdev, struct mlx5_core_dev *mdev,
+                         const struct mlx5e_profile *new_profile, void *new_ppriv)
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
        int err;
@@ -5868,6 +5855,25 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde
        err = new_profile->init(priv->mdev, priv->netdev);
        if (err)
                goto priv_cleanup;
+
+       return 0;
+
+priv_cleanup:
+       mlx5e_priv_cleanup(priv);
+       return err;
+}
+
+static int
+mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mdev,
+                           const struct mlx5e_profile *new_profile, void *new_ppriv)
+{
+       struct mlx5e_priv *priv = netdev_priv(netdev);
+       int err;
+
+       err = mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv);
+       if (err)
+               return err;
+
        err = mlx5e_attach_netdev(priv);
        if (err)
                goto profile_cleanup;
@@ -5875,7 +5881,6 @@ mlx5e_netdev_attach_profile(struct net_device *netdev, struct mlx5_core_dev *mde
 
 profile_cleanup:
        new_profile->cleanup(priv);
-priv_cleanup:
        mlx5e_priv_cleanup(priv);
        return err;
 }
@@ -5894,6 +5899,12 @@ int mlx5e_netdev_change_profile(struct mlx5e_priv *priv,
        priv->profile->cleanup(priv);
        mlx5e_priv_cleanup(priv);
 
+       if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR) {
+               mlx5e_netdev_init_profile(netdev, mdev, new_profile, new_ppriv);
+               set_bit(MLX5E_STATE_DESTROYING, &priv->state);
+               return -EIO;
+       }
+
        err = mlx5e_netdev_attach_profile(netdev, mdev, new_profile, new_ppriv);
        if (err) { /* roll back to original profile */
                netdev_warn(netdev, "%s: new profile init failed, %d\n", __func__, err);
@@ -5955,8 +5966,11 @@ static int mlx5e_suspend(struct auxiliary_device *adev, pm_message_t state)
        struct net_device *netdev = priv->netdev;
        struct mlx5_core_dev *mdev = priv->mdev;
 
-       if (!netif_device_present(netdev))
+       if (!netif_device_present(netdev)) {
+               if (test_bit(MLX5E_STATE_DESTROYING, &priv->state))
+                       mlx5e_destroy_mdev_resources(mdev);
                return -ENODEV;
+       }
 
        mlx5e_detach_netdev(priv);
        mlx5e_destroy_mdev_resources(mdev);
@@ -6002,9 +6016,6 @@ static int mlx5e_probe(struct auxiliary_device *adev,
        priv->profile = profile;
        priv->ppriv = NULL;
 
-       priv->dfs_root = debugfs_create_dir("nic",
-                                           mlx5_debugfs_get_dev_root(priv->mdev));
-
        err = profile->init(mdev, netdev);
        if (err) {
                mlx5_core_err(mdev, "mlx5e_nic_profile init failed, %d\n", err);
@@ -6033,7 +6044,6 @@ err_resume:
 err_profile_cleanup:
        profile->cleanup(priv);
 err_destroy_netdev:
-       debugfs_remove_recursive(priv->dfs_root);
        mlx5e_destroy_netdev(priv);
 err_devlink_port_unregister:
        mlx5e_devlink_port_unregister(mlx5e_dev);
@@ -6053,7 +6063,6 @@ static void mlx5e_remove(struct auxiliary_device *adev)
        unregister_netdev(priv->netdev);
        mlx5e_suspend(adev, state);
        priv->profile->cleanup(priv);
-       debugfs_remove_recursive(priv->dfs_root);
        mlx5e_destroy_netdev(priv);
        mlx5e_devlink_port_unregister(mlx5e_dev);
        mlx5e_destroy_devlink(mlx5e_dev);
index 1fc386e..3e7041b 100644 (file)
@@ -30,6 +30,7 @@
  * SOFTWARE.
  */
 
+#include <linux/debugfs.h>
 #include <linux/mlx5/fs.h>
 #include <net/switchdev.h>
 #include <net/pkt_cls.h>
@@ -812,11 +813,15 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev,
 {
        struct mlx5e_priv *priv = netdev_priv(netdev);
 
+       priv->dfs_root = debugfs_create_dir("nic",
+                                           mlx5_debugfs_get_dev_root(mdev));
+
        priv->fs = mlx5e_fs_init(priv->profile, mdev,
                                 !test_bit(MLX5E_STATE_DESTROYING, &priv->state),
                                 priv->dfs_root);
        if (!priv->fs) {
                netdev_err(priv->netdev, "FS allocation failed\n");
+               debugfs_remove_recursive(priv->dfs_root);
                return -ENOMEM;
        }
 
@@ -829,6 +834,7 @@ static int mlx5e_init_ul_rep(struct mlx5_core_dev *mdev,
 static void mlx5e_cleanup_rep(struct mlx5e_priv *priv)
 {
        mlx5e_fs_cleanup(priv->fs);
+       debugfs_remove_recursive(priv->dfs_root);
        priv->fs = NULL;
 }
 
index e95414e..8a5a870 100644 (file)
@@ -1700,91 +1700,6 @@ int mlx5e_tc_query_route_vport(struct net_device *out_dev, struct net_device *ro
 }
 
 static int
-set_encap_dests(struct mlx5e_priv *priv,
-               struct mlx5e_tc_flow *flow,
-               struct mlx5_flow_attr *attr,
-               struct netlink_ext_ack *extack,
-               bool *vf_tun)
-{
-       struct mlx5e_tc_flow_parse_attr *parse_attr;
-       struct mlx5_esw_flow_attr *esw_attr;
-       struct net_device *encap_dev = NULL;
-       struct mlx5e_rep_priv *rpriv;
-       struct mlx5e_priv *out_priv;
-       int out_index;
-       int err = 0;
-
-       if (!mlx5e_is_eswitch_flow(flow))
-               return 0;
-
-       parse_attr = attr->parse_attr;
-       esw_attr = attr->esw_attr;
-       *vf_tun = false;
-
-       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
-               struct net_device *out_dev;
-               int mirred_ifindex;
-
-               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
-                       continue;
-
-               mirred_ifindex = parse_attr->mirred_ifindex[out_index];
-               out_dev = dev_get_by_index(dev_net(priv->netdev), mirred_ifindex);
-               if (!out_dev) {
-                       NL_SET_ERR_MSG_MOD(extack, "Requested mirred device not found");
-                       err = -ENODEV;
-                       goto out;
-               }
-               err = mlx5e_attach_encap(priv, flow, attr, out_dev, out_index,
-                                        extack, &encap_dev);
-               dev_put(out_dev);
-               if (err)
-                       goto out;
-
-               if (esw_attr->dests[out_index].flags &
-                   MLX5_ESW_DEST_CHAIN_WITH_SRC_PORT_CHANGE &&
-                   !esw_attr->dest_int_port)
-                       *vf_tun = true;
-
-               out_priv = netdev_priv(encap_dev);
-               rpriv = out_priv->ppriv;
-               esw_attr->dests[out_index].rep = rpriv->rep;
-               esw_attr->dests[out_index].mdev = out_priv->mdev;
-       }
-
-       if (*vf_tun && esw_attr->out_count > 1) {
-               NL_SET_ERR_MSG_MOD(extack, "VF tunnel encap with mirroring is not supported");
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-out:
-       return err;
-}
-
-static void
-clean_encap_dests(struct mlx5e_priv *priv,
-                 struct mlx5e_tc_flow *flow,
-                 struct mlx5_flow_attr *attr)
-{
-       struct mlx5_esw_flow_attr *esw_attr;
-       int out_index;
-
-       if (!mlx5e_is_eswitch_flow(flow))
-               return;
-
-       esw_attr = attr->esw_attr;
-
-       for (out_index = 0; out_index < MLX5_MAX_FLOW_FWD_VPORTS; out_index++) {
-               if (!(esw_attr->dests[out_index].flags & MLX5_ESW_DEST_ENCAP))
-                       continue;
-
-               mlx5e_detach_encap(priv, flow, attr, out_index);
-               kfree(attr->parse_attr->tun_info[out_index]);
-       }
-}
-
-static int
 verify_attr_actions(u32 actions, struct netlink_ext_ack *extack)
 {
        if (!(actions &
@@ -1820,7 +1735,7 @@ post_process_attr(struct mlx5e_tc_flow *flow,
        if (err)
                goto err_out;
 
-       err = set_encap_dests(flow->priv, flow, attr, extack, &vf_tun);
+       err = mlx5e_tc_tun_encap_dests_set(flow->priv, flow, attr, extack, &vf_tun);
        if (err)
                goto err_out;
 
@@ -3944,8 +3859,8 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
        struct mlx5_flow_attr *prev_attr;
        struct flow_action_entry *act;
        struct mlx5e_tc_act *tc_act;
+       int err, i, i_split = 0;
        bool is_missable;
-       int err, i;
 
        ns_type = mlx5e_get_flow_namespace(flow);
        list_add(&attr->list, &flow->attrs);
@@ -3986,7 +3901,8 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
                    i < flow_action->num_entries - 1)) {
                        is_missable = tc_act->is_missable ? tc_act->is_missable(act) : false;
 
-                       err = mlx5e_tc_act_post_parse(parse_state, flow_action, attr, ns_type);
+                       err = mlx5e_tc_act_post_parse(parse_state, flow_action, i_split, i, attr,
+                                                     ns_type);
                        if (err)
                                goto out_free_post_acts;
 
@@ -3996,6 +3912,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
                                goto out_free_post_acts;
                        }
 
+                       i_split = i + 1;
                        list_add(&attr->list, &flow->attrs);
                }
 
@@ -4010,7 +3927,7 @@ parse_tc_actions(struct mlx5e_tc_act_parse_state *parse_state,
                }
        }
 
-       err = mlx5e_tc_act_post_parse(parse_state, flow_action, attr, ns_type);
+       err = mlx5e_tc_act_post_parse(parse_state, flow_action, i_split, i, attr, ns_type);
        if (err)
                goto out_free_post_acts;
 
@@ -4324,7 +4241,7 @@ mlx5_free_flow_attr_actions(struct mlx5e_tc_flow *flow, struct mlx5_flow_attr *a
        if (attr->post_act_handle)
                mlx5e_tc_post_act_del(get_post_action(flow->priv), attr->post_act_handle);
 
-       clean_encap_dests(flow->priv, flow, attr);
+       mlx5e_tc_tun_encap_dests_unset(flow->priv, flow, attr);
 
        if (attr->action & MLX5_FLOW_CONTEXT_ACTION_COUNT)
                mlx5_fc_destroy(counter_dev, attr->counter);
index fe698c7..3db4866 100644 (file)
@@ -824,7 +824,7 @@ static int comp_irqs_request_pci(struct mlx5_core_dev *dev)
        ncomp_eqs = table->num_comp_eqs;
        cpus = kcalloc(ncomp_eqs, sizeof(*cpus), GFP_KERNEL);
        if (!cpus)
-               ret = -ENOMEM;
+               return -ENOMEM;
 
        i = 0;
        rcu_read_lock();
index a7eb65c..d6ee016 100644 (file)
@@ -923,7 +923,6 @@ static int mlx5_pci_init(struct mlx5_core_dev *dev, struct pci_dev *pdev,
        }
 
        mlx5_pci_vsc_init(dev);
-       dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev);
        return 0;
 
 err_clr_master:
@@ -1155,6 +1154,7 @@ static int mlx5_function_setup(struct mlx5_core_dev *dev, bool boot, u64 timeout
                goto err_cmd_cleanup;
        }
 
+       dev->caps.embedded_cpu = mlx5_read_embedded_cpu(dev);
        mlx5_cmd_set_state(dev, MLX5_CMDIF_STATE_UP);
 
        mlx5_start_health_poll(dev);
@@ -1802,15 +1802,16 @@ static void remove_one(struct pci_dev *pdev)
        struct devlink *devlink = priv_to_devlink(dev);
 
        set_bit(MLX5_BREAK_FW_WAIT, &dev->intf_state);
-       /* mlx5_drain_fw_reset() is using devlink APIs. Hence, we must drain
-        * fw_reset before unregistering the devlink.
+       /* mlx5_drain_fw_reset() and mlx5_drain_health_wq() are using
+        * devlink notify APIs.
+        * Hence, we must drain them before unregistering the devlink.
         */
        mlx5_drain_fw_reset(dev);
+       mlx5_drain_health_wq(dev);
        devlink_unregister(devlink);
        mlx5_sriov_disable(pdev);
        mlx5_thermal_uninit(dev);
        mlx5_crdump_disable(dev);
-       mlx5_drain_health_wq(dev);
        mlx5_uninit_one(dev);
        mlx5_pci_close(dev);
        mlx5_mdev_uninit(dev);
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 9d735c3..678f0be 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <linux/kernel.h>
 #include <linux/mlx5/driver.h>
+#include <linux/mlx5/qp.h>
 #include "mlx5_core.h"
 
 int mlx5_core_create_mkey(struct mlx5_core_dev *dev, u32 *mkey, u32 *in,
@@ -122,3 +123,23 @@ int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num)
        return mlx5_cmd_exec_in(dev, destroy_psv, in);
 }
 EXPORT_SYMBOL(mlx5_core_destroy_psv);
+
+__be32 mlx5_core_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev)
+{
+       u32 out[MLX5_ST_SZ_DW(query_special_contexts_out)] = {};
+       u32 in[MLX5_ST_SZ_DW(query_special_contexts_in)] = {};
+       u32 mkey;
+
+       if (!MLX5_CAP_GEN(dev, terminate_scatter_list_mkey))
+               return MLX5_TERMINATE_SCATTER_LIST_LKEY;
+
+       MLX5_SET(query_special_contexts_in, in, opcode,
+                MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS);
+       if (mlx5_cmd_exec_inout(dev, query_special_contexts, in, out))
+               return MLX5_TERMINATE_SCATTER_LIST_LKEY;
+
+       mkey = MLX5_GET(query_special_contexts_out, out,
+                       terminate_scatter_list_mkey);
+       return cpu_to_be32(mkey);
+}
+EXPORT_SYMBOL(mlx5_core_get_terminate_scatter_list_mkey);
index db5687d..843da89 100644 (file)
@@ -141,7 +141,7 @@ static void irq_release(struct mlx5_irq *irq)
        irq_update_affinity_hint(irq->map.virq, NULL);
 #ifdef CONFIG_RFS_ACCEL
        rmap = mlx5_eq_table_get_rmap(pool->dev);
-       if (rmap && irq->map.index)
+       if (rmap)
                irq_cpu_rmap_remove(rmap, irq->map.virq);
 #endif
 
@@ -232,12 +232,13 @@ struct mlx5_irq *mlx5_irq_alloc(struct mlx5_irq_pool *pool, int i,
        if (!irq)
                return ERR_PTR(-ENOMEM);
        if (!i || !pci_msix_can_alloc_dyn(dev->pdev)) {
-               /* The vector at index 0 was already allocated.
-                * Just get the irq number. If dynamic irq is not supported
-                * vectors have also been allocated.
+               /* The vector at index 0 is always statically allocated. If
+                * dynamic irq is not supported all vectors are statically
+                * allocated. In both cases just get the irq number and set
+                * the index.
                 */
                irq->map.virq = pci_irq_vector(dev->pdev, i);
-               irq->map.index = 0;
+               irq->map.index = i;
        } else {
                irq->map = pci_msix_alloc_irq_at(dev->pdev, MSI_ANY_INDEX, af_desc);
                if (!irq->map.virq) {
@@ -570,11 +571,11 @@ int mlx5_irqs_request_vectors(struct mlx5_core_dev *dev, u16 *cpus, int nirqs,
 
        af_desc.is_managed = false;
        for (i = 0; i < nirqs; i++) {
+               cpumask_clear(&af_desc.mask);
                cpumask_set_cpu(cpus[i], &af_desc.mask);
                irq = mlx5_irq_request(dev, i + 1, &af_desc, rmap);
                if (IS_ERR(irq))
                        break;
-               cpumask_clear(&af_desc.mask);
                irqs[i] = irq;
        }
 
index e2f26d0..0692363 100644 (file)
@@ -63,6 +63,7 @@ static void mlx5_sf_dev_remove(struct auxiliary_device *adev)
        struct mlx5_sf_dev *sf_dev = container_of(adev, struct mlx5_sf_dev, adev);
        struct devlink *devlink = priv_to_devlink(sf_dev->mdev);
 
+       mlx5_drain_health_wq(sf_dev->mdev);
        devlink_unregister(devlink);
        mlx5_uninit_one(sf_dev->mdev);
        iounmap(sf_dev->mdev->iseg);
index 13e06a6..d6947fe 100644 (file)
@@ -213,6 +213,8 @@ struct mlx5dr_ptrn_mgr *mlx5dr_ptrn_mgr_create(struct mlx5dr_domain *dmn)
        }
 
        INIT_LIST_HEAD(&mgr->ptrn_list);
+       mutex_init(&mgr->modify_hdr_mutex);
+
        return mgr;
 
 free_mgr:
@@ -237,5 +239,6 @@ void mlx5dr_ptrn_mgr_destroy(struct mlx5dr_ptrn_mgr *mgr)
        }
 
        mlx5dr_icm_pool_destroy(mgr->ptrn_icm_pool);
+       mutex_destroy(&mgr->modify_hdr_mutex);
        kfree(mgr);
 }
index afa3b92..0d5a41a 100644 (file)
@@ -245,12 +245,6 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts)
 
                skb = priv->rx_skb[rx_pi_rem];
 
-               skb_put(skb, datalen);
-
-               skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */
-
-               skb->protocol = eth_type_trans(skb, netdev);
-
                /* Alloc another RX SKB for this same index */
                rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ,
                                              &rx_buf_dma, DMA_FROM_DEVICE);
@@ -259,6 +253,13 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts)
                priv->rx_skb[rx_pi_rem] = rx_skb;
                dma_unmap_single(priv->dev, *rx_wqe_addr,
                                 MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE);
+
+               skb_put(skb, datalen);
+
+               skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */
+
+               skb->protocol = eth_type_trans(skb, netdev);
+
                *rx_wqe_addr = rx_buf_dma;
        } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) {
                priv->stats.rx_mac_errors++;
index 06d6292..d907727 100644 (file)
@@ -1279,8 +1279,6 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
        if (comp_read < 1)
                return;
 
-       apc->eth_stats.tx_cqes = comp_read;
-
        for (i = 0; i < comp_read; i++) {
                struct mana_tx_comp_oob *cqe_oob;
 
@@ -1363,8 +1361,6 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
                WARN_ON_ONCE(1);
 
        cq->work_done = pkt_transmitted;
-
-       apc->eth_stats.tx_cqes -= pkt_transmitted;
 }
 
 static void mana_post_pkt_rxq(struct mana_rxq *rxq)
@@ -1626,15 +1622,11 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
 {
        struct gdma_comp *comp = cq->gdma_comp_buf;
        struct mana_rxq *rxq = cq->rxq;
-       struct mana_port_context *apc;
        int comp_read, i;
 
-       apc = netdev_priv(rxq->ndev);
-
        comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER);
        WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER);
 
-       apc->eth_stats.rx_cqes = comp_read;
        rxq->xdp_flush = false;
 
        for (i = 0; i < comp_read; i++) {
@@ -1646,8 +1638,6 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
                        return;
 
                mana_process_rx_cqe(rxq, cq, &comp[i]);
-
-               apc->eth_stats.rx_cqes--;
        }
 
        if (rxq->xdp_flush)
index a64c814..0dc7867 100644 (file)
@@ -13,11 +13,9 @@ static const struct {
 } mana_eth_stats[] = {
        {"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)},
        {"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)},
-       {"tx_cqes", offsetof(struct mana_ethtool_stats, tx_cqes)},
        {"tx_cq_err", offsetof(struct mana_ethtool_stats, tx_cqe_err)},
        {"tx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
                                        tx_cqe_unknown_type)},
-       {"rx_cqes", offsetof(struct mana_ethtool_stats, rx_cqes)},
        {"rx_coalesced_err", offsetof(struct mana_ethtool_stats,
                                        rx_coalesced_err)},
        {"rx_cqe_unknown_type", offsetof(struct mana_ethtool_stats,
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 29afadd..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;
@@ -1485,7 +1496,7 @@ static netdev_tx_t rswitch_start_xmit(struct sk_buff *skb, struct net_device *nd
 
        if (rswitch_get_num_cur_queues(gq) >= gq->ring_size - 1) {
                netif_stop_subqueue(ndev, 0);
-               return ret;
+               return NETDEV_TX_BUSY;
        }
 
        if (skb_put_padto(skb, ETH_ZLEN))
@@ -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 0327639..c004443 100644 (file)
@@ -624,13 +624,12 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
        if (!found) { /* We don't care. */
                netif_dbg(efx, drv, efx->net_dev,
                          "Ignoring foreign filter that doesn't egdev us\n");
-               rc = -EOPNOTSUPP;
-               goto release;
+               return -EOPNOTSUPP;
        }
 
        rc = efx_mae_match_check_caps(efx, &match.mask, NULL);
        if (rc)
-               goto release;
+               return rc;
 
        if (efx_tc_match_is_encap(&match.mask)) {
                enum efx_encap_type type;
@@ -639,8 +638,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
                if (type == EFX_ENCAP_TYPE_NONE) {
                        NL_SET_ERR_MSG_MOD(extack,
                                           "Egress encap match on unsupported tunnel device");
-                       rc = -EOPNOTSUPP;
-                       goto release;
+                       return -EOPNOTSUPP;
                }
 
                rc = efx_mae_check_encap_type_supported(efx, type);
@@ -648,25 +646,24 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
                        NL_SET_ERR_MSG_FMT_MOD(extack,
                                               "Firmware reports no support for %s encap match",
                                               efx_tc_encap_type_name(type));
-                       goto release;
+                       return rc;
                }
 
                rc = efx_tc_flower_record_encap_match(efx, &match, type,
                                                      extack);
                if (rc)
-                       goto release;
+                       return rc;
        } else {
                /* This is not a tunnel decap rule, ignore it */
                netif_dbg(efx, drv, efx->net_dev,
                          "Ignoring foreign filter without encap match\n");
-               rc = -EOPNOTSUPP;
-               goto release;
+               return -EOPNOTSUPP;
        }
 
        rule = kzalloc(sizeof(*rule), GFP_USER);
        if (!rule) {
                rc = -ENOMEM;
-               goto release;
+               goto out_free;
        }
        INIT_LIST_HEAD(&rule->acts.list);
        rule->cookie = tc->cookie;
@@ -678,7 +675,7 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx,
                          "Ignoring already-offloaded rule (cookie %lx)\n",
                          tc->cookie);
                rc = -EEXIST;
-               goto release;
+               goto out_free;
        }
 
        act = kzalloc(sizeof(*act), GFP_USER);
@@ -843,6 +840,7 @@ release:
                                       efx_tc_match_action_ht_params);
                efx_tc_free_action_set_list(efx, &rule->acts, false);
        }
+out_free:
        kfree(rule);
        if (match.encap)
                efx_tc_flower_release_encap_match(efx, match.encap);
@@ -899,8 +897,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
                return rc;
        if (efx_tc_match_is_encap(&match.mask)) {
                NL_SET_ERR_MSG_MOD(extack, "Ingress enc_key matches not supported");
-               rc = -EOPNOTSUPP;
-               goto release;
+               return -EOPNOTSUPP;
        }
 
        if (tc->common.chain_index) {
@@ -924,9 +921,9 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
        if (old) {
                netif_dbg(efx, drv, efx->net_dev,
                          "Already offloaded rule (cookie %lx)\n", tc->cookie);
-               rc = -EEXIST;
                NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded");
-               goto release;
+               kfree(rule);
+               return -EEXIST;
        }
 
        /* Parse actions */
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 0fca815..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);
        }
 
@@ -7233,8 +7238,7 @@ int stmmac_dvr_probe(struct device *device,
        ndev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                            NETIF_F_RXCSUM;
        ndev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_REDIRECT |
-                            NETDEV_XDP_ACT_XSK_ZEROCOPY |
-                            NETDEV_XDP_ACT_NDO_XMIT;
+                            NETDEV_XDP_ACT_XSK_ZEROCOPY;
 
        ret = stmmac_tc_init(priv, priv);
        if (!ret) {
index 9d4d8c3..aa6f16d 100644 (file)
@@ -117,6 +117,9 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
                return -EOPNOTSUPP;
        }
 
+       if (!prog)
+               xdp_features_clear_redirect_target(dev);
+
        need_update = !!priv->xdp_prog != !!prog;
        if (if_running && need_update)
                stmmac_xdp_release(dev);
@@ -131,5 +134,8 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog,
        if (if_running && need_update)
                stmmac_xdp_open(dev);
 
+       if (prog)
+               xdp_features_set_redirect_target(dev, false);
+
        return 0;
 }
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 2ee80ed..afa1d56 100644 (file)
@@ -119,7 +119,7 @@ enum ipa_status_field_id {
 };
 
 /* Size in bytes of an IPA packet status structure */
-#define IPA_STATUS_SIZE                        sizeof(__le32[4])
+#define IPA_STATUS_SIZE                        sizeof(__le32[8])
 
 /* IPA status structure decoder; looks up field values for a structure */
 static u32 ipa_status_extract(struct ipa *ipa, const void *data,
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 6301a9a..ea1073a 100644 (file)
@@ -274,13 +274,6 @@ static int gpy_config_init(struct phy_device *phydev)
        return ret < 0 ? ret : 0;
 }
 
-static bool gpy_has_broken_mdint(struct phy_device *phydev)
-{
-       /* At least these PHYs are known to have broken interrupt handling */
-       return phydev->drv->phy_id == PHY_ID_GPY215B ||
-              phydev->drv->phy_id == PHY_ID_GPY215C;
-}
-
 static int gpy_probe(struct phy_device *phydev)
 {
        struct device *dev = &phydev->mdio.dev;
@@ -300,8 +293,7 @@ static int gpy_probe(struct phy_device *phydev)
        phydev->priv = priv;
        mutex_init(&priv->mbox_lock);
 
-       if (gpy_has_broken_mdint(phydev) &&
-           !device_property_present(dev, "maxlinear,use-broken-interrupts"))
+       if (!device_property_present(dev, "maxlinear,use-broken-interrupts"))
                phydev->dev_flags |= PHY_F_NO_IRQ;
 
        fw_version = phy_read(phydev, PHY_FWV);
@@ -659,11 +651,9 @@ static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
         * frame. Therefore, polling is the best we can do and won't do any more
         * harm.
         * It was observed that this bug happens on link state and link speed
-        * changes on a GPY215B and GYP215C independent of the firmware version
-        * (which doesn't mean that this list is exhaustive).
+        * changes independent of the firmware version.
         */
-       if (gpy_has_broken_mdint(phydev) &&
-           (reg & (PHY_IMASK_LSTC | PHY_IMASK_LSPC))) {
+       if (reg & (PHY_IMASK_LSTC | PHY_IMASK_LSPC)) {
                reg = gpy_mbox_read(phydev, REG_GPIO0_OUT);
                if (reg < 0) {
                        phy_error(phydev);
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 571e37e..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 */
@@ -1325,7 +1327,7 @@ static const struct usb_device_id products[] = {
        {QMI_FIXED_INTF(0x2001, 0x7e3d, 4)},    /* D-Link DWM-222 A2 */
        {QMI_FIXED_INTF(0x2020, 0x2031, 4)},    /* Olicard 600 */
        {QMI_FIXED_INTF(0x2020, 0x2033, 4)},    /* BroadMobi BM806U */
-       {QMI_FIXED_INTF(0x2020, 0x2060, 4)},    /* BroadMobi BM818 */
+       {QMI_QUIRK_SET_DTR(0x2020, 0x2060, 4)}, /* BroadMobi BM818 */
        {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
        {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
        {QMI_FIXED_INTF(0x1199, 0x68a2, 8)},    /* Sierra Wireless MC7710 in QMI mode */
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 44eeb17..a55381f 100644 (file)
@@ -336,10 +336,6 @@ static struct dentry *nfcsim_debugfs_root;
 static void nfcsim_debugfs_init(void)
 {
        nfcsim_debugfs_root = debugfs_create_dir("nfcsim", NULL);
-
-       if (!nfcsim_debugfs_root)
-               pr_err("Could not create debugfs entry\n");
-
 }
 
 static void nfcsim_debugfs_remove(void)
index bc523ca..5e4f884 100644 (file)
@@ -21,7 +21,7 @@ static const char * const nvme_ops[] = {
        [nvme_cmd_resv_release] = "Reservation Release",
        [nvme_cmd_zone_mgmt_send] = "Zone Management Send",
        [nvme_cmd_zone_mgmt_recv] = "Zone Management Receive",
-       [nvme_cmd_zone_append] = "Zone Management Append",
+       [nvme_cmd_zone_append] = "Zone Append",
 };
 
 static const char * const nvme_admin_ops[] = {
index 1f0cbb7..3ec38e2 100644 (file)
@@ -397,7 +397,16 @@ void nvme_complete_rq(struct request *req)
        trace_nvme_complete_rq(req);
        nvme_cleanup_cmd(req);
 
-       if (ctrl->kas)
+       /*
+        * Completions of long-running commands should not be able to
+        * defer sending of periodic keep alives, since the controller
+        * may have completed processing such commands a long time ago
+        * (arbitrarily close to command submission time).
+        * req->deadline - req->timeout is the command submission time
+        * in jiffies.
+        */
+       if (ctrl->kas &&
+           req->deadline - req->timeout >= ctrl->ka_last_check_time)
                ctrl->comp_seen = true;
 
        switch (nvme_decide_disposition(req)) {
@@ -1115,7 +1124,7 @@ u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode)
 }
 EXPORT_SYMBOL_NS_GPL(nvme_passthru_start, NVME_TARGET_PASSTHRU);
 
-void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects,
+void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects,
                       struct nvme_command *cmd, int status)
 {
        if (effects & NVME_CMD_EFFECTS_CSE_MASK) {
@@ -1132,6 +1141,8 @@ void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects,
                nvme_queue_scan(ctrl);
                flush_work(&ctrl->scan_work);
        }
+       if (ns)
+               return;
 
        switch (cmd->common.opcode) {
        case nvme_admin_set_features:
@@ -1161,9 +1172,25 @@ EXPORT_SYMBOL_NS_GPL(nvme_passthru_end, NVME_TARGET_PASSTHRU);
  *   The host should send Keep Alive commands at half of the Keep Alive Timeout
  *   accounting for transport roundtrip times [..].
  */
+static unsigned long nvme_keep_alive_work_period(struct nvme_ctrl *ctrl)
+{
+       unsigned long delay = ctrl->kato * HZ / 2;
+
+       /*
+        * When using Traffic Based Keep Alive, we need to run
+        * nvme_keep_alive_work at twice the normal frequency, as one
+        * command completion can postpone sending a keep alive command
+        * by up to twice the delay between runs.
+        */
+       if (ctrl->ctratt & NVME_CTRL_ATTR_TBKAS)
+               delay /= 2;
+       return delay;
+}
+
 static void nvme_queue_keep_alive_work(struct nvme_ctrl *ctrl)
 {
-       queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ / 2);
+       queue_delayed_work(nvme_wq, &ctrl->ka_work,
+                          nvme_keep_alive_work_period(ctrl));
 }
 
 static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq,
@@ -1172,6 +1199,20 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq,
        struct nvme_ctrl *ctrl = rq->end_io_data;
        unsigned long flags;
        bool startka = false;
+       unsigned long rtt = jiffies - (rq->deadline - rq->timeout);
+       unsigned long delay = nvme_keep_alive_work_period(ctrl);
+
+       /*
+        * Subtract off the keepalive RTT so nvme_keep_alive_work runs
+        * at the desired frequency.
+        */
+       if (rtt <= delay) {
+               delay -= rtt;
+       } else {
+               dev_warn(ctrl->device, "long keepalive RTT (%u ms)\n",
+                        jiffies_to_msecs(rtt));
+               delay = 0;
+       }
 
        blk_mq_free_request(rq);
 
@@ -1182,6 +1223,7 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq,
                return RQ_END_IO_NONE;
        }
 
+       ctrl->ka_last_check_time = jiffies;
        ctrl->comp_seen = false;
        spin_lock_irqsave(&ctrl->lock, flags);
        if (ctrl->state == NVME_CTRL_LIVE ||
@@ -1189,7 +1231,7 @@ static enum rq_end_io_ret nvme_keep_alive_end_io(struct request *rq,
                startka = true;
        spin_unlock_irqrestore(&ctrl->lock, flags);
        if (startka)
-               nvme_queue_keep_alive_work(ctrl);
+               queue_delayed_work(nvme_wq, &ctrl->ka_work, delay);
        return RQ_END_IO_NONE;
 }
 
@@ -1200,6 +1242,8 @@ static void nvme_keep_alive_work(struct work_struct *work)
        bool comp_seen = ctrl->comp_seen;
        struct request *rq;
 
+       ctrl->ka_last_check_time = jiffies;
+
        if ((ctrl->ctratt & NVME_CTRL_ATTR_TBKAS) && comp_seen) {
                dev_dbg(ctrl->device,
                        "reschedule traffic based keep-alive timer\n");
index 81c5c9e..f15e733 100644 (file)
@@ -254,7 +254,7 @@ static int nvme_submit_user_cmd(struct request_queue *q,
        blk_mq_free_request(req);
 
        if (effects)
-               nvme_passthru_end(ctrl, effects, cmd, ret);
+               nvme_passthru_end(ctrl, ns, effects, cmd, ret);
 
        return ret;
 }
index a2d4f59..8657811 100644 (file)
@@ -328,6 +328,7 @@ struct nvme_ctrl {
        struct delayed_work ka_work;
        struct delayed_work failfast_work;
        struct nvme_command ka_cmd;
+       unsigned long ka_last_check_time;
        struct work_struct fw_act_work;
        unsigned long events;
 
@@ -1077,7 +1078,7 @@ u32 nvme_command_effects(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
                         u8 opcode);
 u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u8 opcode);
 int nvme_execute_rq(struct request *rq, bool at_head);
-void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects,
+void nvme_passthru_end(struct nvme_ctrl *ctrl, struct nvme_ns *ns, u32 effects,
                       struct nvme_command *cmd, int status);
 struct nvme_ctrl *nvme_ctrl_from_file(struct file *file);
 struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid);
index 511c980..71a9c1c 100644 (file)
@@ -243,7 +243,7 @@ static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
        blk_mq_free_request(rq);
 
        if (effects)
-               nvme_passthru_end(ctrl, effects, req->cmd, status);
+               nvme_passthru_end(ctrl, ns, effects, req->cmd, status);
 }
 
 static enum rq_end_io_ret nvmet_passthru_req_done(struct request *rq,
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 df5e5b7..84aa357 100644 (file)
@@ -3796,6 +3796,7 @@ struct qla_qpair {
        uint64_t retry_term_jiff;
        struct qla_tgt_counters tgt_counters;
        uint16_t cpuid;
+       bool cpu_mapped;
        struct qla_fw_resources fwres ____cacheline_aligned;
        struct  qla_buf_pool buf_pool;
        u32     cmd_cnt;
index ec0423e..1a955c3 100644 (file)
@@ -9426,6 +9426,9 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos,
                qpair->rsp->req = qpair->req;
                qpair->rsp->qpair = qpair;
 
+               if (!qpair->cpu_mapped)
+                       qla_cpu_update(qpair, raw_smp_processor_id());
+
                if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
                        if (ha->fw_attributes & BIT_4)
                                qpair->difdix_supported = 1;
index cce6e42..7b42558 100644 (file)
@@ -539,11 +539,14 @@ qla_mapq_init_qp_cpu_map(struct qla_hw_data *ha,
        if (!ha->qp_cpu_map)
                return;
        mask = pci_irq_get_affinity(ha->pdev, msix->vector_base0);
+       if (!mask)
+               return;
        qpair->cpuid = cpumask_first(mask);
        for_each_cpu(cpu, mask) {
                ha->qp_cpu_map[cpu] = qpair;
        }
        msix->cpuid = qpair->cpuid;
+       qpair->cpu_mapped = true;
 }
 
 static inline void
index 71feda2..245e3a5 100644 (file)
@@ -3770,6 +3770,9 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 
        if (rsp->qpair->cpuid != smp_processor_id() || !rsp->qpair->rcv_intr) {
                rsp->qpair->rcv_intr = 1;
+
+               if (!rsp->qpair->cpu_mapped)
+                       qla_cpu_update(rsp->qpair, raw_smp_processor_id());
        }
 
 #define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in)                 \
index 5b230e1..8ffb75b 100644 (file)
@@ -109,7 +109,9 @@ enum {
        TASK_ATTRIBUTE_HEADOFQUEUE              = 0x1,
        TASK_ATTRIBUTE_ORDERED                  = 0x2,
        TASK_ATTRIBUTE_ACA                      = 0x4,
+};
 
+enum {
        SS_STS_NORMAL                           = 0x80000000,
        SS_STS_DONE                             = 0x40000000,
        SS_STS_HANDSHAKE                        = 0x20000000,
@@ -121,7 +123,9 @@ enum {
        SS_I2H_REQUEST_RESET                    = 0x2000,
 
        SS_MU_OPERATIONAL                       = 0x80000000,
+};
 
+enum {
        STEX_CDB_LENGTH                         = 16,
        STATUS_VAR_LEN                          = 128,
 
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 7268c2f..e0d0966 100644 (file)
@@ -36,7 +36,7 @@ config UCC
 config CPM_TSA
        tristate "CPM TSA support"
        depends on OF && HAS_IOMEM
-       depends on CPM1 || COMPILE_TEST
+       depends on CPM1 || (CPM && COMPILE_TEST)
        help
          Freescale CPM Time Slot Assigner (TSA)
          controller.
@@ -47,7 +47,7 @@ config CPM_TSA
 config CPM_QMC
        tristate "CPM QMC support"
        depends on OF && HAS_IOMEM
-       depends on CPM1 || (FSL_SOC && COMPILE_TEST)
+       depends on CPM1 || (FSL_SOC && CPM && COMPILE_TEST)
        depends on CPM_TSA
        help
          Freescale CPM QUICC Multichannel Controller
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 63de214..c079368 100644 (file)
@@ -373,7 +373,7 @@ static int ov2680_get_fmt(struct v4l2_subdev *sd,
 static int ov2680_detect(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
-       u32 high, low;
+       u32 high = 0, low = 0;
        int ret;
        u16 id;
        u8 revision;
@@ -383,7 +383,7 @@ static int ov2680_detect(struct i2c_client *client)
 
        ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_H, &high);
        if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
+               dev_err(&client->dev, "sensor_id_high read failed (%d)\n", ret);
                return -ENODEV;
        }
        ret = ov_read_reg8(client, OV2680_SC_CMMN_CHIP_ID_L, &low);
index 32700cb..ca2efcc 100644 (file)
@@ -354,7 +354,7 @@ static int imx8mq_mipi_csi_start_stream(struct csi_state *state,
                                        struct v4l2_subdev_state *sd_state)
 {
        int ret;
-       u32 hs_settle;
+       u32 hs_settle = 0;
 
        ret = imx8mq_mipi_csi_sw_reset(state);
        if (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 834cce5..b516c28 100644 (file)
@@ -364,8 +364,6 @@ struct iscsi_np *iscsit_add_np(
        init_completion(&np->np_restart_comp);
        INIT_LIST_HEAD(&np->np_list);
 
-       timer_setup(&np->np_login_timer, iscsi_handle_login_thread_timeout, 0);
-
        ret = iscsi_target_setup_login_socket(np, sockaddr);
        if (ret != 0) {
                kfree(np);
index 274bdd7..90b870f 100644 (file)
@@ -811,59 +811,6 @@ void iscsi_post_login_handler(
        iscsit_dec_conn_usage_count(conn);
 }
 
-void iscsi_handle_login_thread_timeout(struct timer_list *t)
-{
-       struct iscsi_np *np = from_timer(np, t, np_login_timer);
-
-       spin_lock_bh(&np->np_thread_lock);
-       pr_err("iSCSI Login timeout on Network Portal %pISpc\n",
-                       &np->np_sockaddr);
-
-       if (np->np_login_timer_flags & ISCSI_TF_STOP) {
-               spin_unlock_bh(&np->np_thread_lock);
-               return;
-       }
-
-       if (np->np_thread)
-               send_sig(SIGINT, np->np_thread, 1);
-
-       np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
-       spin_unlock_bh(&np->np_thread_lock);
-}
-
-static void iscsi_start_login_thread_timer(struct iscsi_np *np)
-{
-       /*
-        * This used the TA_LOGIN_TIMEOUT constant because at this
-        * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout
-        */
-       spin_lock_bh(&np->np_thread_lock);
-       np->np_login_timer_flags &= ~ISCSI_TF_STOP;
-       np->np_login_timer_flags |= ISCSI_TF_RUNNING;
-       mod_timer(&np->np_login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
-
-       pr_debug("Added timeout timer to iSCSI login request for"
-                       " %u seconds.\n", TA_LOGIN_TIMEOUT);
-       spin_unlock_bh(&np->np_thread_lock);
-}
-
-static void iscsi_stop_login_thread_timer(struct iscsi_np *np)
-{
-       spin_lock_bh(&np->np_thread_lock);
-       if (!(np->np_login_timer_flags & ISCSI_TF_RUNNING)) {
-               spin_unlock_bh(&np->np_thread_lock);
-               return;
-       }
-       np->np_login_timer_flags |= ISCSI_TF_STOP;
-       spin_unlock_bh(&np->np_thread_lock);
-
-       del_timer_sync(&np->np_login_timer);
-
-       spin_lock_bh(&np->np_thread_lock);
-       np->np_login_timer_flags &= ~ISCSI_TF_RUNNING;
-       spin_unlock_bh(&np->np_thread_lock);
-}
-
 int iscsit_setup_np(
        struct iscsi_np *np,
        struct sockaddr_storage *sockaddr)
@@ -1123,10 +1070,13 @@ static struct iscsit_conn *iscsit_alloc_conn(struct iscsi_np *np)
        spin_lock_init(&conn->nopin_timer_lock);
        spin_lock_init(&conn->response_queue_lock);
        spin_lock_init(&conn->state_lock);
+       spin_lock_init(&conn->login_worker_lock);
+       spin_lock_init(&conn->login_timer_lock);
 
        timer_setup(&conn->nopin_response_timer,
                    iscsit_handle_nopin_response_timeout, 0);
        timer_setup(&conn->nopin_timer, iscsit_handle_nopin_timeout, 0);
+       timer_setup(&conn->login_timer, iscsit_login_timeout, 0);
 
        if (iscsit_conn_set_transport(conn, np->np_transport) < 0)
                goto free_conn;
@@ -1304,7 +1254,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                goto new_sess_out;
        }
 
-       iscsi_start_login_thread_timer(np);
+       iscsit_start_login_timer(conn, current);
 
        pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n");
        conn->conn_state = TARG_CONN_STATE_XPT_UP;
@@ -1417,8 +1367,6 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        if (ret < 0)
                goto new_sess_out;
 
-       iscsi_stop_login_thread_timer(np);
-
        if (ret == 1) {
                tpg_np = conn->tpg_np;
 
@@ -1434,7 +1382,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
 new_sess_out:
        new_sess = true;
 old_sess_out:
-       iscsi_stop_login_thread_timer(np);
+       iscsit_stop_login_timer(conn);
        tpg_np = conn->tpg_np;
        iscsi_target_login_sess_out(conn, zero_tsih, new_sess);
        new_sess = false;
@@ -1448,7 +1396,6 @@ old_sess_out:
        return 1;
 
 exit:
-       iscsi_stop_login_thread_timer(np);
        spin_lock_bh(&np->np_thread_lock);
        np->np_thread_state = ISCSI_NP_THREAD_EXIT;
        spin_unlock_bh(&np->np_thread_lock);
index 24040c1..fa3fb5f 100644 (file)
@@ -535,25 +535,6 @@ static void iscsi_target_login_drop(struct iscsit_conn *conn, struct iscsi_login
        iscsi_target_login_sess_out(conn, zero_tsih, true);
 }
 
-struct conn_timeout {
-       struct timer_list timer;
-       struct iscsit_conn *conn;
-};
-
-static void iscsi_target_login_timeout(struct timer_list *t)
-{
-       struct conn_timeout *timeout = from_timer(timeout, t, timer);
-       struct iscsit_conn *conn = timeout->conn;
-
-       pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
-
-       if (conn->login_kworker) {
-               pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n",
-                        conn->login_kworker->comm, conn->login_kworker->pid);
-               send_sig(SIGINT, conn->login_kworker, 1);
-       }
-}
-
 static void iscsi_target_do_login_rx(struct work_struct *work)
 {
        struct iscsit_conn *conn = container_of(work,
@@ -562,12 +543,15 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
        struct iscsi_np *np = login->np;
        struct iscsi_portal_group *tpg = conn->tpg;
        struct iscsi_tpg_np *tpg_np = conn->tpg_np;
-       struct conn_timeout timeout;
        int rc, zero_tsih = login->zero_tsih;
        bool state;
 
        pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n",
                        conn, current->comm, current->pid);
+
+       spin_lock(&conn->login_worker_lock);
+       set_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags);
+       spin_unlock(&conn->login_worker_lock);
        /*
         * If iscsi_target_do_login_rx() has been invoked by ->sk_data_ready()
         * before initial PDU processing in iscsi_target_start_negotiation()
@@ -597,19 +581,16 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
                goto err;
        }
 
-       conn->login_kworker = current;
        allow_signal(SIGINT);
-
-       timeout.conn = conn;
-       timer_setup_on_stack(&timeout.timer, iscsi_target_login_timeout, 0);
-       mod_timer(&timeout.timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
-       pr_debug("Starting login timer for %s/%d\n", current->comm, current->pid);
+       rc = iscsit_set_login_timer_kworker(conn, current);
+       if (rc < 0) {
+               /* The login timer has already expired */
+               pr_debug("iscsi_target_do_login_rx, login failed\n");
+               goto err;
+       }
 
        rc = conn->conn_transport->iscsit_get_login_rx(conn, login);
-       del_timer_sync(&timeout.timer);
-       destroy_timer_on_stack(&timeout.timer);
        flush_signals(current);
-       conn->login_kworker = NULL;
 
        if (rc < 0)
                goto err;
@@ -646,7 +627,17 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
                if (iscsi_target_sk_check_and_clear(conn,
                                                    LOGIN_FLAGS_WRITE_ACTIVE))
                        goto err;
+
+               /*
+                * Set the login timer thread pointer to NULL to prevent the
+                * login process from getting stuck if the initiator
+                * stops sending data.
+                */
+               rc = iscsit_set_login_timer_kworker(conn, NULL);
+               if (rc < 0)
+                       goto err;
        } else if (rc == 1) {
+               iscsit_stop_login_timer(conn);
                cancel_delayed_work(&conn->login_work);
                iscsi_target_nego_release(conn);
                iscsi_post_login_handler(np, conn, zero_tsih);
@@ -656,6 +647,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work)
 
 err:
        iscsi_target_restore_sock_callbacks(conn);
+       iscsit_stop_login_timer(conn);
        cancel_delayed_work(&conn->login_work);
        iscsi_target_login_drop(conn, login);
        iscsit_deaccess_np(np, tpg, tpg_np);
@@ -1130,6 +1122,7 @@ int iscsi_target_locate_portal(
        iscsi_target_set_sock_callbacks(conn);
 
        login->np = np;
+       conn->tpg = NULL;
 
        login_req = (struct iscsi_login_req *) login->req;
        payload_length = ntoh24(login_req->dlength);
@@ -1197,7 +1190,6 @@ int iscsi_target_locate_portal(
         */
        sessiontype = strncmp(s_buf, DISCOVERY, 9);
        if (!sessiontype) {
-               conn->tpg = iscsit_global->discovery_tpg;
                if (!login->leading_connection)
                        goto get_target;
 
@@ -1214,9 +1206,11 @@ int iscsi_target_locate_portal(
                 * Serialize access across the discovery struct iscsi_portal_group to
                 * process login attempt.
                 */
+               conn->tpg = iscsit_global->discovery_tpg;
                if (iscsit_access_np(np, conn->tpg) < 0) {
                        iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+                       conn->tpg = NULL;
                        ret = -1;
                        goto out;
                }
@@ -1368,14 +1362,30 @@ int iscsi_target_start_negotiation(
         * and perform connection cleanup now.
         */
        ret = iscsi_target_do_login(conn, login);
-       if (!ret && iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU))
-               ret = -1;
+       if (!ret) {
+               spin_lock(&conn->login_worker_lock);
+
+               if (iscsi_target_sk_check_and_clear(conn, LOGIN_FLAGS_INITIAL_PDU))
+                       ret = -1;
+               else if (!test_bit(LOGIN_FLAGS_WORKER_RUNNING, &conn->login_flags)) {
+                       if (iscsit_set_login_timer_kworker(conn, NULL) < 0) {
+                               /*
+                                * The timeout has expired already.
+                                * Schedule login_work to perform the cleanup.
+                                */
+                               schedule_delayed_work(&conn->login_work, 0);
+                       }
+               }
+
+               spin_unlock(&conn->login_worker_lock);
+       }
 
        if (ret < 0) {
                iscsi_target_restore_sock_callbacks(conn);
                iscsi_remove_failed_auth_entry(conn);
        }
        if (ret != 0) {
+               iscsit_stop_login_timer(conn);
                cancel_delayed_work_sync(&conn->login_work);
                iscsi_target_nego_release(conn);
        }
index 26dc8ed..b14835f 100644 (file)
@@ -1040,6 +1040,57 @@ void iscsit_stop_nopin_timer(struct iscsit_conn *conn)
        spin_unlock_bh(&conn->nopin_timer_lock);
 }
 
+void iscsit_login_timeout(struct timer_list *t)
+{
+       struct iscsit_conn *conn = from_timer(conn, t, login_timer);
+       struct iscsi_login *login = conn->login;
+
+       pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
+
+       spin_lock_bh(&conn->login_timer_lock);
+       login->login_failed = 1;
+
+       if (conn->login_kworker) {
+               pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n",
+                        conn->login_kworker->comm, conn->login_kworker->pid);
+               send_sig(SIGINT, conn->login_kworker, 1);
+       } else {
+               schedule_delayed_work(&conn->login_work, 0);
+       }
+       spin_unlock_bh(&conn->login_timer_lock);
+}
+
+void iscsit_start_login_timer(struct iscsit_conn *conn, struct task_struct *kthr)
+{
+       pr_debug("Login timer started\n");
+
+       conn->login_kworker = kthr;
+       mod_timer(&conn->login_timer, jiffies + TA_LOGIN_TIMEOUT * HZ);
+}
+
+int iscsit_set_login_timer_kworker(struct iscsit_conn *conn, struct task_struct *kthr)
+{
+       struct iscsi_login *login = conn->login;
+       int ret = 0;
+
+       spin_lock_bh(&conn->login_timer_lock);
+       if (login->login_failed) {
+               /* The timer has already expired */
+               ret = -1;
+       } else {
+               conn->login_kworker = kthr;
+       }
+       spin_unlock_bh(&conn->login_timer_lock);
+
+       return ret;
+}
+
+void iscsit_stop_login_timer(struct iscsit_conn *conn)
+{
+       pr_debug("Login timer stopped\n");
+       timer_delete_sync(&conn->login_timer);
+}
+
 int iscsit_send_tx_data(
        struct iscsit_cmd *cmd,
        struct iscsit_conn *conn,
index 33ea799..24b8e57 100644 (file)
@@ -56,6 +56,10 @@ extern void iscsit_handle_nopin_timeout(struct timer_list *t);
 extern void __iscsit_start_nopin_timer(struct iscsit_conn *);
 extern void iscsit_start_nopin_timer(struct iscsit_conn *);
 extern void iscsit_stop_nopin_timer(struct iscsit_conn *);
+extern void iscsit_login_timeout(struct timer_list *t);
+extern void iscsit_start_login_timer(struct iscsit_conn *, struct task_struct *kthr);
+extern void iscsit_stop_login_timer(struct iscsit_conn *);
+extern int iscsit_set_login_timer_kworker(struct iscsit_conn *, struct task_struct *kthr);
 extern int iscsit_send_tx_data(struct iscsit_cmd *, struct iscsit_conn *, int);
 extern int iscsit_fe_sendpage_sg(struct iscsit_cmd *, struct iscsit_conn *);
 extern int iscsit_tx_login_rsp(struct iscsit_conn *, u8, u8);
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 2509e7f..89956bb 100644 (file)
@@ -113,13 +113,15 @@ static int tegra_uart_probe(struct platform_device *pdev)
 
        ret = serial8250_register_8250_port(&port8250);
        if (ret < 0)
-               goto err_clkdisable;
+               goto err_ctrl_assert;
 
        platform_set_drvdata(pdev, uart);
        uart->line = ret;
 
        return 0;
 
+err_ctrl_assert:
+       reset_control_assert(uart->rst);
 err_clkdisable:
        clk_disable_unprepare(uart->clk);
 
index 398e5aa..3e3fb37 100644 (file)
@@ -762,7 +762,7 @@ config SERIAL_PMACZILOG_CONSOLE
 
 config SERIAL_CPM
        tristate "CPM SCC/SMC serial port support"
-       depends on CPM2 || CPM1 || (PPC32 && COMPILE_TEST)
+       depends on CPM2 || CPM1
        select SERIAL_CORE
        help
          This driver supports the SCC and SMC serial ports on Motorola 
index 0577618..46c03ed 100644 (file)
@@ -19,8 +19,6 @@ struct gpio_desc;
 #include "cpm_uart_cpm2.h"
 #elif defined(CONFIG_CPM1)
 #include "cpm_uart_cpm1.h"
-#elif defined(CONFIG_COMPILE_TEST)
-#include "cpm_uart_cpm2.h"
 #endif
 
 #define SERIAL_CPM_MAJOR       204
index c91916e..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 = {
@@ -1495,34 +1495,36 @@ static void lpuart_break_ctl(struct uart_port *port, int break_state)
 
 static void lpuart32_break_ctl(struct uart_port *port, int break_state)
 {
-       unsigned long temp, modem;
-       struct tty_struct *tty;
-       unsigned int cflag = 0;
-
-       tty = tty_port_tty_get(&port->state->port);
-       if (tty) {
-               cflag = tty->termios.c_cflag;
-               tty_kref_put(tty);
-       }
+       unsigned long temp;
 
-       temp = lpuart32_read(port, UARTCTRL) & ~UARTCTRL_SBK;
-       modem = lpuart32_read(port, UARTMODIR);
+       temp = lpuart32_read(port, UARTCTRL);
 
+       /*
+        * LPUART IP now has two known bugs, one is CTS has higher priority than the
+        * break signal, which causes the break signal sending through UARTCTRL_SBK
+        * may impacted by the CTS input if the HW flow control is enabled. It
+        * exists on all platforms we support in this driver.
+        * Another bug is i.MX8QM LPUART may have an additional break character
+        * being sent after SBK was cleared.
+        * To avoid above two bugs, we use Transmit Data Inversion function to send
+        * the break signal instead of UARTCTRL_SBK.
+        */
        if (break_state != 0) {
-               temp |= UARTCTRL_SBK;
                /*
-                * LPUART CTS has higher priority than SBK, need to disable CTS before
-                * asserting SBK to avoid any interference if flow control is enabled.
+                * Disable the transmitter to prevent any data from being sent out
+                * during break, then invert the TX line to send break.
                 */
-               if (cflag & CRTSCTS && modem & UARTMODIR_TXCTSE)
-                       lpuart32_write(port, modem & ~UARTMODIR_TXCTSE, UARTMODIR);
+               temp &= ~UARTCTRL_TE;
+               lpuart32_write(port, temp, UARTCTRL);
+               temp |= UARTCTRL_TXINV;
+               lpuart32_write(port, temp, UARTCTRL);
        } else {
-               /* Re-enable the CTS when break off. */
-               if (cflag & CRTSCTS && !(modem & UARTMODIR_TXCTSE))
-                       lpuart32_write(port, modem | UARTMODIR_TXCTSE, UARTMODIR);
+               /* Disable the TXINV to turn off break and re-enable transmitter. */
+               temp &= ~UARTCTRL_TXINV;
+               lpuart32_write(port, temp, UARTCTRL);
+               temp |= UARTCTRL_TE;
+               lpuart32_write(port, temp, UARTCTRL);
        }
-
-       lpuart32_write(port, temp, UARTCTRL);
 }
 
 static void lpuart_setup_watermark(struct lpuart_port *sport)
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 ccfaebc..1dcadef 100644 (file)
@@ -2097,6 +2097,19 @@ int cdns3_ep_config(struct cdns3_endpoint *priv_ep, bool enable)
        else
                priv_ep->trb_burst_size = 16;
 
+       /*
+        * In versions preceding DEV_VER_V2, for example, iMX8QM, there exit the bugs
+        * in the DMA. These bugs occur when the trb_burst_size exceeds 16 and the
+        * address is not aligned to 128 Bytes (which is a product of the 64-bit AXI
+        * and AXI maximum burst length of 16 or 0xF+1, dma_axi_ctrl0[3:0]). This
+        * results in data corruption when it crosses the 4K border. The corruption
+        * specifically occurs from the position (4K - (address & 0x7F)) to 4K.
+        *
+        * So force trb_burst_size to 16 at such platform.
+        */
+       if (priv_dev->dev_ver < DEV_VER_V2)
+               priv_ep->trb_burst_size = 16;
+
        mult = min_t(u8, mult, EP_CFG_MULT_MAX);
        buffering = min_t(u8, buffering, EP_CFG_BUFFERING_MAX);
        maxburst = min_t(u8, maxburst, EP_CFG_MAXBURST_MAX);
index fbb087b..268ccbe 100644 (file)
@@ -172,3 +172,44 @@ void hcd_buffer_free(
        }
        dma_free_coherent(hcd->self.sysdev, size, addr, dma);
 }
+
+void *hcd_buffer_alloc_pages(struct usb_hcd *hcd,
+               size_t size, gfp_t mem_flags, dma_addr_t *dma)
+{
+       if (size == 0)
+               return NULL;
+
+       if (hcd->localmem_pool)
+               return gen_pool_dma_alloc_align(hcd->localmem_pool,
+                               size, dma, PAGE_SIZE);
+
+       /* some USB hosts just use PIO */
+       if (!hcd_uses_dma(hcd)) {
+               *dma = DMA_MAPPING_ERROR;
+               return (void *)__get_free_pages(mem_flags,
+                               get_order(size));
+       }
+
+       return dma_alloc_coherent(hcd->self.sysdev,
+                       size, dma, mem_flags);
+}
+
+void hcd_buffer_free_pages(struct usb_hcd *hcd,
+               size_t size, void *addr, dma_addr_t dma)
+{
+       if (!addr)
+               return;
+
+       if (hcd->localmem_pool) {
+               gen_pool_free(hcd->localmem_pool,
+                               (unsigned long)addr, size);
+               return;
+       }
+
+       if (!hcd_uses_dma(hcd)) {
+               free_pages((unsigned long)addr, get_order(size));
+               return;
+       }
+
+       dma_free_coherent(hcd->self.sysdev, size, addr, dma);
+}
index e501a03..fcf6881 100644 (file)
@@ -186,6 +186,7 @@ static int connected(struct usb_dev_state *ps)
 static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
 {
        struct usb_dev_state *ps = usbm->ps;
+       struct usb_hcd *hcd = bus_to_hcd(ps->dev->bus);
        unsigned long flags;
 
        spin_lock_irqsave(&ps->lock, flags);
@@ -194,8 +195,8 @@ static void dec_usb_memory_use_count(struct usb_memory *usbm, int *count)
                list_del(&usbm->memlist);
                spin_unlock_irqrestore(&ps->lock, flags);
 
-               usb_free_coherent(ps->dev, usbm->size, usbm->mem,
-                               usbm->dma_handle);
+               hcd_buffer_free_pages(hcd, usbm->size,
+                               usbm->mem, usbm->dma_handle);
                usbfs_decrease_memory_usage(
                        usbm->size + sizeof(struct usb_memory));
                kfree(usbm);
@@ -234,7 +235,7 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
        size_t size = vma->vm_end - vma->vm_start;
        void *mem;
        unsigned long flags;
-       dma_addr_t dma_handle;
+       dma_addr_t dma_handle = DMA_MAPPING_ERROR;
        int ret;
 
        ret = usbfs_increase_memory_usage(size + sizeof(struct usb_memory));
@@ -247,8 +248,8 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
                goto error_decrease_mem;
        }
 
-       mem = usb_alloc_coherent(ps->dev, size, GFP_USER | __GFP_NOWARN,
-                       &dma_handle);
+       mem = hcd_buffer_alloc_pages(hcd,
+                       size, GFP_USER | __GFP_NOWARN, &dma_handle);
        if (!mem) {
                ret = -ENOMEM;
                goto error_free_usbm;
@@ -264,7 +265,14 @@ static int usbdev_mmap(struct file *file, struct vm_area_struct *vma)
        usbm->vma_use_count = 1;
        INIT_LIST_HEAD(&usbm->memlist);
 
-       if (hcd->localmem_pool || !hcd_uses_dma(hcd)) {
+       /*
+        * In DMA-unavailable cases, hcd_buffer_alloc_pages allocates
+        * normal pages and assigns DMA_MAPPING_ERROR to dma_handle. Check
+        * whether we are in such cases, and then use remap_pfn_range (or
+        * dma_mmap_coherent) to map normal (or DMA) pages into the user
+        * space, respectively.
+        */
+       if (dma_handle == DMA_MAPPING_ERROR) {
                if (remap_pfn_range(vma, vma->vm_start,
                                    virt_to_phys(usbm->mem) >> PAGE_SHIFT,
                                    size, vma->vm_page_prot) < 0) {
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 a13c946..f41a385 100644 (file)
@@ -3535,6 +3535,7 @@ static void ffs_func_unbind(struct usb_configuration *c,
        /* Drain any pending AIO completions */
        drain_workqueue(ffs->io_completion_wq);
 
+       ffs_event_add(ffs, FUNCTIONFS_UNBIND);
        if (!--opts->refcnt)
                functionfs_unbind(ffs);
 
@@ -3559,7 +3560,6 @@ static void ffs_func_unbind(struct usb_configuration *c,
        func->function.ssp_descriptors = NULL;
        func->interfaces_nums = NULL;
 
-       ffs_event_add(ffs, FUNCTIONFS_UNBIND);
 }
 
 static struct usb_function *ffs_alloc(struct usb_function_instance *fi)
index c80f9bd..a36913a 100644 (file)
@@ -170,6 +170,9 @@ static int udc_pci_probe(
                retval = -ENODEV;
                goto err_probe;
        }
+
+       udc = dev;
+
        return 0;
 
 err_probe:
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 438cc40..603dbd4 100644 (file)
@@ -920,7 +920,7 @@ static int __maybe_unused tps6598x_resume(struct device *dev)
                enable_irq(client->irq);
        }
 
-       if (client->irq)
+       if (!client->irq)
                queue_delayed_work(system_power_efficient_wq, &tps->wq_poll,
                                   msecs_to_jiffies(POLL_INTERVAL));
 
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 a92af08..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);
-               wake_up_process(dev->worker->vtsk->task);
+               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);
 
@@ -333,31 +333,21 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        __vhost_vq_meta_reset(vq);
 }
 
-static int vhost_worker(void *data)
+static bool vhost_worker(void *data)
 {
        struct vhost_worker *worker = data;
        struct vhost_work *work, *work_next;
        struct llist_node *node;
 
-       for (;;) {
-               /* mb paired w/ kthread_stop */
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (vhost_task_should_stop(worker->vtsk)) {
-                       __set_current_state(TASK_RUNNING);
-                       break;
-               }
-
-               node = llist_del_all(&worker->work_list);
-               if (!node)
-                       schedule();
+       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();
                llist_for_each_entry_safe(work, work_next, node, node) {
                        clear_bit(VHOST_WORK_QUEUED, &work->flags);
-                       __set_current_state(TASK_RUNNING);
                        kcov_remote_start_common(worker->kcov_handle);
                        work->fn(work);
                        kcov_remote_stop();
@@ -365,7 +355,7 @@ static int vhost_worker(void *data)
                }
        }
 
-       return 0;
+       return !!node;
 }
 
 static void vhost_vq_free_iovecs(struct vhost_virtqueue *vq)
@@ -468,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;
@@ -542,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 */
@@ -1626,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;
@@ -2575,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 024d0ee..08d15e4 100644 (file)
@@ -590,7 +590,7 @@ err_fb_alloc:
        return retval;
 }
 
-static int arcfb_remove(struct platform_device *dev)
+static void arcfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -601,12 +601,11 @@ static int arcfb_remove(struct platform_device *dev)
                vfree((void __force *)info->screen_base);
                framebuffer_release(info);
        }
-       return 0;
 }
 
 static struct platform_driver arcfb_driver = {
        .probe  = arcfb_probe,
-       .remove = arcfb_remove,
+       .remove_new = arcfb_remove,
        .driver = {
                .name   = "arcfb",
        },
index 519313b..648d6ca 100644 (file)
@@ -520,13 +520,10 @@ failed:
        return -ENODEV;
 }
 
-int au1100fb_drv_remove(struct platform_device *dev)
+void au1100fb_drv_remove(struct platform_device *dev)
 {
        struct au1100fb_device *fbdev = NULL;
 
-       if (!dev)
-               return -ENODEV;
-
        fbdev = platform_get_drvdata(dev);
 
 #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
@@ -543,8 +540,6 @@ int au1100fb_drv_remove(struct platform_device *dev)
                clk_disable_unprepare(fbdev->lcdclk);
                clk_put(fbdev->lcdclk);
        }
-
-       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -593,9 +588,9 @@ static struct platform_driver au1100fb_driver = {
                .name           = "au1100-lcd",
        },
        .probe          = au1100fb_drv_probe,
-        .remove                = au1100fb_drv_remove,
+       .remove_new     = au1100fb_drv_remove,
        .suspend        = au1100fb_drv_suspend,
-        .resume                = au1100fb_drv_resume,
+       .resume         = au1100fb_drv_resume,
 };
 module_platform_driver(au1100fb_driver);
 
index b6b22fa..aed88ce 100644 (file)
@@ -1765,7 +1765,7 @@ failed:
        return ret;
 }
 
-static int au1200fb_drv_remove(struct platform_device *dev)
+static void au1200fb_drv_remove(struct platform_device *dev)
 {
        struct au1200fb_platdata *pd = platform_get_drvdata(dev);
        struct fb_info *fbi;
@@ -1788,8 +1788,6 @@ static int au1200fb_drv_remove(struct platform_device *dev)
        }
 
        free_irq(platform_get_irq(dev, 0), (void *)dev);
-
-       return 0;
 }
 
 #ifdef CONFIG_PM
@@ -1840,7 +1838,7 @@ static struct platform_driver au1200fb_driver = {
                .pm     = AU1200FB_PMOPS,
        },
        .probe          = au1200fb_drv_probe,
-       .remove         = au1200fb_drv_remove,
+       .remove_new     = au1200fb_drv_remove,
 };
 module_platform_driver(au1200fb_driver);
 
index 55e62dd..b518cac 100644 (file)
@@ -1193,7 +1193,7 @@ err:
 
 }
 
-static int broadsheetfb_remove(struct platform_device *dev)
+static void broadsheetfb_remove(struct platform_device *dev)
 {
        struct fb_info *info = platform_get_drvdata(dev);
 
@@ -1209,12 +1209,11 @@ static int broadsheetfb_remove(struct platform_device *dev)
                module_put(par->board->owner);
                framebuffer_release(info);
        }
-       return 0;
 }
 
 static struct platform_driver broadsheetfb_driver = {
        .probe  = broadsheetfb_probe,
-       .remove = broadsheetfb_remove,
+       .remove_new = broadsheetfb_remove,
        .driver = {
                .name   = "broadsheetfb",
        },
index 9cbadcd..025d663 100644 (file)
@@ -352,7 +352,7 @@ out_err:
        return err;
 }
 
-static int bw2_remove(struct platform_device *op)
+static void bw2_remove(struct platform_device *op)
 {
        struct fb_info *info = dev_get_drvdata(&op->dev);
        struct bw2_par *par = info->par;
@@ -363,8 +363,6 @@ static int bw2_remove(struct platform_device *op)
        of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
 
        framebuffer_release(info);
-
-       return 0;
 }
 
 static const struct of_device_id bw2_match[] = {
@@ -381,7 +379,7 @@ static struct platform_driver bw2_driver = {
                .of_match_table = bw2_match,
        },
        .probe          = bw2_probe,
-       .remove         = bw2_remove,
+       .remove_new     = bw2_remove,
 };
 
 static int __init bw2_init(void)
index f98e8f2..8587c9d 100644 (file)
@@ -247,6 +247,9 @@ static void bit_cursor(struct vc_data *vc, struct fb_info *info, int mode,
 
        cursor.set = 0;
 
+       if (!vc->vc_font.data)
+               return;
+
        c = scr_readw((u16 *) vc->vc_pos);
        attribute = get_attribute(info, c);
        src = vc->vc_font.data + ((c & charmask) * (w * vc->vc_font.height));
index 975dd68..ee7d01a 100644 (file)
@@ -1452,9 +1452,13 @@ static int init_imstt(struct fb_info *info)
                      FBINFO_HWACCEL_FILLRECT |
                      FBINFO_HWACCEL_YPAN;
 
-       fb_alloc_cmap(&info->cmap, 0, 0);
+       if (fb_alloc_cmap(&info->cmap, 0, 0)) {
+               framebuffer_release(info);
+               return -ENODEV;
+       }
 
        if (register_framebuffer(info) < 0) {
+               fb_dealloc_cmap(&info->cmap);
                framebuffer_release(info);
                return -ENODEV;
        }
@@ -1531,8 +1535,10 @@ static int imsttfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto error;
        info->pseudo_palette = par->palette;
        ret = init_imstt(info);
-       if (!ret)
-               pci_set_drvdata(pdev, info);
+       if (ret)
+               goto error;
+
+       pci_set_drvdata(pdev, info);
        return ret;
 
 error:
index 727a10a..b15a8ad 100644 (file)
@@ -1291,7 +1291,7 @@ static struct i2c_driver maven_driver={
        .driver = {
                .name   = "maven",
        },
-       .probe_new      = maven_probe,
+       .probe          = maven_probe,
        .remove         = maven_remove,
        .id_table       = maven_id,
 };
index 046b999..132d1a2 100644 (file)
@@ -844,7 +844,7 @@ static const struct i2c_device_id ssd1307fb_i2c_id[] = {
 MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id);
 
 static struct i2c_driver ssd1307fb_driver = {
-       .probe_new = ssd1307fb_probe,
+       .probe = ssd1307fb_probe,
        .remove = ssd1307fb_remove,
        .id_table = ssd1307fb_i2c_id,
        .driver = {
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 5379c47..b3ad0f5 100644 (file)
@@ -330,7 +330,7 @@ static void btrfs_end_bio_work(struct work_struct *work)
        if (bbio->inode && !(bbio->bio.bi_opf & REQ_META))
                btrfs_check_read_bio(bbio, bbio->bio.bi_private);
        else
-               bbio->end_io(bbio);
+               btrfs_orig_bbio_end_io(bbio);
 }
 
 static void btrfs_simple_end_io(struct bio *bio)
@@ -811,10 +811,6 @@ void btrfs_submit_repair_write(struct btrfs_bio *bbio, int mirror_num, bool dev_
                goto fail;
 
        if (dev_replace) {
-               if (btrfs_op(&bbio->bio) == BTRFS_MAP_WRITE && btrfs_is_zoned(fs_info)) {
-                       bbio->bio.bi_opf &= ~REQ_OP_WRITE;
-                       bbio->bio.bi_opf |= REQ_OP_ZONE_APPEND;
-               }
                ASSERT(smap.dev == fs_info->dev_replace.srcdev);
                smap.dev = fs_info->dev_replace.tgtdev;
        }
index 6de6dcf..dabc79c 100644 (file)
@@ -96,7 +96,7 @@ static void csum_tree_block(struct extent_buffer *buf, u8 *result)
        crypto_shash_update(shash, kaddr + BTRFS_CSUM_SIZE,
                            first_page_part - BTRFS_CSUM_SIZE);
 
-       for (i = 1; i < num_pages; i++) {
+       for (i = 1; i < num_pages && INLINE_EXTENT_BUFFER_PAGES > 1; i++) {
                kaddr = page_address(buf->pages[i]);
                crypto_shash_update(shash, kaddr, PAGE_SIZE);
        }
@@ -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 dd37cba..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;
@@ -1137,6 +1146,35 @@ static void scrub_write_endio(struct btrfs_bio *bbio)
                wake_up(&stripe->io_wait);
 }
 
+static void scrub_submit_write_bio(struct scrub_ctx *sctx,
+                                  struct scrub_stripe *stripe,
+                                  struct btrfs_bio *bbio, bool dev_replace)
+{
+       struct btrfs_fs_info *fs_info = sctx->fs_info;
+       u32 bio_len = bbio->bio.bi_iter.bi_size;
+       u32 bio_off = (bbio->bio.bi_iter.bi_sector << SECTOR_SHIFT) -
+                     stripe->logical;
+
+       fill_writer_pointer_gap(sctx, stripe->physical + bio_off);
+       atomic_inc(&stripe->pending_io);
+       btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace);
+       if (!btrfs_is_zoned(fs_info))
+               return;
+       /*
+        * For zoned writeback, queue depth must be 1, thus we must wait for
+        * the write to finish before the next write.
+        */
+       wait_scrub_stripe_io(stripe);
+
+       /*
+        * And also need to update the write pointer if write finished
+        * successfully.
+        */
+       if (!test_bit(bio_off >> fs_info->sectorsize_bits,
+                     &stripe->write_error_bitmap))
+               sctx->write_pointer += bio_len;
+}
+
 /*
  * Submit the write bio(s) for the sectors specified by @write_bitmap.
  *
@@ -1155,7 +1193,6 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
 {
        struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
        struct btrfs_bio *bbio = NULL;
-       const bool zoned = btrfs_is_zoned(fs_info);
        int sector_nr;
 
        for_each_set_bit(sector_nr, &write_bitmap, stripe->nr_sectors) {
@@ -1168,13 +1205,7 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
 
                /* Cannot merge with previous sector, submit the current one. */
                if (bbio && sector_nr && !test_bit(sector_nr - 1, &write_bitmap)) {
-                       fill_writer_pointer_gap(sctx, stripe->physical +
-                                       (sector_nr << fs_info->sectorsize_bits));
-                       atomic_inc(&stripe->pending_io);
-                       btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace);
-                       /* For zoned writeback, queue depth must be 1. */
-                       if (zoned)
-                               wait_scrub_stripe_io(stripe);
+                       scrub_submit_write_bio(sctx, stripe, bbio, dev_replace);
                        bbio = NULL;
                }
                if (!bbio) {
@@ -1187,14 +1218,8 @@ static void scrub_write_sectors(struct scrub_ctx *sctx, struct scrub_stripe *str
                ret = bio_add_page(&bbio->bio, page, fs_info->sectorsize, pgoff);
                ASSERT(ret == fs_info->sectorsize);
        }
-       if (bbio) {
-               fill_writer_pointer_gap(sctx, bbio->bio.bi_iter.bi_sector <<
-                                       SECTOR_SHIFT);
-               atomic_inc(&stripe->pending_io);
-               btrfs_submit_repair_write(bbio, stripe->mirror_num, dev_replace);
-               if (zoned)
-                       wait_scrub_stripe_io(stripe);
-       }
+       if (bbio)
+               scrub_submit_write_bio(sctx, stripe, bbio, dev_replace);
 }
 
 /*
@@ -1474,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;
@@ -1714,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;
 
@@ -2238,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 9b212e8..d2755d5 100644 (file)
@@ -6158,7 +6158,7 @@ static int log_delayed_deletions_incremental(struct btrfs_trans_handle *trans,
 {
        struct btrfs_root *log = inode->root->log_root;
        const struct btrfs_delayed_item *curr;
-       u64 last_range_start;
+       u64 last_range_start = 0;
        u64 last_range_end = 0;
        struct btrfs_key key;
 
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 ece7bad..88740c5 100644 (file)
@@ -371,7 +371,9 @@ static int zap_process(struct task_struct *start, int exit_code)
                if (t != current && !(t->flags & PF_POSTCOREDUMP)) {
                        sigaddset(&t->pending.signal, SIGKILL);
                        signal_wake_up(t, 1);
-                       nr++;
+                       /* The vhost_worker does not particpate in coredumps */
+                       if ((t->flags & (PF_USER_WORKER | PF_IO_WORKER)) != PF_USER_WORKER)
+                               nr++;
                }
        }
 
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 6948d67..8104a21 100644 (file)
@@ -918,11 +918,13 @@ do {                                                                             \
  *                       where the second inode has larger inode number
  *                       than the first
  *  I_DATA_SEM_QUOTA  - Used for quota inodes only
+ *  I_DATA_SEM_EA     - Used for ea_inodes only
  */
 enum {
        I_DATA_SEM_NORMAL = 0,
        I_DATA_SEM_OTHER,
        I_DATA_SEM_QUOTA,
+       I_DATA_SEM_EA
 };
 
 
@@ -2901,7 +2903,8 @@ typedef enum {
        EXT4_IGET_NORMAL =      0,
        EXT4_IGET_SPECIAL =     0x0001, /* OK to iget a system inode */
        EXT4_IGET_HANDLE =      0x0002, /* Inode # is from a handle */
-       EXT4_IGET_BAD =         0x0004  /* Allow to iget a bad inode */
+       EXT4_IGET_BAD =         0x0004, /* Allow to iget a bad inode */
+       EXT4_IGET_EA_INODE =    0x0008  /* Inode should contain an EA value */
 } ext4_iget_flags;
 
 extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
index f65fdb2..2a14320 100644 (file)
@@ -108,6 +108,13 @@ static int ext4_fsync_journal(struct inode *inode, bool datasync,
        journal_t *journal = EXT4_SB(inode->i_sb)->s_journal;
        tid_t commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid;
 
+       /*
+        * Fastcommit does not really support fsync on directories or other
+        * special files. Force a full commit.
+        */
+       if (!S_ISREG(inode->i_mode))
+               return ext4_force_commit(inode->i_sb);
+
        if (journal->j_flags & JBD2_BARRIER &&
            !jbd2_trans_will_send_data_barrier(journal, commit_tid))
                *needs_barrier = true;
index ce5f21b..02de439 100644 (file)
@@ -4641,6 +4641,24 @@ static inline void ext4_inode_set_iversion_queried(struct inode *inode, u64 val)
                inode_set_iversion_queried(inode, val);
 }
 
+static const char *check_igot_inode(struct inode *inode, ext4_iget_flags flags)
+
+{
+       if (flags & EXT4_IGET_EA_INODE) {
+               if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
+                       return "missing EA_INODE flag";
+               if (ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
+                   EXT4_I(inode)->i_file_acl)
+                       return "ea_inode with extended attributes";
+       } else {
+               if ((EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL))
+                       return "unexpected EA_INODE flag";
+       }
+       if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD))
+               return "unexpected bad inode w/o EXT4_IGET_BAD";
+       return NULL;
+}
+
 struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
                          ext4_iget_flags flags, const char *function,
                          unsigned int line)
@@ -4650,6 +4668,7 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
        struct ext4_inode_info *ei;
        struct ext4_super_block *es = EXT4_SB(sb)->s_es;
        struct inode *inode;
+       const char *err_str;
        journal_t *journal = EXT4_SB(sb)->s_journal;
        long ret;
        loff_t size;
@@ -4677,8 +4696,14 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
        inode = iget_locked(sb, ino);
        if (!inode)
                return ERR_PTR(-ENOMEM);
-       if (!(inode->i_state & I_NEW))
+       if (!(inode->i_state & I_NEW)) {
+               if ((err_str = check_igot_inode(inode, flags)) != NULL) {
+                       ext4_error_inode(inode, function, line, 0, err_str);
+                       iput(inode);
+                       return ERR_PTR(-EFSCORRUPTED);
+               }
                return inode;
+       }
 
        ei = EXT4_I(inode);
        iloc.bh = NULL;
@@ -4944,10 +4969,9 @@ struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
        if (IS_CASEFOLDED(inode) && !ext4_has_feature_casefold(inode->i_sb))
                ext4_error_inode(inode, function, line, 0,
                                 "casefold flag without casefold feature");
-       if (is_bad_inode(inode) && !(flags & EXT4_IGET_BAD)) {
-               ext4_error_inode(inode, function, line, 0,
-                                "bad inode without EXT4_IGET_BAD flag");
-               ret = -EUCLEAN;
+       if ((err_str = check_igot_inode(inode, flags)) != NULL) {
+               ext4_error_inode(inode, function, line, 0, err_str);
+               ret = -EFSCORRUPTED;
                goto bad_inode;
        }
 
index 7b2e36d..20f67a2 100644 (file)
@@ -2062,7 +2062,7 @@ static void ext4_mb_check_limits(struct ext4_allocation_context *ac,
        if (bex->fe_len < gex->fe_len)
                return;
 
-       if (finish_group)
+       if (finish_group || ac->ac_found > sbi->s_mb_min_to_scan)
                ext4_mb_use_best_found(ac, e4b);
 }
 
@@ -2074,6 +2074,20 @@ static void ext4_mb_check_limits(struct ext4_allocation_context *ac,
  * in the context. Later, the best found extent will be used, if
  * mballoc can't find good enough extent.
  *
+ * The algorithm used is roughly as follows:
+ *
+ * * If free extent found is exactly as big as goal, then
+ *   stop the scan and use it immediately
+ *
+ * * If free extent found is smaller than goal, then keep retrying
+ *   upto a max of sbi->s_mb_max_to_scan times (default 200). After
+ *   that stop scanning and use whatever we have.
+ *
+ * * If free extent found is bigger than goal, then keep retrying
+ *   upto a max of sbi->s_mb_min_to_scan times (default 10) before
+ *   stopping the scan and using the extent.
+ *
+ *
  * FIXME: real allocation policy is to be designed yet!
  */
 static void ext4_mb_measure_extent(struct ext4_allocation_context *ac,
index 9680fe7..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));
@@ -6589,18 +6588,6 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
        }
 
        /*
-        * Reinitialize lazy itable initialization thread based on
-        * current settings
-        */
-       if (sb_rdonly(sb) || !test_opt(sb, INIT_INODE_TABLE))
-               ext4_unregister_li_request(sb);
-       else {
-               ext4_group_t first_not_zeroed;
-               first_not_zeroed = ext4_has_uninit_itable(sb);
-               ext4_register_li_request(sb, first_not_zeroed);
-       }
-
-       /*
         * Handle creation of system zone data early because it can fail.
         * Releasing of existing data is done when we are sure remount will
         * succeed.
@@ -6634,8 +6621,17 @@ 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
+        */
+       if (sb_rdonly(sb) || !test_opt(sb, INIT_INODE_TABLE))
+               ext4_unregister_li_request(sb);
+       else {
+               ext4_group_t first_not_zeroed;
+               first_not_zeroed = ext4_has_uninit_itable(sb);
+               ext4_register_li_request(sb, first_not_zeroed);
+       }
 
        if (!ext4_has_feature_mmp(sb) || sb_rdonly(sb))
                ext4_stop_mmpd(sbi);
index dfc2e22..321e3a8 100644 (file)
@@ -121,7 +121,11 @@ ext4_expand_inode_array(struct ext4_xattr_inode_array **ea_inode_array,
 #ifdef CONFIG_LOCKDEP
 void ext4_xattr_inode_set_class(struct inode *ea_inode)
 {
+       struct ext4_inode_info *ei = EXT4_I(ea_inode);
+
        lockdep_set_subclass(&ea_inode->i_rwsem, 1);
+       (void) ei;      /* shut up clang warning if !CONFIG_LOCKDEP */
+       lockdep_set_subclass(&ei->i_data_sem, I_DATA_SEM_EA);
 }
 #endif
 
@@ -433,7 +437,7 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
                return -EFSCORRUPTED;
        }
 
-       inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_NORMAL);
+       inode = ext4_iget(parent->i_sb, ea_ino, EXT4_IGET_EA_INODE);
        if (IS_ERR(inode)) {
                err = PTR_ERR(inode);
                ext4_error(parent->i_sb,
@@ -441,23 +445,6 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
                           err);
                return err;
        }
-
-       if (is_bad_inode(inode)) {
-               ext4_error(parent->i_sb,
-                          "error while reading EA inode %lu is_bad_inode",
-                          ea_ino);
-               err = -EIO;
-               goto error;
-       }
-
-       if (!(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL)) {
-               ext4_error(parent->i_sb,
-                          "EA inode %lu does not have EXT4_EA_INODE_FL flag",
-                           ea_ino);
-               err = -EINVAL;
-               goto error;
-       }
-
        ext4_xattr_inode_set_class(inode);
 
        /*
@@ -478,9 +465,6 @@ static int ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino,
 
        *ea_inode = inode;
        return 0;
-error:
-       iput(inode);
-       return err;
 }
 
 /* Remove entry from mbcache when EA inode is getting evicted */
@@ -1556,11 +1540,11 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
 
        while (ce) {
                ea_inode = ext4_iget(inode->i_sb, ce->e_value,
-                                    EXT4_IGET_NORMAL);
-               if (!IS_ERR(ea_inode) &&
-                   !is_bad_inode(ea_inode) &&
-                   (EXT4_I(ea_inode)->i_flags & EXT4_EA_INODE_FL) &&
-                   i_size_read(ea_inode) == value_len &&
+                                    EXT4_IGET_EA_INODE);
+               if (IS_ERR(ea_inode))
+                       goto next_entry;
+               ext4_xattr_inode_set_class(ea_inode);
+               if (i_size_read(ea_inode) == value_len &&
                    !ext4_xattr_inode_read(ea_inode, ea_data, value_len) &&
                    !ext4_xattr_inode_verify_hashes(ea_inode, NULL, ea_data,
                                                    value_len) &&
@@ -1570,9 +1554,8 @@ ext4_xattr_inode_cache_find(struct inode *inode, const void *value,
                        kvfree(ea_data);
                        return ea_inode;
                }
-
-               if (!IS_ERR(ea_inode))
-                       iput(ea_inode);
+               iput(ea_inode);
+       next_entry:
                ce = mb_cache_entry_find_next(ea_inode_cache, ce);
        }
        kvfree(ea_data);
@@ -2073,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,
@@ -2137,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 c159817..b4fd7a7 100644 (file)
@@ -690,16 +690,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred
        if (err != 0 || fd < 0)
                return -EINVAL;
 
-       if (svc_alien_sock(net, fd)) {
-               printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
-               return -EINVAL;
-       }
-
        err = nfsd_create_serv(net);
        if (err != 0)
                return err;
 
-       err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
+       err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred);
 
        if (err >= 0 &&
            !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1))
index bb9d471..db67f8e 100644 (file)
@@ -536,7 +536,15 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
        inode_lock(inode);
        for (retries = 1;;) {
-               host_err = __nfsd_setattr(dentry, iap);
+               struct iattr attrs;
+
+               /*
+                * notify_change() can alter its iattr argument, making
+                * @iap unsuitable for submission multiple times. Make a
+                * copy for every loop iteration.
+                */
+               attrs = *iap;
+               host_err = __nfsd_setattr(dentry, &attrs);
                if (host_err != -EAGAIN || !retries--)
                        break;
                if (!nfsd_wait_for_delegreturn(rqstp, inode))
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 cb3be58..fff092b 100644 (file)
@@ -321,7 +321,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
        struct tcon_link *tlink;
        struct cifs_sb_info *cifs_sb;
        __u64   ExtAttrBits = 0;
+#ifdef CONFIG_CIFS_POSIX
+#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
        __u64   caps;
+#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */
+#endif /* CONFIG_CIFS_POSIX */
 
        xid = get_xid();
 
@@ -331,9 +335,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        if (pSMBFile == NULL)
                                break;
                        tcon = tlink_tcon(pSMBFile->tlink);
-                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
 #ifdef CONFIG_CIFS_POSIX
 #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
+                       caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
                                __u64   ExtAttrMask = 0;
                                rc = CIFSGetExtAttr(xid, tcon,
index 5065398..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)
@@ -618,7 +658,6 @@ parse_server_interfaces(struct network_interface_info_ioctl_rsp *buf,
                 * Add a new one instead
                 */
                spin_lock(&ses->iface_lock);
-               iface = niface = NULL;
                list_for_each_entry_safe(iface, niface, &ses->iface_list,
                                         iface_head) {
                        ret = iface_cmp(iface, &tmp_iface);
index 9ed61b6..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);
@@ -3725,7 +3735,7 @@ SMB2_change_notify(const unsigned int xid, struct cifs_tcon *tcon,
                if (*out_data == NULL) {
                        rc = -ENOMEM;
                        goto cnotify_exit;
-               } else
+               } else if (plen)
                        *plen = le32_to_cpu(smb_rsp->OutputBufferLength);
        }
 
@@ -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 6d1ccb9..844b303 100644 (file)
@@ -157,13 +157,42 @@ static struct oplock_info *opinfo_get_list(struct ksmbd_inode *ci)
        rcu_read_lock();
        opinfo = list_first_or_null_rcu(&ci->m_op_list, struct oplock_info,
                                        op_entry);
-       if (opinfo && !atomic_inc_not_zero(&opinfo->refcount))
-               opinfo = NULL;
+       if (opinfo) {
+               if (!atomic_inc_not_zero(&opinfo->refcount))
+                       opinfo = NULL;
+               else {
+                       atomic_inc(&opinfo->conn->r_count);
+                       if (ksmbd_conn_releasing(opinfo->conn)) {
+                               atomic_dec(&opinfo->conn->r_count);
+                               atomic_dec(&opinfo->refcount);
+                               opinfo = NULL;
+                       }
+               }
+       }
+
        rcu_read_unlock();
 
        return opinfo;
 }
 
+static void opinfo_conn_put(struct oplock_info *opinfo)
+{
+       struct ksmbd_conn *conn;
+
+       if (!opinfo)
+               return;
+
+       conn = opinfo->conn;
+       /*
+        * Checking waitqueue to dropping pending requests on
+        * disconnection. waitqueue_active is safe because it
+        * uses atomic operation for condition.
+        */
+       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
+               wake_up(&conn->r_count_q);
+       opinfo_put(opinfo);
+}
+
 void opinfo_put(struct oplock_info *opinfo)
 {
        if (!atomic_dec_and_test(&opinfo->refcount))
@@ -666,13 +695,6 @@ static void __smb2_oplock_break_noti(struct work_struct *wk)
 
 out:
        ksmbd_free_work_struct(work);
-       /*
-        * Checking waitqueue to dropping pending requests on
-        * disconnection. waitqueue_active is safe because it
-        * uses atomic operation for condition.
-        */
-       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
-               wake_up(&conn->r_count_q);
 }
 
 /**
@@ -706,7 +728,6 @@ static int smb2_oplock_break_noti(struct oplock_info *opinfo)
        work->conn = conn;
        work->sess = opinfo->sess;
 
-       atomic_inc(&conn->r_count);
        if (opinfo->op_state == OPLOCK_ACK_WAIT) {
                INIT_WORK(&work->work, __smb2_oplock_break_noti);
                ksmbd_queue_work(work);
@@ -776,13 +797,6 @@ static void __smb2_lease_break_noti(struct work_struct *wk)
 
 out:
        ksmbd_free_work_struct(work);
-       /*
-        * Checking waitqueue to dropping pending requests on
-        * disconnection. waitqueue_active is safe because it
-        * uses atomic operation for condition.
-        */
-       if (!atomic_dec_return(&conn->r_count) && waitqueue_active(&conn->r_count_q))
-               wake_up(&conn->r_count_q);
 }
 
 /**
@@ -822,7 +836,6 @@ static int smb2_lease_break_noti(struct oplock_info *opinfo)
        work->conn = conn;
        work->sess = opinfo->sess;
 
-       atomic_inc(&conn->r_count);
        if (opinfo->op_state == OPLOCK_ACK_WAIT) {
                list_for_each_safe(tmp, t, &opinfo->interim_list) {
                        struct ksmbd_work *in_work;
@@ -1144,8 +1157,10 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
        }
        prev_opinfo = opinfo_get_list(ci);
        if (!prev_opinfo ||
-           (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx))
+           (prev_opinfo->level == SMB2_OPLOCK_LEVEL_NONE && lctx)) {
+               opinfo_conn_put(prev_opinfo);
                goto set_lev;
+       }
        prev_op_has_lease = prev_opinfo->is_lease;
        if (prev_op_has_lease)
                prev_op_state = prev_opinfo->o_lease->state;
@@ -1153,19 +1168,19 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
        if (share_ret < 0 &&
            prev_opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
                err = share_ret;
-               opinfo_put(prev_opinfo);
+               opinfo_conn_put(prev_opinfo);
                goto err_out;
        }
 
        if (prev_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
            prev_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
-               opinfo_put(prev_opinfo);
+               opinfo_conn_put(prev_opinfo);
                goto op_break_not_needed;
        }
 
        list_add(&work->interim_entry, &prev_opinfo->interim_list);
        err = oplock_break(prev_opinfo, SMB2_OPLOCK_LEVEL_II);
-       opinfo_put(prev_opinfo);
+       opinfo_conn_put(prev_opinfo);
        if (err == -ENOENT)
                goto set_lev;
        /* Check all oplock was freed by close */
@@ -1228,14 +1243,14 @@ static void smb_break_all_write_oplock(struct ksmbd_work *work,
                return;
        if (brk_opinfo->level != SMB2_OPLOCK_LEVEL_BATCH &&
            brk_opinfo->level != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
-               opinfo_put(brk_opinfo);
+               opinfo_conn_put(brk_opinfo);
                return;
        }
 
        brk_opinfo->open_trunc = is_trunc;
        list_add(&work->interim_entry, &brk_opinfo->interim_list);
        oplock_break(brk_opinfo, SMB2_OPLOCK_LEVEL_II);
-       opinfo_put(brk_opinfo);
+       opinfo_conn_put(brk_opinfo);
 }
 
 /**
@@ -1263,6 +1278,13 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
        list_for_each_entry_rcu(brk_op, &ci->m_op_list, op_entry) {
                if (!atomic_inc_not_zero(&brk_op->refcount))
                        continue;
+
+               atomic_inc(&brk_op->conn->r_count);
+               if (ksmbd_conn_releasing(brk_op->conn)) {
+                       atomic_dec(&brk_op->conn->r_count);
+                       continue;
+               }
+
                rcu_read_unlock();
                if (brk_op->is_lease && (brk_op->o_lease->state &
                    (~(SMB2_LEASE_READ_CACHING_LE |
@@ -1292,7 +1314,7 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
                brk_op->open_trunc = is_trunc;
                oplock_break(brk_op, SMB2_OPLOCK_LEVEL_NONE);
 next:
-               opinfo_put(brk_op);
+               opinfo_conn_put(brk_op);
                rcu_read_lock();
        }
        rcu_read_unlock();
@@ -1393,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 717bcd2..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;
@@ -326,13 +343,9 @@ int smb2_set_rsp_credits(struct ksmbd_work *work)
        if (hdr->Command == SMB2_NEGOTIATE)
                aux_max = 1;
        else
-               aux_max = conn->vals->max_credits - credit_charge;
+               aux_max = conn->vals->max_credits - conn->total_credits;
        credits_granted = min_t(unsigned short, credits_requested, aux_max);
 
-       if (conn->vals->max_credits - conn->total_credits < credits_granted)
-               credits_granted = conn->vals->max_credits -
-                       conn->total_credits;
-
        conn->total_credits += credits_granted;
        work->credits_granted += credits_granted;
 
@@ -551,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
@@ -562,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,
@@ -849,13 +879,14 @@ static void assemble_neg_contexts(struct ksmbd_conn *conn,
 
 static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
                                  struct smb2_preauth_neg_context *pneg_ctxt,
-                                 int len_of_ctxts)
+                                 int ctxt_len)
 {
        /*
         * sizeof(smb2_preauth_neg_context) assumes SMB311_SALT_SIZE Salt,
         * which may not be present. Only check for used HashAlgorithms[1].
         */
-       if (len_of_ctxts < MIN_PREAUTH_CTXT_DATA_LEN)
+       if (ctxt_len <
+           sizeof(struct smb2_neg_context) + MIN_PREAUTH_CTXT_DATA_LEN)
                return STATUS_INVALID_PARAMETER;
 
        if (pneg_ctxt->HashAlgorithms != SMB2_PREAUTH_INTEGRITY_SHA512)
@@ -867,15 +898,23 @@ static __le32 decode_preauth_ctxt(struct ksmbd_conn *conn,
 
 static void decode_encrypt_ctxt(struct ksmbd_conn *conn,
                                struct smb2_encryption_neg_context *pneg_ctxt,
-                               int len_of_ctxts)
+                               int ctxt_len)
 {
-       int cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
-       int i, cphs_size = cph_cnt * sizeof(__le16);
+       int cph_cnt;
+       int i, cphs_size;
+
+       if (sizeof(struct smb2_encryption_neg_context) > ctxt_len) {
+               pr_err("Invalid SMB2_ENCRYPTION_CAPABILITIES context size\n");
+               return;
+       }
 
        conn->cipher_type = 0;
 
+       cph_cnt = le16_to_cpu(pneg_ctxt->CipherCount);
+       cphs_size = cph_cnt * sizeof(__le16);
+
        if (sizeof(struct smb2_encryption_neg_context) + cphs_size >
-           len_of_ctxts) {
+           ctxt_len) {
                pr_err("Invalid cipher count(%d)\n", cph_cnt);
                return;
        }
@@ -923,15 +962,22 @@ static void decode_compress_ctxt(struct ksmbd_conn *conn,
 
 static void decode_sign_cap_ctxt(struct ksmbd_conn *conn,
                                 struct smb2_signing_capabilities *pneg_ctxt,
-                                int len_of_ctxts)
+                                int ctxt_len)
 {
-       int sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
-       int i, sign_alos_size = sign_algo_cnt * sizeof(__le16);
+       int sign_algo_cnt;
+       int i, sign_alos_size;
+
+       if (sizeof(struct smb2_signing_capabilities) > ctxt_len) {
+               pr_err("Invalid SMB2_SIGNING_CAPABILITIES context length\n");
+               return;
+       }
 
        conn->signing_negotiated = false;
+       sign_algo_cnt = le16_to_cpu(pneg_ctxt->SigningAlgorithmCount);
+       sign_alos_size = sign_algo_cnt * sizeof(__le16);
 
        if (sizeof(struct smb2_signing_capabilities) + sign_alos_size >
-           len_of_ctxts) {
+           ctxt_len) {
                pr_err("Invalid signing algorithm count(%d)\n", sign_algo_cnt);
                return;
        }
@@ -951,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);
@@ -969,18 +1015,16 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
        len_of_ctxts = len_of_smb - offset;
 
        while (i++ < neg_ctxt_cnt) {
-               int clen;
-
-               /* check that offset is not beyond end of SMB */
-               if (len_of_ctxts == 0)
-                       break;
+               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);
                clen = le16_to_cpu(pctx->DataLength);
-               if (clen + sizeof(struct smb2_neg_context) > len_of_ctxts)
+               ctxt_len = clen + sizeof(struct smb2_neg_context);
+
+               if (ctxt_len > len_of_ctxts)
                        break;
 
                if (pctx->ContextType == SMB2_PREAUTH_INTEGRITY_CAPABILITIES) {
@@ -991,7 +1035,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
 
                        status = decode_preauth_ctxt(conn,
                                                     (struct smb2_preauth_neg_context *)pctx,
-                                                    len_of_ctxts);
+                                                    ctxt_len);
                        if (status != STATUS_SUCCESS)
                                break;
                } else if (pctx->ContextType == SMB2_ENCRYPTION_CAPABILITIES) {
@@ -1002,7 +1046,7 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
 
                        decode_encrypt_ctxt(conn,
                                            (struct smb2_encryption_neg_context *)pctx,
-                                           len_of_ctxts);
+                                           ctxt_len);
                } else if (pctx->ContextType == SMB2_COMPRESSION_CAPABILITIES) {
                        ksmbd_debug(SMB,
                                    "deassemble SMB2_COMPRESSION_CAPABILITIES context\n");
@@ -1021,15 +1065,15 @@ static __le32 deassemble_neg_contexts(struct ksmbd_conn *conn,
                } else if (pctx->ContextType == SMB2_SIGNING_CAPABILITIES) {
                        ksmbd_debug(SMB,
                                    "deassemble SMB2_SIGNING_CAPABILITIES context\n");
+
                        decode_sign_cap_ctxt(conn,
                                             (struct smb2_signing_capabilities *)pctx,
-                                            len_of_ctxts);
+                                            ctxt_len);
                }
 
                /* 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;
 }
@@ -1057,16 +1101,16 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
                return rc;
        }
 
-       if (req->DialectCount == 0) {
-               pr_err("malformed packet\n");
+       smb2_buf_len = get_rfc1002_len(work->request_buf);
+       smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
+       if (smb2_neg_size > smb2_buf_len) {
                rsp->hdr.Status = STATUS_INVALID_PARAMETER;
                rc = -EINVAL;
                goto err_out;
        }
 
-       smb2_buf_len = get_rfc1002_len(work->request_buf);
-       smb2_neg_size = offsetof(struct smb2_negotiate_req, Dialects);
-       if (smb2_neg_size > smb2_buf_len) {
+       if (req->DialectCount == 0) {
+               pr_err("malformed packet\n");
                rsp->hdr.Status = STATUS_INVALID_PARAMETER;
                rc = -EINVAL;
                goto err_out;
@@ -2239,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) {
@@ -2253,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,
@@ -2311,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;
@@ -2340,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",
@@ -2387,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");
 }
@@ -2962,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);
@@ -2978,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)) {
@@ -3018,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);
@@ -4358,21 +4399,6 @@ static int get_file_basic_info(struct smb2_query_info_rsp *rsp,
        return 0;
 }
 
-static unsigned long long get_allocation_size(struct inode *inode,
-                                             struct kstat *stat)
-{
-       unsigned long long alloc_size = 0;
-
-       if (!S_ISDIR(stat->mode)) {
-               if ((inode->i_blocks << 9) <= stat->size)
-                       alloc_size = stat->size;
-               else
-                       alloc_size = inode->i_blocks << 9;
-       }
-
-       return alloc_size;
-}
-
 static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
                                   struct ksmbd_file *fp, void *rsp_org)
 {
@@ -4387,7 +4413,7 @@ static void get_file_standard_info(struct smb2_query_info_rsp *rsp,
        sinfo = (struct smb2_file_standard_info *)rsp->Buffer;
        delete_pending = ksmbd_inode_pending_delete(fp);
 
-       sinfo->AllocationSize = cpu_to_le64(get_allocation_size(inode, &stat));
+       sinfo->AllocationSize = cpu_to_le64(inode->i_blocks << 9);
        sinfo->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        sinfo->NumberOfLinks = cpu_to_le32(get_nlink(&stat) - delete_pending);
        sinfo->DeletePending = delete_pending;
@@ -4452,7 +4478,7 @@ static int get_file_all_info(struct ksmbd_work *work,
        file_info->Attributes = fp->f_ci->m_fattr;
        file_info->Pad1 = 0;
        file_info->AllocationSize =
-               cpu_to_le64(get_allocation_size(inode, &stat));
+               cpu_to_le64(inode->i_blocks << 9);
        file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        file_info->NumberOfLinks =
                        cpu_to_le32(get_nlink(&stat) - delete_pending);
@@ -4641,7 +4667,7 @@ static int get_file_network_open_info(struct smb2_query_info_rsp *rsp,
        file_info->ChangeTime = cpu_to_le64(time);
        file_info->Attributes = fp->f_ci->m_fattr;
        file_info->AllocationSize =
-               cpu_to_le64(get_allocation_size(inode, &stat));
+               cpu_to_le64(inode->i_blocks << 9);
        file_info->EndOfFile = S_ISDIR(stat.mode) ? 0 : cpu_to_le64(stat.size);
        file_info->Reserved = cpu_to_le32(0);
        rsp->OutputBufferLength =
@@ -5469,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) {
@@ -5506,7 +5532,7 @@ static int smb2_create_link(struct ksmbd_work *work,
 {
        char *link_name = NULL, *target_name = NULL, *pathname = NULL;
        struct path path;
-       bool file_present = true;
+       bool file_present = false;
        int rc;
 
        if (buf_len < (u64)sizeof(struct smb2_file_link_info) +
@@ -5539,8 +5565,8 @@ static int smb2_create_link(struct ksmbd_work *work,
        if (rc) {
                if (rc != -ENOENT)
                        goto out;
-               file_present = false;
-       }
+       } else
+               file_present = true;
 
        if (file_info->ReplaceIfExists) {
                if (file_present) {
@@ -5634,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");
@@ -7490,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 778c152..81489fd 100644 (file)
@@ -86,12 +86,14 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
        err = vfs_path_parent_lookup(filename, flags,
                                     &parent_path, &last, &type,
                                     root_share_path);
-       putname(filename);
-       if (err)
+       if (err) {
+               putname(filename);
                return err;
+       }
 
        if (unlikely(type != LAST_NORM)) {
                path_put(&parent_path);
+               putname(filename);
                return -ENOENT;
        }
 
@@ -108,12 +110,14 @@ static int ksmbd_vfs_path_lookup_locked(struct ksmbd_share_config *share_conf,
        path->dentry = d;
        path->mnt = share_conf->vfs_path.mnt;
        path_put(&parent_path);
+       putname(filename);
 
        return 0;
 
 err_out:
        inode_unlock(parent_path.dentry->d_inode);
        path_put(&parent_path);
+       putname(filename);
        return -ENOENT;
 }
 
@@ -166,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);
@@ -175,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;
 }
@@ -205,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);
@@ -439,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,
@@ -585,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);
@@ -595,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);
@@ -640,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);
@@ -690,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);
@@ -743,6 +773,7 @@ retry:
        rd.new_dir              = new_path.dentry->d_inode,
        rd.new_dentry           = new_dentry,
        rd.flags                = flags,
+       rd.delegated_inode      = NULL,
        err = vfs_rename(&rd);
        if (err)
                ksmbd_debug(VFS, "vfs_rename failed err %d\n", err);
@@ -752,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);
 
@@ -892,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;
 }
 
@@ -1008,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)
@@ -1019,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)
@@ -1036,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;
 }
@@ -1239,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) {
@@ -1253,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));
@@ -1261,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) {
@@ -1292,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);
                }
@@ -1316,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) +
@@ -1369,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;
@@ -1427,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)
@@ -1517,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;
@@ -1527,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");
@@ -1764,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;
 
@@ -1797,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",
@@ -1808,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;
 
@@ -1825,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;
 
@@ -1836,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",
@@ -1847,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 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 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 eacb7dd..c1a7dc3 100644 (file)
@@ -572,4 +572,10 @@ void cper_print_proc_ia(const char *pfx,
 int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg);
 int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg);
 
+struct acpi_hest_generic_status;
+void cper_estatus_print(const char *pfx,
+                       const struct acpi_hest_generic_status *estatus);
+int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus);
+int cper_estatus_check(const struct acpi_hest_generic_status *estatus);
+
 #endif
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 7aa62c9..571d1a6 100644 (file)
@@ -1338,4 +1338,6 @@ bool efi_config_table_is_usable(const efi_guid_t *guid, unsigned long table)
        return xen_efi_config_table_is_usable(guid, table);
 }
 
+umode_t efi_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n);
+
 #endif /* _LINUX_EFI_H */
index 1716c01..efb6e2c 100644 (file)
@@ -391,7 +391,7 @@ struct fw_iso_packet {
        u32 tag:2;              /* tx: Tag in packet header             */
        u32 sy:4;               /* tx: Sy in packet header              */
        u32 header_length:8;    /* Length of immediate header           */
-       u32 header[0];          /* tx: Top of 1394 isoch. data_block    */
+       u32 header[];           /* tx: Top of 1394 isoch. data_block    */
 };
 
 #define FW_ISO_CONTEXT_TRANSMIT                        0
index dd64e54..9cb6c80 100644 (file)
@@ -135,7 +135,7 @@ static inline int iio_gts_find_int_time_by_sel(struct iio_gts *gts, int sel)
 /**
  * iio_gts_find_sel_by_int_time - find selector matching integration time
  * @gts:       Gain time scale descriptor
- * @gain:      HW-gain for which matching selector is searched for
+ * @time:      Integration time for which matching selector is searched for
  *
  * Return:     a selector matching given integration time or -EINVAL if
  *             selector was not found.
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 a4c4f73..4b9626c 100644 (file)
@@ -1093,6 +1093,7 @@ void mlx5_cmdif_debugfs_cleanup(struct mlx5_core_dev *dev);
 int mlx5_core_create_psv(struct mlx5_core_dev *dev, u32 pdn,
                         int npsvs, u32 *sig_index);
 int mlx5_core_destroy_psv(struct mlx5_core_dev *dev, int psv_num);
+__be32 mlx5_core_get_terminate_scatter_list_mkey(struct mlx5_core_dev *dev);
 void mlx5_core_put_rsc(struct mlx5_core_rsc_common *common);
 int mlx5_query_odp_caps(struct mlx5_core_dev *dev,
                        struct mlx5_odp_caps *odp_caps);
@@ -1237,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 1c68d67..92a2063 100644 (file)
@@ -617,6 +617,12 @@ PAGEFLAG_FALSE(VmemmapSelfHosted, vmemmap_self_hosted)
  * Please note that, confusingly, "page_mapping" refers to the inode
  * address_space which maps the page from disk; whereas "page_mapped"
  * refers to user virtual address space into which the page is mapped.
+ *
+ * For slab pages, since slab reuses the bits in struct page to store its
+ * internal states, the page->mapping does not exist as such, nor do these
+ * flags below.  So in order to avoid testing non-existent bits, please
+ * make sure that PageSlab(page) actually evaluates to false before calling
+ * the following functions (e.g., PageAnon).  See mm/slab.h.
  */
 #define PAGE_MAPPING_ANON      0x1
 #define PAGE_MAPPING_MOVABLE   0x2
index 5e1e115..fdf9c95 100644 (file)
 #include <linux/types.h>
 
 /*
- * Linux EFI stub v1.0 adds the following functionality:
- * - Loading initrd from the LINUX_EFI_INITRD_MEDIA_GUID device path,
- * - Loading/starting the kernel from firmware that targets a different
- *   machine type, via the entrypoint exposed in the .compat PE/COFF section.
+ * Starting from version v3.0, the major version field should be interpreted as
+ * a bit mask of features supported by the kernel's EFI stub:
+ * - 0x1: initrd loading from the LINUX_EFI_INITRD_MEDIA_GUID device path,
+ * - 0x2: initrd loading using the initrd= command line option, where the file
+ *        may be specified using device path notation, and is not required to
+ *        reside on the same volume as the loaded kernel image.
  *
  * The recommended way of loading and starting v1.0 or later kernels is to use
  * the LoadImage() and StartImage() EFI boot services, and expose the initrd
  * via the LINUX_EFI_INITRD_MEDIA_GUID device path.
  *
- * Versions older than v1.0 support initrd loading via the image load options
- * (using initrd=, limited to the volume from which the kernel itself was
- * loaded), or via arch specific means (bootparams, DT, etc).
+ * Versions older than v1.0 may support initrd loading via the image load
+ * options (using initrd=, limited to the volume from which the kernel itself
+ * was loaded), or only via arch specific means (bootparams, DT, etc).
  *
- * On x86, LoadImage() and StartImage() can be omitted if the EFI handover
- * protocol is implemented, which can be inferred from the version,
- * handover_offset and xloadflags fields in the bootparams structure.
+ * The minor version field must remain 0x0.
+ * (https://lore.kernel.org/all/efd6f2d4-547c-1378-1faa-53c044dbd297@gmail.com/)
  */
-#define LINUX_EFISTUB_MAJOR_VERSION            0x1
-#define LINUX_EFISTUB_MINOR_VERSION            0x1
+#define LINUX_EFISTUB_MAJOR_VERSION            0x3
+#define LINUX_EFISTUB_MINOR_VERSION            0x0
 
 /*
  * LINUX_PE_MAGIC appears at offset 0x38 into the MS-DOS header of EFI bootable
index 537cbf9..e0f5ac9 100644 (file)
@@ -29,7 +29,6 @@ struct kernel_clone_args {
        u32 io_thread:1;
        u32 user_worker:1;
        u32 no_files:1;
-       u32 ignore_signals:1;
        unsigned long stack;
        unsigned long stack_size;
        unsigned long tls;
index 6123c10..837a236 100644 (file)
@@ -2,22 +2,13 @@
 #ifndef _LINUX_VHOST_TASK_H
 #define _LINUX_VHOST_TASK_H
 
-#include <linux/completion.h>
 
-struct task_struct;
+struct vhost_task;
 
-struct vhost_task {
-       int (*fn)(void *data);
-       void *data;
-       struct completion exited;
-       unsigned long flags;
-       struct task_struct *task;
-};
-
-struct vhost_task *vhost_task_create(int (*fn)(void *), void *arg,
+struct vhost_task *vhost_task_create(bool (*fn)(void *), void *arg,
                                     const char *name);
 void vhost_task_start(struct vhost_task *vtsk);
 void vhost_task_stop(struct vhost_task *vtsk);
-bool vhost_task_should_stop(struct vhost_task *vtsk);
+void vhost_task_wake(struct vhost_task *vtsk);
 
 #endif
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 d16ae62..a711604 100644 (file)
@@ -61,10 +61,9 @@ int          svc_recv(struct svc_rqst *, long);
 void           svc_send(struct svc_rqst *rqstp);
 void           svc_drop(struct svc_rqst *);
 void           svc_sock_update_bufs(struct svc_serv *serv);
-bool           svc_alien_sock(struct net *net, int fd);
-int            svc_addsock(struct svc_serv *serv, const int fd,
-                                       char *name_return, const size_t len,
-                                       const struct cred *cred);
+int            svc_addsock(struct svc_serv *serv, struct net *net,
+                           const int fd, char *name_return, const size_t len,
+                           const struct cred *cred);
 void           svc_init_xprt_sock(void);
 void           svc_cleanup_xprt_sock(void);
 struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot);
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 094c77e..0c7eff9 100644 (file)
@@ -501,6 +501,11 @@ void *hcd_buffer_alloc(struct usb_bus *bus, size_t size,
 void hcd_buffer_free(struct usb_bus *bus, size_t size,
        void *addr, dma_addr_t dma);
 
+void *hcd_buffer_alloc_pages(struct usb_hcd *hcd,
+               size_t size, gfp_t mem_flags, dma_addr_t *dma);
+void hcd_buffer_free_pages(struct usb_hcd *hcd,
+               size_t size, void *addr, dma_addr_t dma);
+
 /* generic bus glue, needed for host controllers that don't use PCI */
 extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
 
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 cfd19e7..b325df0 100644 (file)
@@ -1119,6 +1119,7 @@ struct v4l2_subdev {
  * @vfh: pointer to &struct v4l2_fh
  * @state: pointer to &struct v4l2_subdev_state
  * @owner: module pointer to the owner of this file handle
+ * @client_caps: bitmask of ``V4L2_SUBDEV_CLIENT_CAP_*``
  */
 struct v4l2_subdev_fh {
        struct v4l2_fh vfh;
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 cd386aa..9eef199 100644 (file)
@@ -347,10 +347,8 @@ struct mana_tx_qp {
 struct mana_ethtool_stats {
        u64 stop_queue;
        u64 wake_queue;
-       u64 tx_cqes;
        u64 tx_cqe_err;
        u64 tx_cqe_unknown_type;
-       u64 rx_cqes;
        u64 rx_coalesced_err;
        u64 rx_cqe_unknown_type;
 };
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 656ea89..6f428a7 100644 (file)
@@ -336,6 +336,7 @@ struct sk_filter;
   *    @sk_cgrp_data: cgroup data for this cgroup
   *    @sk_memcg: this socket's memory cgroup association
   *    @sk_write_pending: a write to stream socket waits to start
+  *    @sk_wait_pending: number of threads blocked on this socket
   *    @sk_state_change: callback to indicate change in the state of the sock
   *    @sk_data_ready: callback to indicate there is data to be processed
   *    @sk_write_space: callback to indicate there is bf sending space available
@@ -428,6 +429,7 @@ struct sock {
        unsigned int            sk_napi_id;
 #endif
        int                     sk_rcvbuf;
+       int                     sk_wait_pending;
 
        struct sk_filter __rcu  *sk_filter;
        union {
@@ -1150,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
 }
@@ -1160,20 +1166,25 @@ 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
 }
 
 #define sk_wait_event(__sk, __timeo, __condition, __wait)              \
        ({      int __rc;                                               \
+               __sk->sk_wait_pending++;                                \
                release_sock(__sk);                                     \
                __rc = __condition;                                     \
                if (!__rc) {                                            \
@@ -1183,6 +1194,7 @@ static inline void sock_rps_reset_rxhash(struct sock *sk)
                }                                                       \
                sched_annotate_sleep();                                 \
                lock_sock(__sk);                                        \
+               __sk->sk_wait_pending--;                                \
                __rc = __condition;                                     \
                __rc;                                                   \
        })
index 18a038d..5066e45 100644 (file)
@@ -632,6 +632,7 @@ void tcp_reset(struct sock *sk, struct sk_buff *skb);
 void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb);
 void tcp_fin(struct sock *sk);
 void tcp_check_space(struct sock *sk);
+void tcp_sack_compress_send_ack(struct sock *sk);
 
 /* tcp_timer.c */
 void tcp_init_xmit_timers(struct sock *);
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 2291181..4c15420 100644 (file)
@@ -562,12 +562,13 @@ struct iscsit_conn {
 #define LOGIN_FLAGS_READ_ACTIVE                2
 #define LOGIN_FLAGS_WRITE_ACTIVE       3
 #define LOGIN_FLAGS_CLOSED             4
+#define LOGIN_FLAGS_WORKER_RUNNING     5
        unsigned long           login_flags;
        struct delayed_work     login_work;
        struct iscsi_login      *login;
        struct timer_list       nopin_timer;
        struct timer_list       nopin_response_timer;
-       struct timer_list       transport_timer;
+       struct timer_list       login_timer;
        struct task_struct      *login_kworker;
        /* Spinlock used for add/deleting cmd's from conn_cmd_list */
        spinlock_t              cmd_lock;
@@ -576,6 +577,8 @@ struct iscsit_conn {
        spinlock_t              nopin_timer_lock;
        spinlock_t              response_queue_lock;
        spinlock_t              state_lock;
+       spinlock_t              login_timer_lock;
+       spinlock_t              login_worker_lock;
        /* libcrypto RX and TX contexts for crc32c */
        struct ahash_request    *conn_rx_hash;
        struct ahash_request    *conn_tx_hash;
@@ -792,7 +795,6 @@ struct iscsi_np {
        enum np_thread_state_table np_thread_state;
        bool                    enabled;
        atomic_t                np_reset_count;
-       enum iscsi_timer_flags_table np_login_timer_flags;
        u32                     np_exports;
        enum np_flags_table     np_flags;
        spinlock_t              np_thread_lock;
@@ -800,7 +802,6 @@ struct iscsi_np {
        struct socket           *np_socket;
        struct sockaddr_storage np_sockaddr;
        struct task_struct      *np_thread;
-       struct timer_list       np_login_timer;
        void                    *np_context;
        struct iscsit_transport *np_transport;
        struct list_head        np_list;
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 9aa74d2..89bff20 100644 (file)
@@ -25,10 +25,6 @@ int io_epoll_ctl_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
 {
        struct io_epoll *epoll = io_kiocb_to_cmd(req, struct io_epoll);
 
-       pr_warn_once("%s: epoll_ctl support in io_uring is deprecated and will "
-                    "be removed in a future Linux kernel version.\n",
-                    current->comm);
-
        if (sqe->buf_index || sqe->splice_fd_in)
                return -EINVAL;
 
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 34b90e2..edb50b4 100644 (file)
@@ -411,7 +411,10 @@ static void coredump_task_exit(struct task_struct *tsk)
        tsk->flags |= PF_POSTCOREDUMP;
        core_state = tsk->signal->core_state;
        spin_unlock_irq(&tsk->sighand->siglock);
-       if (core_state) {
+
+       /* The vhost_worker does not particpate in coredumps */
+       if (core_state &&
+           ((tsk->flags & (PF_IO_WORKER | PF_USER_WORKER)) != PF_USER_WORKER)) {
                struct core_thread self;
 
                self.task = current;
index ed4e01d..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);
@@ -2336,16 +2336,16 @@ __latent_entropy struct task_struct *copy_process(
        p->flags &= ~PF_KTHREAD;
        if (args->kthread)
                p->flags |= PF_KTHREAD;
-       if (args->user_worker)
-               p->flags |= PF_USER_WORKER;
-       if (args->io_thread) {
+       if (args->user_worker) {
                /*
-                * Mark us an IO worker, and block any signal that isn't
+                * Mark us a user worker, and block any signal that isn't
                 * fatal or STOP
                 */
-               p->flags |= PF_IO_WORKER;
+               p->flags |= PF_USER_WORKER;
                siginitsetinv(&p->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP));
        }
+       if (args->io_thread)
+               p->flags |= PF_IO_WORKER;
 
        if (args->name)
                strscpy_pad(p->comm, args->name, sizeof(p->comm));
@@ -2517,9 +2517,6 @@ __latent_entropy struct task_struct *copy_process(
        if (retval)
                goto bad_fork_cleanup_io;
 
-       if (args->ignore_signals)
-               ignore_signals(p);
-
        stackleak_task_init(p);
 
        if (pid != &init_struct_pid) {
index e97232b..8a5d6d6 100644 (file)
@@ -257,7 +257,7 @@ static ssize_t module_zstd_decompress(struct load_info *info,
        do {
                struct page *page = module_get_next_page(info);
 
-               if (!IS_ERR(page)) {
+               if (IS_ERR(page)) {
                        retval = PTR_ERR(page);
                        goto out;
                }
index 044aa2c..4e2cf78 100644 (file)
@@ -1521,14 +1521,14 @@ static void __layout_sections(struct module *mod, struct load_info *info, bool i
                MOD_RODATA,
                MOD_RO_AFTER_INIT,
                MOD_DATA,
-               MOD_INVALID,    /* This is needed to match the masks array */
+               MOD_DATA,
        };
        static const int init_m_to_mem_type[] = {
                MOD_INIT_TEXT,
                MOD_INIT_RODATA,
                MOD_INVALID,
                MOD_INIT_DATA,
-               MOD_INVALID,    /* This is needed to match the masks array */
+               MOD_INIT_DATA,
        };
 
        for (m = 0; m < ARRAY_SIZE(masks); ++m) {
index 8f6330f..2547fa7 100644 (file)
@@ -1368,7 +1368,9 @@ int zap_other_threads(struct task_struct *p)
 
        while_each_thread(p, t) {
                task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK);
-               count++;
+               /* Don't require de_thread to wait for the vhost_worker */
+               if ((t->flags & (PF_IO_WORKER | PF_USER_WORKER)) != PF_USER_WORKER)
+                       count++;
 
                /* Don't bother with already dead threads */
                if (t->exit_state)
@@ -2861,11 +2863,11 @@ relock:
                }
 
                /*
-                * PF_IO_WORKER threads will catch and exit on fatal signals
+                * PF_USER_WORKER threads will catch and exit on fatal signals
                 * themselves. They have cleanup that must be performed, so
                 * we cannot call do_exit() on their behalf.
                 */
-               if (current->flags & PF_IO_WORKER)
+               if (current->flags & PF_USER_WORKER)
                        goto out;
 
                /*
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 ef8ed3b..6a4ecfb 100644 (file)
@@ -308,7 +308,7 @@ trace_probe_primary_from_call(struct trace_event_call *call)
 {
        struct trace_probe_event *tpe = trace_probe_event_from_call(call);
 
-       return list_first_entry(&tpe->probes, struct trace_probe, list);
+       return list_first_entry_or_null(&tpe->probes, struct trace_probe, list);
 }
 
 static inline struct list_head *trace_probe_probe_list(struct trace_probe *tp)
index b7cbd66..da35e5b 100644 (file)
@@ -12,58 +12,90 @@ enum vhost_task_flags {
        VHOST_TASK_FLAGS_STOP,
 };
 
+struct vhost_task {
+       bool (*fn)(void *data);
+       void *data;
+       struct completion exited;
+       unsigned long flags;
+       struct task_struct *task;
+};
+
 static int vhost_task_fn(void *data)
 {
        struct vhost_task *vtsk = data;
-       int ret;
+       bool dead = false;
+
+       for (;;) {
+               bool did_work;
+
+               if (!dead && signal_pending(current)) {
+                       struct ksignal ksig;
+                       /*
+                        * Calling get_signal will block in SIGSTOP,
+                        * or clear fatal_signal_pending, but remember
+                        * what was set.
+                        *
+                        * This thread won't actually exit until all
+                        * of the file descriptors are closed, and
+                        * the release function is called.
+                        */
+                       dead = get_signal(&ksig);
+                       if (dead)
+                               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)
+                       schedule();
+       }
 
-       ret = vtsk->fn(vtsk->data);
        complete(&vtsk->exited);
-       do_exit(ret);
+       do_exit(0);
 }
 
 /**
+ * vhost_task_wake - wakeup the vhost_task
+ * @vtsk: vhost_task to wake
+ *
+ * wake up the vhost_task worker thread
+ */
+void vhost_task_wake(struct vhost_task *vtsk)
+{
+       wake_up_process(vtsk->task);
+}
+EXPORT_SYMBOL_GPL(vhost_task_wake);
+
+/**
  * vhost_task_stop - stop a vhost_task
  * @vtsk: vhost_task to stop
  *
- * Callers must call vhost_task_should_stop and return from their worker
- * function when it returns true;
+ * vhost_task_fn ensures the worker thread exits after
+ * VHOST_TASK_FLAGS_SOP becomes true.
  */
 void vhost_task_stop(struct vhost_task *vtsk)
 {
-       pid_t pid = vtsk->task->pid;
-
        set_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
-       wake_up_process(vtsk->task);
+       vhost_task_wake(vtsk);
        /*
         * Make sure vhost_task_fn is no longer accessing the vhost_task before
-        * freeing it below. If userspace crashed or exited without closing,
-        * then the vhost_task->task could already be marked dead so
-        * kernel_wait will return early.
+        * freeing it below.
         */
        wait_for_completion(&vtsk->exited);
-       /*
-        * If we are just closing/removing a device and the parent process is
-        * not exiting then reap the task.
-        */
-       kernel_wait4(pid, NULL, __WCLONE, NULL);
        kfree(vtsk);
 }
 EXPORT_SYMBOL_GPL(vhost_task_stop);
 
 /**
- * vhost_task_should_stop - should the vhost task return from the work function
- * @vtsk: vhost_task to stop
- */
-bool vhost_task_should_stop(struct vhost_task *vtsk)
-{
-       return test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags);
-}
-EXPORT_SYMBOL_GPL(vhost_task_should_stop);
-
-/**
- * vhost_task_create - create a copy of a process to be used by the kernel
- * @fn: thread stack
+ * vhost_task_create - create a copy of a task to be used by the kernel
+ * @fn: vhost worker function
  * @arg: data to be passed to fn
  * @name: the thread's name
  *
@@ -71,17 +103,17 @@ EXPORT_SYMBOL_GPL(vhost_task_should_stop);
  * failure. The returned task is inactive, and the caller must fire it up
  * through vhost_task_start().
  */
-struct vhost_task *vhost_task_create(int (*fn)(void *), void *arg,
+struct vhost_task *vhost_task_create(bool (*fn)(void *), void *arg,
                                     const char *name)
 {
        struct kernel_clone_args args = {
-               .flags          = CLONE_FS | CLONE_UNTRACED | CLONE_VM,
+               .flags          = CLONE_FS | CLONE_UNTRACED | CLONE_VM |
+                                 CLONE_THREAD | CLONE_SIGHAND,
                .exit_signal    = 0,
                .fn             = vhost_task_fn,
                .name           = name,
                .user_worker    = 1,
                .no_files       = 1,
-               .ignore_signals = 1,
        };
        struct vhost_task *vtsk;
        struct task_struct *tsk;
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 05ed84c..1d7d480 100644 (file)
@@ -45,6 +45,7 @@ struct test_batched_req {
        bool sent;
        const struct firmware *fw;
        const char *name;
+       const char *fw_buf;
        struct completion completion;
        struct task_struct *task;
        struct device *dev;
@@ -175,8 +176,14 @@ static void __test_release_all_firmware(void)
 
        for (i = 0; i < test_fw_config->num_requests; i++) {
                req = &test_fw_config->reqs[i];
-               if (req->fw)
+               if (req->fw) {
+                       if (req->fw_buf) {
+                               kfree_const(req->fw_buf);
+                               req->fw_buf = NULL;
+                       }
                        release_firmware(req->fw);
+                       req->fw = NULL;
+               }
        }
 
        vfree(test_fw_config->reqs);
@@ -353,16 +360,26 @@ static ssize_t config_test_show_str(char *dst,
        return len;
 }
 
-static intest_dev_config_update_bool(const char *buf, size_t size,
+static inline int __test_dev_config_update_bool(const char *buf, size_t size,
                                       bool *cfg)
 {
        int ret;
 
-       mutex_lock(&test_fw_mutex);
        if (kstrtobool(buf, cfg) < 0)
                ret = -EINVAL;
        else
                ret = size;
+
+       return ret;
+}
+
+static int test_dev_config_update_bool(const char *buf, size_t size,
+                                      bool *cfg)
+{
+       int ret;
+
+       mutex_lock(&test_fw_mutex);
+       ret = __test_dev_config_update_bool(buf, size, cfg);
        mutex_unlock(&test_fw_mutex);
 
        return ret;
@@ -373,7 +390,8 @@ static ssize_t test_dev_config_show_bool(char *buf, bool val)
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
-static int test_dev_config_update_size_t(const char *buf,
+static int __test_dev_config_update_size_t(
+                                        const char *buf,
                                         size_t size,
                                         size_t *cfg)
 {
@@ -384,9 +402,7 @@ static int test_dev_config_update_size_t(const char *buf,
        if (ret)
                return ret;
 
-       mutex_lock(&test_fw_mutex);
        *(size_t *)cfg = new;
-       mutex_unlock(&test_fw_mutex);
 
        /* Always return full write size even if we didn't consume all */
        return size;
@@ -402,7 +418,7 @@ static ssize_t test_dev_config_show_int(char *buf, int val)
        return snprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
-static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
+static int __test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
 {
        u8 val;
        int ret;
@@ -411,14 +427,23 @@ static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
        if (ret)
                return ret;
 
-       mutex_lock(&test_fw_mutex);
        *(u8 *)cfg = val;
-       mutex_unlock(&test_fw_mutex);
 
        /* Always return full write size even if we didn't consume all */
        return size;
 }
 
+static int test_dev_config_update_u8(const char *buf, size_t size, u8 *cfg)
+{
+       int ret;
+
+       mutex_lock(&test_fw_mutex);
+       ret = __test_dev_config_update_u8(buf, size, cfg);
+       mutex_unlock(&test_fw_mutex);
+
+       return ret;
+}
+
 static ssize_t test_dev_config_show_u8(char *buf, u8 val)
 {
        return snprintf(buf, PAGE_SIZE, "%u\n", val);
@@ -471,10 +496,10 @@ static ssize_t config_num_requests_store(struct device *dev,
                mutex_unlock(&test_fw_mutex);
                goto out;
        }
-       mutex_unlock(&test_fw_mutex);
 
-       rc = test_dev_config_update_u8(buf, count,
-                                      &test_fw_config->num_requests);
+       rc = __test_dev_config_update_u8(buf, count,
+                                        &test_fw_config->num_requests);
+       mutex_unlock(&test_fw_mutex);
 
 out:
        return rc;
@@ -518,10 +543,10 @@ static ssize_t config_buf_size_store(struct device *dev,
                mutex_unlock(&test_fw_mutex);
                goto out;
        }
-       mutex_unlock(&test_fw_mutex);
 
-       rc = test_dev_config_update_size_t(buf, count,
-                                          &test_fw_config->buf_size);
+       rc = __test_dev_config_update_size_t(buf, count,
+                                            &test_fw_config->buf_size);
+       mutex_unlock(&test_fw_mutex);
 
 out:
        return rc;
@@ -548,10 +573,10 @@ static ssize_t config_file_offset_store(struct device *dev,
                mutex_unlock(&test_fw_mutex);
                goto out;
        }
-       mutex_unlock(&test_fw_mutex);
 
-       rc = test_dev_config_update_size_t(buf, count,
-                                          &test_fw_config->file_offset);
+       rc = __test_dev_config_update_size_t(buf, count,
+                                            &test_fw_config->file_offset);
+       mutex_unlock(&test_fw_mutex);
 
 out:
        return rc;
@@ -652,6 +677,8 @@ static ssize_t trigger_request_store(struct device *dev,
 
        mutex_lock(&test_fw_mutex);
        release_firmware(test_firmware);
+       if (test_fw_config->reqs)
+               __test_release_all_firmware();
        test_firmware = NULL;
        rc = request_firmware(&test_firmware, name, dev);
        if (rc) {
@@ -752,6 +779,8 @@ static ssize_t trigger_async_request_store(struct device *dev,
        mutex_lock(&test_fw_mutex);
        release_firmware(test_firmware);
        test_firmware = NULL;
+       if (test_fw_config->reqs)
+               __test_release_all_firmware();
        rc = request_firmware_nowait(THIS_MODULE, 1, name, dev, GFP_KERNEL,
                                     NULL, trigger_async_request_cb);
        if (rc) {
@@ -794,6 +823,8 @@ static ssize_t trigger_custom_fallback_store(struct device *dev,
 
        mutex_lock(&test_fw_mutex);
        release_firmware(test_firmware);
+       if (test_fw_config->reqs)
+               __test_release_all_firmware();
        test_firmware = NULL;
        rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOUEVENT, name,
                                     dev, GFP_KERNEL, NULL,
@@ -856,6 +887,8 @@ static int test_fw_run_batch_request(void *data)
                                                 test_fw_config->buf_size);
                if (!req->fw)
                        kfree(test_buf);
+               else
+                       req->fw_buf = test_buf;
        } else {
                req->rc = test_fw_config->req_firmware(&req->fw,
                                                       req->name,
@@ -895,6 +928,11 @@ static ssize_t trigger_batched_requests_store(struct device *dev,
 
        mutex_lock(&test_fw_mutex);
 
+       if (test_fw_config->reqs) {
+               rc = -EBUSY;
+               goto out_bail;
+       }
+
        test_fw_config->reqs =
                vzalloc(array3_size(sizeof(struct test_batched_req),
                                    test_fw_config->num_requests, 2));
@@ -911,6 +949,7 @@ static ssize_t trigger_batched_requests_store(struct device *dev,
                req->fw = NULL;
                req->idx = i;
                req->name = test_fw_config->name;
+               req->fw_buf = NULL;
                req->dev = dev;
                init_completion(&req->completion);
                req->task = kthread_run(test_fw_run_batch_request, req,
@@ -993,6 +1032,11 @@ ssize_t trigger_batched_requests_async_store(struct device *dev,
 
        mutex_lock(&test_fw_mutex);
 
+       if (test_fw_config->reqs) {
+               rc = -EBUSY;
+               goto out_bail;
+       }
+
        test_fw_config->reqs =
                vzalloc(array3_size(sizeof(struct test_batched_req),
                                    test_fw_config->num_requests, 2));
@@ -1010,6 +1054,7 @@ ssize_t trigger_batched_requests_async_store(struct device *dev,
        for (i = 0; i < test_fw_config->num_requests; i++) {
                req = &test_fw_config->reqs[i];
                req->name = test_fw_config->name;
+               req->fw_buf = NULL;
                req->fw = NULL;
                req->idx = i;
                init_completion(&req->completion);
index a925415..018a5bd 100644 (file)
@@ -98,6 +98,7 @@ config PAGE_OWNER
 config PAGE_TABLE_CHECK
        bool "Check for invalid mappings in user page tables"
        depends on ARCH_SUPPORTS_PAGE_TABLE_CHECK
+       depends on EXCLUSIVE_SYSTEM_RAM
        select PAGE_EXTENSION
        help
          Check that anonymous page is not being mapped twice with read write
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 25d8610..f2baf97 100644 (file)
@@ -71,6 +71,8 @@ static void page_table_check_clear(struct mm_struct *mm, unsigned long addr,
 
        page = pfn_to_page(pfn);
        page_ext = page_ext_get(page);
+
+       BUG_ON(PageSlab(page));
        anon = PageAnon(page);
 
        for (i = 0; i < pgcnt; i++) {
@@ -107,6 +109,8 @@ static void page_table_check_set(struct mm_struct *mm, unsigned long addr,
 
        page = pfn_to_page(pfn);
        page_ext = page_ext_get(page);
+
+       BUG_ON(PageSlab(page));
        anon = PageAnon(page);
 
        for (i = 0; i < pgcnt; i++) {
@@ -133,6 +137,8 @@ void __page_table_check_zero(struct page *page, unsigned int order)
        struct page_ext *page_ext;
        unsigned long i;
 
+       BUG_ON(PageSlab(page));
+
        page_ext = page_ext_get(page);
        BUG_ON(!page_ext);
        for (i = 0; i < (1ul << order); i++) {
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 653901a..41de3a2 100644 (file)
@@ -2385,6 +2385,37 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[],
                if (tb[IFLA_BROADCAST] &&
                    nla_len(tb[IFLA_BROADCAST]) < dev->addr_len)
                        return -EINVAL;
+
+               if (tb[IFLA_GSO_MAX_SIZE] &&
+                   nla_get_u32(tb[IFLA_GSO_MAX_SIZE]) > dev->tso_max_size) {
+                       NL_SET_ERR_MSG(extack, "too big gso_max_size");
+                       return -EINVAL;
+               }
+
+               if (tb[IFLA_GSO_MAX_SEGS] &&
+                   (nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > GSO_MAX_SEGS ||
+                    nla_get_u32(tb[IFLA_GSO_MAX_SEGS]) > dev->tso_max_segs)) {
+                       NL_SET_ERR_MSG(extack, "too big gso_max_segs");
+                       return -EINVAL;
+               }
+
+               if (tb[IFLA_GRO_MAX_SIZE] &&
+                   nla_get_u32(tb[IFLA_GRO_MAX_SIZE]) > GRO_MAX_SIZE) {
+                       NL_SET_ERR_MSG(extack, "too big gro_max_size");
+                       return -EINVAL;
+               }
+
+               if (tb[IFLA_GSO_IPV4_MAX_SIZE] &&
+                   nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE]) > dev->tso_max_size) {
+                       NL_SET_ERR_MSG(extack, "too big gso_ipv4_max_size");
+                       return -EINVAL;
+               }
+
+               if (tb[IFLA_GRO_IPV4_MAX_SIZE] &&
+                   nla_get_u32(tb[IFLA_GRO_IPV4_MAX_SIZE]) > GRO_MAX_SIZE) {
+                       NL_SET_ERR_MSG(extack, "too big gro_ipv4_max_size");
+                       return -EINVAL;
+               }
        }
 
        if (tb[IFLA_AF_SPEC]) {
@@ -2858,11 +2889,6 @@ static int do_setlink(const struct sk_buff *skb,
        if (tb[IFLA_GSO_MAX_SIZE]) {
                u32 max_size = nla_get_u32(tb[IFLA_GSO_MAX_SIZE]);
 
-               if (max_size > dev->tso_max_size) {
-                       err = -EINVAL;
-                       goto errout;
-               }
-
                if (dev->gso_max_size ^ max_size) {
                        netif_set_gso_max_size(dev, max_size);
                        status |= DO_SETLINK_MODIFIED;
@@ -2872,11 +2898,6 @@ static int do_setlink(const struct sk_buff *skb,
        if (tb[IFLA_GSO_MAX_SEGS]) {
                u32 max_segs = nla_get_u32(tb[IFLA_GSO_MAX_SEGS]);
 
-               if (max_segs > GSO_MAX_SEGS || max_segs > dev->tso_max_segs) {
-                       err = -EINVAL;
-                       goto errout;
-               }
-
                if (dev->gso_max_segs ^ max_segs) {
                        netif_set_gso_max_segs(dev, max_segs);
                        status |= DO_SETLINK_MODIFIED;
@@ -2895,11 +2916,6 @@ static int do_setlink(const struct sk_buff *skb,
        if (tb[IFLA_GSO_IPV4_MAX_SIZE]) {
                u32 max_size = nla_get_u32(tb[IFLA_GSO_IPV4_MAX_SIZE]);
 
-               if (max_size > dev->tso_max_size) {
-                       err = -EINVAL;
-                       goto errout;
-               }
-
                if (dev->gso_ipv4_max_size ^ max_size) {
                        netif_set_gso_ipv4_max_size(dev, max_size);
                        status |= DO_SETLINK_MODIFIED;
@@ -3285,6 +3301,7 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname,
        struct net_device *dev;
        unsigned int num_tx_queues = 1;
        unsigned int num_rx_queues = 1;
+       int err;
 
        if (tb[IFLA_NUM_TX_QUEUES])
                num_tx_queues = nla_get_u32(tb[IFLA_NUM_TX_QUEUES]);
@@ -3320,13 +3337,18 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname,
        if (!dev)
                return ERR_PTR(-ENOMEM);
 
+       err = validate_linkmsg(dev, tb, extack);
+       if (err < 0) {
+               free_netdev(dev);
+               return ERR_PTR(err);
+       }
+
        dev_net_set(dev, net);
        dev->rtnl_link_ops = ops;
        dev->rtnl_link_state = RTNL_LINK_INITIALIZING;
 
        if (tb[IFLA_MTU]) {
                u32 mtu = nla_get_u32(tb[IFLA_MTU]);
-               int err;
 
                err = dev_validate_mtu(dev, mtu, extack);
                if (err) {
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 5440e67..24f2761 100644 (file)
@@ -2381,7 +2381,6 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
 {
        u32 max_segs = 1;
 
-       sk_dst_set(sk, dst);
        sk->sk_route_caps = dst->dev->features;
        if (sk_is_tcp(sk))
                sk->sk_route_caps |= NETIF_F_GSO;
@@ -2400,6 +2399,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
                }
        }
        sk->sk_gso_max_segs = max_segs;
+       sk_dst_set(sk, dst);
 }
 EXPORT_SYMBOL_GPL(sk_setup_caps);
 
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 c4aab3a..4a76ebf 100644 (file)
@@ -586,6 +586,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
 
        add_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending += writebias;
+       sk->sk_wait_pending++;
 
        /* Basic assumption: if someone sets sk->sk_err, he _must_
         * change state of the socket from TCP_SYN_*.
@@ -601,6 +602,7 @@ static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias)
        }
        remove_wait_queue(sk_sleep(sk), &wait);
        sk->sk_write_pending -= writebias;
+       sk->sk_wait_pending--;
        return timeo;
 }
 
index 65ad425..1386787 100644 (file)
@@ -1142,6 +1142,7 @@ struct sock *inet_csk_clone_lock(const struct sock *sk,
        if (newsk) {
                struct inet_connection_sock *newicsk = inet_csk(newsk);
 
+               newsk->sk_wait_pending = 0;
                inet_sk_set_state(newsk, TCP_SYN_RECV);
                newicsk->icsk_bind_hash = NULL;
                newicsk->icsk_bind2_hash = NULL;
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 a60f6f4..8d20d92 100644 (file)
@@ -3081,6 +3081,12 @@ int tcp_disconnect(struct sock *sk, int flags)
        int old_state = sk->sk_state;
        u32 seq;
 
+       /* Deny disconnect if other threads are blocked in sk_wait_event()
+        * or inet_wait_for_connect().
+        */
+       if (sk->sk_wait_pending)
+               return -EBUSY;
+
        if (old_state != TCP_CLOSE)
                tcp_set_state(sk, TCP_CLOSE);
 
@@ -4072,7 +4078,8 @@ int do_tcp_getsockopt(struct sock *sk, int level,
        switch (optname) {
        case TCP_MAXSEG:
                val = tp->mss_cache;
-               if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
+               if (tp->rx_opt.user_mss &&
+                   ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
                        val = tp->rx_opt.user_mss;
                if (tp->repair)
                        val = tp->rx_opt.mss_clamp;
index 61b6710..bf8b222 100644 (file)
@@ -4530,7 +4530,7 @@ static void tcp_sack_maybe_coalesce(struct tcp_sock *tp)
        }
 }
 
-static void tcp_sack_compress_send_ack(struct sock *sk)
+void tcp_sack_compress_send_ack(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
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 b839c2f..39eb947 100644 (file)
@@ -290,9 +290,19 @@ static int tcp_write_timeout(struct sock *sk)
 void tcp_delack_timer_handler(struct sock *sk)
 {
        struct inet_connection_sock *icsk = inet_csk(sk);
+       struct tcp_sock *tp = tcp_sk(sk);
 
-       if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) ||
-           !(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
+       if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))
+               return;
+
+       /* Handling the sack compression case */
+       if (tp->compressed_ack) {
+               tcp_mstamp_refresh(tp);
+               tcp_sack_compress_send_ack(sk);
+               return;
+       }
+
+       if (!(icsk->icsk_ack.pending & ICSK_ACK_TIMER))
                return;
 
        if (time_after(icsk->icsk_ack.timeout, jiffies)) {
@@ -312,7 +322,7 @@ void tcp_delack_timer_handler(struct sock *sk)
                        inet_csk_exit_pingpong_mode(sk);
                        icsk->icsk_ack.ato      = TCP_ATO_MIN;
                }
-               tcp_mstamp_refresh(tcp_sk(sk));
+               tcp_mstamp_refresh(tp);
                tcp_send_ack(sk);
                __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS);
        }
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 08dc53f..67311e7 100644 (file)
@@ -90,8 +90,8 @@ static int __mptcp_socket_create(struct mptcp_sock *msk)
        if (err)
                return err;
 
-       msk->first = ssock->sk;
-       msk->subflow = ssock;
+       WRITE_ONCE(msk->first, ssock->sk);
+       WRITE_ONCE(msk->subflow, ssock);
        subflow = mptcp_subflow_ctx(ssock->sk);
        list_add(&subflow->node, &msk->conn_list);
        sock_hold(ssock->sk);
@@ -603,7 +603,7 @@ static bool mptcp_check_data_fin(struct sock *sk)
                WRITE_ONCE(msk->ack_seq, msk->ack_seq + 1);
                WRITE_ONCE(msk->rcv_data_fin, 0);
 
-               sk->sk_shutdown |= RCV_SHUTDOWN;
+               WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | RCV_SHUTDOWN);
                smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
 
                switch (sk->sk_state) {
@@ -825,6 +825,13 @@ void mptcp_data_ready(struct sock *sk, struct sock *ssk)
        mptcp_data_unlock(sk);
 }
 
+static void mptcp_subflow_joined(struct mptcp_sock *msk, struct sock *ssk)
+{
+       mptcp_subflow_ctx(ssk)->map_seq = READ_ONCE(msk->ack_seq);
+       WRITE_ONCE(msk->allow_infinite_fallback, false);
+       mptcp_event(MPTCP_EVENT_SUB_ESTABLISHED, msk, ssk, GFP_ATOMIC);
+}
+
 static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
 {
        struct sock *sk = (struct sock *)msk;
@@ -839,6 +846,7 @@ static bool __mptcp_finish_join(struct mptcp_sock *msk, struct sock *ssk)
                mptcp_sock_graft(ssk, sk->sk_socket);
 
        mptcp_sockopt_sync_locked(msk, ssk);
+       mptcp_subflow_joined(msk, ssk);
        return true;
 }
 
@@ -910,7 +918,7 @@ static void mptcp_check_for_eof(struct mptcp_sock *msk)
                /* hopefully temporary hack: propagate shutdown status
                 * to msk, when all subflows agree on it
                 */
-               sk->sk_shutdown |= RCV_SHUTDOWN;
+               WRITE_ONCE(sk->sk_shutdown, sk->sk_shutdown | RCV_SHUTDOWN);
 
                smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
                sk->sk_data_ready(sk);
@@ -1702,7 +1710,6 @@ static int mptcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
 
        lock_sock(ssk);
        msg->msg_flags |= MSG_DONTWAIT;
-       msk->connect_flags = O_NONBLOCK;
        msk->fastopening = 1;
        ret = tcp_sendmsg_fastopen(ssk, msg, copied_syn, len, NULL);
        msk->fastopening = 0;
@@ -2283,7 +2290,7 @@ static void mptcp_dispose_initial_subflow(struct mptcp_sock *msk)
 {
        if (msk->subflow) {
                iput(SOCK_INODE(msk->subflow));
-               msk->subflow = NULL;
+               WRITE_ONCE(msk->subflow, NULL);
        }
 }
 
@@ -2420,7 +2427,7 @@ out_release:
        sock_put(ssk);
 
        if (ssk == msk->first)
-               msk->first = NULL;
+               WRITE_ONCE(msk->first, NULL);
 
 out:
        if (ssk == msk->last_snd)
@@ -2527,7 +2534,7 @@ static void mptcp_check_fastclose(struct mptcp_sock *msk)
        }
 
        inet_sk_state_store(sk, TCP_CLOSE);
-       sk->sk_shutdown = SHUTDOWN_MASK;
+       WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
        smp_mb__before_atomic(); /* SHUTDOWN must be visible first */
        set_bit(MPTCP_WORK_CLOSE_SUBFLOW, &msk->flags);
 
@@ -2721,7 +2728,7 @@ static int __mptcp_init_sock(struct sock *sk)
        WRITE_ONCE(msk->rmem_released, 0);
        msk->timer_ival = TCP_RTO_MIN;
 
-       msk->first = NULL;
+       WRITE_ONCE(msk->first, NULL);
        inet_csk(sk)->icsk_sync_mss = mptcp_sync_mss;
        WRITE_ONCE(msk->csum_enabled, mptcp_is_checksum_enabled(sock_net(sk)));
        WRITE_ONCE(msk->allow_infinite_fallback, true);
@@ -2959,7 +2966,7 @@ bool __mptcp_close(struct sock *sk, long timeout)
        bool do_cancel_work = false;
        int subflows_alive = 0;
 
-       sk->sk_shutdown = SHUTDOWN_MASK;
+       WRITE_ONCE(sk->sk_shutdown, SHUTDOWN_MASK);
 
        if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) {
                mptcp_listen_inuse_dec(sk);
@@ -3039,7 +3046,7 @@ static void mptcp_close(struct sock *sk, long timeout)
        sock_put(sk);
 }
 
-void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
+static void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk)
 {
 #if IS_ENABLED(CONFIG_MPTCP_IPV6)
        const struct ipv6_pinfo *ssk6 = inet6_sk(ssk);
@@ -3102,7 +3109,7 @@ static int mptcp_disconnect(struct sock *sk, int flags)
        mptcp_pm_data_reset(msk);
        mptcp_ca_reset(sk);
 
-       sk->sk_shutdown = 0;
+       WRITE_ONCE(sk->sk_shutdown, 0);
        sk_error_report(sk);
        return 0;
 }
@@ -3116,9 +3123,10 @@ static struct ipv6_pinfo *mptcp_inet6_sk(const struct sock *sk)
 }
 #endif
 
-struct sock *mptcp_sk_clone(const struct sock *sk,
-                           const struct mptcp_options_received *mp_opt,
-                           struct request_sock *req)
+struct sock *mptcp_sk_clone_init(const struct sock *sk,
+                                const struct mptcp_options_received *mp_opt,
+                                struct sock *ssk,
+                                struct request_sock *req)
 {
        struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req);
        struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC);
@@ -3137,7 +3145,7 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
        msk = mptcp_sk(nsk);
        msk->local_key = subflow_req->local_key;
        msk->token = subflow_req->token;
-       msk->subflow = NULL;
+       WRITE_ONCE(msk->subflow, NULL);
        msk->in_accept_queue = 1;
        WRITE_ONCE(msk->fully_established, false);
        if (mp_opt->suboptions & OPTION_MPTCP_CSUMREQD)
@@ -3150,10 +3158,30 @@ struct sock *mptcp_sk_clone(const struct sock *sk,
        msk->setsockopt_seq = mptcp_sk(sk)->setsockopt_seq;
 
        sock_reset_flag(nsk, SOCK_RCU_FREE);
-       /* will be fully established after successful MPC subflow creation */
-       inet_sk_state_store(nsk, TCP_SYN_RECV);
-
        security_inet_csk_clone(nsk, req);
+
+       /* this can't race with mptcp_close(), as the msk is
+        * not yet exposted to user-space
+        */
+       inet_sk_state_store(nsk, TCP_ESTABLISHED);
+
+       /* The msk maintain a ref to each subflow in the connections list */
+       WRITE_ONCE(msk->first, ssk);
+       list_add(&mptcp_subflow_ctx(ssk)->node, &msk->conn_list);
+       sock_hold(ssk);
+
+       /* new mpc subflow takes ownership of the newly
+        * created mptcp socket
+        */
+       mptcp_token_accept(subflow_req, msk);
+
+       /* set msk addresses early to ensure mptcp_pm_get_local_id()
+        * uses the correct data
+        */
+       mptcp_copy_inaddrs(nsk, ssk);
+       mptcp_propagate_sndbuf(nsk, ssk);
+
+       mptcp_rcv_space_init(msk, ssk);
        bh_unlock_sock(nsk);
 
        /* note: the newly allocated socket refcount is 2 now */
@@ -3185,7 +3213,7 @@ static struct sock *mptcp_accept(struct sock *sk, int flags, int *err,
        struct socket *listener;
        struct sock *newsk;
 
-       listener = msk->subflow;
+       listener = READ_ONCE(msk->subflow);
        if (WARN_ON_ONCE(!listener)) {
                *err = -EINVAL;
                return NULL;
@@ -3465,14 +3493,16 @@ bool mptcp_finish_join(struct sock *ssk)
                return false;
        }
 
-       if (!list_empty(&subflow->node))
-               goto out;
+       /* active subflow, already present inside the conn_list */
+       if (!list_empty(&subflow->node)) {
+               mptcp_subflow_joined(msk, ssk);
+               return true;
+       }
 
        if (!mptcp_pm_allow_new_subflow(msk))
                goto err_prohibited;
 
-       /* active connections are already on conn_list.
-        * If we can't acquire msk socket lock here, let the release callback
+       /* If we can't acquire msk socket lock here, let the release callback
         * handle it
         */
        mptcp_data_lock(parent);
@@ -3495,11 +3525,6 @@ err_prohibited:
                return false;
        }
 
-       subflow->map_seq = READ_ONCE(msk->ack_seq);
-       WRITE_ONCE(msk->allow_infinite_fallback, false);
-
-out:
-       mptcp_event(MPTCP_EVENT_SUB_ESTABLISHED, msk, ssk, GFP_ATOMIC);
        return true;
 }
 
@@ -3617,9 +3642,9 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
         * acquired the subflow socket lock, too.
         */
        if (msk->fastopening)
-               err = __inet_stream_connect(ssock, uaddr, addr_len, msk->connect_flags, 1);
+               err = __inet_stream_connect(ssock, uaddr, addr_len, O_NONBLOCK, 1);
        else
-               err = inet_stream_connect(ssock, uaddr, addr_len, msk->connect_flags);
+               err = inet_stream_connect(ssock, uaddr, addr_len, O_NONBLOCK);
        inet_sk(sk)->defer_connect = inet_sk(ssock->sk)->defer_connect;
 
        /* on successful connect, the msk state will be moved to established by
@@ -3632,12 +3657,10 @@ static int mptcp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 
        mptcp_copy_inaddrs(sk, ssock->sk);
 
-       /* unblocking connect, mptcp-level inet_stream_connect will error out
-        * without changing the socket state, update it here.
+       /* silence EINPROGRESS and let the caller inet_stream_connect
+        * handle the connection in progress
         */
-       if (err == -EINPROGRESS)
-               sk->sk_socket->state = ssock->state;
-       return err;
+       return 0;
 }
 
 static struct proto mptcp_prot = {
@@ -3696,18 +3719,6 @@ unlock:
        return err;
 }
 
-static int mptcp_stream_connect(struct socket *sock, struct sockaddr *uaddr,
-                               int addr_len, int flags)
-{
-       int ret;
-
-       lock_sock(sock->sk);
-       mptcp_sk(sock->sk)->connect_flags = flags;
-       ret = __inet_stream_connect(sock, uaddr, addr_len, flags, 0);
-       release_sock(sock->sk);
-       return ret;
-}
-
 static int mptcp_listen(struct socket *sock, int backlog)
 {
        struct mptcp_sock *msk = mptcp_sk(sock->sk);
@@ -3751,10 +3762,10 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
 
        pr_debug("msk=%p", msk);
 
-       /* buggy applications can call accept on socket states other then LISTEN
+       /* Buggy applications can call accept on socket states other then LISTEN
         * but no need to allocate the first subflow just to error out.
         */
-       ssock = msk->subflow;
+       ssock = READ_ONCE(msk->subflow);
        if (!ssock)
                return -EINVAL;
 
@@ -3800,9 +3811,6 @@ static __poll_t mptcp_check_writeable(struct mptcp_sock *msk)
 {
        struct sock *sk = (struct sock *)msk;
 
-       if (unlikely(sk->sk_shutdown & SEND_SHUTDOWN))
-               return EPOLLOUT | EPOLLWRNORM;
-
        if (sk_stream_is_writeable(sk))
                return EPOLLOUT | EPOLLWRNORM;
 
@@ -3820,6 +3828,7 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
        struct sock *sk = sock->sk;
        struct mptcp_sock *msk;
        __poll_t mask = 0;
+       u8 shutdown;
        int state;
 
        msk = mptcp_sk(sk);
@@ -3828,23 +3837,30 @@ static __poll_t mptcp_poll(struct file *file, struct socket *sock,
        state = inet_sk_state_load(sk);
        pr_debug("msk=%p state=%d flags=%lx", msk, state, msk->flags);
        if (state == TCP_LISTEN) {
-               if (WARN_ON_ONCE(!msk->subflow || !msk->subflow->sk))
+               struct socket *ssock = READ_ONCE(msk->subflow);
+
+               if (WARN_ON_ONCE(!ssock || !ssock->sk))
                        return 0;
 
-               return inet_csk_listen_poll(msk->subflow->sk);
+               return inet_csk_listen_poll(ssock->sk);
        }
 
+       shutdown = READ_ONCE(sk->sk_shutdown);
+       if (shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
+               mask |= EPOLLHUP;
+       if (shutdown & RCV_SHUTDOWN)
+               mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
+
        if (state != TCP_SYN_SENT && state != TCP_SYN_RECV) {
                mask |= mptcp_check_readable(msk);
-               mask |= mptcp_check_writeable(msk);
+               if (shutdown & SEND_SHUTDOWN)
+                       mask |= EPOLLOUT | EPOLLWRNORM;
+               else
+                       mask |= mptcp_check_writeable(msk);
        } else if (state == TCP_SYN_SENT && inet_sk(sk)->defer_connect) {
                /* cf tcp_poll() note about TFO */
                mask |= EPOLLOUT | EPOLLWRNORM;
        }
-       if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
-               mask |= EPOLLHUP;
-       if (sk->sk_shutdown & RCV_SHUTDOWN)
-               mask |= EPOLLIN | EPOLLRDNORM | EPOLLRDHUP;
 
        /* This barrier is coupled with smp_wmb() in __mptcp_error_report() */
        smp_rmb();
@@ -3859,7 +3875,7 @@ static const struct proto_ops mptcp_stream_ops = {
        .owner             = THIS_MODULE,
        .release           = inet_release,
        .bind              = mptcp_bind,
-       .connect           = mptcp_stream_connect,
+       .connect           = inet_stream_connect,
        .socketpair        = sock_no_socketpair,
        .accept            = mptcp_stream_accept,
        .getname           = inet_getname,
@@ -3954,7 +3970,7 @@ static const struct proto_ops mptcp_v6_stream_ops = {
        .owner             = THIS_MODULE,
        .release           = inet6_release,
        .bind              = mptcp_bind,
-       .connect           = mptcp_stream_connect,
+       .connect           = inet_stream_connect,
        .socketpair        = sock_no_socketpair,
        .accept            = mptcp_stream_accept,
        .getname           = inet6_getname,
index 2d7b2c8..70c957b 100644 (file)
@@ -297,7 +297,6 @@ struct mptcp_sock {
                        nodelay:1,
                        fastopening:1,
                        in_accept_queue:1;
-       int             connect_flags;
        struct work_struct work;
        struct sk_buff  *ooo_last_skb;
        struct rb_root  out_of_order_queue;
@@ -306,7 +305,11 @@ struct mptcp_sock {
        struct list_head rtx_queue;
        struct mptcp_data_frag *first_pending;
        struct list_head join_list;
-       struct socket   *subflow; /* outgoing connect/listener/!mp_capable */
+       struct socket   *subflow; /* outgoing connect/listener/!mp_capable
+                                  * The mptcp ops can safely dereference, using suitable
+                                  * ONCE annotation, the subflow outside the socket
+                                  * lock as such sock is freed after close().
+                                  */
        struct sock     *first;
        struct mptcp_pm_data    pm;
        struct {
@@ -613,7 +616,6 @@ int mptcp_is_checksum_enabled(const struct net *net);
 int mptcp_allow_join_id0(const struct net *net);
 unsigned int mptcp_stale_loss_cnt(const struct net *net);
 int mptcp_get_pm_type(const struct net *net);
-void mptcp_copy_inaddrs(struct sock *msk, const struct sock *ssk);
 void mptcp_subflow_fully_established(struct mptcp_subflow_context *subflow,
                                     const struct mptcp_options_received *mp_opt);
 bool __mptcp_retransmit_pending_data(struct sock *sk);
@@ -683,9 +685,10 @@ void __init mptcp_proto_init(void);
 int __init mptcp_proto_v6_init(void);
 #endif
 
-struct sock *mptcp_sk_clone(const struct sock *sk,
-                           const struct mptcp_options_received *mp_opt,
-                           struct request_sock *req);
+struct sock *mptcp_sk_clone_init(const struct sock *sk,
+                                const struct mptcp_options_received *mp_opt,
+                                struct sock *ssk,
+                                struct request_sock *req);
 void mptcp_get_options(const struct sk_buff *skb,
                       struct mptcp_options_received *mp_opt);
 
@@ -829,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 ba065b6..4688daa 100644 (file)
@@ -815,38 +815,12 @@ create_child:
                ctx->setsockopt_seq = listener->setsockopt_seq;
 
                if (ctx->mp_capable) {
-                       ctx->conn = mptcp_sk_clone(listener->conn, &mp_opt, req);
+                       ctx->conn = mptcp_sk_clone_init(listener->conn, &mp_opt, child, req);
                        if (!ctx->conn)
                                goto fallback;
 
                        owner = mptcp_sk(ctx->conn);
-
-                       /* this can't race with mptcp_close(), as the msk is
-                        * not yet exposted to user-space
-                        */
-                       inet_sk_state_store(ctx->conn, TCP_ESTABLISHED);
-
-                       /* record the newly created socket as the first msk
-                        * subflow, but don't link it yet into conn_list
-                        */
-                       WRITE_ONCE(owner->first, child);
-
-                       /* new mpc subflow takes ownership of the newly
-                        * created mptcp socket
-                        */
-                       owner->setsockopt_seq = ctx->setsockopt_seq;
                        mptcp_pm_new_connection(owner, child, 1);
-                       mptcp_token_accept(subflow_req, owner);
-
-                       /* set msk addresses early to ensure mptcp_pm_get_local_id()
-                        * uses the correct data
-                        */
-                       mptcp_copy_inaddrs(ctx->conn, child);
-                       mptcp_propagate_sndbuf(ctx->conn, child);
-
-                       mptcp_rcv_space_init(owner, child);
-                       list_add(&ctx->node, &owner->conn_list);
-                       sock_hold(child);
 
                        /* with OoO packets we can reach here without ingress
                         * mpc option
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 c878041..3a1e0fd 100644 (file)
@@ -1779,7 +1779,7 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
                                break;
                        }
                }
-               if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen))
+               if (put_user(ALIGN(BITS_TO_BYTES(nlk->ngroups), sizeof(u32)), optlen))
                        err = -EFAULT;
                netlink_unlock_table();
                return err;
index 3f99b43..e2d2af9 100644 (file)
@@ -123,7 +123,7 @@ void nr_write_internal(struct sock *sk, int frametype)
        unsigned char  *dptr;
        int len, timeout;
 
-       len = NR_NETWORK_LEN + NR_TRANSPORT_LEN;
+       len = NR_TRANSPORT_LEN;
 
        switch (frametype & 0x0F) {
        case NR_CONNREQ:
@@ -141,7 +141,8 @@ void nr_write_internal(struct sock *sk, int frametype)
                return;
        }
 
-       if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL)
+       skb = alloc_skb(NR_NETWORK_LEN + len, GFP_ATOMIC);
+       if (!skb)
                return;
 
        /*
@@ -149,7 +150,7 @@ void nr_write_internal(struct sock *sk, int frametype)
         */
        skb_reserve(skb, NR_NETWORK_LEN);
 
-       dptr = skb_put(skb, skb_tailroom(skb));
+       dptr = skb_put(skb, len);
 
        switch (frametype & 0x0F) {
        case NR_CONNREQ:
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 94c6a1f..a2dbeb2 100644 (file)
@@ -3201,6 +3201,9 @@ static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
 
        lock_sock(sk);
        spin_lock(&po->bind_lock);
+       if (!proto)
+               proto = po->num;
+
        rcu_read_lock();
 
        if (po->fanout) {
@@ -3299,7 +3302,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
        memcpy(name, uaddr->sa_data, sizeof(uaddr->sa_data_min));
        name[sizeof(uaddr->sa_data_min)] = 0;
 
-       return packet_do_bind(sk, name, 0, pkt_sk(sk)->num);
+       return packet_do_bind(sk, name, 0, 0);
 }
 
 static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
@@ -3316,8 +3319,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
        if (sll->sll_family != AF_PACKET)
                return -EINVAL;
 
-       return packet_do_bind(sk, NULL, sll->sll_ifindex,
-                             sll->sll_protocol ? : pkt_sk(sk)->num);
+       return packet_do_bind(sk, NULL, sll->sll_ifindex, sll->sll_protocol);
 }
 
 static struct proto packet_proto = {
index d0c4eda..f6b200c 100644 (file)
@@ -143,7 +143,7 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
        rp = nlmsg_data(nlh);
        rp->pdiag_family = AF_PACKET;
        rp->pdiag_type = sk->sk_type;
-       rp->pdiag_num = ntohs(po->num);
+       rp->pdiag_num = ntohs(READ_ONCE(po->num));
        rp->pdiag_ino = sk_ino;
        sock_diag_save_cookie(sk, rp->pdiag_cookie);
 
index 31f738d..da0b3b5 100644 (file)
@@ -980,6 +980,7 @@ static int __init af_rxrpc_init(void)
        BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
 
        ret = -ENOMEM;
+       rxrpc_gen_version_string();
        rxrpc_call_jar = kmem_cache_create(
                "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
                SLAB_HWCACHE_ALIGN, NULL);
index 5d44dc0..e8e14c6 100644 (file)
@@ -1068,6 +1068,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time64_t,
 /*
  * local_event.c
  */
+void rxrpc_gen_version_string(void);
 void rxrpc_send_version_request(struct rxrpc_local *local,
                                struct rxrpc_host_header *hdr,
                                struct sk_buff *skb);
index 5e69ea6..993c69f 100644 (file)
 #include <generated/utsrelease.h>
 #include "ar-internal.h"
 
-static const char rxrpc_version_string[65] = "linux-" UTS_RELEASE " AF_RXRPC";
+static char rxrpc_version_string[65]; // "linux-" UTS_RELEASE " AF_RXRPC";
+
+/*
+ * Generate the VERSION packet string.
+ */
+void rxrpc_gen_version_string(void)
+{
+       snprintf(rxrpc_version_string, sizeof(rxrpc_version_string),
+                "linux-%.49s AF_RXRPC", UTS_RELEASE);
+}
 
 /*
  * Reply to a version request
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 9dbc433..815c3e4 100644 (file)
@@ -1153,6 +1153,9 @@ static int fl_set_geneve_opt(const struct nlattr *nla, struct fl_flow_key *key,
        if (option_len > sizeof(struct geneve_opt))
                data_len = option_len - sizeof(struct geneve_opt);
 
+       if (key->enc_opts.len > FLOW_DIS_TUN_OPTS_MAX - 4)
+               return -ERANGE;
+
        opt = (struct geneve_opt *)&key->enc_opts.data[key->enc_opts.len];
        memset(opt, 0xff, option_len);
        opt->length = data_len / 4;
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 fdb8f42..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)
@@ -1252,7 +1276,12 @@ static struct Qdisc *qdisc_create(struct net_device *dev,
        sch->parent = parent;
 
        if (handle == TC_H_INGRESS) {
-               sch->flags |= TCQ_F_INGRESS;
+               if (!(sch->flags & TCQ_F_INGRESS)) {
+                       NL_SET_ERR_MSG(extack,
+                                      "Specified parent ID is reserved for ingress and clsact Qdiscs");
+                       err = -EINVAL;
+                       goto err_out3;
+               }
                handle = TC_H_MAKE(TC_H_INGRESS, 0);
        } else {
                if (handle == 0) {
@@ -1473,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);
@@ -1559,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);
@@ -1591,11 +1620,20 @@ replay:
                                        NL_SET_ERR_MSG(extack, "Invalid qdisc name");
                                        return -EINVAL;
                                }
+                               if (q->flags & TCQ_F_INGRESS) {
+                                       NL_SET_ERR_MSG(extack,
+                                                      "Cannot regraft ingress or clsact Qdiscs");
+                                       return -EINVAL;
+                               }
                                if (q == p ||
                                    (p && check_loop(q, p, 0))) {
                                        NL_SET_ERR_MSG(extack, "Qdisc parent/child loop detected");
                                        return -ELOOP;
                                }
+                               if (clid == TC_H_INGRESS) {
+                                       NL_SET_ERR_MSG(extack, "Ingress cannot graft directly");
+                                       return -EINVAL;
+                               }
                                qdisc_refcount_inc(q);
                                goto graft;
                        } else {
@@ -1791,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;
 
@@ -2235,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:
@@ -2288,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 8483812..e43a454 100644 (file)
@@ -80,6 +80,9 @@ static int ingress_init(struct Qdisc *sch, struct nlattr *opt,
        struct net_device *dev = qdisc_dev(sch);
        int err;
 
+       if (sch->parent != TC_H_INGRESS)
+               return -EOPNOTSUPP;
+
        net_inc_ingress_queue();
 
        mini_qdisc_pair_init(&q->miniqp, sch, &dev->miniq_ingress);
@@ -101,6 +104,9 @@ static void ingress_destroy(struct Qdisc *sch)
 {
        struct ingress_sched_data *q = qdisc_priv(sch);
 
+       if (sch->parent != TC_H_INGRESS)
+               return;
+
        tcf_block_put_ext(q->block, sch, &q->block_info);
        net_dec_ingress_queue();
 }
@@ -134,7 +140,7 @@ static struct Qdisc_ops ingress_qdisc_ops __read_mostly = {
        .cl_ops                 =       &ingress_class_ops,
        .id                     =       "ingress",
        .priv_size              =       sizeof(struct ingress_sched_data),
-       .static_flags           =       TCQ_F_CPUSTATS,
+       .static_flags           =       TCQ_F_INGRESS | TCQ_F_CPUSTATS,
        .init                   =       ingress_init,
        .destroy                =       ingress_destroy,
        .dump                   =       ingress_dump,
@@ -219,6 +225,9 @@ static int clsact_init(struct Qdisc *sch, struct nlattr *opt,
        struct net_device *dev = qdisc_dev(sch);
        int err;
 
+       if (sch->parent != TC_H_CLSACT)
+               return -EOPNOTSUPP;
+
        net_inc_ingress_queue();
        net_inc_egress_queue();
 
@@ -248,6 +257,9 @@ static void clsact_destroy(struct Qdisc *sch)
 {
        struct clsact_sched_data *q = qdisc_priv(sch);
 
+       if (sch->parent != TC_H_CLSACT)
+               return;
+
        tcf_block_put_ext(q->egress_block, sch, &q->egress_block_info);
        tcf_block_put_ext(q->ingress_block, sch, &q->ingress_block_info);
 
@@ -269,7 +281,7 @@ static struct Qdisc_ops clsact_qdisc_ops __read_mostly = {
        .cl_ops                 =       &clsact_class_ops,
        .id                     =       "clsact",
        .priv_size              =       sizeof(struct clsact_sched_data),
-       .static_flags           =       TCQ_F_CPUSTATS,
+       .static_flags           =       TCQ_F_INGRESS | TCQ_F_CPUSTATS,
        .init                   =       clsact_init,
        .destroy                =       clsact_destroy,
        .dump                   =       ingress_dump,
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 a0840b8..90f0b60 100644 (file)
@@ -578,7 +578,10 @@ static struct smc_buf_desc *smc_llc_get_next_rmb(struct smc_link_group *lgr,
 {
        struct smc_buf_desc *buf_next;
 
-       if (!buf_pos || list_is_last(&buf_pos->list, &lgr->rmbs[*buf_lst])) {
+       if (!buf_pos)
+               return _smc_llc_get_next_rmb(lgr, buf_lst);
+
+       if (list_is_last(&buf_pos->list, &lgr->rmbs[*buf_lst])) {
                (*buf_lst)++;
                return _smc_llc_get_next_rmb(lgr, buf_lst);
        }
@@ -614,6 +617,8 @@ static int smc_llc_fill_ext_v2(struct smc_llc_msg_add_link_v2_ext *ext,
                goto out;
        buf_pos = smc_llc_get_first_rmb(lgr, &buf_lst);
        for (i = 0; i < ext->num_rkeys; i++) {
+               while (buf_pos && !(buf_pos)->used)
+                       buf_pos = smc_llc_get_next_rmb(lgr, &buf_lst, buf_pos);
                if (!buf_pos)
                        break;
                rmb = buf_pos;
@@ -623,8 +628,6 @@ static int smc_llc_fill_ext_v2(struct smc_llc_msg_add_link_v2_ext *ext,
                        cpu_to_be64((uintptr_t)rmb->cpu_addr) :
                        cpu_to_be64((u64)sg_dma_address(rmb->sgt[lnk_idx].sgl));
                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);
        }
        len += i * sizeof(ext->rt[0]);
 out:
@@ -848,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;
@@ -864,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 63fe7a3..f77cebe 100644 (file)
@@ -1480,25 +1480,10 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        return svsk;
 }
 
-bool svc_alien_sock(struct net *net, int fd)
-{
-       int err;
-       struct socket *sock = sockfd_lookup(fd, &err);
-       bool ret = false;
-
-       if (!sock)
-               goto out;
-       if (sock_net(sock->sk) != net)
-               ret = true;
-       sockfd_put(sock);
-out:
-       return ret;
-}
-EXPORT_SYMBOL_GPL(svc_alien_sock);
-
 /**
  * svc_addsock - add a listener socket to an RPC service
  * @serv: pointer to RPC service to which to add a new listener
+ * @net: caller's network namespace
  * @fd: file descriptor of the new listener
  * @name_return: pointer to buffer to fill in with name of listener
  * @len: size of the buffer
@@ -1508,8 +1493,8 @@ EXPORT_SYMBOL_GPL(svc_alien_sock);
  * Name is terminated with '\n'.  On error, returns a negative errno
  * value.
  */
-int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
-               const size_t len, const struct cred *cred)
+int svc_addsock(struct svc_serv *serv, struct net *net, const int fd,
+               char *name_return, const size_t len, const struct cred *cred)
 {
        int err = 0;
        struct socket *so = sockfd_lookup(fd, &err);
@@ -1520,6 +1505,9 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return,
 
        if (!so)
                return err;
+       err = -EINVAL;
+       if (sock_net(so->sk) != net)
+               goto out;
        err = -EAFNOSUPPORT;
        if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6))
                goto out;
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 da95abb..f37f4a0 100644 (file)
@@ -20,7 +20,9 @@ static void tls_strp_abort_strp(struct tls_strparser *strp, int err)
        strp->stopped = 1;
 
        /* Report an error on the lower socket */
-       strp->sk->sk_err = -err;
+       WRITE_ONCE(strp->sk->sk_err, -err);
+       /* Paired with smp_rmb() in tcp_poll() */
+       smp_wmb();
        sk_error_report(strp->sk);
 }
 
index 6e6a7c3..1a53c8f 100644 (file)
@@ -70,7 +70,9 @@ noinline void tls_err_abort(struct sock *sk, int err)
 {
        WARN_ON_ONCE(err >= 0);
        /* sk->sk_err should contain a positive error code. */
-       sk->sk_err = -err;
+       WRITE_ONCE(sk->sk_err, -err);
+       /* Paired with smp_rmb() in tcp_poll() */
+       smp_wmb();
        sk_error_report(sk);
 }
 
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 0aecf93..8b21520 100644 (file)
@@ -26,5 +26,9 @@ quiet_cmd_flask = GEN     $(obj)/flask.h $(obj)/av_permissions.h
       cmd_flask = $< $(obj)/flask.h $(obj)/av_permissions.h
 
 targets += flask.h av_permissions.h
-$(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/genheaders/genheaders FORCE
+# once make >= 4.3 is required, we can use grouped targets in the rule below,
+# which basically involves adding both headers and a '&' before the colon, see
+# the example below:
+#   $(obj)/flask.h $(obj)/av_permissions.h &: scripts/selinux/...
+$(obj)/flask.h: scripts/selinux/genheaders/genheaders FORCE
        $(call if_changed,flask)
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 cef3b1c..51ac441 100644 (file)
  */
 #define CORESIGHT_LEGACY_CPU_TRACE_ID(cpu)  (0x10 + (cpu * 2))
 
-/* CoreSight trace ID is currently the bottom 7 bits of the value */
-#define CORESIGHT_TRACE_ID_VAL_MASK    GENMASK(6, 0)
-
-/*
- * perf record will set the legacy meta data values as unused initially.
- * This allows perf report to manage the decoders created when dynamic
- * allocation in operation.
- */
-#define CORESIGHT_TRACE_ID_UNUSED_FLAG BIT(31)
-
-/* Value to set for unused trace ID values */
-#define CORESIGHT_TRACE_ID_UNUSED_VAL  0x7F
-
 /*
  * Below are the definition of bit offsets for perf option, and works as
  * arbitrary values for all ETM versions.
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 4b7f2df..e682ab6 100644 (file)
@@ -163,6 +163,7 @@ struct in_addr {
 #define IP_MULTICAST_ALL               49
 #define IP_UNICAST_IF                  50
 #define IP_LOCAL_PORT_RANGE            51
+#define IP_PROTOCOL                    52
 
 #define MCAST_EXCLUDE  0
 #define MCAST_INCLUDE  1
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 aa77bca..3144f33 100644 (file)
@@ -591,8 +591,9 @@ class YnlFamily(SpecFamily):
                         print('Unexpected message: ' + repr(gm))
                         continue
 
-                rsp.append(self._decode(gm.raw_attrs, op.attr_set.name)
-                           | gm.fixed_header_attrs)
+                rsp_msg = self._decode(gm.raw_attrs, op.attr_set.name)
+                rsp_msg.update(gm.fixed_header_attrs)
+                rsp.append(rsp_msg)
 
         if not rsp:
             return None
index 7026844..a794d9e 100644 (file)
@@ -927,6 +927,7 @@ ifndef NO_DEMANGLE
     EXTLIBS += -lstdc++
     CFLAGS += -DHAVE_CXA_DEMANGLE_SUPPORT
     CXXFLAGS += -DHAVE_CXA_DEMANGLE_SUPPORT
+    $(call detected,CONFIG_CXX_DEMANGLE)
   endif
   ifdef BUILD_NONDISTRO
     ifeq ($(filter -liberty,$(EXTLIBS)),)
index 1593c5d..f487948 100644 (file)
@@ -181,7 +181,6 @@ HOSTCC  ?= gcc
 HOSTLD  ?= ld
 HOSTAR  ?= ar
 CLANG   ?= clang
-LLVM_STRIP ?= llvm-strip
 
 PKG_CONFIG = $(CROSS_COMPILE)pkg-config
 
@@ -1083,7 +1082,7 @@ $(BPFTOOL): | $(SKEL_TMP_OUT)
 
 $(SKEL_TMP_OUT)/%.bpf.o: util/bpf_skel/%.bpf.c $(LIBBPF) | $(SKEL_TMP_OUT)
        $(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -Wall -Werror $(BPF_INCLUDE) $(TOOLS_UAPI_INCLUDE) \
-         -c $(filter util/bpf_skel/%.bpf.c,$^) -o $@ && $(LLVM_STRIP) -g $@
+         -c $(filter util/bpf_skel/%.bpf.c,$^) -o $@
 
 $(SKEL_OUT)/%.skel.h: $(SKEL_TMP_OUT)/%.bpf.o | $(BPFTOOL)
        $(QUIET_GENSKEL)$(BPFTOOL) gen skeleton $< > $@
index 860a8b4..a9623b1 100644 (file)
@@ -12,7 +12,7 @@
 #include "arm-spe.h"
 #include "hisi-ptt.h"
 #include "../../../util/pmu.h"
-#include "../cs-etm.h"
+#include "../../../util/cs-etm.h"
 
 struct perf_event_attr
 *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
index 810e337..f9906f5 100644 (file)
@@ -1175,7 +1175,7 @@ int cmd_ftrace(int argc, const char **argv)
        OPT_BOOLEAN('b', "use-bpf", &ftrace.target.use_bpf,
                    "Use BPF to measure function latency"),
 #endif
-       OPT_BOOLEAN('n', "--use-nsec", &ftrace.use_nsec,
+       OPT_BOOLEAN('n', "use-nsec", &ftrace.use_nsec,
                    "Use nano-second histogram"),
        OPT_PARENT(common_options),
        };
index bd18fe5..f9df1df 100644 (file)
@@ -214,7 +214,7 @@ perf-$(CONFIG_ZSTD) += zstd.o
 
 perf-$(CONFIG_LIBCAP) += cap.o
 
-perf-y += demangle-cxx.o
+perf-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
 perf-y += demangle-ocaml.o
 perf-y += demangle-java.o
 perf-y += demangle-rust.o
index cffe493..fb94f52 100644 (file)
@@ -25,7 +25,7 @@ struct perf_sample_data___new {
 } __attribute__((preserve_access_index));
 
 /* new kernel perf_mem_data_src definition */
-union perf_mem_data_src__new {
+union perf_mem_data_src___new {
        __u64 val;
        struct {
                __u64   mem_op:5,       /* type of opcode */
@@ -108,7 +108,7 @@ static inline __u64 perf_get_sample(struct bpf_perf_event_data_kern *kctx,
                if (entry->part == 7)
                        return kctx->data->data_src.mem_blk;
                if (entry->part == 8) {
-                       union perf_mem_data_src__new *data = (void *)&kctx->data->data_src;
+                       union perf_mem_data_src___new *data = (void *)&kctx->data->data_src;
 
                        if (bpf_core_field_exists(data->mem_hops))
                                return data->mem_hops;
index 70cac03..ecca407 100644 (file)
@@ -227,6 +227,19 @@ struct cs_etm_packet_queue {
 #define INFO_HEADER_SIZE (sizeof(((struct perf_record_auxtrace_info *)0)->type) + \
                          sizeof(((struct perf_record_auxtrace_info *)0)->reserved__))
 
+/* CoreSight trace ID is currently the bottom 7 bits of the value */
+#define CORESIGHT_TRACE_ID_VAL_MASK    GENMASK(6, 0)
+
+/*
+ * perf record will set the legacy meta data values as unused initially.
+ * This allows perf report to manage the decoders created when dynamic
+ * allocation in operation.
+ */
+#define CORESIGHT_TRACE_ID_UNUSED_FLAG BIT(31)
+
+/* Value to set for unused trace ID values */
+#define CORESIGHT_TRACE_ID_UNUSED_VAL  0x7F
+
 int cs_etm__process_auxtrace_info(union perf_event *event,
                                  struct perf_session *session);
 struct perf_event_attr *cs_etm_get_default_config(struct perf_pmu *pmu);
index 2f5910b..c2dbb56 100644 (file)
@@ -282,6 +282,7 @@ void evsel__init(struct evsel *evsel,
        evsel->bpf_fd      = -1;
        INIT_LIST_HEAD(&evsel->config_terms);
        INIT_LIST_HEAD(&evsel->bpf_counter_list);
+       INIT_LIST_HEAD(&evsel->bpf_filters);
        perf_evsel__object.init(evsel);
        evsel->sample_size = __evsel__sample_size(attr->sample_type);
        evsel__calc_id_pos(evsel);
index df89287..0f54f28 100644 (file)
@@ -151,10 +151,8 @@ struct evsel {
         */
        struct bpf_counter_ops  *bpf_counter_ops;
 
-       union {
-               struct list_head        bpf_counter_list; /* for perf-stat -b */
-               struct list_head        bpf_filters; /* for perf-record --filter */
-       };
+       struct list_head        bpf_counter_list; /* for perf-stat -b */
+       struct list_head        bpf_filters; /* for perf-record --filter */
 
        /* for perf-stat --use-bpf */
        int                     bperf_leader_prog_fd;
index b2ed9cc..63882a4 100644 (file)
 #include <bfd.h>
 #endif
 
+#if defined(HAVE_LIBBFD_SUPPORT) || defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+#ifndef DMGL_PARAMS
+#define DMGL_PARAMS     (1 << 0)  /* Include function args */
+#define DMGL_ANSI       (1 << 1)  /* Include const, volatile, etc */
+#endif
+#endif
+
 #ifndef EM_AARCH64
 #define EM_AARCH64     183  /* ARM 64 bit */
 #endif
@@ -271,6 +278,26 @@ static bool want_demangle(bool is_kernel_sym)
        return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle;
 }
 
+/*
+ * Demangle C++ function signature, typically replaced by demangle-cxx.cpp
+ * version.
+ */
+__weak char *cxx_demangle_sym(const char *str __maybe_unused, bool params __maybe_unused,
+                             bool modifiers __maybe_unused)
+{
+#ifdef HAVE_LIBBFD_SUPPORT
+       int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
+
+       return bfd_demangle(NULL, str, flags);
+#elif defined(HAVE_CPLUS_DEMANGLE_SUPPORT)
+       int flags = (params ? DMGL_PARAMS : 0) | (modifiers ? DMGL_ANSI : 0);
+
+       return cplus_demangle(str, flags);
+#else
+       return NULL;
+#endif
+}
+
 static char *demangle_sym(struct dso *dso, int kmodule, const char *elf_name)
 {
        char *demangled = NULL;
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 e2ff3bf..2de7c61 100644 (file)
@@ -9,18 +9,33 @@ fail() { #msg
     exit_fail
 }
 
-echo "Test event filter function name"
+sample_events() {
+    echo > trace
+    echo 1 > events/kmem/kmem_cache_free/enable
+    echo 1 > tracing_on
+    ls > /dev/null
+    echo 0 > tracing_on
+    echo 0 > events/kmem/kmem_cache_free/enable
+}
+
 echo 0 > tracing_on
 echo 0 > events/enable
+
+echo "Get the most frequently calling function"
+sample_events
+
+target_func=`cut -d: -f3 trace | sed 's/call_site=\([^+]*\)+0x.*/\1/' | sort | uniq -c | sort | tail -n 1 | sed 's/^[ 0-9]*//'`
+if [ -z "$target_func" ]; then
+    exit_fail
+fi
 echo > trace
-echo 'call_site.function == exit_mmap' > events/kmem/kmem_cache_free/filter
-echo 1 > events/kmem/kmem_cache_free/enable
-echo 1 > tracing_on
-ls > /dev/null
-echo 0 > events/kmem/kmem_cache_free/enable
 
-hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l`
-misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l`
+echo "Test event filter function name"
+echo "call_site.function == $target_func" > events/kmem/kmem_cache_free/filter
+sample_events
+
+hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
+misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
 
 if [ $hitcnt -eq 0 ]; then
        exit_fail
@@ -30,20 +45,14 @@ if [ $misscnt -gt 0 ]; then
        exit_fail
 fi
 
-address=`grep ' exit_mmap$' /proc/kallsyms | cut -d' ' -f1`
+address=`grep " ${target_func}\$" /proc/kallsyms | cut -d' ' -f1`
 
 echo "Test event filter function address"
-echo 0 > tracing_on
-echo 0 > events/enable
-echo > trace
 echo "call_site.function == 0x$address" > events/kmem/kmem_cache_free/filter
-echo 1 > events/kmem/kmem_cache_free/enable
-echo 1 > tracing_on
-sleep 1
-echo 0 > events/kmem/kmem_cache_free/enable
+sample_events
 
-hitcnt=`grep kmem_cache_free trace| grep exit_mmap | wc -l`
-misscnt=`grep kmem_cache_free trace| grep -v exit_mmap | wc -l`
+hitcnt=`grep kmem_cache_free trace| grep $target_func | wc -l`
+misscnt=`grep kmem_cache_free trace| grep -v $target_func | wc -l`
 
 if [ $hitcnt -eq 0 ]; then
        exit_fail
index 7a5ff64..4761b76 100644 (file)
@@ -116,6 +116,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
 TEST_GEN_PROGS_x86_64 += x86_64/amx_test
 TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test
 TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test
+TEST_GEN_PROGS_x86_64 += x86_64/recalc_apic_map_test
 TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
 TEST_GEN_PROGS_x86_64 += demand_paging_test
 TEST_GEN_PROGS_x86_64 += dirty_log_test
diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_test.c
new file mode 100644 (file)
index 0000000..4c416eb
--- /dev/null
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test edge cases and race conditions in kvm_recalculate_apic_map().
+ */
+
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <time.h>
+
+#include "processor.h"
+#include "test_util.h"
+#include "kvm_util.h"
+#include "apic.h"
+
+#define TIMEOUT                5       /* seconds */
+
+#define LAPIC_DISABLED 0
+#define LAPIC_X2APIC   (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)
+#define MAX_XAPIC_ID   0xff
+
+static void *race(void *arg)
+{
+       struct kvm_lapic_state lapic = {};
+       struct kvm_vcpu *vcpu = arg;
+
+       while (1) {
+               /* Trigger kvm_recalculate_apic_map(). */
+               vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic);
+               pthread_testcancel();
+       }
+
+       return NULL;
+}
+
+int main(void)
+{
+       struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
+       struct kvm_vcpu *vcpuN;
+       struct kvm_vm *vm;
+       pthread_t thread;
+       time_t t;
+       int i;
+
+       kvm_static_assert(KVM_MAX_VCPUS > MAX_XAPIC_ID);
+
+       /*
+        * Create the max number of vCPUs supported by selftests so that KVM
+        * has decent amount of work to do when recalculating the map, i.e. to
+        * make the problematic window large enough to hit.
+        */
+       vm = vm_create_with_vcpus(KVM_MAX_VCPUS, NULL, vcpus);
+
+       /*
+        * Enable x2APIC on all vCPUs so that KVM doesn't bail from the recalc
+        * due to vCPUs having aliased xAPIC IDs (truncated to 8 bits).
+        */
+       for (i = 0; i < KVM_MAX_VCPUS; i++)
+               vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC);
+
+       ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0);
+
+       vcpuN = vcpus[KVM_MAX_VCPUS - 1];
+       for (t = time(NULL) + TIMEOUT; time(NULL) < t;) {
+               vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_X2APIC);
+               vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED);
+       }
+
+       ASSERT_EQ(pthread_cancel(thread), 0);
+       ASSERT_EQ(pthread_join(thread, NULL), 0);
+
+       kvm_vm_free(vm);
+
+       return 0;
+}
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 43a7236..7b936a9 100644 (file)
@@ -9,7 +9,7 @@ TEST_PROGS := mptcp_connect.sh pm_netlink.sh mptcp_join.sh diag.sh \
 
 TEST_GEN_FILES = mptcp_connect pm_nl_ctl mptcp_sockopt mptcp_inq
 
-TEST_FILES := settings
+TEST_FILES := mptcp_lib.sh settings
 
 EXTRA_CLEAN := *.pcap
 
index 38021a0..6032f9b 100644 (file)
@@ -1,3 +1,4 @@
+CONFIG_KALLSYMS=y
 CONFIG_MPTCP=y
 CONFIG_IPV6=y
 CONFIG_MPTCP_IPV6=y
index ef628b1..fa9e09a 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 sec=$(date +%s)
 rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
 ns="ns1-$rndh"
@@ -31,6 +33,8 @@ cleanup()
        ip netns del $ns
 }
 
+mptcp_lib_check_mptcp
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Could not run test without ip tool"
@@ -51,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
@@ -72,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()
@@ -115,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"
@@ -163,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))
 
@@ -177,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 a43d3e2..773dd77 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 time_start=$(date +%s)
 
 optstring="S:R:d:e:l:r:h4cm:f:tC"
@@ -141,6 +143,9 @@ cleanup()
        done
 }
 
+mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Could not run test without ip tool"
@@ -691,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 {
@@ -763,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
@@ -783,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 26310c1..0ae8caf 100755 (executable)
@@ -10,6 +10,8 @@
 # because it's invoked by variable name, see how the "tests" array is used
 #shellcheck disable=SC2317
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 ret=0
 sin=""
 sinfail=""
@@ -17,11 +19,14 @@ sout=""
 cin=""
 cinfail=""
 cinsent=""
+tmpfile=""
 cout=""
 capout=""
 ns1=""
 ns2=""
 ksft_skip=4
+iptables="iptables"
+ip6tables="ip6tables"
 timeout_poll=30
 timeout_test=$((timeout_poll * 2 + 1))
 capture=0
@@ -79,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
@@ -136,12 +141,19 @@ 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
@@ -175,10 +187,37 @@ cleanup()
 {
        rm -f "$cin" "$cout" "$sinfail"
        rm -f "$sin" "$sout" "$cinsent" "$cinfail"
+       rm -f "$tmpfile"
        rm -rf $evts_ns1 $evts_ns2
        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
@@ -222,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()
 {
@@ -241,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
@@ -295,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 \
@@ -320,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()
@@ -343,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
@@ -383,9 +470,16 @@ check_transfer()
                        fail_test
                        return 1
                fi
-               bytes="--bytes=${bytes}"
+
+               # note: BusyBox's "cmp" command doesn't support --bytes
+               tmpfile=$(mktemp)
+               head --bytes="$bytes" "$in" > "$tmpfile"
+               mv "$tmpfile" "$in"
+               head --bytes="$bytes" "$out" > "$tmpfile"
+               mv "$tmpfile" "$out"
+               tmpfile=""
        fi
-       cmp -l "$in" "$out" ${bytes} | while read -r i a b; do
+       cmp -l "$in" "$out" | while read -r i a b; do
                local sum=$((0${a} + 0${b}))
                if [ $check_invert -eq 0 ] || [ $sum -ne $((0xff)) ]; then
                        echo "[ FAIL ] $what does not match (in, out):"
@@ -454,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
@@ -481,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
@@ -685,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"
@@ -849,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))
@@ -915,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
@@ -1135,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
@@ -1149,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
@@ -1196,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
@@ -1211,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
@@ -1248,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
@@ -1260,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
@@ -1294,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
@@ -1305,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
@@ -1328,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
@@ -1339,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
@@ -1373,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
@@ -1385,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
@@ -1403,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
@@ -1437,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], " \
@@ -1478,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
@@ -1492,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
@@ -1504,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
@@ -1515,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
@@ -1528,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
@@ -1541,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
@@ -1554,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
@@ -1567,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
@@ -1614,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
@@ -1625,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
@@ -1668,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
@@ -1679,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
@@ -1797,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))
@@ -1890,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
@@ -1914,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
@@ -2018,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
 }
 
@@ -2263,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
@@ -2501,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
@@ -2510,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
@@ -2519,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
@@ -2530,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
@@ -2543,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
@@ -2553,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
@@ -2564,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
@@ -2574,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
@@ -2589,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
@@ -2622,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()
@@ -2959,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
@@ -2969,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
@@ -2979,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
@@ -2990,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
@@ -3003,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
@@ -3048,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
@@ -3059,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
@@ -3070,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
@@ -3080,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
@@ -3090,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
@@ -3101,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
@@ -3113,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
@@ -3124,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
@@ -3157,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
diff --git a/tools/testing/selftests/net/mptcp/mptcp_lib.sh b/tools/testing/selftests/net/mptcp/mptcp_lib.sh
new file mode 100644 (file)
index 0000000..f32045b
--- /dev/null
@@ -0,0 +1,104 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+readonly KSFT_FAIL=1
+readonly KSFT_SKIP=4
+
+# SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES env var can be set when validating all
+# features using the last version of the kernel and the selftests to make sure
+# a test is not being skipped by mistake.
+mptcp_lib_expect_all_features() {
+       [ "${SELFTESTS_MPTCP_LIB_EXPECT_ALL_FEATURES:-}" = "1" ]
+}
+
+# $1: msg
+mptcp_lib_fail_if_expected_feature() {
+       if mptcp_lib_expect_all_features; then
+               echo "ERROR: missing feature: ${*}"
+               exit ${KSFT_FAIL}
+       fi
+
+       return 1
+}
+
+# $1: file
+mptcp_lib_has_file() {
+       local f="${1}"
+
+       if [ -f "${f}" ]; then
+               return 0
+       fi
+
+       mptcp_lib_fail_if_expected_feature "${f} file not found"
+}
+
+mptcp_lib_check_mptcp() {
+       if ! mptcp_lib_has_file "/proc/sys/net/mptcp/enabled"; then
+               echo "SKIP: MPTCP support is not available"
+               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 1b70c0a..f295a37 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 ret=0
 sin=""
 sout=""
@@ -84,6 +86,9 @@ cleanup()
        rm -f "$sin" "$sout"
 }
 
+mptcp_lib_check_mptcp
+mptcp_lib_check_kallsyms
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Could not run test without ip tool"
@@ -182,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=$!
 
@@ -192,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=$!
@@ -249,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=$?
 
@@ -303,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 89839d1..d02e0d6 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 ksft_skip=4
 ret=0
 
@@ -34,6 +36,8 @@ cleanup()
        ip netns del $ns1
 }
 
+mptcp_lib_check_mptcp
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Could not run test without ip tool"
@@ -69,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
@@ -117,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
@@ -172,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 9f22f7e..36a3c9d 100755 (executable)
@@ -1,6 +1,8 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(dirname "${0}")/mptcp_lib.sh"
+
 sec=$(date +%s)
 rndh=$(printf %x $sec)-$(mktemp -u XXXXXX)
 ns1="ns1-$rndh"
@@ -34,6 +36,8 @@ cleanup()
        done
 }
 
+mptcp_lib_check_mptcp
+
 ip -Version > /dev/null 2>&1
 if [ $? -ne 0 ];then
        echo "SKIP: Could not run test without ip tool"
index b1eb7bc..98d9e4d 100755 (executable)
@@ -1,10 +1,20 @@
 #!/bin/bash
 # SPDX-License-Identifier: GPL-2.0
 
+. "$(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
@@ -905,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",