Merge branch '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next...
authorJakub Kicinski <kuba@kernel.org>
Fri, 18 Aug 2023 22:22:05 +0000 (15:22 -0700)
committerJakub Kicinski <kuba@kernel.org>
Fri, 18 Aug 2023 22:22:05 +0000 (15:22 -0700)
Tony Nguyen says:

====================
virtchnl: fix fake 1-elem arrays

Alexander Lobakin says:

6.5-rc1 started spitting warning splats when composing virtchnl
messages, precisely on virtchnl_rss_key and virtchnl_lut:

[   84.167709] memcpy: detected field-spanning write (size 52) of single
field "vrk->key" at drivers/net/ethernet/intel/iavf/iavf_virtchnl.c:1095
(size 1)
[   84.169915] WARNING: CPU: 3 PID: 11 at drivers/net/ethernet/intel/
iavf/iavf_virtchnl.c:1095 iavf_set_rss_key+0x123/0x140 [iavf]
...
[   84.191982] Call Trace:
[   84.192439]  <TASK>
[   84.192900]  ? __warn+0xc9/0x1a0
[   84.193353]  ? iavf_set_rss_key+0x123/0x140 [iavf]
[   84.193818]  ? report_bug+0x12c/0x1b0
[   84.194266]  ? handle_bug+0x42/0x70
[   84.194714]  ? exc_invalid_op+0x1a/0x50
[   84.195149]  ? asm_exc_invalid_op+0x1a/0x20
[   84.195592]  ? iavf_set_rss_key+0x123/0x140 [iavf]
[   84.196033]  iavf_watchdog_task+0xb0c/0xe00 [iavf]
...
[   84.225476] memcpy: detected field-spanning write (size 64) of single
field "vrl->lut" at drivers/net/ethernet/intel/iavf/iavf_virtchnl.c:1127
(size 1)
[   84.227190] WARNING: CPU: 27 PID: 1044 at drivers/net/ethernet/intel/
iavf/iavf_virtchnl.c:1127 iavf_set_rss_lut+0x123/0x140 [iavf]
...
[   84.246601] Call Trace:
[   84.247228]  <TASK>
[   84.247840]  ? __warn+0xc9/0x1a0
[   84.248263]  ? iavf_set_rss_lut+0x123/0x140 [iavf]
[   84.248698]  ? report_bug+0x12c/0x1b0
[   84.249122]  ? handle_bug+0x42/0x70
[   84.249549]  ? exc_invalid_op+0x1a/0x50
[   84.249970]  ? asm_exc_invalid_op+0x1a/0x20
[   84.250390]  ? iavf_set_rss_lut+0x123/0x140 [iavf]
[   84.250820]  iavf_watchdog_task+0xb16/0xe00 [iavf]

Gustavo already tried to fix those back in 2021[0][1]. Unfortunately,
a VM can run a different kernel than the host, meaning that those
structures are sorta ABI.
However, it is possible to have proper flex arrays + struct_size()
calculations and still send the very same messages with the same sizes.
The common rule is:

elem[1] -> elem[]
size = struct_size() + <difference between the old and the new msg size>

The "old" size in the current code is calculated 3 different ways for
10 virtchnl structures total. Each commit addresses one of the ways
cumulatively instead of per-structure.

I was planning to send it to -net initially, but given that virtchnl was
renamed from i40evf and got some fat style cleanup commits in the past,
it's not very straightforward to even pick appropriate SHAs, not
speaking of automatic portability. I may send manual backports for
a couple of the latest supported kernels later on if anyone needs it
at all.

[0] https://lore.kernel.org/all/20210525230912.GA175802@embeddedor
[1] https://lore.kernel.org/all/20210525231851.GA176647@embeddedor

* '40GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue:
  virtchnl: fix fake 1-elem arrays for structures allocated as `nents`
  virtchnl: fix fake 1-elem arrays in structures allocated as `nents + 1`
  virtchnl: fix fake 1-elem arrays in structs allocated as `nents + 1` - 1
====================

Link: https://lore.kernel.org/r/20230816210657.1326772-1-anthony.l.nguyen@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
331 files changed:
.mailmap
Documentation/devicetree/bindings/iio/addac/adi,ad74115.yaml
Documentation/networking/nf_conntrack-sysctl.rst
MAINTAINERS
Makefile
arch/alpha/include/asm/processor.h
arch/alpha/kernel/setup.c
arch/arm64/include/asm/processor.h
arch/ia64/include/asm/processor.h
arch/mips/include/asm/mach-cavium-octeon/cpu-feature-overrides.h
arch/parisc/Kconfig.debug
arch/parisc/boot/compressed/misc.c
arch/parisc/include/asm/dma.h
arch/parisc/include/asm/ftrace.h
arch/parisc/include/asm/spinlock.h
arch/parisc/include/asm/spinlock_types.h
arch/parisc/kernel/entry.S
arch/parisc/kernel/firmware.c
arch/parisc/kernel/ftrace.c
arch/parisc/kernel/parisc_ksyms.c
arch/parisc/kernel/pci-dma.c
arch/parisc/kernel/pdt.c
arch/parisc/kernel/perf.c
arch/parisc/kernel/processor.c
arch/parisc/kernel/setup.c
arch/parisc/kernel/signal.c
arch/parisc/kernel/sys_parisc.c
arch/parisc/kernel/syscall.S
arch/parisc/kernel/unaligned.c
arch/parisc/lib/ucmpdi2.c
arch/parisc/mm/fault.c
arch/parisc/mm/init.c
arch/parisc/mm/ioremap.c
arch/powerpc/include/asm/processor.h
arch/riscv/include/asm/cacheflush.h
arch/riscv/include/asm/mmio.h
arch/riscv/include/asm/pgtable.h
arch/riscv/include/asm/vmalloc.h
arch/riscv/kernel/cpu.c
arch/riscv/kernel/elf_kexec.c
arch/riscv/kernel/smp.c
arch/riscv/mm/init.c
arch/riscv/mm/kasan_init.c
arch/sparc/include/asm/processor_64.h
arch/x86/boot/compressed/idt_64.c
arch/x86/boot/compressed/sev.c
arch/x86/entry/vdso/vma.c
arch/x86/include/asm/acpi.h
arch/x86/include/asm/linkage.h
arch/x86/include/asm/processor.h
arch/x86/include/asm/segment.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/cpu/amd.c
block/blk-core.c
block/blk-iocost.c
block/fops.c
drivers/accel/ivpu/ivpu_gem.c
drivers/accel/qaic/qaic_control.c
drivers/accel/qaic/qaic_data.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/android/binder.c
drivers/android/binder_alloc.c
drivers/android/binder_alloc.h
drivers/base/cpu.c
drivers/block/zram/zram_drv.c
drivers/char/tpm/tpm_tis.c
drivers/counter/Kconfig
drivers/cpufreq/amd-pstate.c
drivers/cpuidle/cpuidle-psci-domain.c
drivers/cpuidle/dt_idle_genpd.c
drivers/cpuidle/dt_idle_genpd.h
drivers/gpio/gpio-sim.c
drivers/gpio/gpio-ws16c48.c
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c
drivers/gpu/drm/amd/amdgpu/amdgpu_ring_mux.c
drivers/gpu/drm/amd/amdgpu/amdgpu_xcp.c
drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c
drivers/gpu/drm/amd/amdgpu/psp_v13_0.c
drivers/gpu/drm/amd/amdkfd/kfd_crat.c
drivers/gpu/drm/amd/amdkfd/kfd_device.c
drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
drivers/gpu/drm/amd/amdkfd/kfd_topology.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
drivers/gpu/drm/bridge/ite-it6505.c
drivers/gpu/drm/bridge/lontium-lt9611.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_gem_shmem_helper.c
drivers/gpu/drm/i915/display/intel_display_device.c
drivers/gpu/drm/i915/display/intel_sdvo.c
drivers/gpu/drm/i915/gt/uc/intel_guc_slpc.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
drivers/gpu/drm/nouveau/nvkm/engine/gr/tu102.c
drivers/gpu/drm/panel/panel-jdi-lt070me05000.c
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_dumb.c
drivers/gpu/drm/qxl/qxl_gem.c
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/rockchip/rockchip_drm_vop.c
drivers/hwmon/aquacomputer_d5next.c
drivers/hwmon/pmbus/bel-pfe.c
drivers/iio/adc/ad7192.c
drivers/iio/adc/ina2xx-adc.c
drivers/iio/adc/meson_saradc.c
drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c
drivers/iio/frequency/admv1013.c
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
drivers/iio/industrialio-core.c
drivers/iio/light/rohm-bu27008.c
drivers/iio/light/rohm-bu27034.c
drivers/infiniband/core/umem.c
drivers/infiniband/hw/bnxt_re/main.c
drivers/infiniband/hw/bnxt_re/qplib_res.c
drivers/infiniband/hw/hfi1/chip.c
drivers/interconnect/qcom/bcm-voter.c
drivers/interconnect/qcom/icc-rpmh.h
drivers/interconnect/qcom/sa8775p.c
drivers/interconnect/qcom/sm8450.c
drivers/interconnect/qcom/sm8550.c
drivers/misc/cardreader/rts5227.c
drivers/misc/cardreader/rts5228.c
drivers/misc/cardreader/rts5249.c
drivers/misc/cardreader/rts5260.c
drivers/misc/cardreader/rts5261.c
drivers/misc/cardreader/rtsx_pcr.c
drivers/misc/tps6594-esm.c
drivers/net/Kconfig
drivers/net/dsa/mv88e6xxx/chip.c
drivers/net/ethernet/amazon/ena/ena_netdev.c
drivers/net/ethernet/broadcom/b44.c
drivers/net/ethernet/cadence/macb_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/intel/i40e/i40e_nvm.c
drivers/net/ethernet/intel/iavf/iavf_ethtool.c
drivers/net/ethernet/intel/iavf/iavf_fdir.c
drivers/net/ethernet/intel/iavf/iavf_fdir.h
drivers/net/ethernet/intel/ice/ice_eswitch.c
drivers/net/ethernet/intel/ice/ice_main.c
drivers/net/ethernet/marvell/octeon_ep/octep_ctrl_net.c
drivers/net/ethernet/marvell/octeon_ep/octep_main.c
drivers/net/ethernet/mellanox/mlx5/core/en/xdp.h
drivers/net/ethernet/mellanox/mlx5/core/en_main.c
drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
drivers/net/ethernet/qlogic/qede/qede_main.c
drivers/net/ethernet/sfc/ef100_nic.c
drivers/net/ethernet/sfc/tc.c
drivers/net/ethernet/sfc/tc_conntrack.c
drivers/net/ethernet/ti/am65-cpsw-nuss.c
drivers/net/ethernet/ti/am65-cpsw-qos.c
drivers/net/ethernet/ti/am65-cpsw-qos.h
drivers/net/mdio/mdio-xgene.c
drivers/net/netconsole.c
drivers/net/pcs/pcs-rzn1-miic.c
drivers/net/phy/broadcom.c
drivers/net/phy/phy_device.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/nvme/host/core.c
drivers/nvme/host/ioctl.c
drivers/nvme/host/pci.c
drivers/nvme/host/rdma.c
drivers/nvme/host/tcp.c
drivers/parisc/sba_iommu.c
drivers/pci/controller/Kconfig
drivers/pci/controller/dwc/pcie-designware-host.c
drivers/pci/controller/dwc/pcie-designware.c
drivers/pci/controller/dwc/pcie-designware.h
drivers/pci/hotplug/acpiphp_glue.c
drivers/platform/x86/amd/pmf/sps.c
drivers/platform/x86/intel/speed_select_if/isst_if_common.c
drivers/platform/x86/lenovo-ymc.c
drivers/platform/x86/mlx-platform.c
drivers/platform/x86/msi-ec.c
drivers/platform/x86/serial-multi-instantiate.c
drivers/regulator/da9063-regulator.c
drivers/regulator/qcom-rpmh-regulator.c
drivers/scsi/53c700.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/qedf/qedf_main.c
drivers/scsi/qedi/qedi_main.c
drivers/scsi/raid_class.c
drivers/scsi/scsi_proc.c
drivers/scsi/snic/snic_disc.c
drivers/scsi/storvsc_drv.c
drivers/thunderbolt/tb.c
drivers/thunderbolt/tmu.c
drivers/ufs/host/ufs-renesas.c
drivers/usb/common/usb-conn-gpio.c
drivers/usb/dwc3/gadget.c
drivers/usb/gadget/udc/core.c
drivers/usb/storage/alauda.c
drivers/usb/typec/altmodes/displayport.c
drivers/usb/typec/mux/Kconfig
drivers/usb/typec/mux/nb7vpq904m.c
drivers/usb/typec/tcpm/tcpm.c
drivers/vdpa/mlx5/core/mlx5_vdpa.h
drivers/vdpa/mlx5/core/mr.c
drivers/vdpa/mlx5/net/mlx5_vnet.c
drivers/vdpa/pds/Makefile
drivers/vdpa/pds/debugfs.c
drivers/vdpa/pds/vdpa_dev.c
drivers/vdpa/pds/vdpa_dev.h
drivers/vdpa/vdpa.c
drivers/vdpa/vdpa_user/vduse_dev.c
drivers/vhost/scsi.c
drivers/virtio/virtio_mem.c
drivers/virtio/virtio_mmio.c
drivers/virtio/virtio_pci_common.c
drivers/virtio/virtio_pci_legacy.c
drivers/virtio/virtio_vdpa.c
fs/btrfs/block-group.c
fs/btrfs/block-group.h
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/inode.c
fs/btrfs/relocation.c
fs/btrfs/tree-checker.c
fs/inode.c
fs/nilfs2/inode.c
fs/nilfs2/segment.c
fs/nilfs2/the_nilfs.h
fs/proc/kcore.c
fs/smb/client/cifs_debug.c
fs/smb/client/file.c
fs/zonefs/file.c
fs/zonefs/super.c
fs/zonefs/zonefs.h
include/drm/drm_edid.h
include/linux/bio.h
include/linux/blkdev.h
include/linux/bpf.h
include/linux/prefetch.h
include/linux/virtio_net.h
include/net/inet6_hashtables.h
include/net/inet_hashtables.h
include/net/netfilter/nf_tables.h
include/net/sock.h
include/net/xfrm.h
include/uapi/linux/pkt_sched.h
io_uring/io_uring.c
io_uring/openclose.c
kernel/bpf/bpf_struct_ops.c
kernel/bpf/syscall.c
kernel/power/hibernate.c
lib/scatterlist.c
mm/compaction.c
mm/damon/core.c
mm/hugetlb.c
mm/ksm.c
mm/memory-failure.c
mm/swapfile.c
mm/zsmalloc.c
net/8021q/vlan.c
net/batman-adv/bat_iv_ogm.c
net/batman-adv/bat_v.c
net/batman-adv/gateway_common.c
net/batman-adv/gateway_common.h
net/batman-adv/hard-interface.c
net/batman-adv/main.h
net/batman-adv/netlink.c
net/batman-adv/netlink.h
net/batman-adv/routing.h
net/batman-adv/soft-interface.c
net/batman-adv/types.h
net/core/skbuff.c
net/core/sock.c
net/ipv4/ip_vti.c
net/ipv4/tcp_timer.c
net/ipv6/Kconfig
net/ipv6/ip6_vti.c
net/key/af_key.c
net/mptcp/bpf.c
net/netfilter/ipvs/ip_vs_ctl.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_tables_api.c
net/netfilter/nft_dynset.c
net/netfilter/nft_set_pipapo.c
net/openvswitch/datapath.c
net/sched/sch_netem.c
net/socket.c
net/sunrpc/svcsock.c
net/xfrm/xfrm_compat.c
net/xfrm/xfrm_input.c
net/xfrm/xfrm_interface_core.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
scripts/kallsyms.c
tools/bpf/bpftool/link.c
tools/bpf/bpftool/perf.c
tools/counter/Makefile
tools/lib/bpf/libbpf.c
tools/testing/radix-tree/regression1.c
tools/testing/selftests/bpf/DENYLIST.aarch64
tools/testing/selftests/bpf/benchs/run_bench_rename.sh
tools/testing/selftests/bpf/prog_tests/fill_link_info.c [new file with mode: 0644]
tools/testing/selftests/bpf/prog_tests/kfunc_call.c
tools/testing/selftests/bpf/prog_tests/mptcp.c
tools/testing/selftests/bpf/prog_tests/tc_links.c
tools/testing/selftests/bpf/prog_tests/tc_opts.c
tools/testing/selftests/bpf/progs/mptcpify.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_fill_link_info.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/test_tc_link.c
tools/testing/selftests/cgroup/test_kmem.c
tools/testing/selftests/mm/ksm_tests.c
tools/testing/selftests/net/forwarding/mirror_gre_changes.sh

index 5dd3181..e506625 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -538,6 +538,8 @@ Shuah Khan <shuah@kernel.org> <shuah.kh@samsung.com>
 Sibi Sankar <quic_sibis@quicinc.com> <sibis@codeaurora.org>
 Sid Manning <quic_sidneym@quicinc.com> <sidneym@codeaurora.org>
 Simon Arlott <simon@octiron.net> <simon@fire.lp0.eu>
+Simon Horman <horms@kernel.org> <simon.horman@corigine.com>
+Simon Horman <horms@kernel.org> <simon.horman@netronome.com>
 Simon Kelley <simon@thekelleys.org.uk>
 Sricharan Ramabadhran <quic_srichara@quicinc.com> <sricharan@codeaurora.org>
 Srinivas Ramana <quic_sramana@quicinc.com> <sramana@codeaurora.org>
index 72d2e91..2594fa1 100644 (file)
@@ -216,7 +216,6 @@ properties:
     description: Whether to enable burnout current for EXT1.
 
   adi,ext1-burnout-current-nanoamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description:
       Burnout current in nanoamps to be applied to EXT1.
     enum: [0, 50, 500, 1000, 10000]
@@ -233,7 +232,6 @@ properties:
     description: Whether to enable burnout current for EXT2.
 
   adi,ext2-burnout-current-nanoamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: Burnout current in nanoamps to be applied to EXT2.
     enum: [0, 50, 500, 1000, 10000]
     default: 0
@@ -249,7 +247,6 @@ properties:
     description: Whether to enable burnout current for VIOUT.
 
   adi,viout-burnout-current-nanoamp:
-    $ref: /schemas/types.yaml#/definitions/uint32
     description: Burnout current in nanoamps to be applied to VIOUT.
     enum: [0, 1000, 10000]
     default: 0
index 8b1045c..c383a39 100644 (file)
@@ -178,10 +178,10 @@ nf_conntrack_sctp_timeout_established - INTEGER (seconds)
        Default is set to (hb_interval * path_max_retrans + rto_max)
 
 nf_conntrack_sctp_timeout_shutdown_sent - INTEGER (seconds)
-       default 0.3
+       default 3
 
 nf_conntrack_sctp_timeout_shutdown_recd - INTEGER (seconds)
-       default 0.3
+       default 3
 
 nf_conntrack_sctp_timeout_shutdown_ack_sent - INTEGER (seconds)
        default 3
index f150561..9cc15c5 100644 (file)
@@ -9394,7 +9394,6 @@ F:        drivers/crypto/hisilicon/sgl.c
 F:     include/linux/hisi_acc_qm.h
 
 HISILICON ROCE DRIVER
-M:     Haoyue Xu <xuhaoyue1@hisilicon.com>
 M:     Junxian Huang <huangjunxian6@hisilicon.com>
 L:     linux-rdma@vger.kernel.org
 S:     Maintained
@@ -12499,6 +12498,7 @@ F:      net/mctp/
 
 MAPLE TREE
 M:     Liam R. Howlett <Liam.Howlett@oracle.com>
+L:     maple-tree@lists.infradead.org
 L:     linux-mm@kvack.org
 S:     Supported
 F:     Documentation/core-api/maple_tree.rst
@@ -16312,6 +16312,7 @@ F:      drivers/pci/controller/dwc/pci-exynos.c
 PCI DRIVER FOR SYNOPSYS DESIGNWARE
 M:     Jingoo Han <jingoohan1@gmail.com>
 M:     Gustavo Pimentel <gustavo.pimentel@synopsys.com>
+M:     Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:     linux-pci@vger.kernel.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
@@ -22499,7 +22500,6 @@ L:      virtualization@lists.linux-foundation.org
 S:     Maintained
 F:     drivers/block/virtio_blk.c
 F:     drivers/scsi/virtio_scsi.c
-F:     drivers/vhost/scsi.c
 F:     include/uapi/linux/virtio_blk.h
 F:     include/uapi/linux/virtio_scsi.h
 
@@ -22598,6 +22598,16 @@ F:     include/linux/vhost_iotlb.h
 F:     include/uapi/linux/vhost.h
 F:     kernel/vhost_task.c
 
+VIRTIO HOST (VHOST-SCSI)
+M:     "Michael S. Tsirkin" <mst@redhat.com>
+M:     Jason Wang <jasowang@redhat.com>
+M:     Mike Christie <michael.christie@oracle.com>
+R:     Paolo Bonzini <pbonzini@redhat.com>
+R:     Stefan Hajnoczi <stefanha@redhat.com>
+L:     virtualization@lists.linux-foundation.org
+S:     Maintained
+F:     drivers/vhost/scsi.c
+
 VIRTIO I2C DRIVER
 M:     Conghui Chen <conghui.chen@intel.com>
 M:     Viresh Kumar <viresh.kumar@linaro.org>
index 6bbf9db..00cfb37 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
 VERSION = 6
 PATCHLEVEL = 5
 SUBLEVEL = 0
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc6
 NAME = Hurr durr I'ma ninja sloth
 
 # *DOCUMENTATION*
index 714abe4..55bb1c0 100644 (file)
@@ -47,12 +47,6 @@ unsigned long __get_wchan(struct task_struct *p);
 
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
-
-#ifndef CONFIG_SMP
-/* Nothing to prefetch. */
-#define spin_lock_prefetch(lock)       do { } while (0)
-#endif
 
 extern inline void prefetch(const void *ptr)  
 { 
@@ -64,11 +58,4 @@ extern inline void prefetchw(const void *ptr)
        __builtin_prefetch(ptr, 1, 3);
 }
 
-#ifdef CONFIG_SMP
-extern inline void spin_lock_prefetch(const void *ptr)  
-{
-       __builtin_prefetch(ptr, 1, 3);
-}
-#endif
-
 #endif /* __ASM_ALPHA_PROCESSOR_H */
index b650ff1..3d74735 100644 (file)
@@ -385,8 +385,7 @@ setup_memory(void *kernel_end)
 #endif /* CONFIG_BLK_DEV_INITRD */
 }
 
-int __init
-page_is_ram(unsigned long pfn)
+int page_is_ram(unsigned long pfn)
 {
        struct memclust_struct * cluster;
        struct memdesc_struct * memdesc;
index 3918f2a..e5bc545 100644 (file)
@@ -359,14 +359,6 @@ static inline void prefetchw(const void *ptr)
        asm volatile("prfm pstl1keep, %a0\n" : : "p" (ptr));
 }
 
-#define ARCH_HAS_SPINLOCK_PREFETCH
-static inline void spin_lock_prefetch(const void *ptr)
-{
-       asm volatile(ARM64_LSE_ATOMIC_INSN(
-                    "prfm pstl1strm, %a0",
-                    "nop") : : "p" (ptr));
-}
-
 extern unsigned long __ro_after_init signal_minsigstksz; /* sigframe size */
 extern void __init minsigstksz_setup(void);
 
index d1978e0..47e3801 100644 (file)
@@ -634,7 +634,6 @@ ia64_imva (void *addr)
 
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
 #define PREFETCH_STRIDE                        L1_CACHE_BYTES
 
 static inline void
@@ -649,8 +648,6 @@ prefetchw (const void *x)
        ia64_lfetch_excl(ia64_lfhint_none, x);
 }
 
-#define spin_lock_prefetch(x)  prefetchw(x)
-
 extern unsigned long boot_option_idle_override;
 
 enum idle_boot_override {IDLE_NO_OVERRIDE=0, IDLE_HALT, IDLE_FORCE_MWAIT,
index 9151dcd..af9cea2 100644 (file)
@@ -58,8 +58,6 @@
 
 #define cpu_has_rixi           (cpu_data[0].cputype != CPU_CAVIUM_OCTEON)
 
-#define ARCH_HAS_SPINLOCK_PREFETCH 1
-#define spin_lock_prefetch(x) prefetch(x)
 #define PREFETCH_STRIDE 128
 
 #ifdef __OCTEON__
index 1401e4c..bf2b21b 100644 (file)
@@ -2,7 +2,7 @@
 #
 config LIGHTWEIGHT_SPINLOCK_CHECK
        bool "Enable lightweight spinlock checks"
-       depends on SMP && !DEBUG_SPINLOCK
+       depends on DEBUG_KERNEL && SMP && !DEBUG_SPINLOCK
        default y
        help
          Add checks with low performance impact to the spinlock functions
index 7ee49f5..d389359 100644 (file)
@@ -117,7 +117,7 @@ char *strchr(const char *s, int c)
        return NULL;
 }
 
-int puts(const char *s)
+static int puts(const char *s)
 {
        const char *nuline = s;
 
@@ -172,7 +172,7 @@ static int print_num(unsigned long num, int base)
        return 0;
 }
 
-int printf(const char *fmt, ...)
+static int printf(const char *fmt, ...)
 {
        va_list args;
        int i = 0;
@@ -204,13 +204,13 @@ void abort(void)
 }
 
 #undef malloc
-void *malloc(size_t size)
+static void *malloc(size_t size)
 {
        return malloc_gzip(size);
 }
 
 #undef free
-void free(void *ptr)
+static void free(void *ptr)
 {
        return free_gzip(ptr);
 }
@@ -278,7 +278,7 @@ static void parse_elf(void *output)
        free(phdrs);
 }
 
-unsigned long decompress_kernel(unsigned int started_wide,
+asmlinkage unsigned long __visible decompress_kernel(unsigned int started_wide,
                unsigned int command_line,
                const unsigned int rd_start,
                const unsigned int rd_end)
index 9e8c101..582fb5d 100644 (file)
@@ -14,6 +14,8 @@
 #define dma_outb       outb
 #define dma_inb                inb
 
+extern unsigned long pcxl_dma_start;
+
 /*
 ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
 ** (or rather not merge) DMAs into manageable chunks.
index a7cf0d0..f1cc1ee 100644 (file)
@@ -12,6 +12,10 @@ extern void mcount(void);
 extern unsigned long sys_call_table[];
 
 extern unsigned long return_address(unsigned int);
+struct ftrace_regs;
+extern void ftrace_function_trampoline(unsigned long parent,
+               unsigned long self_addr, unsigned long org_sp_gr3,
+               struct ftrace_regs *fregs);
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 extern void ftrace_caller(void);
index edfcb98..0b326e5 100644 (file)
@@ -7,8 +7,6 @@
 #include <asm/processor.h>
 #include <asm/spinlock_types.h>
 
-#define SPINLOCK_BREAK_INSN    0x0000c006      /* break 6,6 */
-
 static inline void arch_spin_val_check(int lock_val)
 {
        if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK))
index d659340..efd06a8 100644 (file)
@@ -4,6 +4,10 @@
 
 #define __ARCH_SPIN_LOCK_UNLOCKED_VAL  0x1a46
 
+#define SPINLOCK_BREAK_INSN    0x0000c006      /* break 6,6 */
+
+#ifndef __ASSEMBLY__
+
 typedef struct {
 #ifdef CONFIG_PA20
        volatile unsigned int slock;
@@ -27,6 +31,8 @@ typedef struct {
        volatile unsigned int   counter;
 } arch_rwlock_t;
 
+#endif /* __ASSEMBLY__ */
+
 #define __ARCH_RW_LOCK_UNLOCKED__       0x01000000
 #define __ARCH_RW_LOCK_UNLOCKED         { .lock_mutex = __ARCH_SPIN_LOCK_UNLOCKED, \
                                        .counter = __ARCH_RW_LOCK_UNLOCKED__ }
index 0e5ebfe..ae03b86 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/traps.h>
 #include <asm/thread_info.h>
 #include <asm/alternative.h>
+#include <asm/spinlock_types.h>
 
 #include <linux/linkage.h>
 #include <linux/pgtable.h>
        LDREG           0(\ptp),\pte
        bb,<,n          \pte,_PAGE_PRESENT_BIT,3f
        b               \fault
-       stw             \spc,0(\tmp)
+       stw             \tmp1,0(\tmp)
 99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
 2:     LDREG           0(\ptp),\pte
        .endm
 
        /* Release page_table_lock without reloading lock address.
-          Note that the values in the register spc are limited to
-          NR_SPACE_IDS (262144). Thus, the stw instruction always
-          stores a nonzero value even when register spc is 64 bits.
           We use an ordered store to ensure all prior accesses are
           performed prior to releasing the lock. */
-       .macro          ptl_unlock0     spc,tmp
+       .macro          ptl_unlock0     spc,tmp,tmp2
 #ifdef CONFIG_TLB_PTLOCK
-98:    or,COND(=)      %r0,\spc,%r0
-       stw,ma          \spc,0(\tmp)
+98:    ldi             __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmp2
+       or,COND(=)      %r0,\spc,%r0
+       stw,ma          \tmp2,0(\tmp)
 99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        .endm
 
        /* Release page_table_lock. */
-       .macro          ptl_unlock1     spc,tmp
+       .macro          ptl_unlock1     spc,tmp,tmp2
 #ifdef CONFIG_TLB_PTLOCK
 98:    get_ptl         \tmp
-       ptl_unlock0     \spc,\tmp
+       ptl_unlock0     \spc,\tmp,\tmp2
 99:    ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
 #endif
        .endm
@@ -1125,7 +1124,7 @@ dtlb_miss_20w:
        
        idtlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1151,7 +1150,7 @@ nadtlb_miss_20w:
 
        idtlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1185,7 +1184,7 @@ dtlb_miss_11:
 
        mtsp            t1, %sr1        /* Restore sr1 */
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1218,7 +1217,7 @@ nadtlb_miss_11:
 
        mtsp            t1, %sr1        /* Restore sr1 */
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1247,7 +1246,7 @@ dtlb_miss_20:
 
        idtlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1275,7 +1274,7 @@ nadtlb_miss_20:
        
        idtlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1320,7 +1319,7 @@ itlb_miss_20w:
        
        iitlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1344,7 +1343,7 @@ naitlb_miss_20w:
 
        iitlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1378,7 +1377,7 @@ itlb_miss_11:
 
        mtsp            t1, %sr1        /* Restore sr1 */
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1402,7 +1401,7 @@ naitlb_miss_11:
 
        mtsp            t1, %sr1        /* Restore sr1 */
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1432,7 +1431,7 @@ itlb_miss_20:
 
        iitlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1452,7 +1451,7 @@ naitlb_miss_20:
 
        iitlbt          pte,prot
 
-       ptl_unlock1     spc,t0
+       ptl_unlock1     spc,t0,t1
        rfir
        nop
 
@@ -1482,7 +1481,7 @@ dbit_trap_20w:
                
        idtlbt          pte,prot
 
-       ptl_unlock0     spc,t0
+       ptl_unlock0     spc,t0,t1
        rfir
        nop
 #else
@@ -1508,7 +1507,7 @@ dbit_trap_11:
 
        mtsp            t1, %sr1     /* Restore sr1 */
 
-       ptl_unlock0     spc,t0
+       ptl_unlock0     spc,t0,t1
        rfir
        nop
 
@@ -1528,7 +1527,7 @@ dbit_trap_20:
        
        idtlbt          pte,prot
 
-       ptl_unlock0     spc,t0
+       ptl_unlock0     spc,t0,t1
        rfir
        nop
 #endif
index 6d1c781..8f37e75 100644 (file)
@@ -74,8 +74,8 @@
 static DEFINE_SPINLOCK(pdc_lock);
 #endif
 
-unsigned long pdc_result[NUM_PDC_RESULT]  __aligned(8);
-unsigned long pdc_result2[NUM_PDC_RESULT] __aligned(8);
+static unsigned long pdc_result[NUM_PDC_RESULT]  __aligned(8);
+static unsigned long pdc_result2[NUM_PDC_RESULT] __aligned(8);
 
 #ifdef CONFIG_64BIT
 #define WIDE_FIRMWARE 0x1
@@ -334,7 +334,7 @@ int __pdc_cpu_rendezvous(void)
 /**
  * pdc_cpu_rendezvous_lock - Lock PDC while transitioning to rendezvous state
  */
-void pdc_cpu_rendezvous_lock(void)
+void pdc_cpu_rendezvous_lock(void) __acquires(&pdc_lock)
 {
        spin_lock(&pdc_lock);
 }
@@ -342,7 +342,7 @@ void pdc_cpu_rendezvous_lock(void)
 /**
  * pdc_cpu_rendezvous_unlock - Unlock PDC after reaching rendezvous state
  */
-void pdc_cpu_rendezvous_unlock(void)
+void pdc_cpu_rendezvous_unlock(void) __releases(&pdc_lock)
 {
        spin_unlock(&pdc_lock);
 }
index 4d392e4..d1defb9 100644 (file)
@@ -53,7 +53,7 @@ static void __hot prepare_ftrace_return(unsigned long *parent,
 
 static ftrace_func_t ftrace_func;
 
-void notrace __hot ftrace_function_trampoline(unsigned long parent,
+asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent,
                                unsigned long self_addr,
                                unsigned long org_sp_gr3,
                                struct ftrace_regs *fregs)
index 00297e8..6f0c92e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/syscalls.h>
+#include <linux/libgcc.h>
 
 #include <linux/string.h>
 EXPORT_SYMBOL(memset);
@@ -92,12 +93,6 @@ EXPORT_SYMBOL($$divI_12);
 EXPORT_SYMBOL($$divI_14);
 EXPORT_SYMBOL($$divI_15);
 
-extern void __ashrdi3(void);
-extern void __ashldi3(void);
-extern void __lshrdi3(void);
-extern void __muldi3(void);
-extern void __ucmpdi2(void);
-
 EXPORT_SYMBOL(__ashrdi3);
 EXPORT_SYMBOL(__ashldi3);
 EXPORT_SYMBOL(__lshrdi3);
index 3f6b507..bf9f192 100644 (file)
@@ -39,7 +39,7 @@ static struct proc_dir_entry * proc_gsc_root __read_mostly = NULL;
 static unsigned long pcxl_used_bytes __read_mostly;
 static unsigned long pcxl_used_pages __read_mostly;
 
-extern unsigned long pcxl_dma_start; /* Start of pcxl dma mapping area */
+unsigned long pcxl_dma_start __ro_after_init; /* pcxl dma mapping area start */
 static DEFINE_SPINLOCK(pcxl_res_lock);
 static char    *pcxl_res_map;
 static int     pcxl_res_hint;
@@ -381,7 +381,7 @@ pcxl_dma_init(void)
        pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL,
                                            get_order(pcxl_res_size));
        memset(pcxl_res_map, 0, pcxl_res_size);
-       proc_gsc_root = proc_mkdir("gsc", NULL);
+       proc_gsc_root = proc_mkdir("bus/gsc", NULL);
        if (!proc_gsc_root)
                printk(KERN_WARNING
                        "pcxl_dma_init: Unable to create gsc /proc dir entry\n");
index 0d24735..0f9b3b5 100644 (file)
@@ -354,10 +354,8 @@ static int __init pdt_initcall(void)
                return -ENODEV;
 
        kpdtd_task = kthread_run(pdt_mainloop, NULL, "kpdtd");
-       if (IS_ERR(kpdtd_task))
-               return PTR_ERR(kpdtd_task);
 
-       return 0;
+       return PTR_ERR_OR_ZERO(kpdtd_task);
 }
 
 late_initcall(pdt_initcall);
index 90b04d8..b0f0816 100644 (file)
@@ -57,7 +57,7 @@ struct rdr_tbl_ent {
 static int perf_processor_interface __read_mostly = UNKNOWN_INTF;
 static int perf_enabled __read_mostly;
 static DEFINE_SPINLOCK(perf_lock);
-struct parisc_device *cpu_device __read_mostly;
+static struct parisc_device *cpu_device __read_mostly;
 
 /* RDRs to write for PCX-W */
 static const int perf_rdrs_W[] =
index 00b0df9..762289b 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/pdc.h>
+#include <asm/smp.h>
 #include <asm/pdcpat.h>
 #include <asm/irq.h>           /* for struct irq_region */
 #include <asm/parisc-device.h>
index 573f830..211a4af 100644 (file)
 
 static char __initdata command_line[COMMAND_LINE_SIZE];
 
-/* Intended for ccio/sba/cpu statistics under /proc/bus/{runway|gsc} */
-struct proc_dir_entry * proc_runway_root __read_mostly = NULL;
-struct proc_dir_entry * proc_gsc_root __read_mostly = NULL;
-struct proc_dir_entry * proc_mckinley_root __read_mostly = NULL;
-
 static void __init setup_cmdline(char **cmdline_p)
 {
        extern unsigned int boot_args[];
@@ -196,48 +191,6 @@ const struct seq_operations cpuinfo_op = {
        .show   = show_cpuinfo
 };
 
-static void __init parisc_proc_mkdir(void)
-{
-       /*
-       ** Can't call proc_mkdir() until after proc_root_init() has been
-       ** called by start_kernel(). In other words, this code can't
-       ** live in arch/.../setup.c because start_parisc() calls
-       ** start_kernel().
-       */
-       switch (boot_cpu_data.cpu_type) {
-       case pcxl:
-       case pcxl2:
-               if (NULL == proc_gsc_root)
-               {
-                       proc_gsc_root = proc_mkdir("bus/gsc", NULL);
-               }
-               break;
-        case pcxt_:
-        case pcxu:
-        case pcxu_:
-        case pcxw:
-        case pcxw_:
-        case pcxw2:
-                if (NULL == proc_runway_root)
-                {
-                        proc_runway_root = proc_mkdir("bus/runway", NULL);
-                }
-                break;
-       case mako:
-       case mako2:
-                if (NULL == proc_mckinley_root)
-                {
-                        proc_mckinley_root = proc_mkdir("bus/mckinley", NULL);
-                }
-                break;
-       default:
-               /* FIXME: this was added to prevent the compiler 
-                * complaining about missing pcx, pcxs and pcxt
-                * I'm assuming they have neither gsc nor runway */
-               break;
-       }
-}
-
 static struct resource central_bus = {
        .name   = "Central Bus",
        .start  = F_EXTEND(0xfff80000),
@@ -294,7 +247,6 @@ static int __init parisc_init(void)
 {
        u32 osid = (OS_ID_LINUX << 16);
 
-       parisc_proc_mkdir();
        parisc_init_resources();
        do_device_inventory();                  /* probe for hardware */
 
index f886ff0..e8d27de 100644 (file)
@@ -423,7 +423,7 @@ static void check_syscallno_in_delay_branch(struct pt_regs *regs)
        regs->gr[31] -= 8; /* delayed branching */
 
        /* Get assembler opcode of code in delay branch */
-       uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4);
+       uaddr = (u32 __user *) ((regs->gr[31] & ~3) + 4);
        err = get_user(opcode, uaddr);
        if (err)
                return;
index ca2d537..9915062 100644 (file)
 #include <linux/elf-randomize.h>
 
 /*
- * Construct an artificial page offset for the mapping based on the virtual
+ * Construct an artificial page offset for the mapping based on the physical
  * address of the kernel file mapping variable.
- * If filp is zero the calculated pgoff value aliases the memory of the given
- * address. This is useful for io_uring where the mapping shall alias a kernel
- * address and a userspace adress where both the kernel and the userspace
- * access the same memory region.
  */
-#define GET_FILP_PGOFF(filp, addr)             \
-       ((filp ? (((unsigned long) filp->f_mapping) >> 8)       \
-                & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL)        \
-         + (addr >> PAGE_SHIFT))
+#define GET_FILP_PGOFF(filp)           \
+       (filp ? (((unsigned long) filp->f_mapping) >> 8)        \
+                & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL)
 
 static unsigned long shared_align_offset(unsigned long filp_pgoff,
                                         unsigned long pgoff)
@@ -117,7 +112,7 @@ static unsigned long arch_get_unmapped_area_common(struct file *filp,
        do_color_align = 0;
        if (filp || (flags & MAP_SHARED))
                do_color_align = 1;
-       filp_pgoff = GET_FILP_PGOFF(filp, addr);
+       filp_pgoff = GET_FILP_PGOFF(filp);
 
        if (flags & MAP_FIXED) {
                /* Even MAP_FIXED mappings must reside within TASK_SIZE */
index 1373e51..1f51aa9 100644 (file)
@@ -39,6 +39,7 @@ registers).
 #include <asm/assembly.h>
 #include <asm/processor.h>
 #include <asm/cache.h>
+#include <asm/spinlock_types.h>
 
 #include <linux/linkage.h>
 
@@ -66,6 +67,16 @@ registers).
        stw     \reg1, 0(%sr2,\reg2)
        .endm
 
+       /* raise exception if spinlock content is not zero or
+        * __ARCH_SPIN_LOCK_UNLOCKED_VAL */
+       .macro  spinlock_check spin_val,tmpreg
+#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
+       ldi     __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmpreg
+       andcm,= \spin_val, \tmpreg, %r0
+       .word   SPINLOCK_BREAK_INSN
+#endif
+       .endm
+
        .text
 
        .import syscall_exit,code
@@ -508,7 +519,8 @@ lws_start:
 
 lws_exit_noerror:
        lws_pagefault_enable    %r1,%r21
-       stw,ma  %r20, 0(%sr2,%r20)
+       ldi     __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
+       stw,ma  %r21, 0(%sr2,%r20)
        ssm     PSW_SM_I, %r0
        b       lws_exit
        copy    %r0, %r21
@@ -521,7 +533,8 @@ lws_wouldblock:
 
 lws_pagefault:
        lws_pagefault_enable    %r1,%r21
-       stw,ma  %r20, 0(%sr2,%r20)
+       ldi     __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
+       stw,ma  %r21, 0(%sr2,%r20)
        ssm     PSW_SM_I, %r0
        ldo     3(%r0),%r28
        b       lws_exit
@@ -619,6 +632,7 @@ lws_compare_and_swap:
 
        /* Try to acquire the lock */
        LDCW    0(%sr2,%r20), %r28
+       spinlock_check  %r28, %r21
        comclr,<>       %r0, %r28, %r0
        b,n     lws_wouldblock
 
@@ -772,6 +786,7 @@ cas2_lock_start:
 
        /* Try to acquire the lock */
        LDCW    0(%sr2,%r20), %r28
+       spinlock_check  %r28, %r21
        comclr,<>       %r0, %r28, %r0
        b,n     lws_wouldblock
 
@@ -1001,6 +1016,7 @@ atomic_xchg_start:
 
        /* Try to acquire the lock */
        LDCW    0(%sr2,%r20), %r28
+       spinlock_check  %r28, %r21
        comclr,<>       %r0, %r28, %r0
        b,n     lws_wouldblock
 
@@ -1199,6 +1215,7 @@ atomic_store_start:
 
        /* Try to acquire the lock */
        LDCW    0(%sr2,%r20), %r28
+       spinlock_check  %r28, %r21
        comclr,<>       %r0, %r28, %r0
        b,n     lws_wouldblock
 
@@ -1330,7 +1347,7 @@ ENTRY(lws_lock_start)
        /* lws locks */
        .rept 256
        /* Keep locks aligned at 16-bytes */
-       .word 1
+       .word __ARCH_SPIN_LOCK_UNLOCKED_VAL
        .word 0 
        .word 0
        .word 0
index 8130627..170d0dd 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/signal.h>
 #include <linux/ratelimit.h>
 #include <linux/uaccess.h>
+#include <linux/sysctl.h>
 #include <asm/unaligned.h>
 #include <asm/hardirq.h>
 #include <asm/traps.h>
index 8e6014a..9d8b4db 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/module.h>
+#include <linux/libgcc.h>
 
 union ull_union {
        unsigned long long ull;
@@ -9,7 +10,7 @@ union ull_union {
        } ui;
 };
 
-int __ucmpdi2(unsigned long long a, unsigned long long b)
+word_type __ucmpdi2(unsigned long long a, unsigned long long b)
 {
        union ull_union au = {.ull = a};
        union ull_union bu = {.ull = b};
index a4c7c76..2fe5b44 100644 (file)
@@ -192,31 +192,31 @@ int fixup_exception(struct pt_regs *regs)
  * For implementation see handle_interruption() in traps.c
  */
 static const char * const trap_description[] = {
-       [1] "High-priority machine check (HPMC)",
-       [2] "Power failure interrupt",
-       [3] "Recovery counter trap",
-       [5] "Low-priority machine check",
-       [6] "Instruction TLB miss fault",
-       [7] "Instruction access rights / protection trap",
-       [8] "Illegal instruction trap",
-       [9] "Break instruction trap",
-       [10] "Privileged operation trap",
-       [11] "Privileged register trap",
-       [12] "Overflow trap",
-       [13] "Conditional trap",
-       [14] "FP Assist Exception trap",
-       [15] "Data TLB miss fault",
-       [16] "Non-access ITLB miss fault",
-       [17] "Non-access DTLB miss fault",
-       [18] "Data memory protection/unaligned access trap",
-       [19] "Data memory break trap",
-       [20] "TLB dirty bit trap",
-       [21] "Page reference trap",
-       [22] "Assist emulation trap",
-       [25] "Taken branch trap",
-       [26] "Data memory access rights trap",
-       [27] "Data memory protection ID trap",
-       [28] "Unaligned data reference trap",
+       [1] =   "High-priority machine check (HPMC)",
+       [2] =   "Power failure interrupt",
+       [3] =   "Recovery counter trap",
+       [5] =   "Low-priority machine check",
+       [6] =   "Instruction TLB miss fault",
+       [7] =   "Instruction access rights / protection trap",
+       [8] =   "Illegal instruction trap",
+       [9] =   "Break instruction trap",
+       [10] =  "Privileged operation trap",
+       [11] =  "Privileged register trap",
+       [12] =  "Overflow trap",
+       [13] =  "Conditional trap",
+       [14] =  "FP Assist Exception trap",
+       [15] =  "Data TLB miss fault",
+       [16] =  "Non-access ITLB miss fault",
+       [17] =  "Non-access DTLB miss fault",
+       [18] =  "Data memory protection/unaligned access trap",
+       [19] =  "Data memory break trap",
+       [20] =  "TLB dirty bit trap",
+       [21] =  "Page reference trap",
+       [22] =  "Assist emulation trap",
+       [25] =  "Taken branch trap",
+       [26] =  "Data memory access rights trap",
+       [27] =  "Data memory protection ID trap",
+       [28] =  "Unaligned data reference trap",
 };
 
 const char *trap_name(unsigned long code)
index 389941c..a088c24 100644 (file)
@@ -523,10 +523,6 @@ void mark_rodata_ro(void)
 void *parisc_vmalloc_start __ro_after_init;
 EXPORT_SYMBOL(parisc_vmalloc_start);
 
-#ifdef CONFIG_PA11
-unsigned long pcxl_dma_start __ro_after_init;
-#endif
-
 void __init mem_init(void)
 {
        /* Do sanity checks on IPC (compat) structures */
index 345ff0b..d7ee1f4 100644 (file)
@@ -27,7 +27,7 @@
  */
 void __iomem *ioremap(unsigned long phys_addr, unsigned long size)
 {
-       void __iomem *addr;
+       uintptr_t addr;
        struct vm_struct *area;
        unsigned long offset, last_addr;
        pgprot_t pgprot;
@@ -79,10 +79,9 @@ void __iomem *ioremap(unsigned long phys_addr, unsigned long size)
        if (!area)
                return NULL;
 
-       addr = (void __iomem *) area->addr;
-       if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
-                              phys_addr, pgprot)) {
-               vunmap(addr);
+       addr = (uintptr_t) area->addr;
+       if (ioremap_page_range(addr, addr + size, phys_addr, pgprot)) {
+               vunmap(area->addr);
                return NULL;
        }
 
index 8a6754f..a6c7069 100644 (file)
@@ -393,7 +393,6 @@ int validate_sp_size(unsigned long sp, struct task_struct *p,
  */
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
 
 static inline void prefetch(const void *x)
 {
@@ -411,8 +410,6 @@ static inline void prefetchw(const void *x)
        __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (x));
 }
 
-#define spin_lock_prefetch(x)  prefetchw(x)
-
 /* asm stubs */
 extern unsigned long isa300_idle_stop_noloss(unsigned long psscr_val);
 extern unsigned long isa300_idle_stop_mayloss(unsigned long psscr_val);
index 8091b8b..b93ffdd 100644 (file)
@@ -37,6 +37,10 @@ static inline void flush_dcache_page(struct page *page)
 #define flush_icache_user_page(vma, pg, addr, len) \
        flush_icache_mm(vma->vm_mm, 0)
 
+#ifdef CONFIG_64BIT
+#define flush_cache_vmap(start, end)   flush_tlb_kernel_range(start, end)
+#endif
+
 #ifndef CONFIG_SMP
 
 #define flush_icache_all() local_flush_icache_all()
index aff6c33..4c58ee7 100644 (file)
@@ -101,9 +101,9 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
  * Relaxed I/O memory access primitives. These follow the Device memory
  * ordering rules but do not guarantee any ordering relative to Normal memory
  * accesses.  These are defined to order the indicated access (either a read or
- * write) with all other I/O memory accesses. Since the platform specification
- * defines that all I/O regions are strongly ordered on channel 2, no explicit
- * fences are required to enforce this ordering.
+ * write) with all other I/O memory accesses to the same peripheral. Since the
+ * platform specification defines that all I/O regions are strongly ordered on
+ * channel 0, no explicit fences are required to enforce this ordering.
  */
 /* FIXME: These are now the same as asm-generic */
 #define __io_rbr()             do {} while (0)
@@ -125,14 +125,14 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
 #endif
 
 /*
- * I/O memory access primitives. Reads are ordered relative to any
- * following Normal memory access. Writes are ordered relative to any prior
- * Normal memory access.  The memory barriers here are necessary as RISC-V
+ * I/O memory access primitives.  Reads are ordered relative to any following
+ * Normal memory read and delay() loop.  Writes are ordered relative to any
+ * prior Normal memory write.  The memory barriers here are necessary as RISC-V
  * doesn't define any ordering between the memory space and the I/O space.
  */
 #define __io_br()      do {} while (0)
-#define __io_ar(v)     __asm__ __volatile__ ("fence i,r" : : : "memory")
-#define __io_bw()      __asm__ __volatile__ ("fence w,o" : : : "memory")
+#define __io_ar(v)     ({ __asm__ __volatile__ ("fence i,ir" : : : "memory"); })
+#define __io_bw()      ({ __asm__ __volatile__ ("fence w,o" : : : "memory"); })
 #define __io_aw()      mmiowb_set_pending()
 
 #define readb(c)       ({ u8  __v; __io_br(); __v = readb_cpu(c); __io_ar(__v); __v; })
index 75970ee..b5680c9 100644 (file)
@@ -188,6 +188,8 @@ extern struct pt_alloc_ops pt_ops __initdata;
 #define PAGE_KERNEL_IO         __pgprot(_PAGE_IOREMAP)
 
 extern pgd_t swapper_pg_dir[];
+extern pgd_t trampoline_pg_dir[];
+extern pgd_t early_pg_dir[];
 
 #ifdef CONFIG_TRANSPARENT_HUGEPAGE
 static inline int pmd_present(pmd_t pmd)
index 58d3e44..924d01b 100644 (file)
@@ -3,12 +3,14 @@
 
 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP
 
+extern bool pgtable_l4_enabled, pgtable_l5_enabled;
+
 #define IOREMAP_MAX_ORDER (PUD_SHIFT)
 
 #define arch_vmap_pud_supported arch_vmap_pud_supported
 static inline bool arch_vmap_pud_supported(pgprot_t prot)
 {
-       return true;
+       return pgtable_l4_enabled || pgtable_l5_enabled;
 }
 
 #define arch_vmap_pmd_supported arch_vmap_pmd_supported
index a2fc952..35b854c 100644 (file)
 #include <asm/smp.h>
 #include <asm/pgtable.h>
 
+bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
+{
+       return phys_id == cpuid_to_hartid_map(cpu);
+}
+
 /*
  * Returns the hart ID of the given device tree node, or -ENODEV if the node
  * isn't an enabled and valid RISC-V hart node.
index 5372b70..c08bb5c 100644 (file)
@@ -281,7 +281,7 @@ static void *elf_kexec_load(struct kimage *image, char *kernel_buf,
                kbuf.buffer = initrd;
                kbuf.bufsz = kbuf.memsz = initrd_len;
                kbuf.buf_align = PAGE_SIZE;
-               kbuf.top_down = false;
+               kbuf.top_down = true;
                kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
                ret = kexec_add_buffer(&kbuf);
                if (ret)
@@ -425,6 +425,7 @@ int arch_kexec_apply_relocations_add(struct purgatory_info *pi,
                 * sym, instead of searching the whole relsec.
                 */
                case R_RISCV_PCREL_HI20:
+               case R_RISCV_CALL_PLT:
                case R_RISCV_CALL:
                        *(u64 *)loc = CLEAN_IMM(UITYPE, *(u64 *)loc) |
                                 ENCODE_UJTYPE_IMM(val - addr);
index 85bbce0..40420af 100644 (file)
@@ -61,11 +61,6 @@ int riscv_hartid_to_cpuid(unsigned long hartid)
        return -ENOENT;
 }
 
-bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
-{
-       return phys_id == cpuid_to_hartid_map(cpu);
-}
-
 static void ipi_stop(void)
 {
        set_cpu_online(smp_processor_id(), false);
index 9ce5047..e4c35ac 100644 (file)
 #include <linux/kfence.h>
 
 #include <asm/fixmap.h>
-#include <asm/tlbflush.h>
-#include <asm/sections.h>
-#include <asm/soc.h>
 #include <asm/io.h>
-#include <asm/ptdump.h>
 #include <asm/numa.h>
+#include <asm/pgtable.h>
+#include <asm/ptdump.h>
+#include <asm/sections.h>
+#include <asm/soc.h>
+#include <asm/tlbflush.h>
 
 #include "../kernel/head.h"
 
@@ -214,8 +215,13 @@ static void __init setup_bootmem(void)
        memblock_reserve(vmlinux_start, vmlinux_end - vmlinux_start);
 
        phys_ram_end = memblock_end_of_DRAM();
+
+       /*
+        * Make sure we align the start of the memory on a PMD boundary so that
+        * at worst, we map the linear mapping with PMD mappings.
+        */
        if (!IS_ENABLED(CONFIG_XIP_KERNEL))
-               phys_ram_base = memblock_start_of_DRAM();
+               phys_ram_base = memblock_start_of_DRAM() & PMD_MASK;
 
        /*
         * In 64-bit, any use of __va/__pa before this point is wrong as we
index 8fc0efc..a01bc15 100644 (file)
@@ -22,7 +22,6 @@
  * region is not and then we have to go down to the PUD level.
  */
 
-extern pgd_t early_pg_dir[PTRS_PER_PGD];
 pgd_t tmp_pg_dir[PTRS_PER_PGD] __page_aligned_bss;
 p4d_t tmp_p4d[PTRS_PER_P4D] __page_aligned_bss;
 pud_t tmp_pud[PTRS_PER_PUD] __page_aligned_bss;
index 2667f35..0a0d5c3 100644 (file)
@@ -213,7 +213,6 @@ unsigned long __get_wchan(struct task_struct *task);
  */
 #define ARCH_HAS_PREFETCH
 #define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
 
 static inline void prefetch(const void *x)
 {
@@ -239,8 +238,6 @@ static inline void prefetchw(const void *x)
                             : "r" (x));
 }
 
-#define spin_lock_prefetch(x)  prefetchw(x)
-
 #define HAVE_ARCH_PICK_MMAP_LAYOUT
 
 int do_mathemu(struct pt_regs *regs, struct fpustate *f, bool illegal_insn_trap);
index 6debb81..3cdf94b 100644 (file)
@@ -63,7 +63,14 @@ void load_stage2_idt(void)
        set_idt_entry(X86_TRAP_PF, boot_page_fault);
 
 #ifdef CONFIG_AMD_MEM_ENCRYPT
-       set_idt_entry(X86_TRAP_VC, boot_stage2_vc);
+       /*
+        * Clear the second stage #VC handler in case guest types
+        * needing #VC have not been detected.
+        */
+       if (sev_status & BIT(1))
+               set_idt_entry(X86_TRAP_VC, boot_stage2_vc);
+       else
+               set_idt_entry(X86_TRAP_VC, NULL);
 #endif
 
        load_boot_idt(&boot_idt_desc);
index 09dc8c1..c3e343b 100644 (file)
@@ -405,12 +405,45 @@ void sev_enable(struct boot_params *bp)
                bp->cc_blob_address = 0;
 
        /*
+        * Do an initial SEV capability check before snp_init() which
+        * loads the CPUID page and the same checks afterwards are done
+        * without the hypervisor and are trustworthy.
+        *
+        * If the HV fakes SEV support, the guest will crash'n'burn
+        * which is good enough.
+        */
+
+       /* Check for the SME/SEV support leaf */
+       eax = 0x80000000;
+       ecx = 0;
+       native_cpuid(&eax, &ebx, &ecx, &edx);
+       if (eax < 0x8000001f)
+               return;
+
+       /*
+        * Check for the SME/SEV feature:
+        *   CPUID Fn8000_001F[EAX]
+        *   - Bit 0 - Secure Memory Encryption support
+        *   - Bit 1 - Secure Encrypted Virtualization support
+        *   CPUID Fn8000_001F[EBX]
+        *   - Bits 5:0 - Pagetable bit position used to indicate encryption
+        */
+       eax = 0x8000001f;
+       ecx = 0;
+       native_cpuid(&eax, &ebx, &ecx, &edx);
+       /* Check whether SEV is supported */
+       if (!(eax & BIT(1)))
+               return;
+
+       /*
         * Setup/preliminary detection of SNP. This will be sanity-checked
         * against CPUID/MSR values later.
         */
        snp = snp_init(bp);
 
-       /* Check for the SME/SEV support leaf */
+       /* Now repeat the checks with the SNP CPUID table. */
+
+       /* Recheck the SME/SEV support leaf */
        eax = 0x80000000;
        ecx = 0;
        native_cpuid(&eax, &ebx, &ecx, &edx);
@@ -418,7 +451,7 @@ void sev_enable(struct boot_params *bp)
                return;
 
        /*
-        * Check for the SME/SEV feature:
+        * Recheck for the SME/SEV feature:
         *   CPUID Fn8000_001F[EAX]
         *   - Bit 0 - Secure Memory Encryption support
         *   - Bit 1 - Secure Encrypted Virtualization support
index 11a5c68..7645730 100644 (file)
@@ -299,8 +299,8 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
 
        /* Round the lowest possible end address up to a PMD boundary. */
        end = (start + len + PMD_SIZE - 1) & PMD_MASK;
-       if (end >= TASK_SIZE_MAX)
-               end = TASK_SIZE_MAX;
+       if (end >= DEFAULT_MAP_WINDOW)
+               end = DEFAULT_MAP_WINDOW;
        end -= len;
 
        if (end > start) {
index 8eb74cf..2888c0e 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/mpspec.h>
 #include <asm/x86_init.h>
 #include <asm/cpufeature.h>
+#include <asm/irq_vectors.h>
 
 #ifdef CONFIG_ACPI_APEI
 # include <asm/pgtable_types.h>
@@ -31,6 +32,7 @@ extern int acpi_skip_timer_override;
 extern int acpi_use_timer_override;
 extern int acpi_fix_pin2_polarity;
 extern int acpi_disable_cmcff;
+extern bool acpi_int_src_ovr[NR_IRQS_LEGACY];
 
 extern u8 acpi_sci_flags;
 extern u32 acpi_sci_override_gsi;
index 0953aa3..97a3de7 100644 (file)
@@ -21,7 +21,7 @@
 #define FUNCTION_PADDING
 #endif
 
-#if (CONFIG_FUNCTION_ALIGNMENT > 8) && !defined(__DISABLE_EXPORTS) && !defined(BULID_VDSO)
+#if (CONFIG_FUNCTION_ALIGNMENT > 8) && !defined(__DISABLE_EXPORTS) && !defined(BUILD_VDSO)
 # define __FUNC_ALIGN          __ALIGN; FUNCTION_PADDING
 #else
 # define __FUNC_ALIGN          __ALIGN
index 4ae2773..fd75024 100644 (file)
@@ -586,7 +586,6 @@ extern char                 ignore_fpu_irq;
 
 #define HAVE_ARCH_PICK_MMAP_LAYOUT 1
 #define ARCH_HAS_PREFETCHW
-#define ARCH_HAS_SPINLOCK_PREFETCH
 
 #ifdef CONFIG_X86_32
 # define BASE_PREFETCH         ""
@@ -620,11 +619,6 @@ static __always_inline void prefetchw(const void *x)
                          "m" (*(const char *)x));
 }
 
-static inline void spin_lock_prefetch(const void *x)
-{
-       prefetchw(x);
-}
-
 #define TOP_OF_INIT_STACK ((unsigned long)&init_stack + sizeof(init_stack) - \
                           TOP_OF_KERNEL_STACK_PADDING)
 
index 794f696..9d6411c 100644 (file)
@@ -56,7 +56,7 @@
 
 #define GDT_ENTRY_INVALID_SEG  0
 
-#ifdef CONFIG_X86_32
+#if defined(CONFIG_X86_32) && !defined(BUILD_VDSO32_64)
 /*
  * The layout of the per-CPU GDT under Linux:
  *
index 21b542a..53369c5 100644 (file)
@@ -52,6 +52,7 @@ int acpi_lapic;
 int acpi_ioapic;
 int acpi_strict;
 int acpi_disable_cmcff;
+bool acpi_int_src_ovr[NR_IRQS_LEGACY];
 
 /* ACPI SCI override configuration */
 u8 acpi_sci_flags __initdata;
@@ -588,6 +589,9 @@ acpi_parse_int_src_ovr(union acpi_subtable_headers * header,
 
        acpi_table_print_madt_entry(&header->common);
 
+       if (intsrc->source_irq < NR_IRQS_LEGACY)
+               acpi_int_src_ovr[intsrc->source_irq] = true;
+
        if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
                acpi_sci_ioapic_setup(intsrc->source_irq,
                                      intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
index b55d8f8..70f9d56 100644 (file)
@@ -73,6 +73,7 @@ static const int amd_erratum_1054[] =
 static const int amd_zenbleed[] =
        AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
                           AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
+                          AMD_MODEL_RANGE(0x17, 0x90, 0x0, 0x91, 0xf),
                           AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
 
 static const int amd_div0[] =
index 90de500..9866468 100644 (file)
@@ -722,14 +722,9 @@ void submit_bio_noacct(struct bio *bio)
        struct block_device *bdev = bio->bi_bdev;
        struct request_queue *q = bdev_get_queue(bdev);
        blk_status_t status = BLK_STS_IOERR;
-       struct blk_plug *plug;
 
        might_sleep();
 
-       plug = blk_mq_plug(bio);
-       if (plug && plug->nowait)
-               bio->bi_opf |= REQ_NOWAIT;
-
        /*
         * For a REQ_NOWAIT based request, return -EOPNOTSUPP
         * if queue does not support NOWAIT.
@@ -1059,7 +1054,6 @@ void blk_start_plug_nr_ios(struct blk_plug *plug, unsigned short nr_ios)
        plug->rq_count = 0;
        plug->multiple_queues = false;
        plug->has_elevator = false;
-       plug->nowait = false;
        INIT_LIST_HEAD(&plug->cb_list);
 
        /*
index dd64e20..089fcb9 100644 (file)
@@ -3301,11 +3301,12 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
        if (qos[QOS_MIN] > qos[QOS_MAX])
                goto einval;
 
-       if (enable) {
+       if (enable && !ioc->enabled) {
                blk_stat_enable_accounting(disk->queue);
                blk_queue_flag_set(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
                ioc->enabled = true;
-       } else {
+       } else if (!enable && ioc->enabled) {
+               blk_stat_disable_accounting(disk->queue);
                blk_queue_flag_clear(QUEUE_FLAG_RQ_ALLOC_TIME, disk->queue);
                ioc->enabled = false;
        }
index a286bf3..838ffad 100644 (file)
@@ -358,13 +358,14 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
                task_io_account_write(bio->bi_iter.bi_size);
        }
 
+       if (iocb->ki_flags & IOCB_NOWAIT)
+               bio->bi_opf |= REQ_NOWAIT;
+
        if (iocb->ki_flags & IOCB_HIPRI) {
-               bio->bi_opf |= REQ_POLLED | REQ_NOWAIT;
+               bio->bi_opf |= REQ_POLLED;
                submit_bio(bio);
                WRITE_ONCE(iocb->private, bio);
        } else {
-               if (iocb->ki_flags & IOCB_NOWAIT)
-                       bio->bi_opf |= REQ_NOWAIT;
                submit_bio(bio);
        }
        return -EIOCBQUEUED;
index 52b339a..9967fcf 100644 (file)
@@ -173,6 +173,9 @@ static void internal_free_pages_locked(struct ivpu_bo *bo)
 {
        unsigned int i, npages = bo->base.size >> PAGE_SHIFT;
 
+       if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED)
+               set_pages_array_wb(bo->pages, bo->base.size >> PAGE_SHIFT);
+
        for (i = 0; i < npages; i++)
                put_page(bo->pages[i]);
 
@@ -587,6 +590,11 @@ ivpu_bo_alloc_internal(struct ivpu_device *vdev, u64 vpu_addr, u64 size, u32 fla
        if (ivpu_bo_cache_mode(bo) != DRM_IVPU_BO_CACHED)
                drm_clflush_pages(bo->pages, bo->base.size >> PAGE_SHIFT);
 
+       if (bo->flags & DRM_IVPU_BO_WC)
+               set_pages_array_wc(bo->pages, bo->base.size >> PAGE_SHIFT);
+       else if (bo->flags & DRM_IVPU_BO_UNCACHED)
+               set_pages_array_uc(bo->pages, bo->base.size >> PAGE_SHIFT);
+
        prot = ivpu_bo_pgprot(bo, PAGE_KERNEL);
        bo->kvaddr = vmap(bo->pages, bo->base.size >> PAGE_SHIFT, VM_MAP, prot);
        if (!bo->kvaddr) {
index cfbc92d..388abd4 100644 (file)
@@ -392,18 +392,31 @@ static int find_and_map_user_pages(struct qaic_device *qdev,
                                   struct qaic_manage_trans_dma_xfer *in_trans,
                                   struct ioctl_resources *resources, struct dma_xfer *xfer)
 {
+       u64 xfer_start_addr, remaining, end, total;
        unsigned long need_pages;
        struct page **page_list;
        unsigned long nr_pages;
        struct sg_table *sgt;
-       u64 xfer_start_addr;
        int ret;
        int i;
 
-       xfer_start_addr = in_trans->addr + resources->xferred_dma_size;
+       if (check_add_overflow(in_trans->addr, resources->xferred_dma_size, &xfer_start_addr))
+               return -EINVAL;
 
-       need_pages = DIV_ROUND_UP(in_trans->size + offset_in_page(xfer_start_addr) -
-                                 resources->xferred_dma_size, PAGE_SIZE);
+       if (in_trans->size < resources->xferred_dma_size)
+               return -EINVAL;
+       remaining = in_trans->size - resources->xferred_dma_size;
+       if (remaining == 0)
+               return 0;
+
+       if (check_add_overflow(xfer_start_addr, remaining, &end))
+               return -EINVAL;
+
+       total = remaining + offset_in_page(xfer_start_addr);
+       if (total >= SIZE_MAX)
+               return -EINVAL;
+
+       need_pages = DIV_ROUND_UP(total, PAGE_SIZE);
 
        nr_pages = need_pages;
 
@@ -435,7 +448,7 @@ static int find_and_map_user_pages(struct qaic_device *qdev,
 
        ret = sg_alloc_table_from_pages(sgt, page_list, nr_pages,
                                        offset_in_page(xfer_start_addr),
-                                       in_trans->size - resources->xferred_dma_size, GFP_KERNEL);
+                                       remaining, GFP_KERNEL);
        if (ret) {
                ret = -ENOMEM;
                goto free_sgt;
@@ -566,9 +579,6 @@ static int encode_dma(struct qaic_device *qdev, void *trans, struct wrapper_list
            QAIC_MANAGE_EXT_MSG_LENGTH)
                return -ENOMEM;
 
-       if (in_trans->addr + in_trans->size < in_trans->addr || !in_trans->size)
-               return -EINVAL;
-
        xfer = kmalloc(sizeof(*xfer), GFP_KERNEL);
        if (!xfer)
                return -ENOMEM;
index e9a1cb7..6b6d981 100644 (file)
@@ -1021,6 +1021,7 @@ int qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_fi
        bo->dbc = dbc;
        srcu_read_unlock(&dbc->ch_lock, rcu_id);
        drm_gem_object_put(obj);
+       kfree(slice_ent);
        srcu_read_unlock(&qdev->dev_lock, qdev_rcu_id);
        srcu_read_unlock(&usr->qddev_lock, usr_rcu_id);
 
index 1dd8d5a..a4d9f14 100644 (file)
@@ -470,6 +470,45 @@ static const struct dmi_system_id asus_laptop[] = {
        { }
 };
 
+static const struct dmi_system_id tongfang_gm_rg[] = {
+       {
+               .ident = "TongFang GMxRGxx/XMG CORE 15 (M22)/TUXEDO Stellaris 15 Gen4 AMD",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
+               },
+       },
+       { }
+};
+
+static const struct dmi_system_id maingear_laptop[] = {
+       {
+               .ident = "MAINGEAR Vector Pro 2 15",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-15A3070T"),
+               }
+       },
+       {
+               .ident = "MAINGEAR Vector Pro 2 17",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Micro Electronics Inc"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "MG-VCP2-17A3070T"),
+               },
+       },
+       { }
+};
+
+static const struct dmi_system_id pcspecialist_laptop[] = {
+       {
+               .ident = "PCSpecialist Elimina Pro 16 M",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Elimina Pro 16 M"),
+               },
+       },
+       { }
+};
+
 static const struct dmi_system_id lg_laptop[] = {
        {
                .ident = "LG Electronics 17U70P",
@@ -493,6 +532,9 @@ struct irq_override_cmp {
 static const struct irq_override_cmp override_table[] = {
        { medion_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
        { asus_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
+       { tongfang_gm_rg, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true },
+       { maingear_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true },
+       { pcspecialist_laptop, 1, ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_LOW, 1, true },
        { lg_laptop, 1, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW, 0, false },
 };
 
@@ -512,6 +554,28 @@ static bool acpi_dev_irq_override(u32 gsi, u8 triggering, u8 polarity,
                        return entry->override;
        }
 
+#ifdef CONFIG_X86
+       /*
+        * Always use the MADT override info, except for the i8042 PS/2 ctrl
+        * IRQs (1 and 12). For these the DSDT IRQ settings should sometimes
+        * be used otherwise PS/2 keyboards / mice will not work.
+        */
+       if (gsi != 1 && gsi != 12)
+               return true;
+
+       /* If the override comes from an INT_SRC_OVR MADT entry, honor it. */
+       if (acpi_int_src_ovr[gsi])
+               return true;
+
+       /*
+        * IRQ override isn't needed on modern AMD Zen systems and
+        * this override breaks active low IRQs on AMD Ryzen 6000 and
+        * newer systems. Skip it.
+        */
+       if (boot_cpu_has(X86_FEATURE_ZEN))
+               return false;
+#endif
+
        return true;
 }
 
index 5b145f1..87e3855 100644 (file)
@@ -1714,6 +1714,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
                {"BSG1160", },
                {"BSG2150", },
                {"CSC3551", },
+               {"CSC3556", },
                {"INT33FE", },
                {"INT3515", },
                /* Non-conforming _HID for Cirrus Logic already released */
index 486c827..d720f93 100644 (file)
@@ -6617,6 +6617,7 @@ err_init_binder_device_failed:
 
 err_alloc_device_names_failed:
        debugfs_remove_recursive(binder_debugfs_dir_entry_root);
+       binder_alloc_shrinker_exit();
 
        return ret;
 }
index 662a2a2..e3db829 100644 (file)
@@ -1087,6 +1087,12 @@ int binder_alloc_shrinker_init(void)
        return ret;
 }
 
+void binder_alloc_shrinker_exit(void)
+{
+       unregister_shrinker(&binder_shrinker);
+       list_lru_destroy(&binder_alloc_lru);
+}
+
 /**
  * check_buffer() - verify that buffer/offset is safe to access
  * @alloc: binder_alloc for this proc
index 138d1d5..dc1e2b0 100644 (file)
@@ -129,6 +129,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
                                                  int pid);
 extern void binder_alloc_init(struct binder_alloc *alloc);
 extern int binder_alloc_shrinker_init(void);
+extern void binder_alloc_shrinker_exit(void);
 extern void binder_alloc_vma_close(struct binder_alloc *alloc);
 extern struct binder_buffer *
 binder_alloc_prepare_to_free(struct binder_alloc *alloc,
index d7300d8..fe6690e 100644 (file)
@@ -532,7 +532,7 @@ CPU_SHOW_VULN_FALLBACK(srbds);
 CPU_SHOW_VULN_FALLBACK(mmio_stale_data);
 CPU_SHOW_VULN_FALLBACK(retbleed);
 CPU_SHOW_VULN_FALLBACK(spec_rstack_overflow);
-CPU_SHOW_VULN_FALLBACK(gather_data_sampling);
+CPU_SHOW_VULN_FALLBACK(gds);
 
 static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
 static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
@@ -546,7 +546,7 @@ static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
 static DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
 static DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
 static DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
-static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gather_data_sampling, NULL);
+static DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
 
 static struct attribute *cpu_root_vulnerabilities_attrs[] = {
        &dev_attr_meltdown.attr,
index 5676e6d..06673c6 100644 (file)
@@ -1870,15 +1870,16 @@ static void zram_bio_discard(struct zram *zram, struct bio *bio)
 
 static void zram_bio_read(struct zram *zram, struct bio *bio)
 {
-       struct bvec_iter iter;
-       struct bio_vec bv;
-       unsigned long start_time;
+       unsigned long start_time = bio_start_io_acct(bio);
+       struct bvec_iter iter = bio->bi_iter;
 
-       start_time = bio_start_io_acct(bio);
-       bio_for_each_segment(bv, bio, iter) {
+       do {
                u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT;
                u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) <<
                                SECTOR_SHIFT;
+               struct bio_vec bv = bio_iter_iovec(bio, iter);
+
+               bv.bv_len = min_t(u32, bv.bv_len, PAGE_SIZE - offset);
 
                if (zram_bvec_read(zram, &bv, index, offset, bio) < 0) {
                        atomic64_inc(&zram->stats.failed_reads);
@@ -1890,22 +1891,26 @@ static void zram_bio_read(struct zram *zram, struct bio *bio)
                zram_slot_lock(zram, index);
                zram_accessed(zram, index);
                zram_slot_unlock(zram, index);
-       }
+
+               bio_advance_iter_single(bio, &iter, bv.bv_len);
+       } while (iter.bi_size);
+
        bio_end_io_acct(bio, start_time);
        bio_endio(bio);
 }
 
 static void zram_bio_write(struct zram *zram, struct bio *bio)
 {
-       struct bvec_iter iter;
-       struct bio_vec bv;
-       unsigned long start_time;
+       unsigned long start_time = bio_start_io_acct(bio);
+       struct bvec_iter iter = bio->bi_iter;
 
-       start_time = bio_start_io_acct(bio);
-       bio_for_each_segment(bv, bio, iter) {
+       do {
                u32 index = iter.bi_sector >> SECTORS_PER_PAGE_SHIFT;
                u32 offset = (iter.bi_sector & (SECTORS_PER_PAGE - 1)) <<
                                SECTOR_SHIFT;
+               struct bio_vec bv = bio_iter_iovec(bio, iter);
+
+               bv.bv_len = min_t(u32, bv.bv_len, PAGE_SIZE - offset);
 
                if (zram_bvec_write(zram, &bv, index, offset, bio) < 0) {
                        atomic64_inc(&zram->stats.failed_writes);
@@ -1916,7 +1921,10 @@ static void zram_bio_write(struct zram *zram, struct bio *bio)
                zram_slot_lock(zram, index);
                zram_accessed(zram, index);
                zram_slot_unlock(zram, index);
-       }
+
+               bio_advance_iter_single(bio, &iter, bv.bv_len);
+       } while (iter.bi_size);
+
        bio_end_io_acct(bio, start_time);
        bio_endio(bio);
 }
index ac4daaf..7fa3d91 100644 (file)
@@ -89,7 +89,7 @@ static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr)
        tpm_tis_flush(iobase);
 }
 
-static int interrupts = -1;
+static int interrupts;
 module_param(interrupts, int, 0444);
 MODULE_PARM_DESC(interrupts, "Enable interrupts");
 
@@ -183,7 +183,7 @@ static const struct dmi_system_id tpm_tis_dmi_table[] = {
                .ident = "UPX-TGL",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
-                       DMI_MATCH(DMI_PRODUCT_VERSION, "UPX-TGL"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "UPX-TGL01"),
                },
        },
        {}
index bca21df..62962ae 100644 (file)
@@ -3,13 +3,6 @@
 # Counter devices
 #
 
-menuconfig COUNTER
-       tristate "Counter support"
-       help
-         This enables counter device support through the Generic Counter
-         interface. You only need to enable this, if you also want to enable
-         one or more of the counter device drivers below.
-
 config I8254
        tristate
        select COUNTER
@@ -25,6 +18,13 @@ config I8254
 
          If built as a module its name will be i8254.
 
+menuconfig COUNTER
+       tristate "Counter support"
+       help
+         This enables counter device support through the Generic Counter
+         interface. You only need to enable this, if you also want to enable
+         one or more of the counter device drivers below.
+
 if COUNTER
 
 config 104_QUAD_8
index 81fba0d..9a1e194 100644 (file)
@@ -1012,8 +1012,8 @@ static int amd_pstate_update_status(const char *buf, size_t size)
        return 0;
 }
 
-static ssize_t show_status(struct kobject *kobj,
-                          struct kobj_attribute *attr, char *buf)
+static ssize_t status_show(struct device *dev,
+                          struct device_attribute *attr, char *buf)
 {
        ssize_t ret;
 
@@ -1024,7 +1024,7 @@ static ssize_t show_status(struct kobject *kobj,
        return ret;
 }
 
-static ssize_t store_status(struct kobject *a, struct kobj_attribute *b,
+static ssize_t status_store(struct device *a, struct device_attribute *b,
                            const char *buf, size_t count)
 {
        char *p = memchr(buf, '\n', count);
@@ -1043,7 +1043,7 @@ cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
 cpufreq_freq_attr_ro(amd_pstate_highest_perf);
 cpufreq_freq_attr_rw(energy_performance_preference);
 cpufreq_freq_attr_ro(energy_performance_available_preferences);
-define_one_global_rw(status);
+static DEVICE_ATTR_RW(status);
 
 static struct freq_attr *amd_pstate_attr[] = {
        &amd_pstate_max_freq,
@@ -1062,7 +1062,7 @@ static struct freq_attr *amd_pstate_epp_attr[] = {
 };
 
 static struct attribute *pstate_global_attributes[] = {
-       &status.attr,
+       &dev_attr_status.attr,
        NULL
 };
 
index c2d6d9c..b88af12 100644 (file)
@@ -120,20 +120,6 @@ static void psci_pd_remove(void)
        }
 }
 
-static bool psci_pd_try_set_osi_mode(void)
-{
-       int ret;
-
-       if (!psci_has_osi_support())
-               return false;
-
-       ret = psci_set_osi_mode(true);
-       if (ret)
-               return false;
-
-       return true;
-}
-
 static void psci_cpuidle_domain_sync_state(struct device *dev)
 {
        /*
@@ -152,15 +138,12 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
 {
        struct device_node *np = pdev->dev.of_node;
        struct device_node *node;
-       bool use_osi;
+       bool use_osi = psci_has_osi_support();
        int ret = 0, pd_count = 0;
 
        if (!np)
                return -ENODEV;
 
-       /* If OSI mode is supported, let's try to enable it. */
-       use_osi = psci_pd_try_set_osi_mode();
-
        /*
         * Parse child nodes for the "#power-domain-cells" property and
         * initialize a genpd/genpd-of-provider pair when it's found.
@@ -170,33 +153,37 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
                        continue;
 
                ret = psci_pd_init(node, use_osi);
-               if (ret)
-                       goto put_node;
+               if (ret) {
+                       of_node_put(node);
+                       goto exit;
+               }
 
                pd_count++;
        }
 
        /* Bail out if not using the hierarchical CPU topology. */
        if (!pd_count)
-               goto no_pd;
+               return 0;
 
        /* Link genpd masters/subdomains to model the CPU topology. */
        ret = dt_idle_pd_init_topology(np);
        if (ret)
                goto remove_pd;
 
+       /* let's try to enable OSI. */
+       ret = psci_set_osi_mode(use_osi);
+       if (ret)
+               goto remove_pd;
+
        pr_info("Initialized CPU PM domain topology using %s mode\n",
                use_osi ? "OSI" : "PC");
        return 0;
 
-put_node:
-       of_node_put(node);
 remove_pd:
+       dt_idle_pd_remove_topology(np);
        psci_pd_remove();
+exit:
        pr_err("failed to create CPU PM domains ret=%d\n", ret);
-no_pd:
-       if (use_osi)
-               psci_set_osi_mode(false);
        return ret;
 }
 
index b371655..1af63c1 100644 (file)
@@ -152,6 +152,30 @@ int dt_idle_pd_init_topology(struct device_node *np)
        return 0;
 }
 
+int dt_idle_pd_remove_topology(struct device_node *np)
+{
+       struct device_node *node;
+       struct of_phandle_args child, parent;
+       int ret;
+
+       for_each_child_of_node(np, node) {
+               if (of_parse_phandle_with_args(node, "power-domains",
+                                       "#power-domain-cells", 0, &parent))
+                       continue;
+
+               child.np = node;
+               child.args_count = 0;
+               ret = of_genpd_remove_subdomain(&parent, &child);
+               of_node_put(parent.np);
+               if (ret) {
+                       of_node_put(node);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 struct device *dt_idle_attach_cpu(int cpu, const char *name)
 {
        struct device *dev;
index a95483d..3be1f70 100644 (file)
@@ -14,6 +14,8 @@ struct generic_pm_domain *dt_idle_pd_alloc(struct device_node *np,
 
 int dt_idle_pd_init_topology(struct device_node *np);
 
+int dt_idle_pd_remove_topology(struct device_node *np);
+
 struct device *dt_idle_attach_cpu(int cpu, const char *name);
 
 void dt_idle_detach_cpu(struct device *dev);
@@ -36,6 +38,11 @@ static inline int dt_idle_pd_init_topology(struct device_node *np)
        return 0;
 }
 
+static inline int dt_idle_pd_remove_topology(struct device_node *np)
+{
+       return 0;
+}
+
 static inline struct device *dt_idle_attach_cpu(int cpu, const char *name)
 {
        return NULL;
index 8b49b0a..f1f6f1c 100644 (file)
@@ -429,6 +429,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
        gc->set_config = gpio_sim_set_config;
        gc->to_irq = gpio_sim_to_irq;
        gc->free = gpio_sim_free;
+       gc->can_sleep = true;
 
        ret = devm_gpiochip_add_data(dev, gc, chip);
        if (ret)
index e73885a..afb42a8 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
-#define WS16C48_EXTENT 10
+#define WS16C48_EXTENT 11
 #define MAX_NUM_WS16C48 max_num_isa_dev(WS16C48_EXTENT)
 
 static unsigned int base[MAX_NUM_WS16C48];
index a3b86b8..6dc950c 100644 (file)
@@ -1296,6 +1296,7 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev,
 void amdgpu_device_pci_config_reset(struct amdgpu_device *adev);
 int amdgpu_device_pci_reset(struct amdgpu_device *adev);
 bool amdgpu_device_need_post(struct amdgpu_device *adev);
+bool amdgpu_sg_display_supported(struct amdgpu_device *adev);
 bool amdgpu_device_pcie_dynamic_switching_supported(void);
 bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev);
 bool amdgpu_device_aspm_support_quirk(void);
index 040f4cb..fb78a8f 100644 (file)
@@ -295,7 +295,7 @@ static int amdgpu_cs_pass1(struct amdgpu_cs_parser *p,
 
        if (!p->gang_size) {
                ret = -EINVAL;
-               goto free_partial_kdata;
+               goto free_all_kdata;
        }
 
        for (i = 0; i < p->gang_size; ++i) {
index a2cdde0..6238701 100644 (file)
@@ -1459,6 +1459,32 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev)
 }
 
 /*
+ * On APUs with >= 64GB white flickering has been observed w/ SG enabled.
+ * Disable S/G on such systems until we have a proper fix.
+ * https://gitlab.freedesktop.org/drm/amd/-/issues/2354
+ * https://gitlab.freedesktop.org/drm/amd/-/issues/2735
+ */
+bool amdgpu_sg_display_supported(struct amdgpu_device *adev)
+{
+       switch (amdgpu_sg_display) {
+       case -1:
+               break;
+       case 0:
+               return false;
+       case 1:
+               return true;
+       default:
+               return false;
+       }
+       if ((totalram_pages() << (PAGE_SHIFT - 10)) +
+           (adev->gmc.real_vram_size / 1024) >= 64000000) {
+               DRM_WARN("Disabling S/G due to >=64GB RAM\n");
+               return false;
+       }
+       return true;
+}
+
+/*
  * Intel hosts such as Raptor Lake and Sapphire Rapids don't support dynamic
  * speed switching. Until we have confirmation from Intel that a specific host
  * supports it, it's safer that we keep it disabled for all.
@@ -3696,10 +3722,11 @@ static void amdgpu_device_set_mcbp(struct amdgpu_device *adev)
 {
        if (amdgpu_mcbp == 1)
                adev->gfx.mcbp = true;
-
-       if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 0, 0)) &&
-           (adev->ip_versions[GC_HWIP][0] < IP_VERSION(10, 0, 0)) &&
-           adev->gfx.num_gfx_rings)
+       else if (amdgpu_mcbp == 0)
+               adev->gfx.mcbp = false;
+       else if ((adev->ip_versions[GC_HWIP][0] >= IP_VERSION(9, 0, 0)) &&
+                (adev->ip_versions[GC_HWIP][0] < IP_VERSION(10, 0, 0)) &&
+                adev->gfx.num_gfx_rings)
                adev->gfx.mcbp = true;
 
        if (amdgpu_sriov_vf(adev))
@@ -4367,6 +4394,7 @@ int amdgpu_device_suspend(struct drm_device *dev, bool fbcon)
                drm_fb_helper_set_suspend_unlocked(adev_to_drm(adev)->fb_helper, true);
 
        cancel_delayed_work_sync(&adev->delayed_init_work);
+       flush_delayed_work(&adev->gfx.gfx_off_delay_work);
 
        amdgpu_ras_suspend(adev);
 
index c694b41..7537f5a 100644 (file)
@@ -552,6 +552,41 @@ int amdgpu_fence_driver_sw_init(struct amdgpu_device *adev)
 }
 
 /**
+ * amdgpu_fence_need_ring_interrupt_restore - helper function to check whether
+ * fence driver interrupts need to be restored.
+ *
+ * @ring: ring that to be checked
+ *
+ * Interrupts for rings that belong to GFX IP don't need to be restored
+ * when the target power state is s0ix.
+ *
+ * Return true if need to restore interrupts, false otherwise.
+ */
+static bool amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring *ring)
+{
+       struct amdgpu_device *adev = ring->adev;
+       bool is_gfx_power_domain = false;
+
+       switch (ring->funcs->type) {
+       case AMDGPU_RING_TYPE_SDMA:
+       /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */
+               if (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0))
+                       is_gfx_power_domain = true;
+               break;
+       case AMDGPU_RING_TYPE_GFX:
+       case AMDGPU_RING_TYPE_COMPUTE:
+       case AMDGPU_RING_TYPE_KIQ:
+       case AMDGPU_RING_TYPE_MES:
+               is_gfx_power_domain = true;
+               break;
+       default:
+               break;
+       }
+
+       return !(adev->in_s0ix && is_gfx_power_domain);
+}
+
+/**
  * amdgpu_fence_driver_hw_fini - tear down the fence driver
  * for all possible rings.
  *
@@ -579,7 +614,8 @@ void amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev)
                        amdgpu_fence_driver_force_completion(ring);
 
                if (!drm_dev_is_unplugged(adev_to_drm(adev)) &&
-                   ring->fence_drv.irq_src)
+                   ring->fence_drv.irq_src &&
+                   amdgpu_fence_need_ring_interrupt_restore(ring))
                        amdgpu_irq_put(adev, ring->fence_drv.irq_src,
                                       ring->fence_drv.irq_type);
 
@@ -655,7 +691,8 @@ void amdgpu_fence_driver_hw_init(struct amdgpu_device *adev)
                        continue;
 
                /* enable the interrupt */
-               if (ring->fence_drv.irq_src)
+               if (ring->fence_drv.irq_src &&
+                   amdgpu_fence_need_ring_interrupt_restore(ring))
                        amdgpu_irq_get(adev, ring->fence_drv.irq_src,
                                       ring->fence_drv.irq_type);
        }
index a33d4bc..fd81b04 100644 (file)
@@ -692,15 +692,8 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable)
 
                if (adev->gfx.gfx_off_req_count == 0 &&
                    !adev->gfx.gfx_off_state) {
-                       /* If going to s2idle, no need to wait */
-                       if (adev->in_s0ix) {
-                               if (!amdgpu_dpm_set_powergating_by_smu(adev,
-                                               AMD_IP_BLOCK_TYPE_GFX, true))
-                                       adev->gfx.gfx_off_state = true;
-                       } else {
-                               schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
+                       schedule_delayed_work(&adev->gfx.gfx_off_delay_work,
                                              delay);
-                       }
                }
        } else {
                if (adev->gfx.gfx_off_req_count == 0) {
index b779ee4..e1ee1c7 100644 (file)
@@ -397,7 +397,7 @@ void amdgpu_sw_ring_ib_begin(struct amdgpu_ring *ring)
        struct amdgpu_ring_mux *mux = &adev->gfx.muxer;
 
        WARN_ON(!ring->is_sw_ring);
-       if (ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) {
+       if (adev->gfx.mcbp && ring->hw_prio > AMDGPU_RING_PRIO_DEFAULT) {
                if (amdgpu_mcbp_scan(mux) > 0)
                        amdgpu_mcbp_trigger_preempt(mux);
                return;
index 9c9cca1..565a1fa 100644 (file)
@@ -239,8 +239,13 @@ static int amdgpu_xcp_dev_alloc(struct amdgpu_device *adev)
 
        for (i = 1; i < MAX_XCP; i++) {
                ret = amdgpu_xcp_drm_dev_alloc(&p_ddev);
-               if (ret)
+               if (ret == -ENOSPC) {
+                       dev_warn(adev->dev,
+                       "Skip xcp node #%d when out of drm node resource.", i);
+                       return 0;
+               } else if (ret) {
                        return ret;
+               }
 
                /* Redirect all IOCTLs to the primary device */
                adev->xcp_mgr->xcp[i].rdev = p_ddev->render->dev;
@@ -328,6 +333,9 @@ int amdgpu_xcp_dev_register(struct amdgpu_device *adev,
                return 0;
 
        for (i = 1; i < MAX_XCP; i++) {
+               if (!adev->xcp_mgr->xcp[i].ddev)
+                       break;
+
                ret = drm_dev_register(adev->xcp_mgr->xcp[i].ddev, ent->driver_data);
                if (ret)
                        return ret;
@@ -345,6 +353,9 @@ void amdgpu_xcp_dev_unplug(struct amdgpu_device *adev)
                return;
 
        for (i = 1; i < MAX_XCP; i++) {
+               if (!adev->xcp_mgr->xcp[i].ddev)
+                       break;
+
                p_ddev = adev->xcp_mgr->xcp[i].ddev;
                drm_dev_unplug(p_ddev);
                p_ddev->render->dev = adev->xcp_mgr->xcp[i].rdev;
index 3a7af59..0451533 100644 (file)
@@ -471,8 +471,12 @@ static void gfx_v11_0_check_fw_cp_gfx_shadow(struct amdgpu_device *adev)
        case IP_VERSION(11, 0, 3):
                if ((adev->gfx.me_fw_version >= 1505) &&
                    (adev->gfx.pfp_fw_version >= 1600) &&
-                   (adev->gfx.mec_fw_version >= 512))
-                       adev->gfx.cp_gfx_shadow = true;
+                   (adev->gfx.mec_fw_version >= 512)) {
+                       if (amdgpu_sriov_vf(adev))
+                               adev->gfx.cp_gfx_shadow = true;
+                       else
+                               adev->gfx.cp_gfx_shadow = false;
+               }
                break;
        default:
                adev->gfx.cp_gfx_shadow = false;
index e1a392b..af5685f 100644 (file)
@@ -137,14 +137,15 @@ static int psp_v13_0_wait_for_bootloader(struct psp_context *psp)
        int ret;
        int retry_loop;
 
+       /* Wait for bootloader to signify that it is ready having bit 31 of
+        * C2PMSG_35 set to 1. All other bits are expected to be cleared.
+        * If there is an error in processing command, bits[7:0] will be set.
+        * This is applicable for PSP v13.0.6 and newer.
+        */
        for (retry_loop = 0; retry_loop < 10; retry_loop++) {
-               /* Wait for bootloader to signify that is
-                   ready having bit 31 of C2PMSG_35 set to 1 */
-               ret = psp_wait_for(psp,
-                                  SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35),
-                                  0x80000000,
-                                  0x80000000,
-                                  false);
+               ret = psp_wait_for(
+                       psp, SOC15_REG_OFFSET(MP0, 0, regMP0_SMN_C2PMSG_35),
+                       0x80000000, 0xffffffff, false);
 
                if (ret == 0)
                        return 0;
index 49f40d9..f5a6f56 100644 (file)
@@ -1543,11 +1543,7 @@ static bool kfd_ignore_crat(void)
        if (ignore_crat)
                return true;
 
-#ifndef KFD_SUPPORT_IOMMU_V2
        ret = true;
-#else
-       ret = false;
-#endif
 
        return ret;
 }
index 0b3dc75..a53e075 100644 (file)
@@ -194,11 +194,6 @@ static void kfd_device_info_init(struct kfd_dev *kfd,
 
                kfd_device_info_set_event_interrupt_class(kfd);
 
-               /* Raven */
-               if (gc_version == IP_VERSION(9, 1, 0) ||
-                   gc_version == IP_VERSION(9, 2, 2))
-                       kfd->device_info.needs_iommu_device = true;
-
                if (gc_version < IP_VERSION(11, 0, 0)) {
                        /* Navi2x+, Navi1x+ */
                        if (gc_version == IP_VERSION(10, 3, 6))
@@ -233,10 +228,6 @@ static void kfd_device_info_init(struct kfd_dev *kfd,
                    asic_type != CHIP_TONGA)
                        kfd->device_info.supports_cwsr = true;
 
-               if (asic_type == CHIP_KAVERI ||
-                   asic_type == CHIP_CARRIZO)
-                       kfd->device_info.needs_iommu_device = true;
-
                if (asic_type != CHIP_HAWAII && !vf)
                        kfd->device_info.needs_pci_atomics = true;
        }
@@ -249,7 +240,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
        uint32_t gfx_target_version = 0;
 
        switch (adev->asic_type) {
-#ifdef KFD_SUPPORT_IOMMU_V2
 #ifdef CONFIG_DRM_AMDGPU_CIK
        case CHIP_KAVERI:
                gfx_target_version = 70000;
@@ -262,7 +252,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
                if (!vf)
                        f2g = &gfx_v8_kfd2kgd;
                break;
-#endif
 #ifdef CONFIG_DRM_AMDGPU_CIK
        case CHIP_HAWAII:
                gfx_target_version = 70001;
@@ -298,7 +287,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
                        gfx_target_version = 90000;
                        f2g = &gfx_v9_kfd2kgd;
                        break;
-#ifdef KFD_SUPPORT_IOMMU_V2
                /* Raven */
                case IP_VERSION(9, 1, 0):
                case IP_VERSION(9, 2, 2):
@@ -306,7 +294,6 @@ struct kfd_dev *kgd2kfd_probe(struct amdgpu_device *adev, bool vf)
                        if (!vf)
                                f2g = &gfx_v9_kfd2kgd;
                        break;
-#endif
                /* Vega12 */
                case IP_VERSION(9, 2, 1):
                        gfx_target_version = 90004;
index 2df1538..01192f5 100644 (file)
@@ -2538,18 +2538,12 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_node *dev)
        }
 
        switch (dev->adev->asic_type) {
-       case CHIP_CARRIZO:
-               device_queue_manager_init_vi(&dqm->asic_ops);
-               break;
-
        case CHIP_KAVERI:
-               device_queue_manager_init_cik(&dqm->asic_ops);
-               break;
-
        case CHIP_HAWAII:
                device_queue_manager_init_cik_hawaii(&dqm->asic_ops);
                break;
 
+       case CHIP_CARRIZO:
        case CHIP_TONGA:
        case CHIP_FIJI:
        case CHIP_POLARIS10:
index 61fc62f..4a17bb7 100644 (file)
@@ -1965,7 +1965,14 @@ int kfd_topology_add_device(struct kfd_node *gpu)
        const char *asic_name = amdgpu_asic_name[gpu->adev->asic_type];
 
        gpu_id = kfd_generate_gpu_id(gpu);
-       pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
+       if (gpu->xcp && !gpu->xcp->ddev) {
+               dev_warn(gpu->adev->dev,
+               "Won't add GPU (ID: 0x%x) to topology since it has no drm node assigned.",
+               gpu_id);
+               return 0;
+       } else {
+               pr_debug("Adding new GPU (ID: 0x%x) to topology\n", gpu_id);
+       }
 
        /* Check to see if this gpu device exists in the topology_device_list.
         * If so, assign the gpu to that device,
index 0fa739f..e5554a3 100644 (file)
@@ -1638,9 +1638,8 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
                }
                break;
        }
-       if (init_data.flags.gpu_vm_support &&
-           (amdgpu_sg_display == 0))
-               init_data.flags.gpu_vm_support = false;
+       if (init_data.flags.gpu_vm_support)
+               init_data.flags.gpu_vm_support = amdgpu_sg_display_supported(adev);
 
        if (init_data.flags.gpu_vm_support)
                adev->mode_info.gpu_vm_support = true;
index 9bc86de..b885c39 100644 (file)
@@ -1320,7 +1320,7 @@ int compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
                if (computed_streams[i])
                        continue;
 
-               if (!res_pool->funcs->remove_stream_from_ctx ||
+               if (res_pool->funcs->remove_stream_from_ctx &&
                    res_pool->funcs->remove_stream_from_ctx(stream->ctx->dc, dc_state, stream) != DC_OK)
                        return -EINVAL;
 
index 20d4d08..6966420 100644 (file)
@@ -777,7 +777,8 @@ void dce110_edp_wait_for_hpd_ready(
        dal_gpio_destroy_irq(&hpd);
 
        /* ensure that the panel is detected */
-       ASSERT(edp_hpd_high);
+       if (!edp_hpd_high)
+               DC_LOG_DC("%s: wait timed out!\n", __func__);
 }
 
 void dce110_edp_power_control(
index 4cc8de2..9f2e243 100644 (file)
@@ -712,7 +712,7 @@ static const struct dc_debug_options debug_defaults_drv = {
                .timing_trace = false,
                .clock_trace = true,
                .disable_pplib_clock_request = true,
-               .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+               .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
                .force_single_disp_pipe_split = false,
                .disable_dcc = DCC_ENABLE,
                .vsr_support = true,
index e5b7ef7..50dc834 100644 (file)
@@ -357,8 +357,11 @@ void dpp3_set_cursor_attributes(
        int cur_rom_en = 0;
 
        if (color_format == CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA ||
-               color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA)
-               cur_rom_en = 1;
+               color_format == CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA) {
+               if (cursor_attributes->attribute_flags.bits.ENABLE_CURSOR_DEGAMMA) {
+                       cur_rom_en = 1;
+               }
+       }
 
        REG_UPDATE_3(CURSOR0_CONTROL,
                        CUR0_MODE, color_format,
index ce41a83..222af2f 100644 (file)
@@ -1581,9 +1581,9 @@ static int smu_disable_dpms(struct smu_context *smu)
 
        /*
         * For SMU 13.0.4/11, PMFW will handle the features disablement properly
-        * for gpu reset case. Driver involvement is unnecessary.
+        * for gpu reset and S0i3 cases. Driver involvement is unnecessary.
         */
-       if (amdgpu_in_reset(adev)) {
+       if (amdgpu_in_reset(adev) || adev->in_s0ix) {
                switch (adev->ip_versions[MP1_HWIP][0]) {
                case IP_VERSION(13, 0, 4):
                case IP_VERSION(13, 0, 11):
index 0cda3b2..f0800c0 100644 (file)
@@ -588,7 +588,9 @@ err0_out:
        return -ENOMEM;
 }
 
-static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *smu)
+static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *smu,
+                                                          bool use_metrics_v3,
+                                                          bool use_metrics_v2)
 {
        struct smu_table_context *smu_table= &smu->smu_table;
        SmuMetricsExternal_t *metrics_ext =
@@ -596,13 +598,11 @@ static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *s
        uint32_t throttler_status = 0;
        int i;
 
-       if ((smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7)) &&
-            (smu->smc_fw_version >= 0x3A4900)) {
+       if (use_metrics_v3) {
                for (i = 0; i < THROTTLER_COUNT; i++)
                        throttler_status |=
                                (metrics_ext->SmuMetrics_V3.ThrottlingPercentage[i] ? 1U << i : 0);
-       } else if ((smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7)) &&
-            (smu->smc_fw_version >= 0x3A4300)) {
+       } else if (use_metrics_v2) {
                for (i = 0; i < THROTTLER_COUNT; i++)
                        throttler_status |=
                                (metrics_ext->SmuMetrics_V2.ThrottlingPercentage[i] ? 1U << i : 0);
@@ -864,7 +864,7 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
                        metrics->TemperatureVrSoc) * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_THROTTLER_STATUS:
-               *value = sienna_cichlid_get_throttler_status_locked(smu);
+               *value = sienna_cichlid_get_throttler_status_locked(smu, use_metrics_v3, use_metrics_v2);
                break;
        case METRICS_CURR_FANSPEED:
                *value = use_metrics_v3 ? metrics_v3->CurrFanSpeed :
@@ -4017,7 +4017,7 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
        gpu_metrics->current_dclk1 = use_metrics_v3 ? metrics_v3->CurrClock[PPCLK_DCLK_1] :
                use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_1] : metrics->CurrClock[PPCLK_DCLK_1];
 
-       gpu_metrics->throttle_status = sienna_cichlid_get_throttler_status_locked(smu);
+       gpu_metrics->throttle_status = sienna_cichlid_get_throttler_status_locked(smu, use_metrics_v3, use_metrics_v2);
        gpu_metrics->indep_throttle_status =
                        smu_cmn_get_indep_throttler_status(gpu_metrics->throttle_status,
                                                           sienna_cichlid_throttler_map);
index 3d18861..0fb6be1 100644 (file)
@@ -332,10 +332,13 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu)
                table_context->power_play_table;
        struct smu_baco_context *smu_baco = &smu->smu_baco;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
+#if 0
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
        const OverDriveLimits_t * const overdrive_upperlimits =
                                &pptable->SkuTable.OverDriveLimitsBasicMax;
        const OverDriveLimits_t * const overdrive_lowerlimits =
                                &pptable->SkuTable.OverDriveLimitsMin;
+#endif
 
        if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_HARDWAREDC)
                smu->dc_controlled_by_gpio = true;
@@ -347,18 +350,30 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu)
        if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO)
                smu_baco->maco_support = true;
 
+       /*
+        * We are in the transition to a new OD mechanism.
+        * Disable the OD feature support for SMU13 temporarily.
+        * TODO: get this reverted when new OD mechanism online
+        */
+#if 0
        if (!overdrive_lowerlimits->FeatureCtrlMask ||
            !overdrive_upperlimits->FeatureCtrlMask)
                smu->od_enabled = false;
 
-       table_context->thermal_controller_type =
-               powerplay_table->thermal_controller_type;
-
        /*
         * Instead of having its own buffer space and get overdrive_table copied,
         * smu->od_settings just points to the actual overdrive_table
         */
        smu->od_settings = &powerplay_table->overdrive_table;
+#else
+       smu->od_enabled = false;
+#endif
+
+       table_context->thermal_controller_type =
+               powerplay_table->thermal_controller_type;
+
+       smu->adev->pm.no_fan =
+               !(pptable->SkuTable.FeaturesToRun[0] & (1 << FEATURE_FAN_CONTROL_BIT));
 
        return 0;
 }
@@ -1140,7 +1155,6 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
                (OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
        struct smu_13_0_dpm_table *single_dpm_table;
        struct smu_13_0_pcie_table *pcie_table;
-       const int link_width[] = {0, 1, 2, 4, 8, 12, 16};
        uint32_t gen_speed, lane_width;
        int i, curr_freq, size = 0;
        int32_t min_value, max_value;
@@ -1256,7 +1270,7 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
                                        (pcie_table->pcie_lane[i] == 6) ? "x16" : "",
                                        pcie_table->clk_freq[i],
                                        (gen_speed == DECODE_GEN_SPEED(pcie_table->pcie_gen[i])) &&
-                                       (lane_width == DECODE_LANE_WIDTH(link_width[pcie_table->pcie_lane[i]])) ?
+                                       (lane_width == DECODE_LANE_WIDTH(pcie_table->pcie_lane[i])) ?
                                        "*" : "");
                break;
 
index 1ac5521..dc6104a 100644 (file)
 #define EPSILON 1
 
 #define smnPCIE_ESM_CTRL 0x193D0
-#define smnPCIE_LC_LINK_WIDTH_CNTL 0x1ab40288
+#define smnPCIE_LC_LINK_WIDTH_CNTL 0x1a340288
 #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK 0x00000070L
 #define PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT 0x4
+#define MAX_LINK_WIDTH 6
 
 static const struct cmn2asic_msg_mapping smu_v13_0_6_message_map[SMU_MSG_MAX_COUNT] = {
        MSG_MAP(TestMessage,                         PPSMC_MSG_TestMessage,                     0),
@@ -708,16 +709,19 @@ static int smu_v13_0_6_get_smu_metrics_data(struct smu_context *smu,
                *value = SMUQ10_TO_UINT(metrics->SocketPower) << 8;
                break;
        case METRICS_TEMPERATURE_HOTSPOT:
-               *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature);
+               *value = SMUQ10_TO_UINT(metrics->MaxSocketTemperature) *
+                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_TEMPERATURE_MEM:
-               *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature);
+               *value = SMUQ10_TO_UINT(metrics->MaxHbmTemperature) *
+                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        /* This is the max of all VRs and not just SOC VR.
         * No need to define another data type for the same.
         */
        case METRICS_TEMPERATURE_VRSOC:
-               *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature);
+               *value = SMUQ10_TO_UINT(metrics->MaxVrTemperature) *
+                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        default:
                *value = UINT_MAX;
@@ -1966,6 +1970,7 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
        struct amdgpu_device *adev = smu->adev;
        int ret = 0, inst0, xcc0;
        MetricsTable_t *metrics;
+       u16 link_width_level;
 
        inst0 = adev->sdma.instance[0].aid_id;
        xcc0 = GET_INST(GC, 0);
@@ -1993,9 +1998,8 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
 
        gpu_metrics->average_socket_power =
                SMUQ10_TO_UINT(metrics->SocketPower);
-       /* Energy is reported in 15.625mJ units */
-       gpu_metrics->energy_accumulator =
-               SMUQ10_TO_UINT(metrics->SocketEnergyAcc);
+       /* Energy counter reported in 15.259uJ (2^-16) units */
+       gpu_metrics->energy_accumulator = metrics->SocketEnergyAcc;
 
        gpu_metrics->current_gfxclk =
                SMUQ10_TO_UINT(metrics->GfxclkFrequency[xcc0]);
@@ -2017,8 +2021,12 @@ static ssize_t smu_v13_0_6_get_gpu_metrics(struct smu_context *smu, void **table
        gpu_metrics->throttle_status = 0;
 
        if (!(adev->flags & AMD_IS_APU)) {
+               link_width_level = smu_v13_0_6_get_current_pcie_link_width_level(smu);
+               if (link_width_level > MAX_LINK_WIDTH)
+                       link_width_level = 0;
+
                gpu_metrics->pcie_link_width =
-                       smu_v13_0_6_get_current_pcie_link_width_level(smu);
+                       DECODE_LANE_WIDTH(link_width_level);
                gpu_metrics->pcie_link_speed =
                        smu_v13_0_6_get_current_pcie_link_speed(smu);
        }
index b1f0937..62f2886 100644 (file)
@@ -323,10 +323,12 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu)
        struct smu_baco_context *smu_baco = &smu->smu_baco;
        PPTable_t *smc_pptable = table_context->driver_pptable;
        BoardTable_t *BoardTable = &smc_pptable->BoardTable;
+#if 0
        const OverDriveLimits_t * const overdrive_upperlimits =
                                &smc_pptable->SkuTable.OverDriveLimitsBasicMax;
        const OverDriveLimits_t * const overdrive_lowerlimits =
                                &smc_pptable->SkuTable.OverDriveLimitsMin;
+#endif
 
        if (powerplay_table->platform_caps & SMU_13_0_7_PP_PLATFORM_CAP_HARDWAREDC)
                smu->dc_controlled_by_gpio = true;
@@ -338,18 +340,22 @@ static int smu_v13_0_7_check_powerplay_table(struct smu_context *smu)
        if (smu_baco->platform_support && (BoardTable->HsrEnabled || BoardTable->VddqOffEnabled))
                smu_baco->maco_support = true;
 
+#if 0
        if (!overdrive_lowerlimits->FeatureCtrlMask ||
            !overdrive_upperlimits->FeatureCtrlMask)
                smu->od_enabled = false;
 
-       table_context->thermal_controller_type =
-               powerplay_table->thermal_controller_type;
-
        /*
         * Instead of having its own buffer space and get overdrive_table copied,
         * smu->od_settings just points to the actual overdrive_table
         */
        smu->od_settings = &powerplay_table->overdrive_table;
+#else
+       smu->od_enabled = false;
+#endif
+
+       table_context->thermal_controller_type =
+               powerplay_table->thermal_controller_type;
 
        return 0;
 }
index 504d51c..aadb396 100644 (file)
@@ -2517,9 +2517,11 @@ static irqreturn_t it6505_int_threaded_handler(int unused, void *data)
        };
        int int_status[3], i;
 
-       if (it6505->enable_drv_hold || pm_runtime_get_if_in_use(dev) <= 0)
+       if (it6505->enable_drv_hold || !it6505->powered)
                return IRQ_HANDLED;
 
+       pm_runtime_get_sync(dev);
+
        int_status[0] = it6505_read(it6505, INT_STATUS_01);
        int_status[1] = it6505_read(it6505, INT_STATUS_02);
        int_status[2] = it6505_read(it6505, INT_STATUS_03);
index 5163e52..9663601 100644 (file)
@@ -774,9 +774,7 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
        dsi->lanes = 4;
        dsi->format = MIPI_DSI_FMT_RGB888;
        dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
-                         MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO_NO_HSA |
-                         MIPI_DSI_MODE_VIDEO_NO_HFP | MIPI_DSI_MODE_VIDEO_NO_HBP |
-                         MIPI_DSI_MODE_NO_EOT_PACKET;
+                         MIPI_DSI_MODE_VIDEO_HSE;
 
        ret = devm_mipi_dsi_attach(dev, dsi);
        if (ret < 0) {
index e0dbd91..1f47096 100644 (file)
@@ -3456,6 +3456,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
                            connector->base.id, connector->name);
                return NULL;
        }
+       if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
+               drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Composite sync not supported\n",
+                           connector->base.id, connector->name);
+       }
 
        /* it is incorrect if hsync/vsync width is zero */
        if (!hsync_pulse_width || !vsync_pulse_width) {
@@ -3502,27 +3506,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_connector *connecto
        if (info->quirks & EDID_QUIRK_DETAILED_SYNC_PP) {
                mode->flags |= DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC;
        } else {
-               switch (pt->misc & DRM_EDID_PT_SYNC_MASK) {
-               case DRM_EDID_PT_ANALOG_CSYNC:
-               case DRM_EDID_PT_BIPOLAR_ANALOG_CSYNC:
-                       drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Analog composite sync!\n",
-                                   connector->base.id, connector->name);
-                       mode->flags |= DRM_MODE_FLAG_CSYNC | DRM_MODE_FLAG_NCSYNC;
-                       break;
-               case DRM_EDID_PT_DIGITAL_CSYNC:
-                       drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Digital composite sync!\n",
-                                   connector->base.id, connector->name);
-                       mode->flags |= DRM_MODE_FLAG_CSYNC;
-                       mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
-                               DRM_MODE_FLAG_PCSYNC : DRM_MODE_FLAG_NCSYNC;
-                       break;
-               case DRM_EDID_PT_DIGITAL_SEPARATE_SYNC:
-                       mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
-                               DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
-                       mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
-                               DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
-                       break;
-               }
+               mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ?
+                       DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC;
+               mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ?
+                       DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC;
        }
 
 set_size:
index 4ea6507..baaf0e0 100644 (file)
@@ -623,7 +623,13 @@ int drm_gem_shmem_mmap(struct drm_gem_shmem_object *shmem, struct vm_area_struct
        int ret;
 
        if (obj->import_attach) {
+               /* Reset both vm_ops and vm_private_data, so we don't end up with
+                * vm_ops pointing to our implementation if the dma-buf backend
+                * doesn't set those fields.
+                */
                vma->vm_private_data = NULL;
+               vma->vm_ops = NULL;
+
                ret = dma_buf_mmap(obj->dma_buf, vma, 0);
 
                /* Drop the reference drm_gem_mmap_obj() acquired.*/
index f0ee9bc..b0c6a2a 100644 (file)
@@ -662,10 +662,24 @@ static const struct intel_display_device_info xe_lpdp_display = {
                BIT(TRANSCODER_C) | BIT(TRANSCODER_D),
 };
 
+/*
+ * Separate detection for no display cases to keep the display id array simple.
+ *
+ * IVB Q requires subvendor and subdevice matching to differentiate from IVB D
+ * GT2 server.
+ */
+static bool has_no_display(struct pci_dev *pdev)
+{
+       static const struct pci_device_id ids[] = {
+               INTEL_IVB_Q_IDS(0),
+               {}
+       };
+
+       return pci_match_id(ids, pdev);
+}
+
 #undef INTEL_VGA_DEVICE
-#undef INTEL_QUANTA_VGA_DEVICE
 #define INTEL_VGA_DEVICE(id, info) { id, info }
-#define INTEL_QUANTA_VGA_DEVICE(info) { 0x16a, info }
 
 static const struct {
        u32 devid;
@@ -690,7 +704,6 @@ static const struct {
        INTEL_IRONLAKE_M_IDS(&ilk_m_display),
        INTEL_SNB_D_IDS(&snb_display),
        INTEL_SNB_M_IDS(&snb_display),
-       INTEL_IVB_Q_IDS(NULL),          /* must be first IVB in list */
        INTEL_IVB_M_IDS(&ivb_display),
        INTEL_IVB_D_IDS(&ivb_display),
        INTEL_HSW_IDS(&hsw_display),
@@ -775,6 +788,11 @@ intel_display_device_probe(struct drm_i915_private *i915, bool has_gmdid,
        if (has_gmdid)
                return probe_gmdid_display(i915, gmdid_ver, gmdid_rel, gmdid_step);
 
+       if (has_no_display(pdev)) {
+               drm_dbg_kms(&i915->drm, "Device doesn't have display\n");
+               return &no_display;
+       }
+
        for (i = 0; i < ARRAY_SIZE(intel_display_ids); i++) {
                if (intel_display_ids[i].devid == pdev->device)
                        return intel_display_ids[i].info;
index 21f9212..67e3aaf 100644 (file)
@@ -2752,7 +2752,7 @@ static struct intel_sdvo_connector *intel_sdvo_connector_alloc(void)
        __drm_atomic_helper_connector_reset(&sdvo_connector->base.base,
                                            &conn_state->base.base);
 
-       INIT_LIST_HEAD(&sdvo_connector->base.panel.fixed_modes);
+       intel_panel_init_alloc(&sdvo_connector->base);
 
        return sdvo_connector;
 }
index ee9f83a..477df26 100644 (file)
@@ -470,12 +470,19 @@ int intel_guc_slpc_set_ignore_eff_freq(struct intel_guc_slpc *slpc, bool val)
        ret = slpc_set_param(slpc,
                             SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY,
                             val);
-       if (ret)
+       if (ret) {
                guc_probe_error(slpc_to_guc(slpc), "Failed to set efficient freq(%d): %pe\n",
                                val, ERR_PTR(ret));
-       else
+       } else {
                slpc->ignore_eff_freq = val;
 
+               /* Set min to RPn when we disable efficient freq */
+               if (val)
+                       ret = slpc_set_param(slpc,
+                                            SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,
+                                            slpc->min_freq);
+       }
+
        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
        mutex_unlock(&slpc->lock);
        return ret;
@@ -602,9 +609,8 @@ static int slpc_set_softlimits(struct intel_guc_slpc *slpc)
                return ret;
 
        if (!slpc->min_freq_softlimit) {
-               ret = intel_guc_slpc_get_min_freq(slpc, &slpc->min_freq_softlimit);
-               if (unlikely(ret))
-                       return ret;
+               /* Min softlimit is initialized to RPn */
+               slpc->min_freq_softlimit = slpc->min_freq;
                slpc_to_gt(slpc)->defaults.min_freq = slpc->min_freq_softlimit;
        } else {
                return intel_guc_slpc_set_min_freq(slpc,
@@ -755,6 +761,9 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
                return ret;
        }
 
+       /* Set cached value of ignore efficient freq */
+       intel_guc_slpc_set_ignore_eff_freq(slpc, slpc->ignore_eff_freq);
+
        /* Revert SLPC min/max to softlimits if necessary */
        ret = slpc_set_softlimits(slpc);
        if (unlikely(ret)) {
@@ -765,9 +774,6 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
        /* Set cached media freq ratio mode */
        intel_guc_slpc_set_media_ratio_mode(slpc, slpc->media_ratio_mode);
 
-       /* Set cached value of ignore efficient freq */
-       intel_guc_slpc_set_ignore_eff_freq(slpc, slpc->ignore_eff_freq);
-
        return 0;
 }
 
index f75c6f0..622f6eb 100644 (file)
@@ -967,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 && nv_connector->native_mode)
+       if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
                nouveau_connector_detect_depth(connector);
 
        /* Find the native mode if this is a digital panel, if we didn't
@@ -1408,8 +1408,7 @@ nouveau_connector_create(struct drm_device *dev,
                ret = nvif_conn_ctor(&disp->disp, nv_connector->base.name, nv_connector->index,
                                     &nv_connector->conn);
                if (ret) {
-                       kfree(nv_connector);
-                       return ERR_PTR(ret);
+                       goto drm_conn_err;
                }
 
                ret = nvif_conn_event_ctor(&nv_connector->conn, "kmsHotplug",
@@ -1426,8 +1425,7 @@ nouveau_connector_create(struct drm_device *dev,
                        if (ret) {
                                nvif_event_dtor(&nv_connector->hpd);
                                nvif_conn_dtor(&nv_connector->conn);
-                               kfree(nv_connector);
-                               return ERR_PTR(ret);
+                               goto drm_conn_err;
                        }
                }
        }
@@ -1475,4 +1473,9 @@ nouveau_connector_create(struct drm_device *dev,
 
        drm_connector_register(connector);
        return connector;
+
+drm_conn_err:
+       drm_connector_cleanup(connector);
+       kfree(nv_connector);
+       return ERR_PTR(ret);
 }
index 40c8ea4..b8ac66b 100644 (file)
@@ -26,6 +26,8 @@
 #include "head.h"
 #include "ior.h"
 
+#include <drm/display/drm_dp.h>
+
 #include <subdev/bios.h>
 #include <subdev/bios/init.h>
 #include <subdev/gpio.h>
@@ -634,6 +636,50 @@ nvkm_dp_enable_supported_link_rates(struct nvkm_outp *outp)
        return outp->dp.rates != 0;
 }
 
+/* XXX: This is a big fat hack, and this is just drm_dp_read_dpcd_caps()
+ * converted to work inside nvkm. This is a temporary holdover until we start
+ * passing the drm_dp_aux device through NVKM
+ */
+static int
+nvkm_dp_read_dpcd_caps(struct nvkm_outp *outp)
+{
+       struct nvkm_i2c_aux *aux = outp->dp.aux;
+       u8 dpcd_ext[DP_RECEIVER_CAP_SIZE];
+       int ret;
+
+       ret = nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, DP_RECEIVER_CAP_SIZE);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Prior to DP1.3 the bit represented by
+        * DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT was reserved.
+        * If it is set DP_DPCD_REV at 0000h could be at a value less than
+        * the true capability of the panel. The only way to check is to
+        * then compare 0000h and 2200h.
+        */
+       if (!(outp->dp.dpcd[DP_TRAINING_AUX_RD_INTERVAL] &
+             DP_EXTENDED_RECEIVER_CAP_FIELD_PRESENT))
+               return 0;
+
+       ret = nvkm_rdaux(aux, DP_DP13_DPCD_REV, dpcd_ext, sizeof(dpcd_ext));
+       if (ret < 0)
+               return ret;
+
+       if (outp->dp.dpcd[DP_DPCD_REV] > dpcd_ext[DP_DPCD_REV]) {
+               OUTP_DBG(outp, "Extended DPCD rev less than base DPCD rev (%d > %d)\n",
+                        outp->dp.dpcd[DP_DPCD_REV], dpcd_ext[DP_DPCD_REV]);
+               return 0;
+       }
+
+       if (!memcmp(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext)))
+               return 0;
+
+       memcpy(outp->dp.dpcd, dpcd_ext, sizeof(dpcd_ext));
+
+       return 0;
+}
+
 void
 nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
 {
@@ -689,7 +735,7 @@ nvkm_dp_enable(struct nvkm_outp *outp, bool auxpwr)
                        memset(outp->dp.lttpr, 0x00, sizeof(outp->dp.lttpr));
                }
 
-               if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dp.dpcd, sizeof(outp->dp.dpcd))) {
+               if (!nvkm_dp_read_dpcd_caps(outp)) {
                        const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 };
                        const u8 *rate;
                        int rate_max;
index 00dbeda..de161e7 100644 (file)
@@ -117,6 +117,7 @@ void gk104_grctx_generate_r418800(struct gf100_gr *);
 
 extern const struct gf100_grctx_func gk110_grctx;
 void gk110_grctx_generate_r419eb0(struct gf100_gr *);
+void gk110_grctx_generate_r419f78(struct gf100_gr *);
 
 extern const struct gf100_grctx_func gk110b_grctx;
 extern const struct gf100_grctx_func gk208_grctx;
index 94233d0..52a234b 100644 (file)
@@ -906,7 +906,9 @@ static void
 gk104_grctx_generate_r419f78(struct gf100_gr *gr)
 {
        struct nvkm_device *device = gr->base.engine.subdev.device;
-       nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000);
+
+       /* bit 3 set disables loads in fp helper invocations, we need it enabled */
+       nvkm_mask(device, 0x419f78, 0x00000009, 0x00000000);
 }
 
 void
index 4391458..3acdd9e 100644 (file)
@@ -820,6 +820,15 @@ gk110_grctx_generate_r419eb0(struct gf100_gr *gr)
        nvkm_mask(device, 0x419eb0, 0x00001000, 0x00001000);
 }
 
+void
+gk110_grctx_generate_r419f78(struct gf100_gr *gr)
+{
+       struct nvkm_device *device = gr->base.engine.subdev.device;
+
+       /* bit 3 set disables loads in fp helper invocations, we need it enabled */
+       nvkm_mask(device, 0x419f78, 0x00000008, 0x00000000);
+}
+
 const struct gf100_grctx_func
 gk110_grctx = {
        .main  = gf100_grctx_generate_main,
@@ -854,4 +863,5 @@ gk110_grctx = {
        .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
        .r418800 = gk104_grctx_generate_r418800,
        .r419eb0 = gk110_grctx_generate_r419eb0,
+       .r419f78 = gk110_grctx_generate_r419f78,
 };
index 7b9a34f..5597e87 100644 (file)
@@ -103,4 +103,5 @@ gk110b_grctx = {
        .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
        .r418800 = gk104_grctx_generate_r418800,
        .r419eb0 = gk110_grctx_generate_r419eb0,
+       .r419f78 = gk110_grctx_generate_r419f78,
 };
index c78d07a..6126564 100644 (file)
@@ -568,4 +568,5 @@ gk208_grctx = {
        .dist_skip_table = gf117_grctx_generate_dist_skip_table,
        .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
        .r418800 = gk104_grctx_generate_r418800,
+       .r419f78 = gk110_grctx_generate_r419f78,
 };
index beac66e..9906974 100644 (file)
@@ -988,4 +988,5 @@ gm107_grctx = {
        .r406500 = gm107_grctx_generate_r406500,
        .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
        .r419e00 = gm107_grctx_generate_r419e00,
+       .r419f78 = gk110_grctx_generate_r419f78,
 };
index 3b6c810..a7775aa 100644 (file)
@@ -206,19 +206,6 @@ tu102_gr_av_to_init_veid(struct nvkm_blob *blob, struct gf100_gr_pack **ppack)
        return gk20a_gr_av_to_init_(blob, 64, 0x00100000, ppack);
 }
 
-int
-tu102_gr_load(struct gf100_gr *gr, int ver, const struct gf100_gr_fwif *fwif)
-{
-       int ret;
-
-       ret = gm200_gr_load(gr, ver, fwif);
-       if (ret)
-               return ret;
-
-       return gk20a_gr_load_net(gr, "gr/", "sw_veid_bundle_init", ver, tu102_gr_av_to_init_veid,
-                                &gr->bundle_veid);
-}
-
 static const struct gf100_gr_fwif
 tu102_gr_fwif[] = {
        {  0, gm200_gr_load, &tu102_gr, &gp108_gr_fecs_acr, &gp108_gr_gpccs_acr },
index 8f4f137..2130084 100644 (file)
@@ -404,38 +404,30 @@ static int jdi_panel_add(struct jdi_panel *jdi)
 
        ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
                                      jdi->supplies);
-       if (ret < 0) {
-               dev_err(dev, "failed to init regulator, ret=%d\n", ret);
-               return ret;
-       }
+       if (ret < 0)
+               return dev_err_probe(dev, ret,
+                                    "failed to init regulator, ret=%d\n", ret);
 
        jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
        if (IS_ERR(jdi->enable_gpio)) {
-               ret = PTR_ERR(jdi->enable_gpio);
-               dev_err(dev, "cannot get enable-gpio %d\n", ret);
-               return ret;
+               return dev_err_probe(dev, PTR_ERR(jdi->enable_gpio),
+                                    "cannot get enable-gpio %d\n", ret);
        }
 
        jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
-       if (IS_ERR(jdi->reset_gpio)) {
-               ret = PTR_ERR(jdi->reset_gpio);
-               dev_err(dev, "cannot get reset-gpios %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(jdi->reset_gpio))
+               return dev_err_probe(dev, PTR_ERR(jdi->reset_gpio),
+                                    "cannot get reset-gpios %d\n", ret);
 
        jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
-       if (IS_ERR(jdi->dcdc_en_gpio)) {
-               ret = PTR_ERR(jdi->dcdc_en_gpio);
-               dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(jdi->dcdc_en_gpio))
+               return dev_err_probe(dev, PTR_ERR(jdi->dcdc_en_gpio),
+                                    "cannot get dcdc-en-gpio %d\n", ret);
 
        jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
-       if (IS_ERR(jdi->backlight)) {
-               ret = PTR_ERR(jdi->backlight);
-               dev_err(dev, "failed to register backlight %d\n", ret);
-               return ret;
-       }
+       if (IS_ERR(jdi->backlight))
+               return dev_err_probe(dev, PTR_ERR(jdi->backlight),
+                                    "failed to register backlight %d\n", ret);
 
        drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
                       DRM_MODE_CONNECTOR_DSI);
index aaba36b..b38d0e9 100644 (file)
@@ -999,21 +999,21 @@ static const struct panel_desc auo_g104sn02 = {
        .connector_type = DRM_MODE_CONNECTOR_LVDS,
 };
 
-static const struct drm_display_mode auo_g121ean01_mode = {
-       .clock = 66700,
-       .hdisplay = 1280,
-       .hsync_start = 1280 + 58,
-       .hsync_end = 1280 + 58 + 8,
-       .htotal = 1280 + 58 + 8 + 70,
-       .vdisplay = 800,
-       .vsync_start = 800 + 6,
-       .vsync_end = 800 + 6 + 4,
-       .vtotal = 800 + 6 + 4 + 10,
+static const struct display_timing auo_g121ean01_timing = {
+       .pixelclock = { 60000000, 74400000, 90000000 },
+       .hactive = { 1280, 1280, 1280 },
+       .hfront_porch = { 20, 50, 100 },
+       .hback_porch = { 20, 50, 100 },
+       .hsync_len = { 30, 100, 200 },
+       .vactive = { 800, 800, 800 },
+       .vfront_porch = { 2, 10, 25 },
+       .vback_porch = { 2, 10, 25 },
+       .vsync_len = { 4, 18, 50 },
 };
 
 static const struct panel_desc auo_g121ean01 = {
-       .modes = &auo_g121ean01_mode,
-       .num_modes = 1,
+       .timings = &auo_g121ean01_timing,
+       .num_timings = 1,
        .bpc = 8,
        .size = {
                .width = 261,
index ea993d7..307a890 100644 (file)
@@ -310,7 +310,7 @@ int qxl_gem_object_create_with_handle(struct qxl_device *qdev,
                                      u32 domain,
                                      size_t size,
                                      struct qxl_surface *surf,
-                                     struct qxl_bo **qobj,
+                                     struct drm_gem_object **gobj,
                                      uint32_t *handle);
 void qxl_gem_object_free(struct drm_gem_object *gobj);
 int qxl_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv);
index d636ba6..17df5c7 100644 (file)
@@ -34,6 +34,7 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
 {
        struct qxl_device *qdev = to_qxl(dev);
        struct qxl_bo *qobj;
+       struct drm_gem_object *gobj;
        uint32_t handle;
        int r;
        struct qxl_surface surf;
@@ -62,11 +63,13 @@ int qxl_mode_dumb_create(struct drm_file *file_priv,
 
        r = qxl_gem_object_create_with_handle(qdev, file_priv,
                                              QXL_GEM_DOMAIN_CPU,
-                                             args->size, &surf, &qobj,
+                                             args->size, &surf, &gobj,
                                              &handle);
        if (r)
                return r;
+       qobj = gem_to_qxl_bo(gobj);
        qobj->is_dumb = true;
+       drm_gem_object_put(gobj);
        args->pitch = pitch;
        args->handle = handle;
        return 0;
index a08da0b..fc5e376 100644 (file)
@@ -72,32 +72,41 @@ int qxl_gem_object_create(struct qxl_device *qdev, int size,
        return 0;
 }
 
+/*
+ * If the caller passed a valid gobj pointer, it is responsible to call
+ * drm_gem_object_put() when it no longer needs to acess the object.
+ *
+ * If gobj is NULL, it is handled internally.
+ */
 int qxl_gem_object_create_with_handle(struct qxl_device *qdev,
                                      struct drm_file *file_priv,
                                      u32 domain,
                                      size_t size,
                                      struct qxl_surface *surf,
-                                     struct qxl_bo **qobj,
+                                     struct drm_gem_object **gobj,
                                      uint32_t *handle)
 {
-       struct drm_gem_object *gobj;
        int r;
+       struct drm_gem_object *local_gobj;
 
-       BUG_ON(!qobj);
        BUG_ON(!handle);
 
        r = qxl_gem_object_create(qdev, size, 0,
                                  domain,
                                  false, false, surf,
-                                 &gobj);
+                                 &local_gobj);
        if (r)
                return -ENOMEM;
-       r = drm_gem_handle_create(file_priv, gobj, handle);
+       r = drm_gem_handle_create(file_priv, local_gobj, handle);
        if (r)
                return r;
-       /* drop reference from allocate - handle holds it now */
-       *qobj = gem_to_qxl_bo(gobj);
-       drm_gem_object_put(gobj);
+
+       if (gobj)
+               *gobj = local_gobj;
+       else
+               /* drop reference from allocate - handle holds it now */
+               drm_gem_object_put(local_gobj);
+
        return 0;
 }
 
index 30f58b2..dd0f834 100644 (file)
@@ -38,7 +38,6 @@ int qxl_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_pr
        struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_alloc *qxl_alloc = data;
        int ret;
-       struct qxl_bo *qobj;
        uint32_t handle;
        u32 domain = QXL_GEM_DOMAIN_VRAM;
 
@@ -50,7 +49,7 @@ int qxl_alloc_ioctl(struct drm_device *dev, void *data, struct drm_file *file_pr
                                                domain,
                                                qxl_alloc->size,
                                                NULL,
-                                               &qobj, &handle);
+                                               NULL, &handle);
        if (ret) {
                DRM_ERROR("%s: failed to create gem ret=%d\n",
                          __func__, ret);
@@ -386,7 +385,6 @@ int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
 {
        struct qxl_device *qdev = to_qxl(dev);
        struct drm_qxl_alloc_surf *param = data;
-       struct qxl_bo *qobj;
        int handle;
        int ret;
        int size, actual_stride;
@@ -406,7 +404,7 @@ int qxl_alloc_surf_ioctl(struct drm_device *dev, void *data, struct drm_file *fi
                                                QXL_GEM_DOMAIN_SURFACE,
                                                size,
                                                &surf,
-                                               &qobj, &handle);
+                                               NULL, &handle);
        if (ret) {
                DRM_ERROR("%s: failed to create gem ret=%d\n",
                          __func__, ret);
index a530ecc..bf34498 100644 (file)
@@ -833,12 +833,12 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
         * need align with 2 pixel.
         */
        if (fb->format->is_yuv && ((new_plane_state->src.x1 >> 16) % 2)) {
-               DRM_ERROR("Invalid Source: Yuv format not support odd xpos\n");
+               DRM_DEBUG_KMS("Invalid Source: Yuv format not support odd xpos\n");
                return -EINVAL;
        }
 
        if (fb->format->is_yuv && new_plane_state->rotation & DRM_MODE_REFLECT_Y) {
-               DRM_ERROR("Invalid Source: Yuv format does not support this rotation\n");
+               DRM_DEBUG_KMS("Invalid Source: Yuv format does not support this rotation\n");
                return -EINVAL;
        }
 
@@ -846,7 +846,7 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
                struct vop *vop = to_vop(crtc);
 
                if (!vop->data->afbc) {
-                       DRM_ERROR("vop does not support AFBC\n");
+                       DRM_DEBUG_KMS("vop does not support AFBC\n");
                        return -EINVAL;
                }
 
@@ -855,15 +855,16 @@ static int vop_plane_atomic_check(struct drm_plane *plane,
                        return ret;
 
                if (new_plane_state->src.x1 || new_plane_state->src.y1) {
-                       DRM_ERROR("AFBC does not support offset display, xpos=%d, ypos=%d, offset=%d\n",
-                                 new_plane_state->src.x1,
-                                 new_plane_state->src.y1, fb->offsets[0]);
+                       DRM_DEBUG_KMS("AFBC does not support offset display, " \
+                                     "xpos=%d, ypos=%d, offset=%d\n",
+                                     new_plane_state->src.x1, new_plane_state->src.y1,
+                                     fb->offsets[0]);
                        return -EINVAL;
                }
 
                if (new_plane_state->rotation && new_plane_state->rotation != DRM_MODE_ROTATE_0) {
-                       DRM_ERROR("No rotation support in AFBC, rotation=%d\n",
-                                 new_plane_state->rotation);
+                       DRM_DEBUG_KMS("No rotation support in AFBC, rotation=%d\n",
+                                     new_plane_state->rotation);
                        return -EINVAL;
                }
        }
index a997dbc..0238078 100644 (file)
 
 #include <linux/crc16.h>
 #include <linux/debugfs.h>
+#include <linux/delay.h>
 #include <linux/hid.h>
 #include <linux/hwmon.h>
 #include <linux/jiffies.h>
+#include <linux/ktime.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/seq_file.h>
@@ -63,6 +65,8 @@ static const char *const aqc_device_names[] = {
 #define CTRL_REPORT_ID                 0x03
 #define AQUAERO_CTRL_REPORT_ID         0x0b
 
+#define CTRL_REPORT_DELAY              200     /* ms */
+
 /* The HID report that the official software always sends
  * after writing values, currently same for all devices
  */
@@ -527,6 +531,9 @@ struct aqc_data {
        int secondary_ctrl_report_size;
        u8 *secondary_ctrl_report;
 
+       ktime_t last_ctrl_report_op;
+       int ctrl_report_delay;  /* Delay between two ctrl report operations, in ms */
+
        int buffer_size;
        u8 *buffer;
        int checksum_start;
@@ -611,17 +618,35 @@ static int aqc_aquastreamxt_convert_fan_rpm(u16 val)
        return 0;
 }
 
+static void aqc_delay_ctrl_report(struct aqc_data *priv)
+{
+       /*
+        * If previous read or write is too close to this one, delay the current operation
+        * to give the device enough time to process the previous one.
+        */
+       if (priv->ctrl_report_delay) {
+               s64 delta = ktime_ms_delta(ktime_get(), priv->last_ctrl_report_op);
+
+               if (delta < priv->ctrl_report_delay)
+                       msleep(priv->ctrl_report_delay - delta);
+       }
+}
+
 /* Expects the mutex to be locked */
 static int aqc_get_ctrl_data(struct aqc_data *priv)
 {
        int ret;
 
+       aqc_delay_ctrl_report(priv);
+
        memset(priv->buffer, 0x00, priv->buffer_size);
        ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
                                 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
        if (ret < 0)
                ret = -ENODATA;
 
+       priv->last_ctrl_report_op = ktime_get();
+
        return ret;
 }
 
@@ -631,6 +656,8 @@ static int aqc_send_ctrl_data(struct aqc_data *priv)
        int ret;
        u16 checksum;
 
+       aqc_delay_ctrl_report(priv);
+
        /* Checksum is not needed for Aquaero */
        if (priv->kind != aquaero) {
                /* Init and xorout value for CRC-16/USB is 0xffff */
@@ -646,12 +673,16 @@ static int aqc_send_ctrl_data(struct aqc_data *priv)
        ret = hid_hw_raw_request(priv->hdev, priv->ctrl_report_id, priv->buffer, priv->buffer_size,
                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
        if (ret < 0)
-               return ret;
+               goto record_access_and_ret;
 
        /* The official software sends this report after every change, so do it here as well */
        ret = hid_hw_raw_request(priv->hdev, priv->secondary_ctrl_report_id,
                                 priv->secondary_ctrl_report, priv->secondary_ctrl_report_size,
                                 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+
+record_access_and_ret:
+       priv->last_ctrl_report_op = ktime_get();
+
        return ret;
 }
 
@@ -1524,6 +1555,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
 
                priv->buffer_size = AQUAERO_CTRL_REPORT_SIZE;
                priv->temp_ctrl_offset = AQUAERO_TEMP_CTRL_OFFSET;
+               priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
                priv->temp_label = label_temp_sensors;
                priv->virtual_temp_label = label_virtual_temp_sensors;
@@ -1547,6 +1579,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                priv->temp_ctrl_offset = D5NEXT_TEMP_CTRL_OFFSET;
 
                priv->buffer_size = D5NEXT_CTRL_REPORT_SIZE;
+               priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
                priv->power_cycle_count_offset = D5NEXT_POWER_CYCLES;
 
@@ -1597,6 +1630,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                priv->temp_ctrl_offset = OCTO_TEMP_CTRL_OFFSET;
 
                priv->buffer_size = OCTO_CTRL_REPORT_SIZE;
+               priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
                priv->power_cycle_count_offset = OCTO_POWER_CYCLES;
 
@@ -1624,6 +1658,7 @@ static int aqc_probe(struct hid_device *hdev, const struct hid_device_id *id)
                priv->temp_ctrl_offset = QUADRO_TEMP_CTRL_OFFSET;
 
                priv->buffer_size = QUADRO_CTRL_REPORT_SIZE;
+               priv->ctrl_report_delay = CTRL_REPORT_DELAY;
 
                priv->flow_pulses_ctrl_offset = QUADRO_FLOW_PULSES_CTRL_OFFSET;
                priv->power_cycle_count_offset = QUADRO_POWER_CYCLES;
index fa5070a..7c5f4b1 100644 (file)
 enum chips {pfe1100, pfe3000};
 
 /*
- * Disable status check for pfe3000 devices, because some devices report
- * communication error (invalid command) for VOUT_MODE command (0x20)
- * although correct VOUT_MODE (0x16) is returned: it leads to incorrect
- * exponent in linear mode.
+ * Disable status check because some devices report communication error
+ * (invalid command) for VOUT_MODE command (0x20) although the correct
+ * VOUT_MODE (0x16) is returned: it leads to incorrect exponent in linear
+ * mode.
+ * This affects both pfe3000 and pfe1100.
  */
-static struct pmbus_platform_data pfe3000_plat_data = {
+static struct pmbus_platform_data pfe_plat_data = {
        .flags = PMBUS_SKIP_STATUS_CHECK,
 };
 
@@ -94,16 +95,15 @@ static int pfe_pmbus_probe(struct i2c_client *client)
        int model;
 
        model = (int)i2c_match_id(pfe_device_id, client)->driver_data;
+       client->dev.platform_data = &pfe_plat_data;
 
        /*
         * PFE3000-12-069RA devices may not stay in page 0 during device
         * probe which leads to probe failure (read status word failed).
         * So let's set the device to page 0 at the beginning.
         */
-       if (model == pfe3000) {
-               client->dev.platform_data = &pfe3000_plat_data;
+       if (model == pfe3000)
                i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0);
-       }
 
        return pmbus_do_probe(client, &pfe_driver_info[model]);
 }
index 8685e0b..7bc3ebf 100644 (file)
@@ -62,7 +62,6 @@
 #define AD7192_MODE_STA_MASK   BIT(20) /* Status Register transmission Mask */
 #define AD7192_MODE_CLKSRC(x)  (((x) & 0x3) << 18) /* Clock Source Select */
 #define AD7192_MODE_SINC3      BIT(15) /* SINC3 Filter Select */
-#define AD7192_MODE_ACX                BIT(14) /* AC excitation enable(AD7195 only)*/
 #define AD7192_MODE_ENPAR      BIT(13) /* Parity Enable */
 #define AD7192_MODE_CLKDIV     BIT(12) /* Clock divide by 2 (AD7190/2 only)*/
 #define AD7192_MODE_SCYCLE     BIT(11) /* Single cycle conversion */
@@ -91,6 +90,7 @@
 /* Configuration Register Bit Designations (AD7192_REG_CONF) */
 
 #define AD7192_CONF_CHOP       BIT(23) /* CHOP enable */
+#define AD7192_CONF_ACX                BIT(22) /* AC excitation enable(AD7195 only) */
 #define AD7192_CONF_REFSEL     BIT(20) /* REFIN1/REFIN2 Reference Select */
 #define AD7192_CONF_CHAN(x)    ((x) << 8) /* Channel select */
 #define AD7192_CONF_CHAN_MASK  (0x7FF << 8) /* Channel select mask */
@@ -472,7 +472,7 @@ static ssize_t ad7192_show_ac_excitation(struct device *dev,
        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
        struct ad7192_state *st = iio_priv(indio_dev);
 
-       return sysfs_emit(buf, "%d\n", !!(st->mode & AD7192_MODE_ACX));
+       return sysfs_emit(buf, "%d\n", !!(st->conf & AD7192_CONF_ACX));
 }
 
 static ssize_t ad7192_show_bridge_switch(struct device *dev,
@@ -513,13 +513,13 @@ static ssize_t ad7192_set(struct device *dev,
 
                ad_sd_write_reg(&st->sd, AD7192_REG_GPOCON, 1, st->gpocon);
                break;
-       case AD7192_REG_MODE:
+       case AD7192_REG_CONF:
                if (val)
-                       st->mode |= AD7192_MODE_ACX;
+                       st->conf |= AD7192_CONF_ACX;
                else
-                       st->mode &= ~AD7192_MODE_ACX;
+                       st->conf &= ~AD7192_CONF_ACX;
 
-               ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode);
+               ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf);
                break;
        default:
                ret = -EINVAL;
@@ -579,12 +579,11 @@ static IIO_DEVICE_ATTR(bridge_switch_en, 0644,
 
 static IIO_DEVICE_ATTR(ac_excitation_en, 0644,
                       ad7192_show_ac_excitation, ad7192_set,
-                      AD7192_REG_MODE);
+                      AD7192_REG_CONF);
 
 static struct attribute *ad7192_attributes[] = {
        &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
        &iio_dev_attr_bridge_switch_en.dev_attr.attr,
-       &iio_dev_attr_ac_excitation_en.dev_attr.attr,
        NULL
 };
 
@@ -595,6 +594,7 @@ static const struct attribute_group ad7192_attribute_group = {
 static struct attribute *ad7195_attributes[] = {
        &iio_dev_attr_filter_low_pass_3db_frequency_available.dev_attr.attr,
        &iio_dev_attr_bridge_switch_en.dev_attr.attr,
+       &iio_dev_attr_ac_excitation_en.dev_attr.attr,
        NULL
 };
 
index 213526c..aea83f3 100644 (file)
@@ -124,6 +124,7 @@ static const struct regmap_config ina2xx_regmap_config = {
 enum ina2xx_ids { ina219, ina226 };
 
 struct ina2xx_config {
+       const char *name;
        u16 config_default;
        int calibration_value;
        int shunt_voltage_lsb;  /* nV */
@@ -155,6 +156,7 @@ struct ina2xx_chip_info {
 
 static const struct ina2xx_config ina2xx_config[] = {
        [ina219] = {
+               .name = "ina219",
                .config_default = INA219_CONFIG_DEFAULT,
                .calibration_value = 4096,
                .shunt_voltage_lsb = 10000,
@@ -164,6 +166,7 @@ static const struct ina2xx_config ina2xx_config[] = {
                .chip_id = ina219,
        },
        [ina226] = {
+               .name = "ina226",
                .config_default = INA226_CONFIG_DEFAULT,
                .calibration_value = 2048,
                .shunt_voltage_lsb = 2500,
@@ -996,7 +999,7 @@ static int ina2xx_probe(struct i2c_client *client)
        /* Patch the current config register with default. */
        val = chip->config->config_default;
 
-       if (id->driver_data == ina226) {
+       if (type == ina226) {
                ina226_set_average(chip, INA226_DEFAULT_AVG, &val);
                ina226_set_int_time_vbus(chip, INA226_DEFAULT_IT, &val);
                ina226_set_int_time_vshunt(chip, INA226_DEFAULT_IT, &val);
@@ -1015,7 +1018,7 @@ static int ina2xx_probe(struct i2c_client *client)
        }
 
        indio_dev->modes = INDIO_DIRECT_MODE;
-       if (id->driver_data == ina226) {
+       if (type == ina226) {
                indio_dev->channels = ina226_channels;
                indio_dev->num_channels = ARRAY_SIZE(ina226_channels);
                indio_dev->info = &ina226_info;
@@ -1024,7 +1027,7 @@ static int ina2xx_probe(struct i2c_client *client)
                indio_dev->num_channels = ARRAY_SIZE(ina219_channels);
                indio_dev->info = &ina219_info;
        }
-       indio_dev->name = id->name;
+       indio_dev->name = id ? id->name : chip->config->name;
 
        ret = devm_iio_kfifo_buffer_setup(&client->dev, indio_dev,
                                          &ina2xx_setup_ops);
index af6bfcc..eb78a6f 100644 (file)
@@ -916,12 +916,6 @@ static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev)
                goto err_vref;
        }
 
-       ret = clk_prepare_enable(priv->core_clk);
-       if (ret) {
-               dev_err(dev, "failed to enable core clk\n");
-               goto err_core_clk;
-       }
-
        regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1);
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0,
                           MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval);
@@ -948,8 +942,6 @@ err_adc_clk:
        regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3,
                           MESON_SAR_ADC_REG3_ADC_EN, 0);
        meson_sar_adc_set_bandgap(indio_dev, false);
-       clk_disable_unprepare(priv->core_clk);
-err_core_clk:
        regulator_disable(priv->vref);
 err_vref:
        meson_sar_adc_unlock(indio_dev);
@@ -977,8 +969,6 @@ static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
 
        meson_sar_adc_set_bandgap(indio_dev, false);
 
-       clk_disable_unprepare(priv->core_clk);
-
        regulator_disable(priv->vref);
 
        if (!ret)
@@ -1211,7 +1201,7 @@ static int meson_sar_adc_probe(struct platform_device *pdev)
        if (IS_ERR(priv->clkin))
                return dev_err_probe(dev, PTR_ERR(priv->clkin), "failed to get clkin\n");
 
-       priv->core_clk = devm_clk_get(dev, "core");
+       priv->core_clk = devm_clk_get_enabled(dev, "core");
        if (IS_ERR(priv->core_clk))
                return dev_err_probe(dev, PTR_ERR(priv->core_clk), "failed to get core clk\n");
 
@@ -1294,15 +1284,26 @@ static int meson_sar_adc_remove(struct platform_device *pdev)
 static int meson_sar_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
 
        meson_sar_adc_hw_disable(indio_dev);
 
+       clk_disable_unprepare(priv->core_clk);
+
        return 0;
 }
 
 static int meson_sar_adc_resume(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
+       int ret;
+
+       ret = clk_prepare_enable(priv->core_clk);
+       if (ret) {
+               dev_err(dev, "failed to enable core clk\n");
+               return ret;
+       }
 
        return meson_sar_adc_hw_enable(indio_dev);
 }
index 943e9e1..b72d39f 100644 (file)
@@ -253,7 +253,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
        platform_set_drvdata(pdev, indio_dev);
 
        state->ec = ec->ec_dev;
-       state->msg = devm_kzalloc(&pdev->dev,
+       state->msg = devm_kzalloc(&pdev->dev, sizeof(*state->msg) +
                                max((u16)sizeof(struct ec_params_motion_sense),
                                state->ec->max_response), GFP_KERNEL);
        if (!state->msg)
index 9bf8337..8c8e0bb 100644 (file)
@@ -344,9 +344,12 @@ static int admv1013_update_quad_filters(struct admv1013_state *st)
 
 static int admv1013_update_mixer_vgate(struct admv1013_state *st)
 {
-       unsigned int vcm, mixer_vgate;
+       unsigned int mixer_vgate;
+       int vcm;
 
        vcm = regulator_get_voltage(st->reg);
+       if (vcm < 0)
+               return vcm;
 
        if (vcm < 1800000)
                mixer_vgate = (2389 * vcm / 1000000 + 8100) / 100;
index 6a18b36..b6e6b1d 100644 (file)
@@ -2687,7 +2687,7 @@ unknown_format:
 static int lsm6dsx_get_acpi_mount_matrix(struct device *dev,
                                          struct iio_mount_matrix *orientation)
 {
-       return false;
+       return -EOPNOTSUPP;
 }
 
 #endif
index c117f50..adcba83 100644 (file)
@@ -1888,7 +1888,7 @@ static const struct iio_buffer_setup_ops noop_ring_setup_ops;
 int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
 {
        struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
-       struct fwnode_handle *fwnode;
+       struct fwnode_handle *fwnode = NULL;
        int ret;
 
        if (!indio_dev->info)
@@ -1899,7 +1899,8 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod)
        /* If the calling driver did not initialize firmware node, do it here */
        if (dev_fwnode(&indio_dev->dev))
                fwnode = dev_fwnode(&indio_dev->dev);
-       else
+       /* The default dummy IIO device has no parent */
+       else if (indio_dev->dev.parent)
                fwnode = dev_fwnode(indio_dev->dev.parent);
        device_set_node(&indio_dev->dev, fwnode);
 
index 489902b..b50bf89 100644 (file)
@@ -190,7 +190,7 @@ static const struct iio_itime_sel_mul bu27008_itimes[] = {
        .address = BU27008_REG_##data##_LO,                                     \
        .scan_index = BU27008_##color,                                          \
        .scan_type = {                                                          \
-               .sign = 's',                                                    \
+               .sign = 'u',                                                    \
                .realbits = 16,                                                 \
                .storagebits = 16,                                              \
                .endianness = IIO_LE,                                           \
@@ -633,7 +633,7 @@ static int bu27008_try_find_new_time_gain(struct bu27008_data *data, int val,
        for (i = 0; i < data->gts.num_itime; i++) {
                new_time_sel = data->gts.itime_table[i].sel;
                ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts,
-                                       new_time_sel, val, val2 * 1000, gain_sel);
+                                       new_time_sel, val, val2, gain_sel);
                if (!ret)
                        break;
        }
@@ -662,7 +662,7 @@ static int bu27008_set_scale(struct bu27008_data *data,
                goto unlock_out;
 
        ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
-                                               val, val2 * 1000, &gain_sel);
+                                               val, val2, &gain_sel);
        if (ret) {
                ret = bu27008_try_find_new_time_gain(data, val, val2, &gain_sel);
                if (ret)
@@ -677,6 +677,21 @@ unlock_out:
        return ret;
 }
 
+static int bu27008_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long mask)
+{
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_INT_TIME:
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int bu27008_write_raw(struct iio_dev *idev,
                             struct iio_chan_spec const *chan,
                             int val, int val2, long mask)
@@ -756,6 +771,7 @@ static int bu27008_update_scan_mode(struct iio_dev *idev,
 static const struct iio_info bu27008_info = {
        .read_raw = &bu27008_read_raw,
        .write_raw = &bu27008_write_raw,
+       .write_raw_get_fmt = &bu27008_write_raw_get_fmt,
        .read_avail = &bu27008_read_avail,
        .update_scan_mode = bu27008_update_scan_mode,
        .validate_trigger = iio_validate_own_trigger,
index e63ef57..bf3de85 100644 (file)
@@ -575,7 +575,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
                return -EINVAL;
 
        if (chan == BU27034_CHAN_ALS) {
-               if (val == 0 && val2 == 1000)
+               if (val == 0 && val2 == 1000000)
                        return 0;
 
                return -EINVAL;
@@ -587,7 +587,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
                goto unlock_out;
 
        ret = iio_gts_find_gain_sel_for_scale_using_time(&data->gts, time_sel,
-                                               val, val2 * 1000, &gain_sel);
+                                               val, val2, &gain_sel);
        if (ret) {
                /*
                 * Could not support scale with given time. Need to change time.
@@ -624,7 +624,7 @@ static int bu27034_set_scale(struct bu27034_data *data, int chan,
 
                        /* Can we provide requested scale with this time? */
                        ret = iio_gts_find_gain_sel_for_scale_using_time(
-                               &data->gts, new_time_sel, val, val2 * 1000,
+                               &data->gts, new_time_sel, val, val2,
                                &gain_sel);
                        if (ret)
                                continue;
@@ -1217,6 +1217,21 @@ static int bu27034_read_raw(struct iio_dev *idev,
        }
 }
 
+static int bu27034_write_raw_get_fmt(struct iio_dev *indio_dev,
+                                    struct iio_chan_spec const *chan,
+                                    long mask)
+{
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_INT_TIME:
+               return IIO_VAL_INT_PLUS_MICRO;
+       default:
+               return -EINVAL;
+       }
+}
+
 static int bu27034_write_raw(struct iio_dev *idev,
                             struct iio_chan_spec const *chan,
                             int val, int val2, long mask)
@@ -1267,6 +1282,7 @@ static int bu27034_read_avail(struct iio_dev *idev,
 static const struct iio_info bu27034_info = {
        .read_raw = &bu27034_read_raw,
        .write_raw = &bu27034_write_raw,
+       .write_raw_get_fmt = &bu27034_write_raw_get_fmt,
        .read_avail = &bu27034_read_avail,
 };
 
index 755a9c5..f9ab671 100644 (file)
@@ -85,6 +85,8 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
        dma_addr_t mask;
        int i;
 
+       umem->iova = va = virt;
+
        if (umem->is_odp) {
                unsigned int page_size = BIT(to_ib_umem_odp(umem)->page_shift);
 
@@ -100,7 +102,6 @@ unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
         */
        pgsz_bitmap &= GENMASK(BITS_PER_LONG - 1, PAGE_SHIFT);
 
-       umem->iova = va = virt;
        /* The best result is the smallest page size that results in the minimum
         * number of required pages. Compute the largest page size that could
         * work based on VA address bits that don't change.
index b42166f..63e98e2 100644 (file)
@@ -1253,6 +1253,8 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode)
 
        rc = bnxt_re_setup_chip_ctx(rdev, wqe_mode);
        if (rc) {
+               bnxt_unregister_dev(rdev->en_dev);
+               clear_bit(BNXT_RE_FLAG_NETDEV_REGISTERED, &rdev->flags);
                ibdev_err(&rdev->ibdev, "Failed to get chip context\n");
                return -EINVAL;
        }
@@ -1526,8 +1528,8 @@ static void bnxt_re_remove(struct auxiliary_device *adev)
        }
        bnxt_re_setup_cc(rdev, false);
        ib_unregister_device(&rdev->ibdev);
-       ib_dealloc_device(&rdev->ibdev);
        bnxt_re_dev_uninit(rdev);
+       ib_dealloc_device(&rdev->ibdev);
 skip_remove:
        mutex_unlock(&bnxt_re_mutex);
 }
index 5fd8f7c..739d942 100644 (file)
@@ -819,6 +819,7 @@ static int bnxt_qplib_alloc_dpi_tbl(struct bnxt_qplib_res *res,
        }
 
        memset((u8 *)dpit->tbl, 0xFF, bytes);
+       mutex_init(&res->dpi_tbl_lock);
        dpit->priv_db = dpit->ucreg.bar_reg + dpit->ucreg.offset;
 
        return 0;
index 9dbb89e..baaa440 100644 (file)
@@ -12307,6 +12307,7 @@ static void free_cntrs(struct hfi1_devdata *dd)
 
        if (dd->synth_stats_timer.function)
                del_timer_sync(&dd->synth_stats_timer);
+       cancel_work_sync(&dd->update_cntr_work);
        ppd = (struct hfi1_pportdata *)(dd + 1);
        for (i = 0; i < dd->num_pports; i++, ppd++) {
                kfree(ppd->cntrs);
index 8f385f9..d5f2a6b 100644 (file)
@@ -83,6 +83,11 @@ static void bcm_aggregate(struct qcom_icc_bcm *bcm)
 
                temp = agg_peak[bucket] * bcm->vote_scale;
                bcm->vote_y[bucket] = bcm_div(temp, bcm->aux_data.unit);
+
+               if (bcm->enable_mask && (bcm->vote_x[bucket] || bcm->vote_y[bucket])) {
+                       bcm->vote_x[bucket] = 0;
+                       bcm->vote_y[bucket] = bcm->enable_mask;
+               }
        }
 
        if (bcm->keepalive && bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 &&
index 04391c1..7843d88 100644 (file)
@@ -81,6 +81,7 @@ struct qcom_icc_node {
  * @vote_x: aggregated threshold values, represents sum_bw when @type is bw bcm
  * @vote_y: aggregated threshold values, represents peak_bw when @type is bw bcm
  * @vote_scale: scaling factor for vote_x and vote_y
+ * @enable_mask: optional mask to send as vote instead of vote_x/vote_y
  * @dirty: flag used to indicate whether the bcm needs to be committed
  * @keepalive: flag used to indicate whether a keepalive is required
  * @aux_data: auxiliary data used when calculating threshold values and
@@ -97,6 +98,7 @@ struct qcom_icc_bcm {
        u64 vote_x[QCOM_ICC_NUM_BUCKETS];
        u64 vote_y[QCOM_ICC_NUM_BUCKETS];
        u64 vote_scale;
+       u32 enable_mask;
        bool dirty;
        bool keepalive;
        struct bcm_db aux_data;
index da21cc3..f565386 100644 (file)
@@ -1873,6 +1873,7 @@ static struct qcom_icc_node srvc_snoc = {
 
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
+       .enable_mask = 0x8,
        .num_nodes = 1,
        .nodes = { &ebi },
 };
index 2d7a8e7..e64c214 100644 (file)
@@ -1337,6 +1337,7 @@ static struct qcom_icc_node qns_mem_noc_sf_disp = {
 
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
+       .enable_mask = 0x8,
        .num_nodes = 1,
        .nodes = { &ebi },
 };
@@ -1349,6 +1350,7 @@ static struct qcom_icc_bcm bcm_ce0 = {
 
 static struct qcom_icc_bcm bcm_cn0 = {
        .name = "CN0",
+       .enable_mask = 0x1,
        .keepalive = true,
        .num_nodes = 55,
        .nodes = { &qnm_gemnoc_cnoc, &qnm_gemnoc_pcie,
@@ -1383,6 +1385,7 @@ static struct qcom_icc_bcm bcm_cn0 = {
 
 static struct qcom_icc_bcm bcm_co0 = {
        .name = "CO0",
+       .enable_mask = 0x1,
        .num_nodes = 2,
        .nodes = { &qxm_nsp, &qns_nsp_gemnoc },
 };
@@ -1403,6 +1406,7 @@ static struct qcom_icc_bcm bcm_mm0 = {
 
 static struct qcom_icc_bcm bcm_mm1 = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 12,
        .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp,
                   &qnm_camnoc_sf, &qnm_mdp,
@@ -1445,6 +1449,7 @@ static struct qcom_icc_bcm bcm_sh0 = {
 
 static struct qcom_icc_bcm bcm_sh1 = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 7,
        .nodes = { &alm_gpu_tcu, &alm_sys_tcu,
                   &qnm_nsp_gemnoc, &qnm_pcie,
@@ -1461,6 +1466,7 @@ static struct qcom_icc_bcm bcm_sn0 = {
 
 static struct qcom_icc_bcm bcm_sn1 = {
        .name = "SN1",
+       .enable_mask = 0x1,
        .num_nodes = 4,
        .nodes = { &qhm_gic, &qxm_pimem,
                   &xm_gic, &qns_gemnoc_gc },
@@ -1492,6 +1498,7 @@ static struct qcom_icc_bcm bcm_sn7 = {
 
 static struct qcom_icc_bcm bcm_acv_disp = {
        .name = "ACV",
+       .enable_mask = 0x1,
        .num_nodes = 1,
        .nodes = { &ebi_disp },
 };
@@ -1510,6 +1517,7 @@ static struct qcom_icc_bcm bcm_mm0_disp = {
 
 static struct qcom_icc_bcm bcm_mm1_disp = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 3,
        .nodes = { &qnm_mdp_disp, &qnm_rot_disp,
                   &qns_mem_noc_sf_disp },
@@ -1523,6 +1531,7 @@ static struct qcom_icc_bcm bcm_sh0_disp = {
 
 static struct qcom_icc_bcm bcm_sh1_disp = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 1,
        .nodes = { &qnm_pcie_disp },
 };
index d823ba9..0864ed2 100644 (file)
@@ -1473,6 +1473,7 @@ static struct qcom_icc_node qns_mem_noc_sf_cam_ife_2 = {
 
 static struct qcom_icc_bcm bcm_acv = {
        .name = "ACV",
+       .enable_mask = 0x8,
        .num_nodes = 1,
        .nodes = { &ebi },
 };
@@ -1485,6 +1486,7 @@ static struct qcom_icc_bcm bcm_ce0 = {
 
 static struct qcom_icc_bcm bcm_cn0 = {
        .name = "CN0",
+       .enable_mask = 0x1,
        .keepalive = true,
        .num_nodes = 54,
        .nodes = { &qsm_cfg, &qhs_ahb2phy0,
@@ -1524,6 +1526,7 @@ static struct qcom_icc_bcm bcm_cn1 = {
 
 static struct qcom_icc_bcm bcm_co0 = {
        .name = "CO0",
+       .enable_mask = 0x1,
        .num_nodes = 2,
        .nodes = { &qxm_nsp, &qns_nsp_gemnoc },
 };
@@ -1549,6 +1552,7 @@ static struct qcom_icc_bcm bcm_mm0 = {
 
 static struct qcom_icc_bcm bcm_mm1 = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 8,
        .nodes = { &qnm_camnoc_hf, &qnm_camnoc_icp,
                   &qnm_camnoc_sf, &qnm_vapss_hcp,
@@ -1589,6 +1593,7 @@ static struct qcom_icc_bcm bcm_sh0 = {
 
 static struct qcom_icc_bcm bcm_sh1 = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 13,
        .nodes = { &alm_gpu_tcu, &alm_sys_tcu,
                   &chm_apps, &qnm_gpu,
@@ -1608,6 +1613,7 @@ static struct qcom_icc_bcm bcm_sn0 = {
 
 static struct qcom_icc_bcm bcm_sn1 = {
        .name = "SN1",
+       .enable_mask = 0x1,
        .num_nodes = 3,
        .nodes = { &qhm_gic, &xm_gic,
                   &qns_gemnoc_gc },
@@ -1633,6 +1639,7 @@ static struct qcom_icc_bcm bcm_sn7 = {
 
 static struct qcom_icc_bcm bcm_acv_disp = {
        .name = "ACV",
+       .enable_mask = 0x1,
        .num_nodes = 1,
        .nodes = { &ebi_disp },
 };
@@ -1657,12 +1664,14 @@ static struct qcom_icc_bcm bcm_sh0_disp = {
 
 static struct qcom_icc_bcm bcm_sh1_disp = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 2,
        .nodes = { &qnm_mnoc_hf_disp, &qnm_pcie_disp },
 };
 
 static struct qcom_icc_bcm bcm_acv_cam_ife_0 = {
        .name = "ACV",
+       .enable_mask = 0x0,
        .num_nodes = 1,
        .nodes = { &ebi_cam_ife_0 },
 };
@@ -1681,6 +1690,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_0 = {
 
 static struct qcom_icc_bcm bcm_mm1_cam_ife_0 = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 4,
        .nodes = { &qnm_camnoc_hf_cam_ife_0, &qnm_camnoc_icp_cam_ife_0,
                   &qnm_camnoc_sf_cam_ife_0, &qns_mem_noc_sf_cam_ife_0 },
@@ -1694,6 +1704,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_0 = {
 
 static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 3,
        .nodes = { &qnm_mnoc_hf_cam_ife_0, &qnm_mnoc_sf_cam_ife_0,
                   &qnm_pcie_cam_ife_0 },
@@ -1701,6 +1712,7 @@ static struct qcom_icc_bcm bcm_sh1_cam_ife_0 = {
 
 static struct qcom_icc_bcm bcm_acv_cam_ife_1 = {
        .name = "ACV",
+       .enable_mask = 0x0,
        .num_nodes = 1,
        .nodes = { &ebi_cam_ife_1 },
 };
@@ -1719,6 +1731,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_1 = {
 
 static struct qcom_icc_bcm bcm_mm1_cam_ife_1 = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 4,
        .nodes = { &qnm_camnoc_hf_cam_ife_1, &qnm_camnoc_icp_cam_ife_1,
                   &qnm_camnoc_sf_cam_ife_1, &qns_mem_noc_sf_cam_ife_1 },
@@ -1732,6 +1745,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_1 = {
 
 static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 3,
        .nodes = { &qnm_mnoc_hf_cam_ife_1, &qnm_mnoc_sf_cam_ife_1,
                   &qnm_pcie_cam_ife_1 },
@@ -1739,6 +1753,7 @@ static struct qcom_icc_bcm bcm_sh1_cam_ife_1 = {
 
 static struct qcom_icc_bcm bcm_acv_cam_ife_2 = {
        .name = "ACV",
+       .enable_mask = 0x0,
        .num_nodes = 1,
        .nodes = { &ebi_cam_ife_2 },
 };
@@ -1757,6 +1772,7 @@ static struct qcom_icc_bcm bcm_mm0_cam_ife_2 = {
 
 static struct qcom_icc_bcm bcm_mm1_cam_ife_2 = {
        .name = "MM1",
+       .enable_mask = 0x1,
        .num_nodes = 4,
        .nodes = { &qnm_camnoc_hf_cam_ife_2, &qnm_camnoc_icp_cam_ife_2,
                   &qnm_camnoc_sf_cam_ife_2, &qns_mem_noc_sf_cam_ife_2 },
@@ -1770,6 +1786,7 @@ static struct qcom_icc_bcm bcm_sh0_cam_ife_2 = {
 
 static struct qcom_icc_bcm bcm_sh1_cam_ife_2 = {
        .name = "SH1",
+       .enable_mask = 0x1,
        .num_nodes = 3,
        .nodes = { &qnm_mnoc_hf_cam_ife_2, &qnm_mnoc_sf_cam_ife_2,
                   &qnm_pcie_cam_ife_2 },
index d676cf6..3dae5e3 100644 (file)
@@ -195,7 +195,7 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
                }
        }
 
-       if (option->force_clkreq_0)
+       if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG)
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG,
                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
        else
index cfebad5..f4ab094 100644 (file)
@@ -435,17 +435,10 @@ static void rts5228_init_from_cfg(struct rtsx_pcr *pcr)
                        option->ltr_enabled = false;
                }
        }
-
-       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-                               | PM_L1_1_EN | PM_L1_2_EN))
-               option->force_clkreq_0 = false;
-       else
-               option->force_clkreq_0 = true;
 }
 
 static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
 {
-       struct rtsx_cr_option *option = &pcr->option;
 
        rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1,
                        CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
@@ -476,17 +469,6 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
        else
                rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
 
-       /*
-        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
-        * to drive low, and we forcibly request clock.
-        */
-       if (option->force_clkreq_0)
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
-       else
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
-
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
 
        if (pcr->rtd3_en) {
index 91d240d..47ab72a 100644 (file)
@@ -327,12 +327,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
                }
        }
 
-
        /*
         * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
         * to drive low, and we forcibly request clock.
         */
-       if (option->force_clkreq_0)
+       if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG)
                rtsx_pci_write_register(pcr, PETXCFG,
                        FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
        else
index 9b42b20..79b18f6 100644 (file)
@@ -517,17 +517,10 @@ static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
                        option->ltr_enabled = false;
                }
        }
-
-       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-                               | PM_L1_1_EN | PM_L1_2_EN))
-               option->force_clkreq_0 = false;
-       else
-               option->force_clkreq_0 = true;
 }
 
 static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
 {
-       struct rtsx_cr_option *option = &pcr->option;
 
        /* Set mcu_cnt to 7 to ensure data can be sampled properly */
        rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07);
@@ -546,17 +539,6 @@ static int rts5260_extra_init_hw(struct rtsx_pcr *pcr)
 
        rts5260_init_hw(pcr);
 
-       /*
-        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
-        * to drive low, and we forcibly request clock.
-        */
-       if (option->force_clkreq_0)
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
-       else
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
-
        rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
 
        return 0;
index b1e7603..94af6bf 100644 (file)
@@ -498,17 +498,10 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
                        option->ltr_enabled = false;
                }
        }
-
-       if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
-                               | PM_L1_1_EN | PM_L1_2_EN))
-               option->force_clkreq_0 = false;
-       else
-               option->force_clkreq_0 = true;
 }
 
 static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
 {
-       struct rtsx_cr_option *option = &pcr->option;
        u32 val;
 
        rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1,
@@ -554,17 +547,6 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr)
        else
                rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
 
-       /*
-        * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
-        * to drive low, and we forcibly request clock.
-        */
-       if (option->force_clkreq_0)
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
-       else
-               rtsx_pci_write_register(pcr, PETXCFG,
-                                FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
-
        rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
 
        if (pcr->rtd3_en) {
index 32b7783..a3f4b52 100644 (file)
@@ -1326,8 +1326,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
                        return err;
        }
 
-       if (pcr->aspm_mode == ASPM_MODE_REG)
+       if (pcr->aspm_mode == ASPM_MODE_REG) {
                rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0x30, 0x30);
+               rtsx_pci_write_register(pcr, PETXCFG,
+                               FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
+       }
 
        /* No CD interrupt if probing driver with card inserted.
         * So we need to initialize pcr->card_exist here.
index b488f70..05e2c15 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <linux/mfd/tps6594.h>
 
+#define TPS6594_DEV_REV_1 0x08
+
 static irqreturn_t tps6594_esm_isr(int irq, void *dev_id)
 {
        struct platform_device *pdev = dev_id;
@@ -32,11 +34,26 @@ static int tps6594_esm_probe(struct platform_device *pdev)
 {
        struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
        struct device *dev = &pdev->dev;
+       unsigned int rev;
        int irq;
        int ret;
        int i;
 
-       for (i = 0 ; i < pdev->num_resources ; i++) {
+       /*
+        * Due to a bug in revision 1 of the PMIC, the GPIO3 used for the
+        * SoC ESM function is used to power the load switch instead.
+        * As a consequence, ESM can not be used on those PMIC.
+        * Check the version and return an error in case of revision 1.
+        */
+       ret = regmap_read(tps->regmap, TPS6594_REG_DEV_REV, &rev);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to read PMIC revision\n");
+       if (rev == TPS6594_DEV_REV_1)
+               return dev_err_probe(dev, -ENODEV,
+                             "ESM not supported for revision 1 PMIC\n");
+
+       for (i = 0; i < pdev->num_resources; i++) {
                irq = platform_get_irq_byname(pdev, pdev->resource[i].name);
                if (irq < 0)
                        return dev_err_probe(dev, irq, "Failed to get %s irq\n",
index be43cd0..44eeb5d 100644 (file)
@@ -332,6 +332,28 @@ config NETCONSOLE_DYNAMIC
          at runtime through a userspace interface exported using configfs.
          See <file:Documentation/networking/netconsole.rst> for details.
 
+config NETCONSOLE_EXTENDED_LOG
+       bool "Set kernel extended message by default"
+       depends on NETCONSOLE
+       default n
+       help
+         Set extended log support for netconsole message. If this option is
+         set, log messages are transmitted with extended metadata header in a
+         format similar to /dev/kmsg.  See
+         <file:Documentation/networking/netconsole.rst> for details.
+
+config NETCONSOLE_PREPEND_RELEASE
+       bool "Prepend kernel release version in the message by default"
+       depends on NETCONSOLE_EXTENDED_LOG
+       default n
+       help
+         Set kernel release to be prepended to each netconsole message by
+         default. If this option is set, the kernel release is prepended into
+         the first field of every netconsole message, so, the netconsole
+         server/peer can easily identify what kernel release is logging each
+         message.  See <file:Documentation/networking/netconsole.rst> for
+         details.
+
 config NETPOLL
        def_bool NETCONSOLE
 
index bce9c9e..52a99d8 100644 (file)
@@ -2952,6 +2952,14 @@ static void mv88e6xxx_hardware_reset(struct mv88e6xxx_chip *chip)
 
        /* If there is a GPIO connected to the reset pin, toggle it */
        if (gpiod) {
+               /* If the switch has just been reset and not yet completed
+                * loading EEPROM, the reset may interrupt the I2C transaction
+                * mid-byte, causing the first EEPROM read after the reset
+                * from the wrong location resulting in the switch booting
+                * to wrong mode and inoperable.
+                */
+               mv88e6xxx_g1_wait_eeprom_done(chip);
+
                gpiod_set_value_cansleep(gpiod, 1);
                usleep_range(10000, 20000);
                gpiod_set_value_cansleep(gpiod, 0);
index d19593f..ad32ca8 100644 (file)
@@ -3267,7 +3267,7 @@ static void ena_config_host_info(struct ena_com_dev *ena_dev, struct pci_dev *pd
 
        host_info = ena_dev->host_attr.host_info;
 
-       host_info->bdf = (pdev->bus->number << 8) | pdev->devfn;
+       host_info->bdf = pci_dev_id(pdev);
        host_info->os_type = ENA_ADMIN_OS_LINUX;
        host_info->kernel_ver = LINUX_VERSION_CODE;
        strscpy(host_info->kernel_ver_str, utsname()->version,
index 392ec09..3e4fb3c 100644 (file)
@@ -1793,11 +1793,9 @@ static int b44_nway_reset(struct net_device *dev)
        b44_readphy(bp, MII_BMCR, &bmcr);
        b44_readphy(bp, MII_BMCR, &bmcr);
        r = -EINVAL;
-       if (bmcr & BMCR_ANENABLE) {
-               b44_writephy(bp, MII_BMCR,
-                            bmcr | BMCR_ANRESTART);
-               r = 0;
-       }
+       if (bmcr & BMCR_ANENABLE)
+               r = b44_writephy(bp, MII_BMCR,
+                                bmcr | BMCR_ANRESTART);
        spin_unlock_irq(&bp->lock);
 
        return r;
index b61566a..31f664e 100644 (file)
@@ -5193,6 +5193,9 @@ static int __maybe_unused macb_suspend(struct device *dev)
        unsigned int q;
        int err;
 
+       if (!device_may_wakeup(&bp->dev->dev))
+               phy_exit(bp->sgmii_phy);
+
        if (!netif_running(netdev))
                return 0;
 
@@ -5253,7 +5256,6 @@ static int __maybe_unused macb_suspend(struct device *dev)
        if (!(bp->wol & MACB_WOL_ENABLED)) {
                rtnl_lock();
                phylink_stop(bp->phylink);
-               phy_exit(bp->sgmii_phy);
                rtnl_unlock();
                spin_lock_irqsave(&bp->lock, flags);
                macb_reset_hw(bp);
@@ -5283,6 +5285,9 @@ static int __maybe_unused macb_resume(struct device *dev)
        unsigned int q;
        int err;
 
+       if (!device_may_wakeup(&bp->dev->dev))
+               phy_init(bp->sgmii_phy);
+
        if (!netif_running(netdev))
                return 0;
 
@@ -5343,8 +5348,6 @@ static int __maybe_unused macb_resume(struct device *dev)
        macb_set_rx_mode(netdev);
        macb_restore_features(bp);
        rtnl_lock();
-       if (!device_may_wakeup(&bp->dev->dev))
-               phy_init(bp->sgmii_phy);
 
        phylink_start(bp->phylink);
        rtnl_unlock();
index f77105f..e23a559 100644 (file)
@@ -1494,7 +1494,7 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id, int budget)
                        }
 
                        /* Free the sk buffer associated with this last transmit */
-                       dev_kfree_skb_any(skb);
+                       napi_consume_skb(skb, budget);
                } else if (txq->tx_buf[index].type == FEC_TXBUF_T_XDP_NDO) {
                        xdp_return_frame_rx_napi(xdpf);
                } else { /* recycle pages of XDP_TX frames */
index 4bb300f..07a46ad 100644 (file)
@@ -210,11 +210,11 @@ read_nvm_exit:
  * @hw: pointer to the HW structure.
  * @module_pointer: module pointer location in words from the NVM beginning
  * @offset: offset in words from module start
- * @words: number of words to write
- * @data: buffer with words to write to the Shadow RAM
+ * @words: number of words to read
+ * @data: buffer with words to read to the Shadow RAM
  * @last_command: tells the AdminQ that this is the last command
  *
- * Writes a 16 bit words buffer to the Shadow RAM using the admin command.
+ * Reads a 16 bit words buffer to the Shadow RAM using the admin command.
  **/
 static int i40e_read_nvm_aq(struct i40e_hw *hw,
                            u8 module_pointer, u32 offset,
@@ -234,18 +234,18 @@ static int i40e_read_nvm_aq(struct i40e_hw *hw,
         */
        if ((offset + words) > hw->nvm.sr_size)
                i40e_debug(hw, I40E_DEBUG_NVM,
-                          "NVM write error: offset %d beyond Shadow RAM limit %d\n",
+                          "NVM read error: offset %d beyond Shadow RAM limit %d\n",
                           (offset + words), hw->nvm.sr_size);
        else if (words > I40E_SR_SECTOR_SIZE_IN_WORDS)
-               /* We can write only up to 4KB (one sector), in one AQ write */
+               /* We can read only up to 4KB (one sector), in one AQ write */
                i40e_debug(hw, I40E_DEBUG_NVM,
-                          "NVM write fail error: tried to write %d words, limit is %d.\n",
+                          "NVM read fail error: tried to read %d words, limit is %d.\n",
                           words, I40E_SR_SECTOR_SIZE_IN_WORDS);
        else if (((offset + (words - 1)) / I40E_SR_SECTOR_SIZE_IN_WORDS)
                 != (offset / I40E_SR_SECTOR_SIZE_IN_WORDS))
-               /* A single write cannot spread over two sectors */
+               /* A single read cannot spread over two sectors */
                i40e_debug(hw, I40E_DEBUG_NVM,
-                          "NVM write error: cannot spread over two sectors in a single write offset=%d words=%d\n",
+                          "NVM read error: cannot spread over two sectors in a single read offset=%d words=%d\n",
                           offset, words);
        else
                ret_code = i40e_aq_read_nvm(hw, module_pointer,
index 460ca56..a34303a 100644 (file)
@@ -1289,6 +1289,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                fltr->ip_mask.src_port = fsp->m_u.tcp_ip4_spec.psrc;
                fltr->ip_mask.dst_port = fsp->m_u.tcp_ip4_spec.pdst;
                fltr->ip_mask.tos = fsp->m_u.tcp_ip4_spec.tos;
+               fltr->ip_ver = 4;
                break;
        case AH_V4_FLOW:
        case ESP_V4_FLOW:
@@ -1300,6 +1301,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                fltr->ip_mask.v4_addrs.dst_ip = fsp->m_u.ah_ip4_spec.ip4dst;
                fltr->ip_mask.spi = fsp->m_u.ah_ip4_spec.spi;
                fltr->ip_mask.tos = fsp->m_u.ah_ip4_spec.tos;
+               fltr->ip_ver = 4;
                break;
        case IPV4_USER_FLOW:
                fltr->ip_data.v4_addrs.src_ip = fsp->h_u.usr_ip4_spec.ip4src;
@@ -1312,6 +1314,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                fltr->ip_mask.l4_header = fsp->m_u.usr_ip4_spec.l4_4_bytes;
                fltr->ip_mask.tos = fsp->m_u.usr_ip4_spec.tos;
                fltr->ip_mask.proto = fsp->m_u.usr_ip4_spec.proto;
+               fltr->ip_ver = 4;
                break;
        case TCP_V6_FLOW:
        case UDP_V6_FLOW:
@@ -1330,6 +1333,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                fltr->ip_mask.src_port = fsp->m_u.tcp_ip6_spec.psrc;
                fltr->ip_mask.dst_port = fsp->m_u.tcp_ip6_spec.pdst;
                fltr->ip_mask.tclass = fsp->m_u.tcp_ip6_spec.tclass;
+               fltr->ip_ver = 6;
                break;
        case AH_V6_FLOW:
        case ESP_V6_FLOW:
@@ -1345,6 +1349,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                       sizeof(struct in6_addr));
                fltr->ip_mask.spi = fsp->m_u.ah_ip6_spec.spi;
                fltr->ip_mask.tclass = fsp->m_u.ah_ip6_spec.tclass;
+               fltr->ip_ver = 6;
                break;
        case IPV6_USER_FLOW:
                memcpy(&fltr->ip_data.v6_addrs.src_ip, fsp->h_u.usr_ip6_spec.ip6src,
@@ -1361,6 +1366,7 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                fltr->ip_mask.l4_header = fsp->m_u.usr_ip6_spec.l4_4_bytes;
                fltr->ip_mask.tclass = fsp->m_u.usr_ip6_spec.tclass;
                fltr->ip_mask.proto = fsp->m_u.usr_ip6_spec.l4_proto;
+               fltr->ip_ver = 6;
                break;
        case ETHER_FLOW:
                fltr->eth_data.etype = fsp->h_u.ether_spec.h_proto;
@@ -1371,6 +1377,10 @@ iavf_add_fdir_fltr_info(struct iavf_adapter *adapter, struct ethtool_rx_flow_spe
                return -EINVAL;
        }
 
+       err = iavf_validate_fdir_fltr_masks(adapter, fltr);
+       if (err)
+               return err;
+
        if (iavf_fdir_is_dup_fltr(adapter, fltr))
                return -EEXIST;
 
index 505e82e..03e774b 100644 (file)
@@ -18,6 +18,79 @@ static const struct in6_addr ipv6_addr_full_mask = {
        }
 };
 
+static const struct in6_addr ipv6_addr_zero_mask = {
+       .in6_u = {
+               .u6_addr8 = {
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+               }
+       }
+};
+
+/**
+ * iavf_validate_fdir_fltr_masks - validate Flow Director filter fields masks
+ * @adapter: pointer to the VF adapter structure
+ * @fltr: Flow Director filter data structure
+ *
+ * Returns 0 if all masks of packet fields are either full or empty. Returns
+ * error on at least one partial mask.
+ */
+int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
+                                 struct iavf_fdir_fltr *fltr)
+{
+       if (fltr->eth_mask.etype && fltr->eth_mask.etype != htons(U16_MAX))
+               goto partial_mask;
+
+       if (fltr->ip_ver == 4) {
+               if (fltr->ip_mask.v4_addrs.src_ip &&
+                   fltr->ip_mask.v4_addrs.src_ip != htonl(U32_MAX))
+                       goto partial_mask;
+
+               if (fltr->ip_mask.v4_addrs.dst_ip &&
+                   fltr->ip_mask.v4_addrs.dst_ip != htonl(U32_MAX))
+                       goto partial_mask;
+
+               if (fltr->ip_mask.tos && fltr->ip_mask.tos != U8_MAX)
+                       goto partial_mask;
+       } else if (fltr->ip_ver == 6) {
+               if (memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_zero_mask,
+                          sizeof(struct in6_addr)) &&
+                   memcmp(&fltr->ip_mask.v6_addrs.src_ip, &ipv6_addr_full_mask,
+                          sizeof(struct in6_addr)))
+                       goto partial_mask;
+
+               if (memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_zero_mask,
+                          sizeof(struct in6_addr)) &&
+                   memcmp(&fltr->ip_mask.v6_addrs.dst_ip, &ipv6_addr_full_mask,
+                          sizeof(struct in6_addr)))
+                       goto partial_mask;
+
+               if (fltr->ip_mask.tclass && fltr->ip_mask.tclass != U8_MAX)
+                       goto partial_mask;
+       }
+
+       if (fltr->ip_mask.proto && fltr->ip_mask.proto != U8_MAX)
+               goto partial_mask;
+
+       if (fltr->ip_mask.src_port && fltr->ip_mask.src_port != htons(U16_MAX))
+               goto partial_mask;
+
+       if (fltr->ip_mask.dst_port && fltr->ip_mask.dst_port != htons(U16_MAX))
+               goto partial_mask;
+
+       if (fltr->ip_mask.spi && fltr->ip_mask.spi != htonl(U32_MAX))
+               goto partial_mask;
+
+       if (fltr->ip_mask.l4_header &&
+           fltr->ip_mask.l4_header != htonl(U32_MAX))
+               goto partial_mask;
+
+       return 0;
+
+partial_mask:
+       dev_err(&adapter->pdev->dev, "Failed to add Flow Director filter, partial masks are not supported\n");
+       return -EOPNOTSUPP;
+}
+
 /**
  * iavf_pkt_udp_no_pay_len - the length of UDP packet without payload
  * @fltr: Flow Director filter data structure
@@ -263,8 +336,6 @@ iavf_fill_fdir_ip4_hdr(struct iavf_fdir_fltr *fltr,
                VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV4, DST);
        }
 
-       fltr->ip_ver = 4;
-
        return 0;
 }
 
@@ -309,8 +380,6 @@ iavf_fill_fdir_ip6_hdr(struct iavf_fdir_fltr *fltr,
                VIRTCHNL_ADD_PROTO_HDR_FIELD_BIT(hdr, IPV6, DST);
        }
 
-       fltr->ip_ver = 6;
-
        return 0;
 }
 
index 33c55c3..9eb9f73 100644 (file)
@@ -110,6 +110,8 @@ struct iavf_fdir_fltr {
        struct virtchnl_fdir_add vc_add_msg;
 };
 
+int iavf_validate_fdir_fltr_masks(struct iavf_adapter *adapter,
+                                 struct iavf_fdir_fltr *fltr);
 int iavf_fill_fdir_add_msg(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
 void iavf_print_fdir_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
 bool iavf_fdir_is_dup_fltr(struct iavf_adapter *adapter, struct iavf_fdir_fltr *fltr);
index 9a53a5e..03d0e75 100644 (file)
@@ -574,6 +574,12 @@ ice_eswitch_mode_set(struct devlink *devlink, u16 mode,
                break;
        case DEVLINK_ESWITCH_MODE_SWITCHDEV:
        {
+               if (ice_is_adq_active(pf)) {
+                       dev_err(ice_pf_to_dev(pf), "Couldn't change eswitch mode to switchdev - ADQ is active. Delete ADQ configs and try again, e.g. tc qdisc del dev $PF root");
+                       NL_SET_ERR_MSG_MOD(extack, "Couldn't change eswitch mode to switchdev - ADQ is active. Delete ADQ configs and try again, e.g. tc qdisc del dev $PF root");
+                       return -EOPNOTSUPP;
+               }
+
                dev_info(ice_pf_to_dev(pf), "PF %d changed eswitch mode to switchdev",
                         pf->hw.pf_id);
                NL_SET_ERR_MSG_MOD(extack, "Changed eswitch mode to switchdev");
index 0f04347..dba81aa 100644 (file)
@@ -8889,6 +8889,11 @@ ice_setup_tc(struct net_device *netdev, enum tc_setup_type type,
                                                  ice_setup_tc_block_cb,
                                                  np, np, true);
        case TC_SETUP_QDISC_MQPRIO:
+               if (ice_is_eswitch_mode_switchdev(pf)) {
+                       netdev_err(netdev, "TC MQPRIO offload not supported, switchdev is enabled\n");
+                       return -EOPNOTSUPP;
+               }
+
                if (pf->adev) {
                        mutex_lock(&pf->adev_mutex);
                        device_lock(&pf->adev->dev);
index 4c6d91a..17bfd5c 100644 (file)
@@ -76,7 +76,7 @@ static int octep_send_mbox_req(struct octep_device *oct,
        list_add_tail(&d->list, &oct->ctrl_req_wait_list);
        ret = wait_event_interruptible_timeout(oct->ctrl_req_wait_q,
                                               (d->done != 0),
-                                              jiffies + msecs_to_jiffies(500));
+                                              msecs_to_jiffies(500));
        list_del(&d->list);
        if (ret == 0 || ret == 1)
                return -EAGAIN;
index 43eb6e8..4424de2 100644 (file)
@@ -1038,6 +1038,10 @@ static void octep_device_cleanup(struct octep_device *oct)
 {
        int i;
 
+       oct->poll_non_ioq_intr = false;
+       cancel_delayed_work_sync(&oct->intr_poll_task);
+       cancel_work_sync(&oct->ctrl_mbox_task);
+
        dev_info(&oct->pdev->dev, "Cleaning up Octeon Device ...\n");
 
        for (i = 0; i < OCTEP_MAX_VF; i++) {
@@ -1200,14 +1204,11 @@ static void octep_remove(struct pci_dev *pdev)
        if (!oct)
                return;
 
-       cancel_work_sync(&oct->tx_timeout_task);
-       cancel_work_sync(&oct->ctrl_mbox_task);
        netdev = oct->netdev;
        if (netdev->reg_state == NETREG_REGISTERED)
                unregister_netdev(netdev);
 
-       oct->poll_non_ioq_intr = false;
-       cancel_delayed_work_sync(&oct->intr_poll_task);
+       cancel_work_sync(&oct->tx_timeout_task);
        octep_device_cleanup(oct);
        pci_release_mem_regions(pdev);
        free_netdev(netdev);
index 9e8e618..ecfe93a 100644 (file)
@@ -84,6 +84,8 @@ enum mlx5e_xdp_xmit_mode {
  * MLX5E_XDP_XMIT_MODE_XSK:
  *    none.
  */
+#define MLX5E_XDP_FIFO_ENTRIES2DS_MAX_RATIO 4
+
 union mlx5e_xdp_info {
        enum mlx5e_xdp_xmit_mode mode;
        union {
index bc9d5a5..a2ae791 100644 (file)
@@ -1298,11 +1298,13 @@ static int mlx5e_alloc_xdpsq_fifo(struct mlx5e_xdpsq *sq, int numa)
 {
        struct mlx5e_xdp_info_fifo *xdpi_fifo = &sq->db.xdpi_fifo;
        int wq_sz        = mlx5_wq_cyc_get_size(&sq->wq);
-       int entries = wq_sz * MLX5_SEND_WQEBB_NUM_DS * 2; /* upper bound for maximum num of
-                                                          * entries of all xmit_modes.
-                                                          */
+       int entries;
        size_t size;
 
+       /* upper bound for maximum num of entries of all xmit_modes. */
+       entries = roundup_pow_of_two(wq_sz * MLX5_SEND_WQEBB_NUM_DS *
+                                    MLX5E_XDP_FIFO_ENTRIES2DS_MAX_RATIO);
+
        size = array_size(sizeof(*xdpi_fifo->xi), entries);
        xdpi_fifo->xi = kvzalloc_node(size, GFP_KERNEL, numa);
        if (!xdpi_fifo->xi)
index aab7059..244cfd4 100644 (file)
@@ -245,12 +245,20 @@ static int mlx5_cmd_update_root_ft(struct mlx5_flow_root_namespace *ns,
            mlx5_lag_is_shared_fdb(dev) &&
            mlx5_lag_is_master(dev)) {
                struct mlx5_core_dev *peer_dev;
-               int i;
+               int i, j;
 
                mlx5_lag_for_each_peer_mdev(dev, peer_dev, i) {
                        err = mlx5_cmd_set_slave_root_fdb(dev, peer_dev, !disconnect,
                                                          (!disconnect) ? ft->id : 0);
                        if (err && !disconnect) {
+                               mlx5_lag_for_each_peer_mdev(dev, peer_dev, j) {
+                                       if (j < i)
+                                               mlx5_cmd_set_slave_root_fdb(dev, peer_dev, 1,
+                                                                           ns->root_ft->id);
+                                       else
+                                               break;
+                               }
+
                                MLX5_SET(set_flow_table_root_in, in, op_mod, 0);
                                MLX5_SET(set_flow_table_root_in, in, table_id,
                                         ns->root_ft->id);
index 4b004a7..99df00c 100644 (file)
@@ -176,6 +176,15 @@ static int qede_sriov_configure(struct pci_dev *pdev, int num_vfs_param)
 }
 #endif
 
+static int __maybe_unused qede_suspend(struct device *dev)
+{
+       dev_info(dev, "Device does not support suspend operation\n");
+
+       return -EOPNOTSUPP;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(qede_pm_ops, qede_suspend, NULL);
+
 static const struct pci_error_handlers qede_err_handler = {
        .error_detected = qede_io_error_detected,
 };
@@ -190,6 +199,7 @@ static struct pci_driver qede_pci_driver = {
        .sriov_configure = qede_sriov_configure,
 #endif
        .err_handler = &qede_err_handler,
+       .driver.pm = &qede_pm_ops,
 };
 
 static struct qed_eth_cb_ops qede_ll_ops = {
index f3e8ed5..6da0693 100644 (file)
@@ -1194,7 +1194,7 @@ int ef100_probe_netdev_pf(struct efx_nic *efx)
                net_dev->features |= NETIF_F_HW_TC;
                efx->fixed_features |= NETIF_F_HW_TC;
        }
-       return rc;
+       return 0;
 }
 
 int ef100_probe_vf(struct efx_nic *efx)
index 2466572..039180c 100644 (file)
@@ -2090,10 +2090,10 @@ int efx_init_tc(struct efx_nic *efx)
        rc = efx_mae_get_tables(efx);
        if (rc)
                return rc;
-       efx->tc->up = true;
        rc = flow_indr_dev_register(efx_tc_indr_setup_cb, efx);
        if (rc)
                goto out_free;
+       efx->tc->up = true;
        return 0;
 out_free:
        efx_mae_free_tables(efx);
index 54ed288..8e06bfb 100644 (file)
@@ -461,7 +461,7 @@ static int efx_tc_flow_block(enum tc_setup_type type, void *type_data,
                return efx_tc_ct_stats(ct_zone, tcb);
        default:
                break;
-       };
+       }
 
        return -EOPNOTSUPP;
 }
index 09593d6..bea6fc0 100644 (file)
@@ -633,9 +633,6 @@ static int am65_cpsw_nuss_ndo_slave_open(struct net_device *ndev)
        /* restore vlan configurations */
        vlan_for_each(ndev, cpsw_restore_vlans, port);
 
-       /* Initialize QoS */
-       am65_cpsw_qos_mqprio_init(port);
-
        phylink_start(port->slave.phylink);
 
        return 0;
index 3b3e75f..9ac2ff0 100644 (file)
 
 #define AM65_CPSW_REG_CTL                      0x004
 #define AM65_CPSW_PN_REG_CTL                   0x004
-#define AM65_CPSW_PN_REG_TX_PRI_MAP            0x018
-#define AM65_CPSW_PN_REG_RX_PRI_MAP            0x020
 #define AM65_CPSW_PN_REG_FIFO_STATUS           0x050
 #define AM65_CPSW_PN_REG_EST_CTL               0x060
 #define AM65_CPSW_PN_REG_PRI_CIR(pri)          (0x140 + 4 * (pri))
-#define AM65_CPSW_PN_REG_PRI_EIR(pri)          (0x160 + 4 * (pri))
 
 /* AM65_CPSW_REG_CTL register fields */
 #define AM65_CPSW_CTL_EST_EN                   BIT(18)
@@ -59,12 +56,6 @@ enum timer_act {
        TACT_SKIP_PROG,         /* just buffer can be updated */
 };
 
-/* number of traffic classes (FIFOs) per port */
-#define AM65_CPSW_PN_TC_NUM                    8
-#define AM65_CPSW_PN_TX_PRI_MAP_DEFAULT                0x76543210
-
-static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data);
-
 static int am65_cpsw_port_est_enabled(struct am65_cpsw_port *port)
 {
        return port->qos.est_oper || port->qos.est_admin;
@@ -550,6 +541,7 @@ static void am65_cpsw_est_link_up(struct net_device *ndev, int link_speed)
        ktime_t cur_time;
        s64 delta;
 
+       port->qos.link_speed = link_speed;
        if (!am65_cpsw_port_est_enabled(port))
                return;
 
@@ -803,8 +795,6 @@ int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
                return am65_cpsw_tc_query_caps(ndev, type_data);
        case TC_SETUP_QDISC_TAPRIO:
                return am65_cpsw_setup_taprio(ndev, type_data);
-       case TC_SETUP_QDISC_MQPRIO:
-               return am65_cpsw_setup_mqprio(ndev, type_data);
        case TC_SETUP_BLOCK:
                return am65_cpsw_qos_setup_tc_block(ndev, type_data);
        default:
@@ -812,15 +802,10 @@ int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
        }
 }
 
-static void am65_cpsw_tx_pn_shaper_link_up(struct am65_cpsw_port *port);
-
 void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed)
 {
        struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
 
-       port->qos.link_speed = link_speed;
-       am65_cpsw_tx_pn_shaper_link_up(port);
-
        if (!IS_ENABLED(CONFIG_TI_AM65_CPSW_TAS))
                return;
 
@@ -952,281 +937,3 @@ void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common)
                       host->port_base + AM65_CPSW_PN_REG_PRI_CIR(tx_ch));
        }
 }
-
-static void am65_cpsw_tx_pn_shaper_apply(struct am65_cpsw_port *port)
-{
-       struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
-       struct am65_cpsw_common *common = port->common;
-       struct tc_mqprio_qopt_offload *mqprio;
-       bool shaper_en;
-       u32 rate_mbps;
-       int i;
-
-       mqprio = &p_mqprio->mqprio_hw;
-       shaper_en = p_mqprio->shaper_en && !p_mqprio->shaper_susp;
-
-       for (i = 0; i < mqprio->qopt.num_tc; i++) {
-               rate_mbps = 0;
-               if (shaper_en) {
-                       rate_mbps = mqprio->min_rate[i] * 8 / 1000000;
-                       rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps,
-                                                              common->bus_freq);
-               }
-
-               writel(rate_mbps,
-                      port->port_base + AM65_CPSW_PN_REG_PRI_CIR(i));
-       }
-
-       for (i = 0; i < mqprio->qopt.num_tc; i++) {
-               rate_mbps = 0;
-               if (shaper_en && mqprio->max_rate[i]) {
-                       rate_mbps = mqprio->max_rate[i] - mqprio->min_rate[i];
-                       rate_mbps = rate_mbps * 8 / 1000000;
-                       rate_mbps = am65_cpsw_qos_tx_rate_calc(rate_mbps,
-                                                              common->bus_freq);
-               }
-
-               writel(rate_mbps,
-                      port->port_base + AM65_CPSW_PN_REG_PRI_EIR(i));
-       }
-}
-
-static void am65_cpsw_tx_pn_shaper_link_up(struct am65_cpsw_port *port)
-{
-       struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
-       struct am65_cpsw_common *common = port->common;
-       bool shaper_susp = false;
-
-       if (!p_mqprio->enable || !p_mqprio->shaper_en)
-               return;
-
-       if (p_mqprio->max_rate_total > port->qos.link_speed)
-               shaper_susp = true;
-
-       if (p_mqprio->shaper_susp == shaper_susp)
-               return;
-
-       if (shaper_susp)
-               dev_info(common->dev,
-                        "Port%u: total shaper tx rate > link speed - suspend shaper\n",
-                        port->port_id);
-       else
-               dev_info(common->dev,
-                        "Port%u: link recover - resume shaper\n",
-                        port->port_id);
-
-       p_mqprio->shaper_susp = shaper_susp;
-       am65_cpsw_tx_pn_shaper_apply(port);
-}
-
-void am65_cpsw_qos_mqprio_init(struct am65_cpsw_port *port)
-{
-       struct am65_cpsw_host *host = am65_common_get_host(port->common);
-       struct am65_cpsw_mqprio *p_mqprio = &port->qos.mqprio;
-       struct tc_mqprio_qopt_offload *mqprio;
-       u32 tx_prio_map = 0, rx_prio_map;
-       int i, fifo;
-
-       mqprio = &p_mqprio->mqprio_hw;
-       rx_prio_map = readl(host->port_base + AM65_CPSW_PN_REG_RX_PRI_MAP);
-
-       if (p_mqprio->enable) {
-               for (i = 0; i < AM65_CPSW_PN_TC_NUM; i++) {
-                       fifo = mqprio->qopt.prio_tc_map[i];
-                       tx_prio_map |= fifo << (4 * i);
-               }
-
-               netdev_set_num_tc(port->ndev, mqprio->qopt.num_tc);
-               for (i = 0; i < mqprio->qopt.num_tc; i++) {
-                       netdev_set_tc_queue(port->ndev, i,
-                                           mqprio->qopt.count[i],
-                                           mqprio->qopt.offset[i]);
-                       if (!i) {
-                               p_mqprio->tc0_q = mqprio->qopt.offset[i];
-                               rx_prio_map &= ~(0x7 << (4 * p_mqprio->tc0_q));
-                       }
-               }
-       } else {
-               /* restore default configuration */
-               netdev_reset_tc(port->ndev);
-               tx_prio_map = AM65_CPSW_PN_TX_PRI_MAP_DEFAULT;
-               rx_prio_map |= p_mqprio->tc0_q << (4 * p_mqprio->tc0_q);
-               p_mqprio->tc0_q = 0;
-       }
-
-       writel(tx_prio_map,
-              port->port_base + AM65_CPSW_PN_REG_TX_PRI_MAP);
-       writel(rx_prio_map,
-              host->port_base + AM65_CPSW_PN_REG_RX_PRI_MAP);
-
-       am65_cpsw_tx_pn_shaper_apply(port);
-}
-
-static int am65_cpsw_mqprio_verify(struct am65_cpsw_port *port,
-                                  struct tc_mqprio_qopt_offload *mqprio)
-{
-       int i;
-
-       for (i = 0; i < mqprio->qopt.num_tc; i++) {
-               unsigned int last = mqprio->qopt.offset[i] +
-                                   mqprio->qopt.count[i];
-
-               if (mqprio->qopt.offset[i] >= port->ndev->real_num_tx_queues ||
-                   !mqprio->qopt.count[i] ||
-                   last >  port->ndev->real_num_tx_queues)
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int am65_cpsw_mqprio_verify_shaper(struct am65_cpsw_port *port,
-                                         struct tc_mqprio_qopt_offload *mqprio,
-                                         u64 *max_rate)
-{
-       struct am65_cpsw_common *common = port->common;
-       u64 min_rate_total = 0, max_rate_total = 0;
-       u32 min_rate_msk = 0, max_rate_msk = 0;
-       bool has_min_rate, has_max_rate;
-       int num_tc, i;
-
-       has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
-       has_max_rate = !!(mqprio->flags & TC_MQPRIO_F_MAX_RATE);
-
-       if (!has_min_rate && has_max_rate)
-               return -EOPNOTSUPP;
-
-       if (!has_min_rate)
-               return 0;
-
-       num_tc = mqprio->qopt.num_tc;
-
-       for (i = num_tc - 1; i >= 0; i--) {
-               u32 ch_msk;
-
-               if (mqprio->min_rate[i])
-                       min_rate_msk |= BIT(i);
-               min_rate_total +=  mqprio->min_rate[i];
-
-               if (has_max_rate) {
-                       if (mqprio->max_rate[i])
-                               max_rate_msk |= BIT(i);
-                       max_rate_total +=  mqprio->max_rate[i];
-
-                       if (!mqprio->min_rate[i] && mqprio->max_rate[i]) {
-                               dev_err(common->dev, "TX tc%d rate max>0 but min=0\n",
-                                       i);
-                               return -EINVAL;
-                       }
-
-                       if (mqprio->max_rate[i] &&
-                           mqprio->max_rate[i] < mqprio->min_rate[i]) {
-                               dev_err(common->dev, "TX tc%d rate min(%llu)>max(%llu)\n",
-                                       i, mqprio->min_rate[i],
-                                       mqprio->max_rate[i]);
-                               return -EINVAL;
-                       }
-               }
-
-               ch_msk = GENMASK(num_tc - 1, i);
-               if ((min_rate_msk & BIT(i)) && (min_rate_msk ^ ch_msk)) {
-                       dev_err(common->dev, "TX Min rate limiting has to be enabled sequentially hi->lo tx_rate_msk%x\n",
-                               min_rate_msk);
-                       return -EINVAL;
-               }
-
-               if ((max_rate_msk & BIT(i)) && (max_rate_msk ^ ch_msk)) {
-                       dev_err(common->dev, "TX max rate limiting has to be enabled sequentially hi->lo tx_rate_msk%x\n",
-                               max_rate_msk);
-                       return -EINVAL;
-               }
-       }
-       min_rate_total *= 8;
-       min_rate_total /= 1000 * 1000;
-       max_rate_total *= 8;
-       max_rate_total /= 1000 * 1000;
-
-       if (port->qos.link_speed != SPEED_UNKNOWN) {
-               if (min_rate_total > port->qos.link_speed) {
-                       dev_err(common->dev, "TX rate min exceed %llu link speed %d\n",
-                               min_rate_total, port->qos.link_speed);
-                       return -EINVAL;
-               }
-
-               if (max_rate_total > port->qos.link_speed) {
-                       dev_err(common->dev, "TX rate max exceed %llu link speed %d\n",
-                               max_rate_total, port->qos.link_speed);
-                       return -EINVAL;
-               }
-       }
-
-       *max_rate = max_t(u64, min_rate_total, max_rate_total);
-
-       return 0;
-}
-
-static int am65_cpsw_setup_mqprio(struct net_device *ndev, void *type_data)
-{
-       struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
-       struct tc_mqprio_qopt_offload *mqprio = type_data;
-       struct am65_cpsw_common *common = port->common;
-       struct am65_cpsw_mqprio *p_mqprio;
-       bool has_min_rate;
-       int num_tc, ret;
-       u64 max_rate;
-
-       p_mqprio = &port->qos.mqprio;
-
-       if (!mqprio->qopt.hw)
-               goto skip_check;
-
-       if (mqprio->mode != TC_MQPRIO_MODE_CHANNEL)
-               return -EOPNOTSUPP;
-
-       num_tc = mqprio->qopt.num_tc;
-       if (num_tc > AM65_CPSW_PN_TC_NUM)
-               return -ERANGE;
-
-       if ((mqprio->flags & TC_MQPRIO_F_SHAPER) &&
-           mqprio->shaper != TC_MQPRIO_SHAPER_BW_RATE)
-               return -EOPNOTSUPP;
-
-       ret = am65_cpsw_mqprio_verify(port, mqprio);
-       if (ret)
-               return ret;
-
-       ret = am65_cpsw_mqprio_verify_shaper(port, mqprio, &max_rate);
-       if (ret)
-               return ret;
-
-skip_check:
-       ret = pm_runtime_get_sync(common->dev);
-       if (ret < 0) {
-               pm_runtime_put_noidle(common->dev);
-               return ret;
-       }
-
-       if (mqprio->qopt.hw) {
-               memcpy(&p_mqprio->mqprio_hw, mqprio, sizeof(*mqprio));
-               has_min_rate = !!(mqprio->flags & TC_MQPRIO_F_MIN_RATE);
-               p_mqprio->enable = 1;
-               p_mqprio->shaper_en = has_min_rate;
-               p_mqprio->shaper_susp = !has_min_rate;
-               p_mqprio->max_rate_total = max_rate;
-       } else {
-               unsigned int tc0_q = p_mqprio->tc0_q;
-
-               memset(p_mqprio, 0, sizeof(*p_mqprio));
-               p_mqprio->mqprio_hw.qopt.num_tc = AM65_CPSW_PN_TC_NUM;
-               p_mqprio->tc0_q = tc0_q;
-       }
-
-       if (!netif_running(ndev))
-               goto exit_put;
-
-       am65_cpsw_qos_mqprio_init(port);
-
-exit_put:
-       pm_runtime_put(common->dev);
-       return 0;
-}
index 247a427..0cc2a3b 100644 (file)
@@ -7,10 +7,8 @@
 
 #include <linux/netdevice.h>
 #include <net/pkt_sched.h>
-#include <net/pkt_cls.h>
 
 struct am65_cpsw_common;
-struct am65_cpsw_port;
 
 struct am65_cpsw_est {
        int buf;
@@ -18,16 +16,6 @@ struct am65_cpsw_est {
        struct tc_taprio_qopt_offload taprio;
 };
 
-struct am65_cpsw_mqprio {
-       struct tc_mqprio_qopt_offload mqprio_hw;
-       u64 max_rate_total;
-
-       unsigned enable:1;
-       unsigned shaper_en:1;
-       unsigned shaper_susp:1;
-       unsigned tc0_q:3;
-};
-
 struct am65_cpsw_ale_ratelimit {
        unsigned long cookie;
        u64 rate_packet_ps;
@@ -38,7 +26,6 @@ struct am65_cpsw_qos {
        struct am65_cpsw_est *est_oper;
        ktime_t link_down_time;
        int link_speed;
-       struct am65_cpsw_mqprio mqprio;
 
        struct am65_cpsw_ale_ratelimit ale_bc_ratelimit;
        struct am65_cpsw_ale_ratelimit ale_mc_ratelimit;
@@ -48,7 +35,6 @@ int am65_cpsw_qos_ndo_setup_tc(struct net_device *ndev, enum tc_setup_type type,
                               void *type_data);
 void am65_cpsw_qos_link_up(struct net_device *ndev, int link_speed);
 void am65_cpsw_qos_link_down(struct net_device *ndev);
-void am65_cpsw_qos_mqprio_init(struct am65_cpsw_port *port);
 int am65_cpsw_qos_ndo_tx_p0_set_maxrate(struct net_device *ndev, int queue, u32 rate_mbps);
 void am65_cpsw_qos_tx_p0_rate_init(struct am65_cpsw_common *common);
 
index 683e8f8..1af7a4d 100644 (file)
@@ -335,7 +335,7 @@ static int xgene_mdio_probe(struct platform_device *pdev)
 
        of_id = of_match_device(xgene_mdio_of_match, &pdev->dev);
        if (of_id) {
-               mdio_id = (enum xgene_mdio_id)of_id->data;
+               mdio_id = (uintptr_t)of_id->data;
        } else {
 #ifdef CONFIG_ACPI
                const struct acpi_device_id *acpi_id;
index 87f18ae..3111e16 100644 (file)
@@ -167,19 +167,21 @@ static void netconsole_target_put(struct netconsole_target *nt)
 
 #endif /* CONFIG_NETCONSOLE_DYNAMIC */
 
-/* Allocate new target (from boot/module param) and setup netpoll for it */
-static struct netconsole_target *alloc_param_target(char *target_config)
+/* Allocate and initialize with defaults.
+ * Note that these targets get their config_item fields zeroed-out.
+ */
+static struct netconsole_target *alloc_and_init(void)
 {
-       int err = -ENOMEM;
        struct netconsole_target *nt;
 
-       /*
-        * Allocate and initialize with defaults.
-        * Note that these targets get their config_item fields zeroed-out.
-        */
        nt = kzalloc(sizeof(*nt), GFP_KERNEL);
        if (!nt)
-               goto fail;
+               return nt;
+
+       if (IS_ENABLED(CONFIG_NETCONSOLE_EXTENDED_LOG))
+               nt->extended = true;
+       if (IS_ENABLED(CONFIG_NETCONSOLE_PREPEND_RELEASE))
+               nt->release = true;
 
        nt->np.name = "netconsole";
        strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
@@ -187,6 +189,21 @@ static struct netconsole_target *alloc_param_target(char *target_config)
        nt->np.remote_port = 6666;
        eth_broadcast_addr(nt->np.remote_mac);
 
+       return nt;
+}
+
+/* Allocate new target (from boot/module param) and setup netpoll for it */
+static struct netconsole_target *alloc_param_target(char *target_config)
+{
+       struct netconsole_target *nt;
+       int err;
+
+       nt = alloc_and_init();
+       if (!nt) {
+               err = -ENOMEM;
+               goto fail;
+       }
+
        if (*target_config == '+') {
                nt->extended = true;
                target_config++;
@@ -195,6 +212,7 @@ static struct netconsole_target *alloc_param_target(char *target_config)
        if (*target_config == 'r') {
                if (!nt->extended) {
                        pr_err("Netconsole configuration error. Release feature requires extended log message");
+                       err = -EINVAL;
                        goto fail;
                }
                nt->release = true;
@@ -664,23 +682,13 @@ static const struct config_item_type netconsole_target_type = {
 static struct config_item *make_netconsole_target(struct config_group *group,
                                                  const char *name)
 {
-       unsigned long flags;
        struct netconsole_target *nt;
+       unsigned long flags;
 
-       /*
-        * Allocate and initialize with defaults.
-        * Target is disabled at creation (!enabled).
-        */
-       nt = kzalloc(sizeof(*nt), GFP_KERNEL);
+       nt = alloc_and_init();
        if (!nt)
                return ERR_PTR(-ENOMEM);
 
-       nt->np.name = "netconsole";
-       strscpy(nt->np.dev_name, "eth0", IFNAMSIZ);
-       nt->np.local_port = 6665;
-       nt->np.remote_port = 6666;
-       eth_broadcast_addr(nt->np.remote_mac);
-
        /* Initialize the config_item member */
        config_item_init_type_name(&nt->item, name, &netconsole_target_type);
 
index e5d642c..97139c0 100644 (file)
@@ -314,15 +314,21 @@ struct phylink_pcs *miic_create(struct device *dev, struct device_node *np)
 
        pdev = of_find_device_by_node(pcs_np);
        of_node_put(pcs_np);
-       if (!pdev || !platform_get_drvdata(pdev))
+       if (!pdev || !platform_get_drvdata(pdev)) {
+               if (pdev)
+                       put_device(&pdev->dev);
                return ERR_PTR(-EPROBE_DEFER);
+       }
 
        miic_port = kzalloc(sizeof(*miic_port), GFP_KERNEL);
-       if (!miic_port)
+       if (!miic_port) {
+               put_device(&pdev->dev);
                return ERR_PTR(-ENOMEM);
+       }
 
        miic = platform_get_drvdata(pdev);
        device_link_add(dev, miic->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+       put_device(&pdev->dev);
 
        miic_port->miic = miic;
        miic_port->port = port - 1;
index 59cae0d..04b2e6e 100644 (file)
@@ -542,6 +542,17 @@ static int bcm54xx_resume(struct phy_device *phydev)
        return bcm54xx_config_init(phydev);
 }
 
+static int bcm54810_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
+{
+       return -EOPNOTSUPP;
+}
+
+static int bcm54810_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
+                             u16 val)
+{
+       return -EOPNOTSUPP;
+}
+
 static int bcm54811_config_init(struct phy_device *phydev)
 {
        int err, reg;
@@ -1103,6 +1114,8 @@ static struct phy_driver broadcom_drivers[] = {
        .get_strings    = bcm_phy_get_strings,
        .get_stats      = bcm54xx_get_stats,
        .probe          = bcm54xx_phy_probe,
+       .read_mmd       = bcm54810_read_mmd,
+       .write_mmd      = bcm54810_write_mmd,
        .config_init    = bcm54xx_config_init,
        .config_aneg    = bcm5481_config_aneg,
        .config_intr    = bcm_phy_config_intr,
index 17cb3e0..2ce7459 100644 (file)
@@ -3284,6 +3284,8 @@ static int phy_probe(struct device *dev)
                        goto out;
        }
 
+       phy_disable_interrupts(phydev);
+
        /* Start out supporting everything. Eventually,
         * a controller will attach, and may modify one
         * or both of these values
@@ -3401,16 +3403,6 @@ static int phy_remove(struct device *dev)
        return 0;
 }
 
-static void phy_shutdown(struct device *dev)
-{
-       struct phy_device *phydev = to_phy_device(dev);
-
-       if (phydev->state == PHY_READY || !phydev->attached_dev)
-               return;
-
-       phy_disable_interrupts(phydev);
-}
-
 /**
  * phy_driver_register - register a phy_driver with the PHY layer
  * @new_driver: new phy_driver to register
@@ -3444,7 +3436,6 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner)
        new_driver->mdiodrv.driver.bus = &mdio_bus_type;
        new_driver->mdiodrv.driver.probe = phy_probe;
        new_driver->mdiodrv.driver.remove = phy_remove;
-       new_driver->mdiodrv.driver.shutdown = phy_shutdown;
        new_driver->mdiodrv.driver.owner = owner;
        new_driver->mdiodrv.driver.probe_type = PROBE_FORCE_SYNCHRONOUS;
 
index 8243563..e8b9458 100644 (file)
@@ -2188,7 +2188,9 @@ static void team_setup(struct net_device *dev)
 
        dev->hw_features = TEAM_VLAN_FEATURES |
                           NETIF_F_HW_VLAN_CTAG_RX |
-                          NETIF_F_HW_VLAN_CTAG_FILTER;
+                          NETIF_F_HW_VLAN_CTAG_FILTER |
+                          NETIF_F_HW_VLAN_STAG_RX |
+                          NETIF_F_HW_VLAN_STAG_FILTER;
 
        dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
        dev->features |= dev->hw_features;
index d4bd762..89ab9ef 100644 (file)
@@ -3743,7 +3743,7 @@ err_linkops:
        return ret;
 }
 
-static void tun_cleanup(void)
+static void __exit tun_cleanup(void)
 {
        misc_deregister(&tun_miscdev);
        rtnl_link_unregister(&tun_link_ops);
index 953f6d8..8d5e12a 100644 (file)
@@ -1081,8 +1081,9 @@ static int __veth_napi_enable_range(struct net_device *dev, int start, int end)
 err_xdp_ring:
        for (i--; i >= start; i--)
                ptr_ring_cleanup(&priv->rq[i].xdp_ring, veth_ptr_free);
+       i = end;
 err_page_pool:
-       for (i = start; i < end; i++) {
+       for (i--; i >= start; i--) {
                page_pool_destroy(priv->rq[i].page_pool);
                priv->rq[i].page_pool = NULL;
        }
index 9999f81..494242b 100644 (file)
@@ -2770,7 +2770,7 @@ static void virtnet_init_default_rss(struct virtnet_info *vi)
                vi->ctrl->rss.indirection_table[i] = indir_val;
        }
 
-       vi->ctrl->rss.max_tx_vq = vi->curr_queue_pairs;
+       vi->ctrl->rss.max_tx_vq = vi->has_rss ? vi->curr_queue_pairs : 0;
        vi->ctrl->rss.hash_key_length = vi->rss_key_size;
 
        netdev_rss_key_fill(vi->ctrl->rss.key, vi->rss_key_size);
@@ -4358,8 +4358,6 @@ static int virtnet_probe(struct virtio_device *vdev)
        if (vi->has_rss || vi->has_rss_hash_report)
                virtnet_init_default_rss(vi);
 
-       _virtnet_set_queues(vi, vi->curr_queue_pairs);
-
        /* serialize netdev register + virtio_device_ready() with ndo_open() */
        rtnl_lock();
 
@@ -4372,6 +4370,8 @@ static int virtnet_probe(struct virtio_device *vdev)
 
        virtio_device_ready(vdev);
 
+       _virtnet_set_queues(vi, vi->curr_queue_pairs);
+
        /* a random MAC address has been assigned, notify the device.
         * We don't fail probe if VIRTIO_NET_F_CTRL_MAC_ADDR is not there
         * because many devices work fine without getting MAC explicitly
index 37b6fa7..f3a01b7 100644 (file)
@@ -3933,6 +3933,12 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
         */
        nvme_mpath_clear_ctrl_paths(ctrl);
 
+       /*
+        * Unquiesce io queues so any pending IO won't hang, especially
+        * those submitted from scan work
+        */
+       nvme_unquiesce_io_queues(ctrl);
+
        /* prevent racing with ns scanning */
        flush_work(&ctrl->scan_work);
 
@@ -3942,10 +3948,8 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
         * removing the namespaces' disks; fail all the queues now to avoid
         * potentially having to clean up the failed sync later.
         */
-       if (ctrl->state == NVME_CTRL_DEAD) {
+       if (ctrl->state == NVME_CTRL_DEAD)
                nvme_mark_namespaces_dead(ctrl);
-               nvme_unquiesce_io_queues(ctrl);
-       }
 
        /* this is a no-op when called from the controller reset handler */
        nvme_change_ctrl_state(ctrl, NVME_CTRL_DELETING_NOIO);
index 5c3250f..d39f321 100644 (file)
@@ -786,11 +786,9 @@ int nvme_ns_chr_uring_cmd_iopoll(struct io_uring_cmd *ioucmd,
        if (!(ioucmd->flags & IORING_URING_CMD_POLLED))
                return 0;
 
-       rcu_read_lock();
        req = READ_ONCE(ioucmd->cookie);
        if (req && blk_rq_is_poll(req))
                ret = blk_rq_poll(req, iob, poll_flags);
-       rcu_read_unlock();
        return ret;
 }
 #ifdef CONFIG_NVME_MULTIPATH
index baf69af..2f57da1 100644 (file)
@@ -3402,7 +3402,8 @@ static const struct pci_device_id nvme_id_table[] = {
        { PCI_DEVICE(0x1d97, 0x2263),   /* SPCC */
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
        { PCI_DEVICE(0x144d, 0xa80b),   /* Samsung PM9B1 256G and 512G */
-               .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
+               .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES |
+                               NVME_QUIRK_BOGUS_NID, },
        { PCI_DEVICE(0x144d, 0xa809),   /* Samsung MZALQ256HBJD 256G */
                .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, },
        { PCI_DEVICE(0x144d, 0xa802),   /* Samsung SM953 */
index d433b2e..337a624 100644 (file)
@@ -883,6 +883,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
                goto out_cleanup_tagset;
 
        if (!new) {
+               nvme_start_freeze(&ctrl->ctrl);
                nvme_unquiesce_io_queues(&ctrl->ctrl);
                if (!nvme_wait_freeze_timeout(&ctrl->ctrl, NVME_IO_TIMEOUT)) {
                        /*
@@ -891,6 +892,7 @@ static int nvme_rdma_configure_io_queues(struct nvme_rdma_ctrl *ctrl, bool new)
                         * to be safe.
                         */
                        ret = -ENODEV;
+                       nvme_unfreeze(&ctrl->ctrl);
                        goto out_wait_freeze_timed_out;
                }
                blk_mq_update_nr_hw_queues(ctrl->ctrl.tagset,
@@ -940,7 +942,6 @@ static void nvme_rdma_teardown_io_queues(struct nvme_rdma_ctrl *ctrl,
                bool remove)
 {
        if (ctrl->ctrl.queue_count > 1) {
-               nvme_start_freeze(&ctrl->ctrl);
                nvme_quiesce_io_queues(&ctrl->ctrl);
                nvme_sync_io_queues(&ctrl->ctrl);
                nvme_rdma_stop_io_queues(ctrl);
index 9ce417c..5b332d9 100644 (file)
@@ -1868,6 +1868,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
                goto out_cleanup_connect_q;
 
        if (!new) {
+               nvme_start_freeze(ctrl);
                nvme_unquiesce_io_queues(ctrl);
                if (!nvme_wait_freeze_timeout(ctrl, NVME_IO_TIMEOUT)) {
                        /*
@@ -1876,6 +1877,7 @@ static int nvme_tcp_configure_io_queues(struct nvme_ctrl *ctrl, bool new)
                         * to be safe.
                         */
                        ret = -ENODEV;
+                       nvme_unfreeze(ctrl);
                        goto out_wait_freeze_timed_out;
                }
                blk_mq_update_nr_hw_queues(ctrl->tagset,
@@ -1980,7 +1982,6 @@ static void nvme_tcp_teardown_io_queues(struct nvme_ctrl *ctrl,
        if (ctrl->queue_count <= 1)
                return;
        nvme_quiesce_admin_queue(ctrl);
-       nvme_start_freeze(ctrl);
        nvme_quiesce_io_queues(ctrl);
        nvme_sync_io_queues(ctrl);
        nvme_tcp_stop_io_queues(ctrl);
index bf3405f..8b1dcd5 100644 (file)
@@ -121,6 +121,8 @@ module_param(sba_reserve_agpgart, int, 0444);
 MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
 #endif
 
+struct proc_dir_entry *proc_runway_root __ro_after_init;
+struct proc_dir_entry *proc_mckinley_root __ro_after_init;
 
 /************************************
 ** SBA register read and write support
@@ -1968,11 +1970,15 @@ static int __init sba_driver_callback(struct parisc_device *dev)
 #ifdef CONFIG_PROC_FS
        switch (dev->id.hversion) {
        case PLUTO_MCKINLEY_PORT:
+               if (!proc_mckinley_root)
+                       proc_mckinley_root = proc_mkdir("bus/mckinley", NULL);
                root = proc_mckinley_root;
                break;
        case ASTRO_RUNWAY_PORT:
        case IKE_MERCED_PORT:
        default:
+               if (!proc_runway_root)
+                       proc_runway_root = proc_mkdir("bus/runway", NULL);
                root = proc_runway_root;
                break;
        }
index 8d49bad..0859be8 100644 (file)
@@ -179,7 +179,6 @@ config PCI_MVEBU
        depends on MVEBU_MBUS
        depends on ARM
        depends on OF
-       depends on BROKEN
        select PCI_BRIDGE_EMUL
        help
         Add support for Marvell EBU PCIe controller. This PCIe controller
index cf61733..9952057 100644 (file)
@@ -485,20 +485,15 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
        if (ret)
                goto err_remove_edma;
 
-       if (dw_pcie_link_up(pci)) {
-               dw_pcie_print_link_status(pci);
-       } else {
+       if (!dw_pcie_link_up(pci)) {
                ret = dw_pcie_start_link(pci);
                if (ret)
                        goto err_remove_edma;
-
-               if (pci->ops && pci->ops->start_link) {
-                       ret = dw_pcie_wait_for_link(pci);
-                       if (ret)
-                               goto err_stop_link;
-               }
        }
 
+       /* Ignore errors, the link may come up later */
+       dw_pcie_wait_for_link(pci);
+
        bridge->sysdata = pp;
 
        ret = pci_host_probe(bridge);
index c87848c..1f2ee71 100644 (file)
@@ -644,20 +644,9 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index)
        dw_pcie_writel_atu(pci, dir, index, PCIE_ATU_REGION_CTRL2, 0);
 }
 
-void dw_pcie_print_link_status(struct dw_pcie *pci)
-{
-       u32 offset, val;
-
-       offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
-       val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
-
-       dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
-                FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
-                FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
-}
-
 int dw_pcie_wait_for_link(struct dw_pcie *pci)
 {
+       u32 offset, val;
        int retries;
 
        /* Check if the link is up or not */
@@ -673,7 +662,12 @@ int dw_pcie_wait_for_link(struct dw_pcie *pci)
                return -ETIMEDOUT;
        }
 
-       dw_pcie_print_link_status(pci);
+       offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
+       val = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
+
+       dev_info(pci->dev, "PCIe Gen.%u x%u link up\n",
+                FIELD_GET(PCI_EXP_LNKSTA_CLS, val),
+                FIELD_GET(PCI_EXP_LNKSTA_NLW, val));
 
        return 0;
 }
index 6156606..79713ce 100644 (file)
@@ -429,7 +429,6 @@ void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
 int dw_pcie_edma_detect(struct dw_pcie *pci);
 void dw_pcie_edma_remove(struct dw_pcie *pci);
-void dw_pcie_print_link_status(struct dw_pcie *pci);
 
 static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
 {
index 328d1e4..6011297 100644 (file)
@@ -498,6 +498,7 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge)
                                acpiphp_native_scan_bridge(dev);
                }
        } else {
+               LIST_HEAD(add_list);
                int max, pass;
 
                acpiphp_rescan_slot(slot);
@@ -511,10 +512,15 @@ static void enable_slot(struct acpiphp_slot *slot, bool bridge)
                                if (pass && dev->subordinate) {
                                        check_hotplug_bridge(slot, dev);
                                        pcibios_resource_survey_bus(dev->subordinate);
+                                       if (pci_is_root_bus(bus))
+                                               __pci_bus_size_bridges(dev->subordinate, &add_list);
                                }
                        }
                }
-               pci_assign_unassigned_bridge_resources(bus->self);
+               if (pci_is_root_bus(bus))
+                       __pci_bus_assign_resources(bus, &add_list, NULL);
+               else
+                       pci_assign_unassigned_bridge_resources(bus->self);
        }
 
        acpiphp_sanitize_bus(bus);
index ab69d51..a70e677 100644 (file)
@@ -176,7 +176,8 @@ int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf)
 
 int amd_pmf_power_slider_update_event(struct amd_pmf_dev *dev)
 {
-       u8 mode, flag = 0;
+       u8 flag = 0;
+       int mode;
        int src;
 
        mode = amd_pmf_get_pprof_modes(dev);
index 1f59ac5..a95004e 100644 (file)
@@ -335,8 +335,8 @@ static struct pci_dev *_isst_if_get_pci_dev(int cpu, int bus_no, int dev, int fn
 
                node = dev_to_node(&_pci_dev->dev);
                if (node == NUMA_NO_NODE) {
-                       pr_info("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n",
-                               cpu, bus_no, dev, fn);
+                       pr_info_once("Fail to get numa node for CPU:%d bus:%d dev:%d fn:%d\n",
+                                    cpu, bus_no, dev, fn);
                        continue;
                }
 
index 4167618..f360370 100644 (file)
@@ -24,6 +24,10 @@ static bool ec_trigger __read_mostly;
 module_param(ec_trigger, bool, 0444);
 MODULE_PARM_DESC(ec_trigger, "Enable EC triggering work-around to force emitting tablet mode events");
 
+static bool force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force loading on boards without a convertible DMI chassis-type");
+
 static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = {
        {
                /* Lenovo Yoga 7 14ARB7 */
@@ -35,6 +39,20 @@ static const struct dmi_system_id ec_trigger_quirk_dmi_table[] = {
        { }
 };
 
+static const struct dmi_system_id allowed_chasis_types_dmi_table[] = {
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "31" /* Convertible */),
+               },
+       },
+       {
+               .matches = {
+                       DMI_EXACT_MATCH(DMI_CHASSIS_TYPE, "32" /* Detachable */),
+               },
+       },
+       { }
+};
+
 struct lenovo_ymc_private {
        struct input_dev *input_dev;
        struct acpi_device *ec_acpi_dev;
@@ -111,6 +129,13 @@ static int lenovo_ymc_probe(struct wmi_device *wdev, const void *ctx)
        struct input_dev *input_dev;
        int err;
 
+       if (!dmi_check_system(allowed_chasis_types_dmi_table)) {
+               if (force)
+                       dev_info(&wdev->dev, "Force loading Lenovo YMC support\n");
+               else
+                       return -ENODEV;
+       }
+
        ec_trigger |= dmi_check_system(ec_trigger_quirk_dmi_table);
 
        priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
index 67367f0..7d33977 100644 (file)
 #define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET        0x37
 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET       0x3a
 #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET  0x3b
-#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET       0x3c
-#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET       0x3d
-#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET       0x3e
-#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET       0x3f
 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET     0x40
 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET        0x41
 #define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET     0x42
 #define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET        0xaa
 #define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab
 #define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON         0xb2
+#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET       0xb6
+#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET       0xb7
+#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET       0xb8
+#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET       0xb9
 #define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET     0xc2
 #define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT   0xc3
 #define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET   0xc7
                                         MLXPLAT_CPLD_AGGR_MASK_LC_SDWN)
 #define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1
 #define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2       BIT(2)
-#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT     BIT(4)
+#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT     GENMASK(5, 4)
 #define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6)
 #define MLXPLAT_CPLD_PSU_MASK          GENMASK(1, 0)
 #define MLXPLAT_CPLD_PWR_MASK          GENMASK(1, 0)
 #define MLXPLAT_CPLD_GWP_MASK          GENMASK(0, 0)
 #define MLXPLAT_CPLD_EROT_MASK         GENMASK(1, 0)
 #define MLXPLAT_CPLD_PWR_BUTTON_MASK   BIT(0)
-#define MLXPLAT_CPLD_LATCH_RST_MASK    BIT(5)
+#define MLXPLAT_CPLD_LATCH_RST_MASK    BIT(6)
 #define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3)
 #define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4)
 #define MLXPLAT_CPLD_INTRUSION_MASK    BIT(6)
@@ -2356,7 +2356,7 @@ mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_k
                                             u8 action)
 {
        dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button");
-       kernel_halt();
+       kernel_power_off();
        return 0;
 }
 
@@ -2475,7 +2475,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = {
                .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET,
                .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK,
                .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data),
-               .inversed = 0,
+               .inversed = 1,
                .health = false,
        },
        {
@@ -2484,7 +2484,7 @@ static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = {
                .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
                .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK,
                .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data),
-               .inversed = 0,
+               .inversed = 1,
                .health = false,
                .ind = 8,
        },
@@ -3677,7 +3677,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
        {
                .label = "latch_reset",
                .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
-               .mask = GENMASK(7, 0) & ~BIT(5),
+               .mask = GENMASK(7, 0) & ~BIT(6),
                .mode = 0200,
        },
        {
@@ -6238,8 +6238,6 @@ static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv)
                if (priv->pdev_mux[i])
                        platform_device_unregister(priv->pdev_mux[i]);
        }
-
-       mlxplat_post_exit();
 }
 
 static int mlxplat_i2c_main_complition_notify(void *handle, int id)
@@ -6369,6 +6367,7 @@ static void __exit mlxplat_exit(void)
                pm_power_off = NULL;
        mlxplat_pre_exit(priv);
        mlxplat_i2c_main_exit(priv);
+       mlxplat_post_exit();
 }
 module_exit(mlxplat_exit);
 
index ff93986..f26a312 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/string.h>
 
-static const char *const SM_ECO_NAME       = "eco";
-static const char *const SM_COMFORT_NAME   = "comfort";
-static const char *const SM_SPORT_NAME     = "sport";
-static const char *const SM_TURBO_NAME     = "turbo";
-
-static const char *const FM_AUTO_NAME     = "auto";
-static const char *const FM_SILENT_NAME   = "silent";
-static const char *const FM_BASIC_NAME    = "basic";
-static const char *const FM_ADVANCED_NAME = "advanced";
+#define SM_ECO_NAME            "eco"
+#define SM_COMFORT_NAME                "comfort"
+#define SM_SPORT_NAME          "sport"
+#define SM_TURBO_NAME          "turbo"
+
+#define FM_AUTO_NAME           "auto"
+#define FM_SILENT_NAME         "silent"
+#define FM_BASIC_NAME          "basic"
+#define FM_ADVANCED_NAME       "advanced"
 
 static const char * const ALLOWED_FW_0[] __initconst = {
        "14C1EMS1.012",
index 2c2abf6..8158e3c 100644 (file)
@@ -329,6 +329,19 @@ static const struct smi_node cs35l41_hda = {
        .bus_type = SMI_AUTO_DETECT,
 };
 
+static const struct smi_node cs35l56_hda = {
+       .instances = {
+               { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
+               { "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
+               /* a 5th entry is an alias address, not a real device */
+               { "cs35l56-hda_dummy_dev" },
+               {}
+       },
+       .bus_type = SMI_AUTO_DETECT,
+};
+
 /*
  * Note new device-ids must also be added to ignore_serial_bus_ids in
  * drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
@@ -337,6 +350,7 @@ static const struct acpi_device_id smi_acpi_ids[] = {
        { "BSG1160", (unsigned long)&bsg1160_data },
        { "BSG2150", (unsigned long)&bsg2150_data },
        { "CSC3551", (unsigned long)&cs35l41_hda },
+       { "CSC3556", (unsigned long)&cs35l56_hda },
        { "INT3515", (unsigned long)&int3515_data },
        /* Non-conforming _HID for Cirrus Logic already released */
        { "CLSA0100", (unsigned long)&cs35l41_hda },
index dfd5ec9..a062166 100644 (file)
@@ -778,9 +778,6 @@ static int da9063_check_xvp_constraints(struct regulator_config *config)
        const struct notification_limit *uv_l = &constr->under_voltage_limits;
        const struct notification_limit *ov_l = &constr->over_voltage_limits;
 
-       if (!config->init_data) /* No config in DT, pointers will be invalid */
-               return 0;
-
        /* make sure that only one severity is used to clarify if unchanged, enabled or disabled */
        if ((!!uv_l->prot + !!uv_l->err + !!uv_l->warn) > 1) {
                dev_err(config->dev, "%s: at most one voltage monitoring severity allowed!\n",
@@ -1031,9 +1028,12 @@ static int da9063_regulator_probe(struct platform_device *pdev)
                        config.of_node = da9063_reg_matches[id].of_node;
                config.regmap = da9063->regmap;
 
-               ret = da9063_check_xvp_constraints(&config);
-               if (ret)
-                       return ret;
+               /* Checking constraints requires init_data from DT. */
+               if (config.init_data) {
+                       ret = da9063_check_xvp_constraints(&config);
+                       if (ret)
+                               return ret;
+               }
 
                regl->rdev = devm_regulator_register(&pdev->dev, &regl->desc,
                                                     &config);
index f3b280a..cd077b7 100644 (file)
@@ -1068,7 +1068,7 @@ static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
        RPMH_VREG("ldo9",   "ldo%s9",  &pmic5_pldo,    "vdd-l8-l9"),
        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("ldo12",  "ldo%s12", &pmic5_nldo515,    "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_nldo515,    "vdd-l15"),
index e1e4f9d..857be0f 100644 (file)
@@ -1598,7 +1598,7 @@ NCR_700_intr(int irq, void *dev_id)
                                printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
 #endif
                                resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
-                       } else if(dsp >= to32bit(&slot->pSG[0].ins) &&
+                       } else if (slot && dsp >= to32bit(&slot->pSG[0].ins) &&
                                  dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) {
                                int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
                                int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List);
index d82de34..e51e92f 100644 (file)
@@ -27,7 +27,7 @@
 
 #define DRV_NAME               "fnic"
 #define DRV_DESCRIPTION                "Cisco FCoE HBA Driver"
-#define DRV_VERSION            "1.6.0.54"
+#define DRV_VERSION            "1.6.0.55"
 #define PFX                    DRV_NAME ": "
 #define DFX                     DRV_NAME "%d: "
 
index 26dbd34..be89ce9 100644 (file)
@@ -2139,7 +2139,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                                     bool new_sc)
 
 {
-       int ret = SUCCESS;
+       int ret = 0;
        struct fnic_pending_aborts_iter_data iter_data = {
                .fnic = fnic,
                .lun_dev = lr_sc->device,
@@ -2159,9 +2159,11 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
 
        /* walk again to check, if IOs are still pending in fw */
        if (fnic_is_abts_pending(fnic, lr_sc))
-               ret = FAILED;
+               ret = 1;
 
 clean_pending_aborts_end:
+       FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host,
+                       "%s: exit status: %d\n", __func__, ret);
        return ret;
 }
 
index a62e091..d26941b 100644 (file)
@@ -109,8 +109,6 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba,
        }
 }
 
-#define LPFC_INVALID_REFTAG ((u32)-1)
-
 /**
  * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread
  * @phba: The Hba for which this call is being executed.
@@ -978,8 +976,6 @@ lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        sgpe = scsi_prot_sglist(sc);
        lba = scsi_prot_ref_tag(sc);
-       if (lba == LPFC_INVALID_REFTAG)
-               return 0;
 
        /* First check if we need to match the LBA */
        if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) {
@@ -1560,8 +1556,6 @@ lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command for pde*/
        reftag = scsi_prot_ref_tag(sc);
-       if (reftag == LPFC_INVALID_REFTAG)
-               goto out;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
@@ -1723,8 +1717,6 @@ lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        /* extract some info from the scsi command */
        blksize = scsi_prot_interval(sc);
        reftag = scsi_prot_ref_tag(sc);
-       if (reftag == LPFC_INVALID_REFTAG)
-               goto out;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
@@ -1953,8 +1945,6 @@ lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc,
 
        /* extract some info from the scsi command for pde*/
        reftag = scsi_prot_ref_tag(sc);
-       if (reftag == LPFC_INVALID_REFTAG)
-               goto out;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
@@ -2154,8 +2144,6 @@ lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc,
        /* extract some info from the scsi command */
        blksize = scsi_prot_interval(sc);
        reftag = scsi_prot_ref_tag(sc);
-       if (reftag == LPFC_INVALID_REFTAG)
-               goto out;
 
 #ifdef CONFIG_SCSI_LPFC_DEBUG_FS
        rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1);
@@ -2746,8 +2734,6 @@ lpfc_calc_bg_err(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd)
 
                src = (struct scsi_dif_tuple *)sg_virt(sgpe);
                start_ref_tag = scsi_prot_ref_tag(cmd);
-               if (start_ref_tag == LPFC_INVALID_REFTAG)
-                       goto out;
                start_app_tag = src->app_tag;
                len = sgpe->length;
                while (src && protsegcnt) {
@@ -3493,11 +3479,11 @@ err:
                             scsi_cmnd->sc_data_direction);
 
        lpfc_printf_log(phba, KERN_ERR, LOG_TRACE_EVENT,
-                       "9084 Cannot setup S/G List for HBA"
-                       "IO segs %d/%d SGL %d SCSI %d: %d %d\n",
+                       "9084 Cannot setup S/G List for HBA "
+                       "IO segs %d/%d SGL %d SCSI %d: %d %d %d\n",
                        lpfc_cmd->seg_cnt, lpfc_cmd->prot_seg_cnt,
                        phba->cfg_total_seg_cnt, phba->cfg_sg_seg_cnt,
-                       prot_group_type, num_sge);
+                       prot_group_type, num_sge, ret);
 
        lpfc_cmd->seg_cnt = 0;
        lpfc_cmd->prot_seg_cnt = 0;
index 2a31ddc..7825765 100644 (file)
@@ -31,6 +31,7 @@ static void qedf_remove(struct pci_dev *pdev);
 static void qedf_shutdown(struct pci_dev *pdev);
 static void qedf_schedule_recovery_handler(void *dev);
 static void qedf_recovery_handler(struct work_struct *work);
+static int qedf_suspend(struct pci_dev *pdev, pm_message_t state);
 
 /*
  * Driver module parameters.
@@ -3271,6 +3272,7 @@ static struct pci_driver qedf_pci_driver = {
        .probe = qedf_probe,
        .remove = qedf_remove,
        .shutdown = qedf_shutdown,
+       .suspend = qedf_suspend,
 };
 
 static int __qedf_probe(struct pci_dev *pdev, int mode)
@@ -4000,6 +4002,22 @@ static void qedf_shutdown(struct pci_dev *pdev)
        __qedf_remove(pdev, QEDF_MODE_NORMAL);
 }
 
+static int qedf_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct qedf_ctx *qedf;
+
+       if (!pdev) {
+               QEDF_ERR(NULL, "pdev is NULL.\n");
+               return -ENODEV;
+       }
+
+       qedf = pci_get_drvdata(pdev);
+
+       QEDF_ERR(&qedf->dbg_ctx, "%s: Device does not support suspend operation\n", __func__);
+
+       return -EPERM;
+}
+
 /*
  * Recovery handler code
  */
index 450522b..cd0180b 100644 (file)
@@ -69,6 +69,7 @@ static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi);
 static void qedi_recovery_handler(struct work_struct *work);
 static void qedi_schedule_hw_err_handler(void *dev,
                                         enum qed_hw_err_type err_type);
+static int qedi_suspend(struct pci_dev *pdev, pm_message_t state);
 
 static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle)
 {
@@ -1976,8 +1977,9 @@ static int qedi_cpu_offline(unsigned int cpu)
        struct qedi_percpu_s *p = this_cpu_ptr(&qedi_percpu);
        struct qedi_work *work, *tmp;
        struct task_struct *thread;
+       unsigned long flags;
 
-       spin_lock_bh(&p->p_work_lock);
+       spin_lock_irqsave(&p->p_work_lock, flags);
        thread = p->iothread;
        p->iothread = NULL;
 
@@ -1988,7 +1990,7 @@ static int qedi_cpu_offline(unsigned int cpu)
                        kfree(work);
        }
 
-       spin_unlock_bh(&p->p_work_lock);
+       spin_unlock_irqrestore(&p->p_work_lock, flags);
        if (thread)
                kthread_stop(thread);
        return 0;
@@ -2510,6 +2512,22 @@ static void qedi_shutdown(struct pci_dev *pdev)
        __qedi_remove(pdev, QEDI_MODE_SHUTDOWN);
 }
 
+static int qedi_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct qedi_ctx *qedi;
+
+       if (!pdev) {
+               QEDI_ERR(NULL, "pdev is NULL.\n");
+               return -ENODEV;
+       }
+
+       qedi = pci_get_drvdata(pdev);
+
+       QEDI_ERR(&qedi->dbg_ctx, "%s: Device does not support suspend operation\n", __func__);
+
+       return -EPERM;
+}
+
 static int __qedi_probe(struct pci_dev *pdev, int mode)
 {
        struct qedi_ctx *qedi;
@@ -2868,6 +2886,7 @@ static struct pci_driver qedi_pci_driver = {
        .remove = qedi_remove,
        .shutdown = qedi_shutdown,
        .err_handler = &qedi_err_handler,
+       .suspend = qedi_suspend,
 };
 
 static int __init qedi_init(void)
index 898a0bd..711252e 100644 (file)
@@ -248,6 +248,7 @@ int raid_component_add(struct raid_template *r,struct device *raid_dev,
        return 0;
 
 err_out:
+       put_device(&rc->dev);
        list_del(&rc->node);
        rd->component_count--;
        put_device(component_dev);
index 4a6eb17..41f23cd 100644 (file)
@@ -406,7 +406,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
                               size_t length, loff_t *ppos)
 {
        int host, channel, id, lun;
-       char *buffer, *p;
+       char *buffer, *end, *p;
        int err;
 
        if (!buf || length > PAGE_SIZE)
@@ -421,10 +421,14 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
                goto out;
 
        err = -EINVAL;
-       if (length < PAGE_SIZE)
-               buffer[length] = '\0';
-       else if (buffer[PAGE_SIZE-1])
-               goto out;
+       if (length < PAGE_SIZE) {
+               end = buffer + length;
+               *end = '\0';
+       } else {
+               end = buffer + PAGE_SIZE - 1;
+               if (*end)
+                       goto out;
+       }
 
        /*
         * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
@@ -433,10 +437,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
        if (!strncmp("scsi add-single-device", buffer, 22)) {
                p = buffer + 23;
 
-               host = simple_strtoul(p, &p, 0);
-               channel = simple_strtoul(p + 1, &p, 0);
-               id = simple_strtoul(p + 1, &p, 0);
-               lun = simple_strtoul(p + 1, &p, 0);
+               host    = (p     < end) ? simple_strtoul(p, &p, 0) : 0;
+               channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
+               id      = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
+               lun     = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
 
                err = scsi_add_single_device(host, channel, id, lun);
 
@@ -447,10 +451,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
        } else if (!strncmp("scsi remove-single-device", buffer, 25)) {
                p = buffer + 26;
 
-               host = simple_strtoul(p, &p, 0);
-               channel = simple_strtoul(p + 1, &p, 0);
-               id = simple_strtoul(p + 1, &p, 0);
-               lun = simple_strtoul(p + 1, &p, 0);
+               host    = (p     < end) ? simple_strtoul(p, &p, 0) : 0;
+               channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
+               id      = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
+               lun     = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
 
                err = scsi_remove_single_device(host, channel, id, lun);
        }
index 3e2e578..e429ad2 100644 (file)
@@ -303,6 +303,7 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid)
                              "Snic Tgt: device_add, with err = %d\n",
                              ret);
 
+               put_device(&tgt->dev);
                put_device(&snic->shost->shost_gendev);
                spin_lock_irqsave(snic->shost->host_lock, flags);
                list_del(&tgt->list);
index f282321..047ffaf 100644 (file)
@@ -1674,10 +1674,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
  */
 static enum scsi_timeout_action storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
 {
-#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
-       if (scmnd->device->host->transportt == fc_transport_template)
-               return fc_eh_timed_out(scmnd);
-#endif
        return SCSI_EH_RESET_TIMER;
 }
 
index 62b26b7..3fb4553 100644 (file)
@@ -1964,6 +1964,8 @@ unlock:
 
        pm_runtime_mark_last_busy(&tb->dev);
        pm_runtime_put_autosuspend(&tb->dev);
+
+       kfree(ev);
 }
 
 static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port)
index 1269f41..0dfd1e0 100644 (file)
@@ -579,7 +579,9 @@ int tb_switch_tmu_disable(struct tb_switch *sw)
                 * uni-directional mode and we don't want to change it's TMU
                 * mode.
                 */
-               tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);
+               ret = tb_switch_tmu_rate_write(sw, tmu_rates[TB_SWITCH_TMU_MODE_OFF]);
+               if (ret)
+                       return ret;
 
                tb_port_tmu_time_sync_disable(up);
                ret = tb_port_tmu_time_sync_disable(down);
index f8a5e79..ab0652d 100644 (file)
@@ -359,7 +359,7 @@ static int ufs_renesas_init(struct ufs_hba *hba)
 {
        struct ufs_renesas_priv *priv;
 
-       priv = devm_kmalloc(hba->dev, sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(hba->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
                return -ENOMEM;
        ufshcd_set_variant(hba, priv);
index 766005d..501e8bc 100644 (file)
@@ -42,6 +42,7 @@ struct usb_conn_info {
 
        struct power_supply_desc desc;
        struct power_supply *charger;
+       bool initial_detection;
 };
 
 /*
@@ -86,11 +87,13 @@ static void usb_conn_detect_cable(struct work_struct *work)
        dev_dbg(info->dev, "role %s -> %s, gpios: id %d, vbus %d\n",
                usb_role_string(info->last_role), usb_role_string(role), id, vbus);
 
-       if (info->last_role == role) {
+       if (!info->initial_detection && info->last_role == role) {
                dev_warn(info->dev, "repeated role: %s\n", usb_role_string(role));
                return;
        }
 
+       info->initial_detection = false;
+
        if (info->last_role == USB_ROLE_HOST && info->vbus)
                regulator_disable(info->vbus);
 
@@ -258,6 +261,7 @@ static int usb_conn_probe(struct platform_device *pdev)
        device_set_wakeup_capable(&pdev->dev, true);
 
        /* Perform initial detection */
+       info->initial_detection = true;
        usb_conn_queue_dwork(info, 0);
 
        return 0;
index 5fd0671..858fe4c 100644 (file)
@@ -4455,9 +4455,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
        u32 count;
 
        if (pm_runtime_suspended(dwc->dev)) {
+               dwc->pending_events = true;
+               /*
+                * Trigger runtime resume. The get() function will be balanced
+                * after processing the pending events in dwc3_process_pending
+                * events().
+                */
                pm_runtime_get(dwc->dev);
                disable_irq_nosync(dwc->irq_gadget);
-               dwc->pending_events = true;
                return IRQ_HANDLED;
        }
 
@@ -4718,6 +4723,8 @@ void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
 {
        if (dwc->pending_events) {
                dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
+               dwc3_thread_interrupt(dwc->irq_gadget, dwc->ev_buf);
+               pm_runtime_put(dwc->dev);
                dwc->pending_events = false;
                enable_irq(dwc->irq_gadget);
        }
index cd58f2a..7d49d8a 100644 (file)
@@ -822,6 +822,9 @@ EXPORT_SYMBOL_GPL(usb_gadget_disconnect);
  * usb_gadget_activate() is called.  For example, user mode components may
  * need to be activated before the system can talk to hosts.
  *
+ * This routine may sleep; it must not be called in interrupt context
+ * (such as from within a gadget driver's disconnect() callback).
+ *
  * Returns zero on success, else negative errno.
  */
 int usb_gadget_deactivate(struct usb_gadget *gadget)
@@ -860,6 +863,8 @@ EXPORT_SYMBOL_GPL(usb_gadget_deactivate);
  * This routine activates gadget which was previously deactivated with
  * usb_gadget_deactivate() call. It calls usb_gadget_connect() if needed.
  *
+ * This routine may sleep; it must not be called in interrupt context.
+ *
  * Returns zero on success, else negative errno.
  */
 int usb_gadget_activate(struct usb_gadget *gadget)
@@ -1638,7 +1643,11 @@ static void gadget_unbind_driver(struct device *dev)
        usb_gadget_disable_async_callbacks(udc);
        if (gadget->irq)
                synchronize_irq(gadget->irq);
+       mutex_unlock(&udc->connect_lock);
+
        udc->driver->unbind(gadget);
+
+       mutex_lock(&udc->connect_lock);
        usb_gadget_udc_stop_locked(udc);
        mutex_unlock(&udc->connect_lock);
 
index 5e912dd..115f05a 100644 (file)
@@ -318,7 +318,8 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data)
        rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
                command, 0xc0, 0, 1, data, 2);
 
-       usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
+       if (rc == USB_STOR_XFER_GOOD)
+               usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
 
        return rc;
 }
@@ -454,9 +455,14 @@ static int alauda_init_media(struct us_data *us)
 static int alauda_check_media(struct us_data *us)
 {
        struct alauda_info *info = (struct alauda_info *) us->extra;
-       unsigned char status[2];
+       unsigned char *status = us->iobuf;
+       int rc;
 
-       alauda_get_media_status(us, status);
+       rc = alauda_get_media_status(us, status);
+       if (rc != USB_STOR_XFER_GOOD) {
+               status[0] = 0xF0;       /* Pretend there's no media */
+               status[1] = 0;
+       }
 
        /* Check for no media or door open */
        if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)
index 66de880..cdf8261 100644 (file)
@@ -60,6 +60,7 @@ struct dp_altmode {
 
        enum dp_state state;
        bool hpd;
+       bool pending_hpd;
 
        struct mutex lock; /* device lock */
        struct work_struct work;
@@ -144,8 +145,13 @@ static int dp_altmode_status_update(struct dp_altmode *dp)
                dp->state = DP_STATE_EXIT;
        } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) {
                ret = dp_altmode_configure(dp, con);
-               if (!ret)
+               if (!ret) {
                        dp->state = DP_STATE_CONFIGURE;
+                       if (dp->hpd != hpd) {
+                               dp->hpd = hpd;
+                               dp->pending_hpd = true;
+                       }
+               }
        } else {
                if (dp->hpd != hpd) {
                        drm_connector_oob_hotplug_event(dp->connector_fwnode);
@@ -161,6 +167,16 @@ static int dp_altmode_configured(struct dp_altmode *dp)
 {
        sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
        sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
+       /*
+        * If the DFP_D/UFP_D sends a change in HPD when first notifying the
+        * DisplayPort driver that it is connected, then we wait until
+        * configuration is complete to signal HPD.
+        */
+       if (dp->pending_hpd) {
+               drm_connector_oob_hotplug_event(dp->connector_fwnode);
+               sysfs_notify(&dp->alt->dev.kobj, "displayport", "hpd");
+               dp->pending_hpd = false;
+       }
 
        return dp_altmode_notify(dp);
 }
index 784b9d8..65da611 100644 (file)
@@ -29,6 +29,7 @@ config TYPEC_MUX_INTEL_PMC
        tristate "Intel PMC mux control"
        depends on ACPI
        depends on INTEL_SCU_IPC
+       select USB_COMMON
        select USB_ROLE_SWITCH
        help
          Driver for USB muxes controlled by Intel PMC FW. Intel PMC FW can
index 80e580d..4d1122d 100644 (file)
@@ -463,16 +463,18 @@ static int nb7vpq904m_probe(struct i2c_client *client)
 
        ret = nb7vpq904m_register_bridge(nb7);
        if (ret)
-               return ret;
+               goto err_disable_gpio;
 
        sw_desc.drvdata = nb7;
        sw_desc.fwnode = dev->fwnode;
        sw_desc.set = nb7vpq904m_sw_set;
 
        nb7->sw = typec_switch_register(dev, &sw_desc);
-       if (IS_ERR(nb7->sw))
-               return dev_err_probe(dev, PTR_ERR(nb7->sw),
-                                    "Error registering typec switch\n");
+       if (IS_ERR(nb7->sw)) {
+               ret = dev_err_probe(dev, PTR_ERR(nb7->sw),
+                                   "Error registering typec switch\n");
+               goto err_disable_gpio;
+       }
 
        retimer_desc.drvdata = nb7;
        retimer_desc.fwnode = dev->fwnode;
@@ -480,12 +482,21 @@ static int nb7vpq904m_probe(struct i2c_client *client)
 
        nb7->retimer = typec_retimer_register(dev, &retimer_desc);
        if (IS_ERR(nb7->retimer)) {
-               typec_switch_unregister(nb7->sw);
-               return dev_err_probe(dev, PTR_ERR(nb7->retimer),
-                                    "Error registering typec retimer\n");
+               ret = dev_err_probe(dev, PTR_ERR(nb7->retimer),
+                                   "Error registering typec retimer\n");
+               goto err_switch_unregister;
        }
 
        return 0;
+
+err_switch_unregister:
+       typec_switch_unregister(nb7->sw);
+
+err_disable_gpio:
+       gpiod_set_value(nb7->enable_gpio, 0);
+       regulator_disable(nb7->vcc_supply);
+
+       return ret;
 }
 
 static void nb7vpq904m_remove(struct i2c_client *client)
index 829d75e..cc1d839 100644 (file)
@@ -5349,6 +5349,10 @@ static void _tcpm_pd_vbus_off(struct tcpm_port *port)
                /* Do nothing, vbus drop expected */
                break;
 
+       case SNK_HARD_RESET_WAIT_VBUS:
+               /* Do nothing, its OK to receive vbus off events */
+               break;
+
        default:
                if (port->pwr_role == TYPEC_SINK && port->attached)
                        tcpm_set_state(port, SNK_UNATTACHED, tcpm_wait_for_discharge(port));
@@ -5395,6 +5399,9 @@ static void _tcpm_pd_vbus_vsafe0v(struct tcpm_port *port)
        case SNK_DEBOUNCED:
                /*Do nothing, still waiting for VSAFE5V for connect */
                break;
+       case SNK_HARD_RESET_WAIT_VBUS:
+               /* Do nothing, its OK to receive vbus off events */
+               break;
        default:
                if (port->pwr_role == TYPEC_SINK && port->auto_vbus_discharge_enabled)
                        tcpm_set_state(port, SNK_UNATTACHED, 0);
index 25fc412..b53420e 100644 (file)
@@ -31,6 +31,7 @@ struct mlx5_vdpa_mr {
        struct list_head head;
        unsigned long num_directs;
        unsigned long num_klms;
+       /* state of dvq mr */
        bool initialized;
 
        /* serialize mkey creation and destruction */
@@ -121,6 +122,7 @@ int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *io
 int mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb,
                        unsigned int asid);
 void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev);
+void mlx5_vdpa_destroy_mr_asid(struct mlx5_vdpa_dev *mvdev, unsigned int asid);
 
 #define mlx5_vdpa_warn(__dev, format, ...)                                                         \
        dev_warn((__dev)->mdev->device, "%s:%d:(pid %d) warning: " format, __func__, __LINE__,     \
index 03e5432..5a1971f 100644 (file)
@@ -489,60 +489,103 @@ static void destroy_user_mr(struct mlx5_vdpa_dev *mvdev, struct mlx5_vdpa_mr *mr
        }
 }
 
-void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
+static void _mlx5_vdpa_destroy_cvq_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
+{
+       if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] != asid)
+               return;
+
+       prune_iotlb(mvdev);
+}
+
+static void _mlx5_vdpa_destroy_dvq_mr(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
 {
        struct mlx5_vdpa_mr *mr = &mvdev->mr;
 
-       mutex_lock(&mr->mkey_mtx);
+       if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] != asid)
+               return;
+
        if (!mr->initialized)
-               goto out;
+               return;
 
-       prune_iotlb(mvdev);
        if (mr->user_mr)
                destroy_user_mr(mvdev, mr);
        else
                destroy_dma_mr(mvdev, mr);
 
        mr->initialized = false;
-out:
+}
+
+void mlx5_vdpa_destroy_mr_asid(struct mlx5_vdpa_dev *mvdev, unsigned int asid)
+{
+       struct mlx5_vdpa_mr *mr = &mvdev->mr;
+
+       mutex_lock(&mr->mkey_mtx);
+
+       _mlx5_vdpa_destroy_dvq_mr(mvdev, asid);
+       _mlx5_vdpa_destroy_cvq_mr(mvdev, asid);
+
        mutex_unlock(&mr->mkey_mtx);
 }
 
-static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
-                               struct vhost_iotlb *iotlb, unsigned int asid)
+void mlx5_vdpa_destroy_mr(struct mlx5_vdpa_dev *mvdev)
+{
+       mlx5_vdpa_destroy_mr_asid(mvdev, mvdev->group2asid[MLX5_VDPA_CVQ_GROUP]);
+       mlx5_vdpa_destroy_mr_asid(mvdev, mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP]);
+}
+
+static int _mlx5_vdpa_create_cvq_mr(struct mlx5_vdpa_dev *mvdev,
+                                   struct vhost_iotlb *iotlb,
+                                   unsigned int asid)
+{
+       if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] != asid)
+               return 0;
+
+       return dup_iotlb(mvdev, iotlb);
+}
+
+static int _mlx5_vdpa_create_dvq_mr(struct mlx5_vdpa_dev *mvdev,
+                                   struct vhost_iotlb *iotlb,
+                                   unsigned int asid)
 {
        struct mlx5_vdpa_mr *mr = &mvdev->mr;
        int err;
 
-       if (mr->initialized)
+       if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] != asid)
                return 0;
 
-       if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] == asid) {
-               if (iotlb)
-                       err = create_user_mr(mvdev, iotlb);
-               else
-                       err = create_dma_mr(mvdev, mr);
+       if (mr->initialized)
+               return 0;
 
-               if (err)
-                       return err;
-       }
+       if (iotlb)
+               err = create_user_mr(mvdev, iotlb);
+       else
+               err = create_dma_mr(mvdev, mr);
 
-       if (mvdev->group2asid[MLX5_VDPA_CVQ_GROUP] == asid) {
-               err = dup_iotlb(mvdev, iotlb);
-               if (err)
-                       goto out_err;
-       }
+       if (err)
+               return err;
 
        mr->initialized = true;
+
+       return 0;
+}
+
+static int _mlx5_vdpa_create_mr(struct mlx5_vdpa_dev *mvdev,
+                               struct vhost_iotlb *iotlb, unsigned int asid)
+{
+       int err;
+
+       err = _mlx5_vdpa_create_dvq_mr(mvdev, iotlb, asid);
+       if (err)
+               return err;
+
+       err = _mlx5_vdpa_create_cvq_mr(mvdev, iotlb, asid);
+       if (err)
+               goto out_err;
+
        return 0;
 
 out_err:
-       if (mvdev->group2asid[MLX5_VDPA_DATAVQ_GROUP] == asid) {
-               if (iotlb)
-                       destroy_user_mr(mvdev, mr);
-               else
-                       destroy_dma_mr(mvdev, mr);
-       }
+       _mlx5_vdpa_destroy_dvq_mr(mvdev, asid);
 
        return err;
 }
index bece4df..40a03b0 100644 (file)
@@ -2517,7 +2517,15 @@ static int mlx5_vdpa_set_driver_features(struct vdpa_device *vdev, u64 features)
        else
                ndev->rqt_size = 1;
 
-       ndev->cur_num_vqs = 2 * ndev->rqt_size;
+       /* Device must start with 1 queue pair, as per VIRTIO v1.2 spec, section
+        * 5.1.6.5.5 "Device operation in multiqueue mode":
+        *
+        * Multiqueue is disabled by default.
+        * The driver enables multiqueue by sending a command using class
+        * VIRTIO_NET_CTRL_MQ. The command selects the mode of multiqueue
+        * operation, as follows: ...
+        */
+       ndev->cur_num_vqs = 2;
 
        update_cvq_info(mvdev);
        return err;
@@ -2636,7 +2644,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev,
                goto err_mr;
 
        teardown_driver(ndev);
-       mlx5_vdpa_destroy_mr(mvdev);
+       mlx5_vdpa_destroy_mr_asid(mvdev, asid);
        err = mlx5_vdpa_create_mr(mvdev, iotlb, asid);
        if (err)
                goto err_mr;
@@ -2652,7 +2660,7 @@ static int mlx5_vdpa_change_map(struct mlx5_vdpa_dev *mvdev,
        return 0;
 
 err_setup:
-       mlx5_vdpa_destroy_mr(mvdev);
+       mlx5_vdpa_destroy_mr_asid(mvdev, asid);
 err_mr:
        return err;
 }
@@ -3548,17 +3556,6 @@ static void mlx5v_remove(struct auxiliary_device *adev)
        kfree(mgtdev);
 }
 
-static void mlx5v_shutdown(struct auxiliary_device *auxdev)
-{
-       struct mlx5_vdpa_mgmtdev *mgtdev;
-       struct mlx5_vdpa_net *ndev;
-
-       mgtdev = auxiliary_get_drvdata(auxdev);
-       ndev = mgtdev->ndev;
-
-       free_irqs(ndev);
-}
-
 static const struct auxiliary_device_id mlx5v_id_table[] = {
        { .name = MLX5_ADEV_NAME ".vnet", },
        {},
@@ -3570,7 +3567,6 @@ static struct auxiliary_driver mlx5v_driver = {
        .name = "vnet",
        .probe = mlx5v_probe,
        .remove = mlx5v_remove,
-       .shutdown = mlx5v_shutdown,
        .id_table = mlx5v_id_table,
 };
 
index 2e22418..c2d314d 100644 (file)
@@ -5,6 +5,5 @@ obj-$(CONFIG_PDS_VDPA) := pds_vdpa.o
 
 pds_vdpa-y := aux_drv.o \
              cmds.o \
+             debugfs.o \
              vdpa_dev.o
-
-pds_vdpa-$(CONFIG_DEBUG_FS) += debugfs.o
index 21a0dc0..9b04aad 100644 (file)
@@ -176,6 +176,7 @@ static int identity_show(struct seq_file *seq, void *v)
 {
        struct pds_vdpa_aux *vdpa_aux = seq->private;
        struct vdpa_mgmt_dev *mgmt;
+       u64 hw_features;
 
        seq_printf(seq, "aux_dev:            %s\n",
                   dev_name(&vdpa_aux->padev->aux_dev.dev));
@@ -183,8 +184,9 @@ static int identity_show(struct seq_file *seq, void *v)
        mgmt = &vdpa_aux->vdpa_mdev;
        seq_printf(seq, "max_vqs:            %d\n", mgmt->max_supported_vqs);
        seq_printf(seq, "config_attr_mask:   %#llx\n", mgmt->config_attr_mask);
-       seq_printf(seq, "supported_features: %#llx\n", mgmt->supported_features);
-       print_feature_bits_all(seq, mgmt->supported_features);
+       hw_features = le64_to_cpu(vdpa_aux->ident.hw_features);
+       seq_printf(seq, "hw_features:        %#llx\n", hw_features);
+       print_feature_bits_all(seq, hw_features);
 
        return 0;
 }
@@ -200,7 +202,6 @@ static int config_show(struct seq_file *seq, void *v)
 {
        struct pds_vdpa_device *pdsv = seq->private;
        struct virtio_net_config vc;
-       u64 driver_features;
        u8 status;
 
        memcpy_fromio(&vc, pdsv->vdpa_aux->vd_mdev.device,
@@ -223,12 +224,8 @@ static int config_show(struct seq_file *seq, void *v)
        status = vp_modern_get_status(&pdsv->vdpa_aux->vd_mdev);
        seq_printf(seq, "dev_status:           %#x\n", status);
        print_status_bits(seq, status);
-
-       seq_printf(seq, "req_features:         %#llx\n", pdsv->req_features);
-       print_feature_bits_all(seq, pdsv->req_features);
-       driver_features = vp_modern_get_driver_features(&pdsv->vdpa_aux->vd_mdev);
-       seq_printf(seq, "driver_features:      %#llx\n", driver_features);
-       print_feature_bits_all(seq, driver_features);
+       seq_printf(seq, "negotiated_features:  %#llx\n", pdsv->negotiated_features);
+       print_feature_bits_all(seq, pdsv->negotiated_features);
        seq_printf(seq, "vdpa_index:           %d\n", pdsv->vdpa_index);
        seq_printf(seq, "num_vqs:              %d\n", pdsv->num_vqs);
 
index 5071a4d..52b2449 100644 (file)
@@ -126,11 +126,9 @@ static void pds_vdpa_release_irq(struct pds_vdpa_device *pdsv, int qid)
 static void pds_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool ready)
 {
        struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev);
-       struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev;
        struct device *dev = &pdsv->vdpa_dev.dev;
        u64 driver_features;
        u16 invert_idx = 0;
-       int irq;
        int err;
 
        dev_dbg(dev, "%s: qid %d ready %d => %d\n",
@@ -143,19 +141,6 @@ static void pds_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool re
                invert_idx = PDS_VDPA_PACKED_INVERT_IDX;
 
        if (ready) {
-               irq = pci_irq_vector(pdev, qid);
-               snprintf(pdsv->vqs[qid].irq_name, sizeof(pdsv->vqs[qid].irq_name),
-                        "vdpa-%s-%d", dev_name(dev), qid);
-
-               err = request_irq(irq, pds_vdpa_isr, 0,
-                                 pdsv->vqs[qid].irq_name, &pdsv->vqs[qid]);
-               if (err) {
-                       dev_err(dev, "%s: no irq for qid %d: %pe\n",
-                               __func__, qid, ERR_PTR(err));
-                       return;
-               }
-               pdsv->vqs[qid].irq = irq;
-
                /* Pass vq setup info to DSC using adminq to gather up and
                 * send all info at once so FW can do its full set up in
                 * one easy operation
@@ -164,7 +149,6 @@ static void pds_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool re
                if (err) {
                        dev_err(dev, "Failed to init vq %d: %pe\n",
                                qid, ERR_PTR(err));
-                       pds_vdpa_release_irq(pdsv, qid);
                        ready = false;
                }
        } else {
@@ -172,7 +156,6 @@ static void pds_vdpa_set_vq_ready(struct vdpa_device *vdpa_dev, u16 qid, bool re
                if (err)
                        dev_err(dev, "%s: reset_vq failed qid %d: %pe\n",
                                __func__, qid, ERR_PTR(err));
-               pds_vdpa_release_irq(pdsv, qid);
        }
 
        pdsv->vqs[qid].ready = ready;
@@ -318,6 +301,7 @@ static int pds_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 featur
        struct device *dev = &pdsv->vdpa_dev.dev;
        u64 driver_features;
        u64 nego_features;
+       u64 hw_features;
        u64 missing;
 
        if (!(features & BIT_ULL(VIRTIO_F_ACCESS_PLATFORM)) && features) {
@@ -325,21 +309,26 @@ static int pds_vdpa_set_driver_features(struct vdpa_device *vdpa_dev, u64 featur
                return -EOPNOTSUPP;
        }
 
-       pdsv->req_features = features;
-
        /* Check for valid feature bits */
-       nego_features = features & le64_to_cpu(pdsv->vdpa_aux->ident.hw_features);
-       missing = pdsv->req_features & ~nego_features;
+       nego_features = features & pdsv->supported_features;
+       missing = features & ~nego_features;
        if (missing) {
                dev_err(dev, "Can't support all requested features in %#llx, missing %#llx features\n",
-                       pdsv->req_features, missing);
+                       features, missing);
                return -EOPNOTSUPP;
        }
 
+       pdsv->negotiated_features = nego_features;
+
        driver_features = pds_vdpa_get_driver_features(vdpa_dev);
        dev_dbg(dev, "%s: %#llx => %#llx\n",
                __func__, driver_features, nego_features);
 
+       /* if we're faking the F_MAC, strip it before writing to device */
+       hw_features = le64_to_cpu(pdsv->vdpa_aux->ident.hw_features);
+       if (!(hw_features & BIT_ULL(VIRTIO_NET_F_MAC)))
+               nego_features &= ~BIT_ULL(VIRTIO_NET_F_MAC);
+
        if (driver_features == nego_features)
                return 0;
 
@@ -352,7 +341,7 @@ static u64 pds_vdpa_get_driver_features(struct vdpa_device *vdpa_dev)
 {
        struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev);
 
-       return vp_modern_get_driver_features(&pdsv->vdpa_aux->vd_mdev);
+       return pdsv->negotiated_features;
 }
 
 static void pds_vdpa_set_config_cb(struct vdpa_device *vdpa_dev,
@@ -389,6 +378,72 @@ static u8 pds_vdpa_get_status(struct vdpa_device *vdpa_dev)
        return vp_modern_get_status(&pdsv->vdpa_aux->vd_mdev);
 }
 
+static int pds_vdpa_request_irqs(struct pds_vdpa_device *pdsv)
+{
+       struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev;
+       struct pds_vdpa_aux *vdpa_aux = pdsv->vdpa_aux;
+       struct device *dev = &pdsv->vdpa_dev.dev;
+       int max_vq, nintrs, qid, err;
+
+       max_vq = vdpa_aux->vdpa_mdev.max_supported_vqs;
+
+       nintrs = pci_alloc_irq_vectors(pdev, max_vq, max_vq, PCI_IRQ_MSIX);
+       if (nintrs < 0) {
+               dev_err(dev, "Couldn't get %d msix vectors: %pe\n",
+                       max_vq, ERR_PTR(nintrs));
+               return nintrs;
+       }
+
+       for (qid = 0; qid < pdsv->num_vqs; ++qid) {
+               int irq = pci_irq_vector(pdev, qid);
+
+               snprintf(pdsv->vqs[qid].irq_name, sizeof(pdsv->vqs[qid].irq_name),
+                        "vdpa-%s-%d", dev_name(dev), qid);
+
+               err = request_irq(irq, pds_vdpa_isr, 0,
+                                 pdsv->vqs[qid].irq_name,
+                                 &pdsv->vqs[qid]);
+               if (err) {
+                       dev_err(dev, "%s: no irq for qid %d: %pe\n",
+                               __func__, qid, ERR_PTR(err));
+                       goto err_release;
+               }
+
+               pdsv->vqs[qid].irq = irq;
+       }
+
+       vdpa_aux->nintrs = nintrs;
+
+       return 0;
+
+err_release:
+       while (qid--)
+               pds_vdpa_release_irq(pdsv, qid);
+
+       pci_free_irq_vectors(pdev);
+
+       vdpa_aux->nintrs = 0;
+
+       return err;
+}
+
+static void pds_vdpa_release_irqs(struct pds_vdpa_device *pdsv)
+{
+       struct pci_dev *pdev = pdsv->vdpa_aux->padev->vf_pdev;
+       struct pds_vdpa_aux *vdpa_aux = pdsv->vdpa_aux;
+       int qid;
+
+       if (!vdpa_aux->nintrs)
+               return;
+
+       for (qid = 0; qid < pdsv->num_vqs; qid++)
+               pds_vdpa_release_irq(pdsv, qid);
+
+       pci_free_irq_vectors(pdev);
+
+       vdpa_aux->nintrs = 0;
+}
+
 static void pds_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
 {
        struct pds_vdpa_device *pdsv = vdpa_to_pdsv(vdpa_dev);
@@ -399,6 +454,11 @@ static void pds_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
        old_status = pds_vdpa_get_status(vdpa_dev);
        dev_dbg(dev, "%s: old %#x new %#x\n", __func__, old_status, status);
 
+       if (status & ~old_status & VIRTIO_CONFIG_S_DRIVER_OK) {
+               if (pds_vdpa_request_irqs(pdsv))
+                       status = old_status | VIRTIO_CONFIG_S_FAILED;
+       }
+
        pds_vdpa_cmd_set_status(pdsv, status);
 
        /* Note: still working with FW on the need for this reset cmd */
@@ -409,6 +469,8 @@ static void pds_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
                        pdsv->vqs[i].avail_idx = 0;
                        pdsv->vqs[i].used_idx = 0;
                }
+
+               pds_vdpa_cmd_set_mac(pdsv, pdsv->mac);
        }
 
        if (status & ~old_status & VIRTIO_CONFIG_S_FEATURES_OK) {
@@ -418,6 +480,20 @@ static void pds_vdpa_set_status(struct vdpa_device *vdpa_dev, u8 status)
                                                        i, &pdsv->vqs[i].notify_pa);
                }
        }
+
+       if (old_status & ~status & VIRTIO_CONFIG_S_DRIVER_OK)
+               pds_vdpa_release_irqs(pdsv);
+}
+
+static void pds_vdpa_init_vqs_entry(struct pds_vdpa_device *pdsv, int qid,
+                                   void __iomem *notify)
+{
+       memset(&pdsv->vqs[qid], 0, sizeof(pdsv->vqs[0]));
+       pdsv->vqs[qid].qid = qid;
+       pdsv->vqs[qid].pdsv = pdsv;
+       pdsv->vqs[qid].ready = false;
+       pdsv->vqs[qid].irq = VIRTIO_MSI_NO_VECTOR;
+       pdsv->vqs[qid].notify = notify;
 }
 
 static int pds_vdpa_reset(struct vdpa_device *vdpa_dev)
@@ -441,14 +517,17 @@ static int pds_vdpa_reset(struct vdpa_device *vdpa_dev)
                        if (err)
                                dev_err(dev, "%s: reset_vq failed qid %d: %pe\n",
                                        __func__, i, ERR_PTR(err));
-                       pds_vdpa_release_irq(pdsv, i);
-                       memset(&pdsv->vqs[i], 0, sizeof(pdsv->vqs[0]));
-                       pdsv->vqs[i].ready = false;
                }
        }
 
        pds_vdpa_set_status(vdpa_dev, 0);
 
+       if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
+               /* Reset the vq info */
+               for (i = 0; i < pdsv->num_vqs && !err; i++)
+                       pds_vdpa_init_vqs_entry(pdsv, i, pdsv->vqs[i].notify);
+       }
+
        return 0;
 }
 
@@ -532,7 +611,6 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
        struct device *dma_dev;
        struct pci_dev *pdev;
        struct device *dev;
-       u8 mac[ETH_ALEN];
        int err;
        int i;
 
@@ -563,7 +641,7 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
 
        if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES)) {
                u64 unsupp_features =
-                       add_config->device_features & ~mgmt->supported_features;
+                       add_config->device_features & ~pdsv->supported_features;
 
                if (unsupp_features) {
                        dev_err(dev, "Unsupported features: %#llx\n", unsupp_features);
@@ -614,29 +692,30 @@ static int pds_vdpa_dev_add(struct vdpa_mgmt_dev *mdev, const char *name,
        }
 
        /* Set a mac, either from the user config if provided
-        * or set a random mac if default is 00:..:00
+        * or use the device's mac if not 00:..:00
+        * or set a random mac
         */
        if (add_config->mask & BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR)) {
-               ether_addr_copy(mac, add_config->net.mac);
-               pds_vdpa_cmd_set_mac(pdsv, mac);
+               ether_addr_copy(pdsv->mac, add_config->net.mac);
        } else {
                struct virtio_net_config __iomem *vc;
 
                vc = pdsv->vdpa_aux->vd_mdev.device;
-               memcpy_fromio(mac, vc->mac, sizeof(mac));
-               if (is_zero_ether_addr(mac)) {
-                       eth_random_addr(mac);
-                       dev_info(dev, "setting random mac %pM\n", mac);
-                       pds_vdpa_cmd_set_mac(pdsv, mac);
+               memcpy_fromio(pdsv->mac, vc->mac, sizeof(pdsv->mac));
+               if (is_zero_ether_addr(pdsv->mac) &&
+                   (pdsv->supported_features & BIT_ULL(VIRTIO_NET_F_MAC))) {
+                       eth_random_addr(pdsv->mac);
+                       dev_info(dev, "setting random mac %pM\n", pdsv->mac);
                }
        }
+       pds_vdpa_cmd_set_mac(pdsv, pdsv->mac);
 
        for (i = 0; i < pdsv->num_vqs; i++) {
-               pdsv->vqs[i].qid = i;
-               pdsv->vqs[i].pdsv = pdsv;
-               pdsv->vqs[i].irq = VIRTIO_MSI_NO_VECTOR;
-               pdsv->vqs[i].notify = vp_modern_map_vq_notify(&pdsv->vdpa_aux->vd_mdev,
-                                                             i, &pdsv->vqs[i].notify_pa);
+               void __iomem *notify;
+
+               notify = vp_modern_map_vq_notify(&pdsv->vdpa_aux->vd_mdev,
+                                                i, &pdsv->vqs[i].notify_pa);
+               pds_vdpa_init_vqs_entry(pdsv, i, notify);
        }
 
        pdsv->vdpa_dev.mdev = &vdpa_aux->vdpa_mdev;
@@ -746,24 +825,19 @@ int pds_vdpa_get_mgmt_info(struct pds_vdpa_aux *vdpa_aux)
 
        max_vqs = min_t(u16, dev_intrs, max_vqs);
        mgmt->max_supported_vqs = min_t(u16, PDS_VDPA_MAX_QUEUES, max_vqs);
-       vdpa_aux->nintrs = mgmt->max_supported_vqs;
+       vdpa_aux->nintrs = 0;
 
        mgmt->ops = &pds_vdpa_mgmt_dev_ops;
        mgmt->id_table = pds_vdpa_id_table;
        mgmt->device = dev;
        mgmt->supported_features = le64_to_cpu(vdpa_aux->ident.hw_features);
+
+       /* advertise F_MAC even if the device doesn't */
+       mgmt->supported_features |= BIT_ULL(VIRTIO_NET_F_MAC);
+
        mgmt->config_attr_mask = BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MACADDR);
        mgmt->config_attr_mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP);
        mgmt->config_attr_mask |= BIT_ULL(VDPA_ATTR_DEV_FEATURES);
 
-       err = pci_alloc_irq_vectors(pdev, vdpa_aux->nintrs, vdpa_aux->nintrs,
-                                   PCI_IRQ_MSIX);
-       if (err < 0) {
-               dev_err(dev, "Couldn't get %d msix vectors: %pe\n",
-                       vdpa_aux->nintrs, ERR_PTR(err));
-               return err;
-       }
-       vdpa_aux->nintrs = err;
-
        return 0;
 }
index a1bc37d..d984ba2 100644 (file)
@@ -35,10 +35,11 @@ struct pds_vdpa_device {
        struct pds_vdpa_aux *vdpa_aux;
 
        struct pds_vdpa_vq_info vqs[PDS_VDPA_MAX_QUEUES];
-       u64 supported_features;         /* specified device features */
-       u64 req_features;               /* features requested by vdpa */
+       u64 supported_features;         /* supported device features */
+       u64 negotiated_features;        /* negotiated features */
        u8 vdpa_index;                  /* rsvd for future subdevice use */
        u8 num_vqs;                     /* num vqs in use */
+       u8 mac[ETH_ALEN];               /* mac selected when the device was added */
        struct vdpa_callback config_cb;
        struct notifier_block nb;
 };
index 965e325..a7612e0 100644 (file)
@@ -1247,44 +1247,41 @@ static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = {
        [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING },
        [VDPA_ATTR_DEV_NAME] = { .type = NLA_STRING },
        [VDPA_ATTR_DEV_NET_CFG_MACADDR] = NLA_POLICY_ETH_ADDR,
+       [VDPA_ATTR_DEV_NET_CFG_MAX_VQP] = { .type = NLA_U16 },
        /* virtio spec 1.1 section 5.1.4.1 for valid MTU range */
        [VDPA_ATTR_DEV_NET_CFG_MTU] = NLA_POLICY_MIN(NLA_U16, 68),
+       [VDPA_ATTR_DEV_QUEUE_INDEX] = { .type = NLA_U32 },
+       [VDPA_ATTR_DEV_FEATURES] = { .type = NLA_U64 },
 };
 
 static const struct genl_ops vdpa_nl_ops[] = {
        {
                .cmd = VDPA_CMD_MGMTDEV_GET,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_mgmtdev_get_doit,
                .dumpit = vdpa_nl_cmd_mgmtdev_get_dumpit,
        },
        {
                .cmd = VDPA_CMD_DEV_NEW,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_dev_add_set_doit,
                .flags = GENL_ADMIN_PERM,
        },
        {
                .cmd = VDPA_CMD_DEV_DEL,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_dev_del_set_doit,
                .flags = GENL_ADMIN_PERM,
        },
        {
                .cmd = VDPA_CMD_DEV_GET,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_dev_get_doit,
                .dumpit = vdpa_nl_cmd_dev_get_dumpit,
        },
        {
                .cmd = VDPA_CMD_DEV_CONFIG_GET,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_dev_config_get_doit,
                .dumpit = vdpa_nl_cmd_dev_config_get_dumpit,
        },
        {
                .cmd = VDPA_CMD_DEV_VSTATS_GET,
-               .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
                .doit = vdpa_nl_cmd_dev_stats_get_doit,
                .flags = GENL_ADMIN_PERM,
        },
index dc38ed2..df78695 100644 (file)
@@ -935,10 +935,10 @@ static void vduse_dev_irq_inject(struct work_struct *work)
 {
        struct vduse_dev *dev = container_of(work, struct vduse_dev, inject);
 
-       spin_lock_irq(&dev->irq_lock);
+       spin_lock_bh(&dev->irq_lock);
        if (dev->config_cb.callback)
                dev->config_cb.callback(dev->config_cb.private);
-       spin_unlock_irq(&dev->irq_lock);
+       spin_unlock_bh(&dev->irq_lock);
 }
 
 static void vduse_vq_irq_inject(struct work_struct *work)
@@ -946,10 +946,10 @@ static void vduse_vq_irq_inject(struct work_struct *work)
        struct vduse_virtqueue *vq = container_of(work,
                                        struct vduse_virtqueue, inject);
 
-       spin_lock_irq(&vq->irq_lock);
+       spin_lock_bh(&vq->irq_lock);
        if (vq->ready && vq->cb.callback)
                vq->cb.callback(vq->cb.private);
-       spin_unlock_irq(&vq->irq_lock);
+       spin_unlock_bh(&vq->irq_lock);
 }
 
 static bool vduse_vq_signal_irqfd(struct vduse_virtqueue *vq)
index c83f7f0..abef061 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/fs.h>
 #include <linux/vmalloc.h>
 #include <linux/miscdevice.h>
+#include <linux/blk_types.h>
+#include <linux/bio.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi_common.h>
 #include <scsi/scsi_proto.h>
@@ -75,6 +77,9 @@ struct vhost_scsi_cmd {
        u32 tvc_prot_sgl_count;
        /* Saved unpacked SCSI LUN for vhost_scsi_target_queue_cmd() */
        u32 tvc_lun;
+       u32 copied_iov:1;
+       const void *saved_iter_addr;
+       struct iov_iter saved_iter;
        /* Pointer to the SGL formatted memory from virtio-scsi */
        struct scatterlist *tvc_sgl;
        struct scatterlist *tvc_prot_sgl;
@@ -328,8 +333,13 @@ static void vhost_scsi_release_cmd_res(struct se_cmd *se_cmd)
        int i;
 
        if (tv_cmd->tvc_sgl_count) {
-               for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
-                       put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+               for (i = 0; i < tv_cmd->tvc_sgl_count; i++) {
+                       if (tv_cmd->copied_iov)
+                               __free_page(sg_page(&tv_cmd->tvc_sgl[i]));
+                       else
+                               put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+               }
+               kfree(tv_cmd->saved_iter_addr);
        }
        if (tv_cmd->tvc_prot_sgl_count) {
                for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++)
@@ -504,6 +514,28 @@ static void vhost_scsi_evt_work(struct vhost_work *work)
        mutex_unlock(&vq->mutex);
 }
 
+static int vhost_scsi_copy_sgl_to_iov(struct vhost_scsi_cmd *cmd)
+{
+       struct iov_iter *iter = &cmd->saved_iter;
+       struct scatterlist *sg = cmd->tvc_sgl;
+       struct page *page;
+       size_t len;
+       int i;
+
+       for (i = 0; i < cmd->tvc_sgl_count; i++) {
+               page = sg_page(&sg[i]);
+               len = sg[i].length;
+
+               if (copy_page_to_iter(page, 0, len, iter) != len) {
+                       pr_err("Could not copy data while handling misaligned cmd. Error %zu\n",
+                              len);
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
 /* Fill in status and signal that we are done processing this command
  *
  * This is scheduled in the vhost work queue so we are called with the owner
@@ -527,15 +559,20 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
 
                pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
                        cmd, se_cmd->residual_count, se_cmd->scsi_status);
-
                memset(&v_rsp, 0, sizeof(v_rsp));
-               v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, se_cmd->residual_count);
-               /* TODO is status_qualifier field needed? */
-               v_rsp.status = se_cmd->scsi_status;
-               v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq,
-                                                se_cmd->scsi_sense_length);
-               memcpy(v_rsp.sense, cmd->tvc_sense_buf,
-                      se_cmd->scsi_sense_length);
+
+               if (cmd->saved_iter_addr && vhost_scsi_copy_sgl_to_iov(cmd)) {
+                       v_rsp.response = VIRTIO_SCSI_S_BAD_TARGET;
+               } else {
+                       v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq,
+                                                    se_cmd->residual_count);
+                       /* TODO is status_qualifier field needed? */
+                       v_rsp.status = se_cmd->scsi_status;
+                       v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq,
+                                                        se_cmd->scsi_sense_length);
+                       memcpy(v_rsp.sense, cmd->tvc_sense_buf,
+                              se_cmd->scsi_sense_length);
+               }
 
                iov_iter_init(&iov_iter, ITER_DEST, cmd->tvc_resp_iov,
                              cmd->tvc_in_iovs, sizeof(v_rsp));
@@ -613,12 +650,12 @@ static int
 vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
                      struct iov_iter *iter,
                      struct scatterlist *sgl,
-                     bool write)
+                     bool is_prot)
 {
        struct page **pages = cmd->tvc_upages;
        struct scatterlist *sg = sgl;
-       ssize_t bytes;
-       size_t offset;
+       ssize_t bytes, mapped_bytes;
+       size_t offset, mapped_offset;
        unsigned int npages = 0;
 
        bytes = iov_iter_get_pages2(iter, pages, LONG_MAX,
@@ -627,13 +664,53 @@ vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
        if (bytes <= 0)
                return bytes < 0 ? bytes : -EFAULT;
 
+       mapped_bytes = bytes;
+       mapped_offset = offset;
+
        while (bytes) {
                unsigned n = min_t(unsigned, PAGE_SIZE - offset, bytes);
+               /*
+                * The block layer requires bios/requests to be a multiple of
+                * 512 bytes, but Windows can send us vecs that are misaligned.
+                * This can result in bios and later requests with misaligned
+                * sizes if we have to break up a cmd/scatterlist into multiple
+                * bios.
+                *
+                * We currently only break up a command into multiple bios if
+                * we hit the vec/seg limit, so check if our sgl_count is
+                * greater than the max and if a vec in the cmd has a
+                * misaligned offset/size.
+                */
+               if (!is_prot &&
+                   (offset & (SECTOR_SIZE - 1) || n & (SECTOR_SIZE - 1)) &&
+                   cmd->tvc_sgl_count > BIO_MAX_VECS) {
+                       WARN_ONCE(true,
+                                 "vhost-scsi detected misaligned IO. Performance may be degraded.");
+                       goto revert_iter_get_pages;
+               }
+
                sg_set_page(sg++, pages[npages++], n, offset);
                bytes -= n;
                offset = 0;
        }
+
        return npages;
+
+revert_iter_get_pages:
+       iov_iter_revert(iter, mapped_bytes);
+
+       npages = 0;
+       while (mapped_bytes) {
+               unsigned int n = min_t(unsigned int, PAGE_SIZE - mapped_offset,
+                                      mapped_bytes);
+
+               put_page(pages[npages++]);
+
+               mapped_bytes -= n;
+               mapped_offset = 0;
+       }
+
+       return -EINVAL;
 }
 
 static int
@@ -657,25 +734,80 @@ vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
 }
 
 static int
-vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write,
-                     struct iov_iter *iter,
-                     struct scatterlist *sg, int sg_count)
+vhost_scsi_copy_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+                          struct scatterlist *sg, int sg_count)
+{
+       size_t len = iov_iter_count(iter);
+       unsigned int nbytes = 0;
+       struct page *page;
+       int i;
+
+       if (cmd->tvc_data_direction == DMA_FROM_DEVICE) {
+               cmd->saved_iter_addr = dup_iter(&cmd->saved_iter, iter,
+                                               GFP_KERNEL);
+               if (!cmd->saved_iter_addr)
+                       return -ENOMEM;
+       }
+
+       for (i = 0; i < sg_count; i++) {
+               page = alloc_page(GFP_KERNEL);
+               if (!page) {
+                       i--;
+                       goto err;
+               }
+
+               nbytes = min_t(unsigned int, PAGE_SIZE, len);
+               sg_set_page(&sg[i], page, nbytes, 0);
+
+               if (cmd->tvc_data_direction == DMA_TO_DEVICE &&
+                   copy_page_from_iter(page, 0, nbytes, iter) != nbytes)
+                       goto err;
+
+               len -= nbytes;
+       }
+
+       cmd->copied_iov = 1;
+       return 0;
+
+err:
+       pr_err("Could not read %u bytes while handling misaligned cmd\n",
+              nbytes);
+
+       for (; i >= 0; i--)
+               __free_page(sg_page(&sg[i]));
+       kfree(cmd->saved_iter_addr);
+       return -ENOMEM;
+}
+
+static int
+vhost_scsi_map_iov_to_sgl(struct vhost_scsi_cmd *cmd, struct iov_iter *iter,
+                         struct scatterlist *sg, int sg_count, bool is_prot)
 {
        struct scatterlist *p = sg;
+       size_t revert_bytes;
        int ret;
 
        while (iov_iter_count(iter)) {
-               ret = vhost_scsi_map_to_sgl(cmd, iter, sg, write);
+               ret = vhost_scsi_map_to_sgl(cmd, iter, sg, is_prot);
                if (ret < 0) {
+                       revert_bytes = 0;
+
                        while (p < sg) {
-                               struct page *page = sg_page(p++);
-                               if (page)
+                               struct page *page = sg_page(p);
+
+                               if (page) {
                                        put_page(page);
+                                       revert_bytes += p->length;
+                               }
+                               p++;
                        }
+
+                       iov_iter_revert(iter, revert_bytes);
                        return ret;
                }
                sg += ret;
        }
+
        return 0;
 }
 
@@ -685,7 +817,6 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
                 size_t data_bytes, struct iov_iter *data_iter)
 {
        int sgl_count, ret;
-       bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE);
 
        if (prot_bytes) {
                sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
@@ -698,9 +829,9 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
                pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
                         cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
 
-               ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter,
-                                           cmd->tvc_prot_sgl,
-                                           cmd->tvc_prot_sgl_count);
+               ret = vhost_scsi_map_iov_to_sgl(cmd, prot_iter,
+                                               cmd->tvc_prot_sgl,
+                                               cmd->tvc_prot_sgl_count, true);
                if (ret < 0) {
                        cmd->tvc_prot_sgl_count = 0;
                        return ret;
@@ -716,8 +847,14 @@ vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
        pr_debug("%s data_sg %p data_sgl_count %u\n", __func__,
                  cmd->tvc_sgl, cmd->tvc_sgl_count);
 
-       ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter,
-                                   cmd->tvc_sgl, cmd->tvc_sgl_count);
+       ret = vhost_scsi_map_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl,
+                                       cmd->tvc_sgl_count, false);
+       if (ret == -EINVAL) {
+               sg_init_table(cmd->tvc_sgl, cmd->tvc_sgl_count);
+               ret = vhost_scsi_copy_iov_to_sgl(cmd, data_iter, cmd->tvc_sgl,
+                                                cmd->tvc_sgl_count);
+       }
+
        if (ret < 0) {
                cmd->tvc_sgl_count = 0;
                return ret;
index 835f6cc..fa5226c 100644 (file)
@@ -38,11 +38,6 @@ module_param(bbm_block_size, ulong, 0444);
 MODULE_PARM_DESC(bbm_block_size,
                 "Big Block size in bytes. Default is 0 (auto-detection).");
 
-static bool bbm_safe_unplug = true;
-module_param(bbm_safe_unplug, bool, 0444);
-MODULE_PARM_DESC(bbm_safe_unplug,
-            "Use a safe unplug mechanism in BBM, avoiding long/endless loops");
-
 /*
  * virtio-mem currently supports the following modes of operation:
  *
@@ -173,6 +168,13 @@ struct virtio_mem {
                        /* The number of subblocks per Linux memory block. */
                        uint32_t sbs_per_mb;
 
+                       /*
+                        * Some of the Linux memory blocks tracked as "partially
+                        * plugged" are completely unplugged and can be offlined
+                        * and removed -- which previously failed.
+                        */
+                       bool have_unplugged_mb;
+
                        /* Summary of all memory block states. */
                        unsigned long mb_count[VIRTIO_MEM_SBM_MB_COUNT];
 
@@ -746,11 +748,15 @@ static int virtio_mem_offline_and_remove_memory(struct virtio_mem *vm,
                 * immediately instead of waiting.
                 */
                virtio_mem_retry(vm);
-       } else {
-               dev_dbg(&vm->vdev->dev,
-                       "offlining and removing memory failed: %d\n", rc);
+               return 0;
        }
-       return rc;
+       dev_dbg(&vm->vdev->dev, "offlining and removing memory failed: %d\n", rc);
+       /*
+        * We don't really expect this to fail, because we fake-offlined all
+        * memory already. But it could fail in corner cases.
+        */
+       WARN_ON_ONCE(rc != -ENOMEM && rc != -EBUSY);
+       return rc == -ENOMEM ? -ENOMEM : -EBUSY;
 }
 
 /*
@@ -767,6 +773,34 @@ static int virtio_mem_sbm_offline_and_remove_mb(struct virtio_mem *vm,
 }
 
 /*
+ * Try (offlining and) removing memory from Linux in case all subblocks are
+ * unplugged. Can be called on online and offline memory blocks.
+ *
+ * May modify the state of memory blocks in virtio-mem.
+ */
+static int virtio_mem_sbm_try_remove_unplugged_mb(struct virtio_mem *vm,
+                                                 unsigned long mb_id)
+{
+       int rc;
+
+       /*
+        * Once all subblocks of a memory block were unplugged, offline and
+        * remove it.
+        */
+       if (!virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb))
+               return 0;
+
+       /* offline_and_remove_memory() works for online and offline memory. */
+       mutex_unlock(&vm->hotplug_mutex);
+       rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id);
+       mutex_lock(&vm->hotplug_mutex);
+       if (!rc)
+               virtio_mem_sbm_set_mb_state(vm, mb_id,
+                                           VIRTIO_MEM_SBM_MB_UNUSED);
+       return rc;
+}
+
+/*
  * See virtio_mem_offline_and_remove_memory(): Try to offline and remove a
  * all Linux memory blocks covered by the big block.
  */
@@ -1155,7 +1189,8 @@ static void virtio_mem_fake_online(unsigned long pfn, unsigned long nr_pages)
  * Try to allocate a range, marking pages fake-offline, effectively
  * fake-offlining them.
  */
-static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages)
+static int virtio_mem_fake_offline(struct virtio_mem *vm, unsigned long pfn,
+                                  unsigned long nr_pages)
 {
        const bool is_movable = is_zone_movable_page(pfn_to_page(pfn));
        int rc, retry_count;
@@ -1168,6 +1203,14 @@ static int virtio_mem_fake_offline(unsigned long pfn, unsigned long nr_pages)
         * some guarantees.
         */
        for (retry_count = 0; retry_count < 5; retry_count++) {
+               /*
+                * If the config changed, stop immediately and go back to the
+                * main loop: avoid trying to keep unplugging if the device
+                * might have decided to not remove any more memory.
+                */
+               if (atomic_read(&vm->config_changed))
+                       return -EAGAIN;
+
                rc = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_MOVABLE,
                                        GFP_KERNEL);
                if (rc == -ENOMEM)
@@ -1917,7 +1960,7 @@ static int virtio_mem_sbm_unplug_sb_online(struct virtio_mem *vm,
        start_pfn = PFN_DOWN(virtio_mem_mb_id_to_phys(mb_id) +
                             sb_id * vm->sbm.sb_size);
 
-       rc = virtio_mem_fake_offline(start_pfn, nr_pages);
+       rc = virtio_mem_fake_offline(vm, start_pfn, nr_pages);
        if (rc)
                return rc;
 
@@ -1989,20 +2032,10 @@ static int virtio_mem_sbm_unplug_any_sb_online(struct virtio_mem *vm,
        }
 
 unplugged:
-       /*
-        * Once all subblocks of a memory block were unplugged, offline and
-        * remove it. This will usually not fail, as no memory is in use
-        * anymore - however some other notifiers might NACK the request.
-        */
-       if (virtio_mem_sbm_test_sb_unplugged(vm, mb_id, 0, vm->sbm.sbs_per_mb)) {
-               mutex_unlock(&vm->hotplug_mutex);
-               rc = virtio_mem_sbm_offline_and_remove_mb(vm, mb_id);
-               mutex_lock(&vm->hotplug_mutex);
-               if (!rc)
-                       virtio_mem_sbm_set_mb_state(vm, mb_id,
-                                                   VIRTIO_MEM_SBM_MB_UNUSED);
-       }
-
+       rc = virtio_mem_sbm_try_remove_unplugged_mb(vm, mb_id);
+       if (rc)
+               vm->sbm.have_unplugged_mb = 1;
+       /* Ignore errors, this is not critical. We'll retry later. */
        return 0;
 }
 
@@ -2111,38 +2144,32 @@ static int virtio_mem_bbm_offline_remove_and_unplug_bb(struct virtio_mem *vm,
                         VIRTIO_MEM_BBM_BB_ADDED))
                return -EINVAL;
 
-       if (bbm_safe_unplug) {
-               /*
-                * Start by fake-offlining all memory. Once we marked the device
-                * block as fake-offline, all newly onlined memory will
-                * automatically be kept fake-offline. Protect from concurrent
-                * onlining/offlining until we have a consistent state.
-                */
-               mutex_lock(&vm->hotplug_mutex);
-               virtio_mem_bbm_set_bb_state(vm, bb_id,
-                                           VIRTIO_MEM_BBM_BB_FAKE_OFFLINE);
+       /*
+        * Start by fake-offlining all memory. Once we marked the device
+        * block as fake-offline, all newly onlined memory will
+        * automatically be kept fake-offline. Protect from concurrent
+        * onlining/offlining until we have a consistent state.
+        */
+       mutex_lock(&vm->hotplug_mutex);
+       virtio_mem_bbm_set_bb_state(vm, bb_id, VIRTIO_MEM_BBM_BB_FAKE_OFFLINE);
 
-               for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
-                       page = pfn_to_online_page(pfn);
-                       if (!page)
-                               continue;
+       for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+               page = pfn_to_online_page(pfn);
+               if (!page)
+                       continue;
 
-                       rc = virtio_mem_fake_offline(pfn, PAGES_PER_SECTION);
-                       if (rc) {
-                               end_pfn = pfn;
-                               goto rollback_safe_unplug;
-                       }
+               rc = virtio_mem_fake_offline(vm, pfn, PAGES_PER_SECTION);
+               if (rc) {
+                       end_pfn = pfn;
+                       goto rollback;
                }
-               mutex_unlock(&vm->hotplug_mutex);
        }
+       mutex_unlock(&vm->hotplug_mutex);
 
        rc = virtio_mem_bbm_offline_and_remove_bb(vm, bb_id);
        if (rc) {
-               if (bbm_safe_unplug) {
-                       mutex_lock(&vm->hotplug_mutex);
-                       goto rollback_safe_unplug;
-               }
-               return rc;
+               mutex_lock(&vm->hotplug_mutex);
+               goto rollback;
        }
 
        rc = virtio_mem_bbm_unplug_bb(vm, bb_id);
@@ -2154,7 +2181,7 @@ static int virtio_mem_bbm_offline_remove_and_unplug_bb(struct virtio_mem *vm,
                                            VIRTIO_MEM_BBM_BB_UNUSED);
        return rc;
 
-rollback_safe_unplug:
+rollback:
        for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
                page = pfn_to_online_page(pfn);
                if (!page)
@@ -2260,12 +2287,13 @@ static int virtio_mem_unplug_request(struct virtio_mem *vm, uint64_t diff)
 
 /*
  * Try to unplug all blocks that couldn't be unplugged before, for example,
- * because the hypervisor was busy.
+ * because the hypervisor was busy. Further, offline and remove any memory
+ * blocks where we previously failed.
  */
-static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm)
+static int virtio_mem_cleanup_pending_mb(struct virtio_mem *vm)
 {
        unsigned long id;
-       int rc;
+       int rc = 0;
 
        if (!vm->in_sbm) {
                virtio_mem_bbm_for_each_bb(vm, id,
@@ -2287,6 +2315,27 @@ static int virtio_mem_unplug_pending_mb(struct virtio_mem *vm)
                                            VIRTIO_MEM_SBM_MB_UNUSED);
        }
 
+       if (!vm->sbm.have_unplugged_mb)
+               return 0;
+
+       /*
+        * Let's retry (offlining and) removing completely unplugged Linux
+        * memory blocks.
+        */
+       vm->sbm.have_unplugged_mb = false;
+
+       mutex_lock(&vm->hotplug_mutex);
+       virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_MOVABLE_PARTIAL)
+               rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+       virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_KERNEL_PARTIAL)
+               rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+       virtio_mem_sbm_for_each_mb(vm, id, VIRTIO_MEM_SBM_MB_OFFLINE_PARTIAL)
+               rc |= virtio_mem_sbm_try_remove_unplugged_mb(vm, id);
+       mutex_unlock(&vm->hotplug_mutex);
+
+       if (rc)
+               vm->sbm.have_unplugged_mb = true;
+       /* Ignore errors, this is not critical. We'll retry later. */
        return 0;
 }
 
@@ -2368,9 +2417,9 @@ retry:
                virtio_mem_refresh_config(vm);
        }
 
-       /* Unplug any leftovers from previous runs */
+       /* Cleanup any leftovers from previous runs */
        if (!rc)
-               rc = virtio_mem_unplug_pending_mb(vm);
+               rc = virtio_mem_cleanup_pending_mb(vm);
 
        if (!rc && vm->requested_size != vm->plugged_size) {
                if (vm->requested_size > vm->plugged_size) {
@@ -2382,6 +2431,13 @@ retry:
                }
        }
 
+       /*
+        * Keep retrying to offline and remove completely unplugged Linux
+        * memory blocks.
+        */
+       if (!rc && vm->in_sbm && vm->sbm.have_unplugged_mb)
+               rc = -EBUSY;
+
        switch (rc) {
        case 0:
                vm->retry_timer_ms = VIRTIO_MEM_RETRY_TIMER_MIN_MS;
index a46a4a2..97760f6 100644 (file)
@@ -607,9 +607,8 @@ static void virtio_mmio_release_dev(struct device *_d)
        struct virtio_device *vdev =
                        container_of(_d, struct virtio_device, dev);
        struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
-       struct platform_device *pdev = vm_dev->pdev;
 
-       devm_kfree(&pdev->dev, vm_dev);
+       kfree(vm_dev);
 }
 
 /* Platform device */
@@ -620,7 +619,7 @@ static int virtio_mmio_probe(struct platform_device *pdev)
        unsigned long magic;
        int rc;
 
-       vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL);
+       vm_dev = kzalloc(sizeof(*vm_dev), GFP_KERNEL);
        if (!vm_dev)
                return -ENOMEM;
 
index a6c86f9..c2524a7 100644 (file)
@@ -557,8 +557,6 @@ static int virtio_pci_probe(struct pci_dev *pci_dev,
 
        pci_set_master(pci_dev);
 
-       vp_dev->is_legacy = vp_dev->ldev.ioaddr ? true : false;
-
        rc = register_virtio_device(&vp_dev->vdev);
        reg_dev = vp_dev;
        if (rc)
index 2257f1b..d9cbb02 100644 (file)
@@ -223,6 +223,7 @@ int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev)
        vp_dev->config_vector = vp_config_vector;
        vp_dev->setup_vq = setup_vq;
        vp_dev->del_vq = del_vq;
+       vp_dev->is_legacy = true;
 
        return 0;
 }
index 989e2d7..961161d 100644 (file)
@@ -393,11 +393,13 @@ static int virtio_vdpa_find_vqs(struct virtio_device *vdev, unsigned int nvqs,
        cb.callback = virtio_vdpa_config_cb;
        cb.private = vd_dev;
        ops->set_config_cb(vdpa, &cb);
+       kfree(masks);
 
        return 0;
 
 err_setup_vq:
        virtio_vdpa_del_vqs(vdev);
+       kfree(masks);
        return err;
 }
 
index 030ab44..82324c3 100644 (file)
@@ -441,13 +441,23 @@ void btrfs_wait_block_group_cache_progress(struct btrfs_block_group *cache,
                                           u64 num_bytes)
 {
        struct btrfs_caching_control *caching_ctl;
+       int progress;
 
        caching_ctl = btrfs_get_caching_control(cache);
        if (!caching_ctl)
                return;
 
+       /*
+        * We've already failed to allocate from this block group, so even if
+        * there's enough space in the block group it isn't contiguous enough to
+        * allow for an allocation, so wait for at least the next wakeup tick,
+        * or for the thing to be done.
+        */
+       progress = atomic_read(&caching_ctl->progress);
+
        wait_event(caching_ctl->wait, btrfs_block_group_done(cache) ||
-                  (cache->free_space_ctl->free_space >= num_bytes));
+                  (progress != atomic_read(&caching_ctl->progress) &&
+                   (cache->free_space_ctl->free_space >= num_bytes)));
 
        btrfs_put_caching_control(caching_ctl);
 }
@@ -802,8 +812,10 @@ next:
 
                        if (total_found > CACHING_CTL_WAKE_UP) {
                                total_found = 0;
-                               if (wakeup)
+                               if (wakeup) {
+                                       atomic_inc(&caching_ctl->progress);
                                        wake_up(&caching_ctl->wait);
+                               }
                        }
                }
                path->slots[0]++;
@@ -910,6 +922,7 @@ int btrfs_cache_block_group(struct btrfs_block_group *cache, bool wait)
        init_waitqueue_head(&caching_ctl->wait);
        caching_ctl->block_group = cache;
        refcount_set(&caching_ctl->count, 2);
+       atomic_set(&caching_ctl->progress, 0);
        btrfs_init_work(&caching_ctl->work, caching_thread, NULL, NULL);
 
        spin_lock(&cache->lock);
index aba5dff..74b61e6 100644 (file)
@@ -90,6 +90,8 @@ struct btrfs_caching_control {
        wait_queue_head_t wait;
        struct btrfs_work work;
        struct btrfs_block_group *block_group;
+       /* Track progress of caching during allocation. */
+       atomic_t progress;
        refcount_t count;
 };
 
index 9b9914e..a9a2c54 100644 (file)
@@ -1103,7 +1103,8 @@ static int btrfs_init_fs_root(struct btrfs_root *root, dev_t anon_dev)
        btrfs_drew_lock_init(&root->snapshot_lock);
 
        if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID &&
-           !btrfs_is_data_reloc_root(root)) {
+           !btrfs_is_data_reloc_root(root) &&
+           is_fstree(root->root_key.objectid)) {
                set_bit(BTRFS_ROOT_SHAREABLE, &root->state);
                btrfs_check_and_init_root_item(&root->root_item);
        }
@@ -1300,6 +1301,16 @@ static struct btrfs_root *btrfs_get_root_ref(struct btrfs_fs_info *fs_info,
        root = btrfs_get_global_root(fs_info, objectid);
        if (root)
                return root;
+
+       /*
+        * If we're called for non-subvolume trees, and above function didn't
+        * find one, do not try to read it from disk.
+        *
+        * This is namely for free-space-tree and quota tree, which can change
+        * at runtime and should only be grabbed from fs_info.
+        */
+       if (!is_fstree(objectid) && objectid != BTRFS_DATA_RELOC_TREE_OBJECTID)
+               return ERR_PTR(-ENOENT);
 again:
        root = btrfs_lookup_fs_root(fs_info, objectid);
        if (root) {
index 911908e..f396a9a 100644 (file)
@@ -4310,8 +4310,11 @@ have_block_group:
                        ret = 0;
                }
 
-               if (unlikely(block_group->cached == BTRFS_CACHE_ERROR))
+               if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) {
+                       if (!cache_block_group_error)
+                               cache_block_group_error = -EIO;
                        goto loop;
+               }
 
                if (!find_free_extent_check_size_class(ffe_ctl, block_group))
                        goto loop;
index a91d5ad..ca765d6 100644 (file)
@@ -2145,6 +2145,12 @@ retry:
                                continue;
                        }
 
+                       if (!folio_test_dirty(folio)) {
+                               /* Someone wrote it for us. */
+                               folio_unlock(folio);
+                               continue;
+                       }
+
                        if (wbc->sync_mode != WB_SYNC_NONE) {
                                if (folio_test_writeback(folio))
                                        submit_write_bio(bio_ctrl, 0);
@@ -2164,11 +2170,12 @@ retry:
                        }
 
                        /*
-                        * the filesystem may choose to bump up nr_to_write.
+                        * The filesystem may choose to bump up nr_to_write.
                         * We have to make sure to honor the new nr_to_write
-                        * at any time
+                        * at any time.
                         */
-                       nr_to_write_done = wbc->nr_to_write <= 0;
+                       nr_to_write_done = (wbc->sync_mode == WB_SYNC_NONE &&
+                                           wbc->nr_to_write <= 0);
                }
                folio_batch_release(&fbatch);
                cond_resched();
index 49cef61..9055e19 100644 (file)
@@ -1654,8 +1654,6 @@ out_unlock:
                                             clear_bits,
                                             page_ops);
                start += cur_alloc_size;
-               if (start >= end)
-                       return ret;
        }
 
        /*
@@ -1664,9 +1662,11 @@ out_unlock:
         * space_info's bytes_may_use counter, reserved in
         * btrfs_check_data_free_space().
         */
-       extent_clear_unlock_delalloc(inode, start, end, locked_page,
-                                    clear_bits | EXTENT_CLEAR_DATA_RESV,
-                                    page_ops);
+       if (start < end) {
+               clear_bits |= EXTENT_CLEAR_DATA_RESV;
+               extent_clear_unlock_delalloc(inode, start, end, locked_page,
+                                            clear_bits, page_ops);
+       }
        return ret;
 }
 
index 25a3361..46c3c1d 100644 (file)
@@ -1916,7 +1916,39 @@ again:
                                err = PTR_ERR(root);
                        break;
                }
-               ASSERT(root->reloc_root == reloc_root);
+
+               if (unlikely(root->reloc_root != reloc_root)) {
+                       if (root->reloc_root) {
+                               btrfs_err(fs_info,
+"reloc tree mismatch, root %lld has reloc root key (%lld %u %llu) gen %llu, expect reloc root key (%lld %u %llu) gen %llu",
+                                         root->root_key.objectid,
+                                         root->reloc_root->root_key.objectid,
+                                         root->reloc_root->root_key.type,
+                                         root->reloc_root->root_key.offset,
+                                         btrfs_root_generation(
+                                                 &root->reloc_root->root_item),
+                                         reloc_root->root_key.objectid,
+                                         reloc_root->root_key.type,
+                                         reloc_root->root_key.offset,
+                                         btrfs_root_generation(
+                                                 &reloc_root->root_item));
+                       } else {
+                               btrfs_err(fs_info,
+"reloc tree mismatch, root %lld has no reloc root, expect reloc root key (%lld %u %llu) gen %llu",
+                                         root->root_key.objectid,
+                                         reloc_root->root_key.objectid,
+                                         reloc_root->root_key.type,
+                                         reloc_root->root_key.offset,
+                                         btrfs_root_generation(
+                                                 &reloc_root->root_item));
+                       }
+                       list_add(&reloc_root->root_list, &reloc_roots);
+                       btrfs_put_root(root);
+                       btrfs_abort_transaction(trans, -EUCLEAN);
+                       if (!err)
+                               err = -EUCLEAN;
+                       break;
+               }
 
                /*
                 * set reference count to 1, so btrfs_recover_relocation
@@ -1989,7 +2021,7 @@ again:
                root = btrfs_get_fs_root(fs_info, reloc_root->root_key.offset,
                                         false);
                if (btrfs_root_refs(&reloc_root->root_item) > 0) {
-                       if (IS_ERR(root)) {
+                       if (WARN_ON(IS_ERR(root))) {
                                /*
                                 * For recovery we read the fs roots on mount,
                                 * and if we didn't find the root then we marked
@@ -1998,17 +2030,14 @@ again:
                                 * memory.  However there's no reason we can't
                                 * handle the error properly here just in case.
                                 */
-                               ASSERT(0);
                                ret = PTR_ERR(root);
                                goto out;
                        }
-                       if (root->reloc_root != reloc_root) {
+                       if (WARN_ON(root->reloc_root != reloc_root)) {
                                /*
-                                * This is actually impossible without something
-                                * going really wrong (like weird race condition
-                                * or cosmic rays).
+                                * This can happen if on-disk metadata has some
+                                * corruption, e.g. bad reloc tree key offset.
                                 */
-                               ASSERT(0);
                                ret = -EINVAL;
                                goto out;
                        }
index 038dfa8..ab08a0b 100644 (file)
@@ -446,6 +446,20 @@ static int check_root_key(struct extent_buffer *leaf, struct btrfs_key *key,
        btrfs_item_key_to_cpu(leaf, &item_key, slot);
        is_root_item = (item_key.type == BTRFS_ROOT_ITEM_KEY);
 
+       /*
+        * Bad rootid for reloc trees.
+        *
+        * Reloc trees are only for subvolume trees, other trees only need
+        * to be COWed to be relocated.
+        */
+       if (unlikely(is_root_item && key->objectid == BTRFS_TREE_RELOC_OBJECTID &&
+                    !is_fstree(key->offset))) {
+               generic_err(leaf, slot,
+               "invalid reloc tree for root %lld, root id is not a subvolume tree",
+                           key->offset);
+               return -EUCLEAN;
+       }
+
        /* No such tree id */
        if (unlikely(key->objectid == 0)) {
                if (is_root_item)
index 8fefb69..67611a3 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/fsnotify.h>
 #include <linux/mount.h>
 #include <linux/posix_acl.h>
-#include <linux/prefetch.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
 #include <linux/list_lru.h>
@@ -1041,8 +1040,6 @@ struct inode *new_inode(struct super_block *sb)
 {
        struct inode *inode;
 
-       spin_lock_prefetch(&sb->s_inode_list_lock);
-
        inode = new_inode_pseudo(sb);
        if (inode)
                inode_sb_list_add(inode);
index a8ce522..35bc793 100644 (file)
@@ -1101,9 +1101,17 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned int nr_dirty)
 
 int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
 {
+       struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
        struct buffer_head *ibh;
        int err;
 
+       /*
+        * Do not dirty inodes after the log writer has been detached
+        * and its nilfs_root struct has been freed.
+        */
+       if (unlikely(nilfs_purging(nilfs)))
+               return 0;
+
        err = nilfs_load_inode_block(inode, &ibh);
        if (unlikely(err)) {
                nilfs_warn(inode->i_sb,
index c255302..581691e 100644 (file)
@@ -2845,6 +2845,7 @@ void nilfs_detach_log_writer(struct super_block *sb)
                nilfs_segctor_destroy(nilfs->ns_writer);
                nilfs->ns_writer = NULL;
        }
+       set_nilfs_purging(nilfs);
 
        /* Force to free the list of dirty files */
        spin_lock(&nilfs->ns_inode_lock);
@@ -2857,4 +2858,5 @@ void nilfs_detach_log_writer(struct super_block *sb)
        up_write(&nilfs->ns_segctor_sem);
 
        nilfs_dispose_list(nilfs, &garbage_list, 1);
+       clear_nilfs_purging(nilfs);
 }
index 47c7dfb..cd4ae1b 100644 (file)
@@ -29,6 +29,7 @@ enum {
        THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
        THE_NILFS_GC_RUNNING,   /* gc process is running */
        THE_NILFS_SB_DIRTY,     /* super block is dirty */
+       THE_NILFS_PURGING,      /* disposing dirty files for cleanup */
 };
 
 /**
@@ -208,6 +209,7 @@ THE_NILFS_FNS(INIT, init)
 THE_NILFS_FNS(DISCONTINUED, discontinued)
 THE_NILFS_FNS(GC_RUNNING, gc_running)
 THE_NILFS_FNS(SB_DIRTY, sb_dirty)
+THE_NILFS_FNS(PURGING, purging)
 
 /*
  * Mount option operations
index 9cb32e1..23fc24d 100644 (file)
@@ -309,6 +309,8 @@ static void append_kcore_note(char *notes, size_t *i, const char *name,
 
 static ssize_t read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter)
 {
+       struct file *file = iocb->ki_filp;
+       char *buf = file->private_data;
        loff_t *fpos = &iocb->ki_pos;
        size_t phdrs_offset, notes_offset, data_offset;
        size_t page_offline_frozen = 1;
@@ -555,10 +557,21 @@ static ssize_t read_kcore_iter(struct kiocb *iocb, struct iov_iter *iter)
                case KCORE_VMEMMAP:
                case KCORE_TEXT:
                        /*
-                        * We use _copy_to_iter() to bypass usermode hardening
-                        * which would otherwise prevent this operation.
+                        * Sadly we must use a bounce buffer here to be able to
+                        * make use of copy_from_kernel_nofault(), as these
+                        * memory regions might not always be mapped on all
+                        * architectures.
                         */
-                       if (_copy_to_iter((char *)start, tsz, iter) != tsz) {
+                       if (copy_from_kernel_nofault(buf, (void *)start, tsz)) {
+                               if (iov_iter_zero(tsz, iter) != tsz) {
+                                       ret = -EFAULT;
+                                       goto out;
+                               }
+                       /*
+                        * We know the bounce buffer is safe to copy from, so
+                        * use _copy_to_iter() directly.
+                        */
+                       } else if (_copy_to_iter(buf, tsz, iter) != tsz) {
                                ret = -EFAULT;
                                goto out;
                        }
@@ -595,6 +608,10 @@ static int open_kcore(struct inode *inode, struct file *filp)
        if (ret)
                return ret;
 
+       filp->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!filp->private_data)
+               return -ENOMEM;
+
        if (kcore_need_update)
                kcore_update_ram();
        if (i_size_read(inode) != proc_root_kcore->size) {
@@ -605,9 +622,16 @@ static int open_kcore(struct inode *inode, struct file *filp)
        return 0;
 }
 
+static int release_kcore(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
 static const struct proc_ops kcore_proc_ops = {
        .proc_read_iter = read_kcore_iter,
        .proc_open      = open_kcore,
+       .proc_release   = release_kcore,
        .proc_lseek     = default_llseek,
 };
 
index fb4162a..aec6e91 100644 (file)
@@ -153,6 +153,11 @@ cifs_dump_channel(struct seq_file *m, int i, struct cifs_chan *chan)
                   in_flight(server),
                   atomic_read(&server->in_send),
                   atomic_read(&server->num_waiters));
+#ifdef CONFIG_NET_NS
+       if (server->net)
+               seq_printf(m, " Net namespace: %u ", server->net->ns.inum);
+#endif /* NET_NS */
+
 }
 
 static inline const char *smb_speed_to_str(size_t bps)
@@ -430,10 +435,15 @@ skip_rdma:
                                server->reconnect_instance,
                                server->srv_count,
                                server->sec_mode, in_flight(server));
+#ifdef CONFIG_NET_NS
+               if (server->net)
+                       seq_printf(m, " Net namespace: %u ", server->net->ns.inum);
+#endif /* NET_NS */
 
                seq_printf(m, "\nIn Send: %d In MaxReq Wait: %d",
                                atomic_read(&server->in_send),
                                atomic_read(&server->num_waiters));
+
                if (server->leaf_fullpath) {
                        seq_printf(m, "\nDFS leaf full path: %s",
                                   server->leaf_fullpath);
index fc5acc9..6bc44f7 100644 (file)
@@ -4681,9 +4681,9 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
 
 io_error:
        kunmap(page);
-       unlock_page(page);
 
 read_complete:
+       unlock_page(page);
        return rc;
 }
 
@@ -4878,9 +4878,11 @@ void cifs_oplock_break(struct work_struct *work)
        struct cifsFileInfo *cfile = container_of(work, struct cifsFileInfo,
                                                  oplock_break);
        struct inode *inode = d_inode(cfile->dentry);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsInodeInfo *cinode = CIFS_I(inode);
-       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
-       struct TCP_Server_Info *server = tcon->ses->server;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
+       struct tcon_link *tlink;
        int rc = 0;
        bool purge_cache = false, oplock_break_cancelled;
        __u64 persistent_fid, volatile_fid;
@@ -4889,6 +4891,12 @@ void cifs_oplock_break(struct work_struct *work)
        wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
                        TASK_UNINTERRUPTIBLE);
 
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               goto out;
+       tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
+
        server->ops->downgrade_oplock(server, cinode, cfile->oplock_level,
                                      cfile->oplock_epoch, &purge_cache);
 
@@ -4938,18 +4946,19 @@ oplock_break_ack:
        /*
         * MS-SMB2 3.2.5.19.1 and 3.2.5.19.2 (and MS-CIFS 3.2.5.42) do not require
         * an acknowledgment to be sent when the file has already been closed.
-        * check for server null, since can race with kill_sb calling tree disconnect.
         */
        spin_lock(&cinode->open_file_lock);
-       if (tcon->ses && tcon->ses->server && !oplock_break_cancelled &&
-                                       !list_empty(&cinode->openFileList)) {
+       /* check list empty since can race with kill_sb calling tree disconnect */
+       if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) {
                spin_unlock(&cinode->open_file_lock);
-               rc = tcon->ses->server->ops->oplock_response(tcon, persistent_fid,
-                                               volatile_fid, net_fid, cinode);
+               rc = server->ops->oplock_response(tcon, persistent_fid,
+                                                 volatile_fid, net_fid, cinode);
                cifs_dbg(FYI, "Oplock release rc = %d\n", rc);
        } else
                spin_unlock(&cinode->open_file_lock);
 
+       cifs_put_tlink(tlink);
+out:
        cifs_done_oplock_break(cinode);
 }
 
index 92c9aaa..789cfb7 100644 (file)
@@ -341,77 +341,6 @@ static loff_t zonefs_file_llseek(struct file *file, loff_t offset, int whence)
        return generic_file_llseek_size(file, offset, whence, isize, isize);
 }
 
-struct zonefs_zone_append_bio {
-       /* The target inode of the BIO */
-       struct inode *inode;
-
-       /* For sync writes, the target append write offset */
-       u64 append_offset;
-
-       /*
-        * This member must come last, bio_alloc_bioset will allocate enough
-        * bytes for entire zonefs_bio but relies on bio being last.
-        */
-       struct bio bio;
-};
-
-static inline struct zonefs_zone_append_bio *
-zonefs_zone_append_bio(struct bio *bio)
-{
-       return container_of(bio, struct zonefs_zone_append_bio, bio);
-}
-
-static void zonefs_file_zone_append_dio_bio_end_io(struct bio *bio)
-{
-       struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio);
-       struct zonefs_zone *z = zonefs_inode_zone(za_bio->inode);
-       sector_t za_sector;
-
-       if (bio->bi_status != BLK_STS_OK)
-               goto bio_end;
-
-       /*
-        * If the file zone was written underneath the file system, the zone
-        * append operation can still succedd (if the zone is not full) but
-        * the write append location will not be where we expect it to be.
-        * Check that we wrote where we intended to, that is, at z->z_wpoffset.
-        */
-       za_sector = z->z_sector + (za_bio->append_offset >> SECTOR_SHIFT);
-       if (bio->bi_iter.bi_sector != za_sector) {
-               zonefs_warn(za_bio->inode->i_sb,
-                           "Invalid write sector %llu for zone at %llu\n",
-                           bio->bi_iter.bi_sector, z->z_sector);
-               bio->bi_status = BLK_STS_IOERR;
-       }
-
-bio_end:
-       iomap_dio_bio_end_io(bio);
-}
-
-static void zonefs_file_zone_append_dio_submit_io(const struct iomap_iter *iter,
-                                                 struct bio *bio,
-                                                 loff_t file_offset)
-{
-       struct zonefs_zone_append_bio *za_bio = zonefs_zone_append_bio(bio);
-       struct inode *inode = iter->inode;
-       struct zonefs_zone *z = zonefs_inode_zone(inode);
-
-       /*
-        * Issue a zone append BIO to process sync dio writes. The append
-        * file offset is saved to check the zone append write location
-        * on completion of the BIO.
-        */
-       za_bio->inode = inode;
-       za_bio->append_offset = file_offset;
-
-       bio->bi_opf &= ~REQ_OP_WRITE;
-       bio->bi_opf |= REQ_OP_ZONE_APPEND;
-       bio->bi_iter.bi_sector = z->z_sector;
-       bio->bi_end_io = zonefs_file_zone_append_dio_bio_end_io;
-
-       submit_bio(bio);
-}
-
 static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
                                        int error, unsigned int flags)
 {
@@ -442,14 +371,6 @@ static int zonefs_file_write_dio_end_io(struct kiocb *iocb, ssize_t size,
        return 0;
 }
 
-static struct bio_set zonefs_zone_append_bio_set;
-
-static const struct iomap_dio_ops zonefs_zone_append_dio_ops = {
-       .submit_io      = zonefs_file_zone_append_dio_submit_io,
-       .end_io         = zonefs_file_write_dio_end_io,
-       .bio_set        = &zonefs_zone_append_bio_set,
-};
-
 static const struct iomap_dio_ops zonefs_write_dio_ops = {
        .end_io         = zonefs_file_write_dio_end_io,
 };
@@ -533,9 +454,6 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
        struct zonefs_zone *z = zonefs_inode_zone(inode);
        struct super_block *sb = inode->i_sb;
-       const struct iomap_dio_ops *dio_ops;
-       bool sync = is_sync_kiocb(iocb);
-       bool append = false;
        ssize_t ret, count;
 
        /*
@@ -543,7 +461,8 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
         * as this can cause write reordering (e.g. the first aio gets EAGAIN
         * on the inode lock but the second goes through but is now unaligned).
         */
-       if (zonefs_zone_is_seq(z) && !sync && (iocb->ki_flags & IOCB_NOWAIT))
+       if (zonefs_zone_is_seq(z) && !is_sync_kiocb(iocb) &&
+           (iocb->ki_flags & IOCB_NOWAIT))
                return -EOPNOTSUPP;
 
        if (iocb->ki_flags & IOCB_NOWAIT) {
@@ -573,18 +492,6 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
                        goto inode_unlock;
                }
                mutex_unlock(&zi->i_truncate_mutex);
-               append = sync;
-       }
-
-       if (append) {
-               unsigned int max = bdev_max_zone_append_sectors(sb->s_bdev);
-
-               max = ALIGN_DOWN(max << SECTOR_SHIFT, sb->s_blocksize);
-               iov_iter_truncate(from, max);
-
-               dio_ops = &zonefs_zone_append_dio_ops;
-       } else {
-               dio_ops = &zonefs_write_dio_ops;
        }
 
        /*
@@ -593,7 +500,7 @@ static ssize_t zonefs_file_dio_write(struct kiocb *iocb, struct iov_iter *from)
         * the user can make sense of the error.
         */
        ret = iomap_dio_rw(iocb, from, &zonefs_write_iomap_ops,
-                          dio_ops, 0, NULL, 0);
+                          &zonefs_write_dio_ops, 0, NULL, 0);
        if (ret == -ENOTBLK)
                ret = -EBUSY;
 
@@ -938,15 +845,3 @@ const struct file_operations zonefs_file_operations = {
        .splice_write   = iter_file_splice_write,
        .iopoll         = iocb_bio_iopoll,
 };
-
-int zonefs_file_bioset_init(void)
-{
-       return bioset_init(&zonefs_zone_append_bio_set, BIO_POOL_SIZE,
-                          offsetof(struct zonefs_zone_append_bio, bio),
-                          BIOSET_NEED_BVECS);
-}
-
-void zonefs_file_bioset_exit(void)
-{
-       bioset_exit(&zonefs_zone_append_bio_set);
-}
index bbe44a2..9350221 100644 (file)
@@ -1412,13 +1412,9 @@ static int __init zonefs_init(void)
 
        BUILD_BUG_ON(sizeof(struct zonefs_super) != ZONEFS_SUPER_SIZE);
 
-       ret = zonefs_file_bioset_init();
-       if (ret)
-               return ret;
-
        ret = zonefs_init_inodecache();
        if (ret)
-               goto destroy_bioset;
+               return ret;
 
        ret = zonefs_sysfs_init();
        if (ret)
@@ -1434,8 +1430,6 @@ sysfs_exit:
        zonefs_sysfs_exit();
 destroy_inodecache:
        zonefs_destroy_inodecache();
-destroy_bioset:
-       zonefs_file_bioset_exit();
 
        return ret;
 }
@@ -1445,7 +1439,6 @@ static void __exit zonefs_exit(void)
        unregister_filesystem(&zonefs_type);
        zonefs_sysfs_exit();
        zonefs_destroy_inodecache();
-       zonefs_file_bioset_exit();
 }
 
 MODULE_AUTHOR("Damien Le Moal");
index f663b8e..8175652 100644 (file)
@@ -279,8 +279,6 @@ extern const struct file_operations zonefs_dir_operations;
 extern const struct address_space_operations zonefs_file_aops;
 extern const struct file_operations zonefs_file_operations;
 int zonefs_file_truncate(struct inode *inode, loff_t isize);
-int zonefs_file_bioset_init(void);
-void zonefs_file_bioset_exit(void);
 
 /* In sysfs.c */
 int zonefs_sysfs_register(struct super_block *sb);
index 169755d..48e93f9 100644 (file)
@@ -61,15 +61,9 @@ struct std_timing {
        u8 vfreq_aspect;
 } __attribute__((packed));
 
-#define DRM_EDID_PT_SYNC_MASK              (3 << 3)
-# define DRM_EDID_PT_ANALOG_CSYNC          (0 << 3)
-# define DRM_EDID_PT_BIPOLAR_ANALOG_CSYNC  (1 << 3)
-# define DRM_EDID_PT_DIGITAL_CSYNC         (2 << 3)
-#  define DRM_EDID_PT_CSYNC_ON_RGB         (1 << 1) /* analog csync only */
-#  define DRM_EDID_PT_CSYNC_SERRATE        (1 << 2)
-# define DRM_EDID_PT_DIGITAL_SEPARATE_SYNC (3 << 3)
-#  define DRM_EDID_PT_HSYNC_POSITIVE       (1 << 1) /* also digital csync */
-#  define DRM_EDID_PT_VSYNC_POSITIVE       (1 << 2)
+#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 1)
+#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 2)
+#define DRM_EDID_PT_SEPARATE_SYNC  (3 << 3)
 #define DRM_EDID_PT_STEREO         (1 << 5)
 #define DRM_EDID_PT_INTERLACED     (1 << 7)
 
index c4f5b52..11984ed 100644 (file)
@@ -791,7 +791,7 @@ static inline int bio_integrity_add_page(struct bio *bio, struct page *page,
 static inline void bio_set_polled(struct bio *bio, struct kiocb *kiocb)
 {
        bio->bi_opf |= REQ_POLLED;
-       if (!is_sync_kiocb(kiocb))
+       if (kiocb->ki_flags & IOCB_NOWAIT)
                bio->bi_opf |= REQ_NOWAIT;
 }
 
index ed44a99..87d94be 100644 (file)
@@ -969,7 +969,6 @@ struct blk_plug {
 
        bool multiple_queues;
        bool has_elevator;
-       bool nowait;
 
        struct list_head cb_list; /* md requires an unplug callback */
 };
index db3fe5a..eced640 100644 (file)
@@ -1550,6 +1550,53 @@ struct bpf_struct_ops_value;
 struct btf_member;
 
 #define BPF_STRUCT_OPS_MAX_NR_MEMBERS 64
+/**
+ * struct bpf_struct_ops - A structure of callbacks allowing a subsystem to
+ *                        define a BPF_MAP_TYPE_STRUCT_OPS map type composed
+ *                        of BPF_PROG_TYPE_STRUCT_OPS progs.
+ * @verifier_ops: A structure of callbacks that are invoked by the verifier
+ *               when determining whether the struct_ops progs in the
+ *               struct_ops map are valid.
+ * @init: A callback that is invoked a single time, and before any other
+ *       callback, to initialize the structure. A nonzero return value means
+ *       the subsystem could not be initialized.
+ * @check_member: When defined, a callback invoked by the verifier to allow
+ *               the subsystem to determine if an entry in the struct_ops map
+ *               is valid. A nonzero return value means that the map is
+ *               invalid and should be rejected by the verifier.
+ * @init_member: A callback that is invoked for each member of the struct_ops
+ *              map to allow the subsystem to initialize the member. A nonzero
+ *              value means the member could not be initialized. This callback
+ *              is exclusive with the @type, @type_id, @value_type, and
+ *              @value_id fields.
+ * @reg: A callback that is invoked when the struct_ops map has been
+ *      initialized and is being attached to. Zero means the struct_ops map
+ *      has been successfully registered and is live. A nonzero return value
+ *      means the struct_ops map could not be registered.
+ * @unreg: A callback that is invoked when the struct_ops map should be
+ *        unregistered.
+ * @update: A callback that is invoked when the live struct_ops map is being
+ *         updated to contain new values. This callback is only invoked when
+ *         the struct_ops map is loaded with BPF_F_LINK. If not defined, the
+ *         it is assumed that the struct_ops map cannot be updated.
+ * @validate: A callback that is invoked after all of the members have been
+ *           initialized. This callback should perform static checks on the
+ *           map, meaning that it should either fail or succeed
+ *           deterministically. A struct_ops map that has been validated may
+ *           not necessarily succeed in being registered if the call to @reg
+ *           fails. For example, a valid struct_ops map may be loaded, but
+ *           then fail to be registered due to there being another active
+ *           struct_ops map on the system in the subsystem already. For this
+ *           reason, if this callback is not defined, the check is skipped as
+ *           the struct_ops map will have final verification performed in
+ *           @reg.
+ * @type: BTF type.
+ * @value_type: Value type.
+ * @name: The name of the struct bpf_struct_ops object.
+ * @func_models: Func models
+ * @type_id: BTF type id.
+ * @value_id: BTF value id.
+ */
 struct bpf_struct_ops {
        const struct bpf_verifier_ops *verifier_ops;
        int (*init)(struct btf *btf);
@@ -2120,7 +2167,6 @@ void bpf_link_cleanup(struct bpf_link_primer *primer);
 void bpf_link_inc(struct bpf_link *link);
 void bpf_link_put(struct bpf_link *link);
 int bpf_link_new_fd(struct bpf_link *link);
-struct file *bpf_link_new_file(struct bpf_link *link, int *reserved_fd);
 struct bpf_link *bpf_link_get_from_fd(u32 ufd);
 struct bpf_link *bpf_link_get_curr_or_next(u32 *id);
 
index b83a3f9..b068e2e 100644 (file)
@@ -25,11 +25,10 @@ struct page;
        prefetch() should be defined by the architecture, if not, the 
        #define below provides a no-op define.  
        
-       There are 3 prefetch() macros:
+       There are 2 prefetch() macros:
        
        prefetch(x)     - prefetches the cacheline at "x" for read
        prefetchw(x)    - prefetches the cacheline at "x" for write
-       spin_lock_prefetch(x) - prefetches the spinlock *x for taking
        
        there is also PREFETCH_STRIDE which is the architecure-preferred 
        "lookahead" size for prefetching streamed operations.
@@ -44,10 +43,6 @@ struct page;
 #define prefetchw(x) __builtin_prefetch(x,1)
 #endif
 
-#ifndef ARCH_HAS_SPINLOCK_PREFETCH
-#define spin_lock_prefetch(x) prefetchw(x)
-#endif
-
 #ifndef PREFETCH_STRIDE
 #define PREFETCH_STRIDE (4*L1_CACHE_BYTES)
 #endif
index bdf8de2..7b4dd69 100644 (file)
@@ -155,6 +155,10 @@ retry:
                if (gso_type & SKB_GSO_UDP)
                        nh_off -= thlen;
 
+               /* Kernel has a special handling for GSO_BY_FRAGS. */
+               if (gso_size == GSO_BY_FRAGS)
+                       return -EINVAL;
+
                /* Too small packets are not really GSO ones. */
                if (skb->len - nh_off > gso_size) {
                        shinfo->gso_size = gso_size;
index 284b5ce..533a733 100644 (file)
@@ -116,7 +116,7 @@ struct sock *inet6_steal_sock(struct net *net, struct sk_buff *skb, int doff,
        if (!sk)
                return NULL;
 
-       if (!prefetched)
+       if (!prefetched || !sk_fullsock(sk))
                return sk;
 
        if (sk->sk_protocol == IPPROTO_TCP) {
index 8435572..3ecfead 100644 (file)
@@ -462,7 +462,7 @@ struct sock *inet_steal_sock(struct net *net, struct sk_buff *skb, int doff,
        if (!sk)
                return NULL;
 
-       if (!prefetched)
+       if (!prefetched || !sk_fullsock(sk))
                return sk;
 
        if (sk->sk_protocol == IPPROTO_TCP) {
index 3587085..e9ae567 100644 (file)
@@ -534,6 +534,7 @@ struct nft_set_elem_expr {
  *     @expr: stateful expression
  *     @ops: set ops
  *     @flags: set flags
+ *     @dead: set will be freed, never cleared
  *     @genmask: generation mask
  *     @klen: key length
  *     @dlen: data length
index 74cbfb1..2b9c0ec 100644 (file)
@@ -1421,6 +1421,12 @@ static inline bool sk_has_memory_pressure(const struct sock *sk)
        return sk->sk_prot->memory_pressure != NULL;
 }
 
+static inline bool sk_under_global_memory_pressure(const struct sock *sk)
+{
+       return sk->sk_prot->memory_pressure &&
+               !!*sk->sk_prot->memory_pressure;
+}
+
 static inline bool sk_under_memory_pressure(const struct sock *sk)
 {
        if (!sk->sk_prot->memory_pressure)
index 151ca95..363c7d5 100644 (file)
@@ -1984,6 +1984,7 @@ static inline void xfrm_dev_state_free(struct xfrm_state *x)
                if (dev->xfrmdev_ops->xdo_dev_state_free)
                        dev->xfrmdev_ops->xdo_dev_state_free(x);
                xso->dev = NULL;
+               xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
                netdev_put(dev, &xso->dev_tracker);
        }
 }
index 00f6ff0..3f85ae5 100644 (file)
@@ -603,6 +603,7 @@ enum {
        TCA_NETEM_JITTER64,
        TCA_NETEM_SLOT,
        TCA_NETEM_SLOT_DIST,
+       TCA_NETEM_PRNG_SEED,
        __TCA_NETEM_MAX,
 };
 
index f4591b9..93db3e4 100644 (file)
@@ -3470,6 +3470,8 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp,
         * - use the kernel virtual address of the shared io_uring context
         *   (instead of the userspace-provided address, which has to be 0UL
         *   anyway).
+        * - use the same pgoff which the get_unmapped_area() uses to
+        *   calculate the page colouring.
         * For architectures without such aliasing requirements, the
         * architecture will return any suitable mapping because addr is 0.
         */
@@ -3478,6 +3480,7 @@ static unsigned long io_uring_mmu_get_unmapped_area(struct file *filp,
        pgoff = 0;      /* has been translated to ptr above */
 #ifdef SHM_COLOUR
        addr = (uintptr_t) ptr;
+       pgoff = addr >> PAGE_SHIFT;
 #else
        addr = 0UL;
 #endif
index 10ca57f..e3fae26 100644 (file)
@@ -35,9 +35,11 @@ static bool io_openat_force_async(struct io_open *open)
 {
        /*
         * Don't bother trying for O_TRUNC, O_CREAT, or O_TMPFILE open,
-        * it'll always -EAGAIN
+        * it'll always -EAGAIN. Note that we test for __O_TMPFILE because
+        * O_TMPFILE includes O_DIRECTORY, which isn't a flag we need to force
+        * async for.
         */
-       return open->how.flags & (O_TRUNC | O_CREAT | O_TMPFILE);
+       return open->how.flags & (O_TRUNC | O_CREAT | __O_TMPFILE);
 }
 
 static int __io_openat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
index eaff04e..fdc3e87 100644 (file)
@@ -509,9 +509,12 @@ static long bpf_struct_ops_map_update_elem(struct bpf_map *map, void *key,
        }
 
        if (st_map->map.map_flags & BPF_F_LINK) {
-               err = st_ops->validate(kdata);
-               if (err)
-                       goto reset_unlock;
+               err = 0;
+               if (st_ops->validate) {
+                       err = st_ops->validate(kdata);
+                       if (err)
+                               goto reset_unlock;
+               }
                set_memory_rox((long)st_map->image, 1);
                /* Let bpf_link handle registration & unregistration.
                 *
@@ -663,9 +666,6 @@ static struct bpf_map *bpf_struct_ops_map_alloc(union bpf_attr *attr)
        if (attr->value_size != vt->size)
                return ERR_PTR(-EINVAL);
 
-       if (attr->map_flags & BPF_F_LINK && (!st_ops->validate || !st_ops->update))
-               return ERR_PTR(-EOPNOTSUPP);
-
        t = st_ops->type;
 
        st_map_size = sizeof(*st_map) +
@@ -823,6 +823,9 @@ static int bpf_struct_ops_map_link_update(struct bpf_link *link, struct bpf_map
        if (!bpf_struct_ops_valid_to_reg(new_map))
                return -EINVAL;
 
+       if (!st_map->st_ops->update)
+               return -EOPNOTSUPP;
+
        mutex_lock(&update_mutex);
 
        old_map = rcu_dereference_protected(st_link->map, lockdep_is_held(&update_mutex));
index 7f4e8c3..cb65854 100644 (file)
@@ -3378,14 +3378,13 @@ static int bpf_perf_link_fill_common(const struct perf_event *event,
 
        if (!ulen ^ !uname)
                return -EINVAL;
-       if (!uname)
-               return 0;
 
        err = bpf_get_perf_event_info(event, &prog_id, fd_type, &buf,
                                      probe_offset, probe_addr);
        if (err)
                return err;
-
+       if (!uname)
+               return 0;
        if (buf) {
                len = strlen(buf);
                err = bpf_copy_to_user(uname, buf, ulen, len);
index e1b4bfa..2b4a946 100644 (file)
@@ -1166,7 +1166,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
        int error;
 
        if (!hibernation_available())
-               return 0;
+               return n;
 
        if (len && buf[len-1] == '\n')
                len--;
index e86231a..c65566b 100644 (file)
@@ -1148,7 +1148,7 @@ static ssize_t extract_user_to_sg(struct iov_iter *iter,
 
 failed:
        while (sgtable->nents > sgtable->orig_nents)
-               put_page(sg_page(&sgtable->sgl[--sgtable->nents]));
+               unpin_user_page(sg_page(&sgtable->sgl[--sgtable->nents]));
        return res;
 }
 
index dbc9f86..eacca27 100644 (file)
@@ -912,11 +912,12 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
 
                /*
                 * Check if the pageblock has already been marked skipped.
-                * Only the aligned PFN is checked as the caller isolates
+                * Only the first PFN is checked as the caller isolates
                 * COMPACT_CLUSTER_MAX at a time so the second call must
                 * not falsely conclude that the block should be skipped.
                 */
-               if (!valid_page && pageblock_aligned(low_pfn)) {
+               if (!valid_page && (pageblock_aligned(low_pfn) ||
+                                   low_pfn == cc->zone->zone_start_pfn)) {
                        if (!isolation_suitable(cc, page)) {
                                low_pfn = end_pfn;
                                folio = NULL;
@@ -2002,7 +2003,8 @@ static isolate_migrate_t isolate_migratepages(struct compact_control *cc)
                 * before making it "skip" so other compaction instances do
                 * not scan the same block.
                 */
-               if (pageblock_aligned(low_pfn) &&
+               if ((pageblock_aligned(low_pfn) ||
+                    low_pfn == cc->zone->zone_start_pfn) &&
                    !fast_find_block && !isolation_suitable(cc, page))
                        continue;
 
index 91cff7f..eb95809 100644 (file)
@@ -273,6 +273,7 @@ struct damos_filter *damos_new_filter(enum damos_filter_type type,
                return NULL;
        filter->type = type;
        filter->matching = matching;
+       INIT_LIST_HEAD(&filter->list);
        return filter;
 }
 
index 64a3239..6da626b 100644 (file)
@@ -1579,9 +1579,37 @@ static inline void destroy_compound_gigantic_folio(struct folio *folio,
                                                unsigned int order) { }
 #endif
 
+static inline void __clear_hugetlb_destructor(struct hstate *h,
+                                               struct folio *folio)
+{
+       lockdep_assert_held(&hugetlb_lock);
+
+       /*
+        * Very subtle
+        *
+        * For non-gigantic pages set the destructor to the normal compound
+        * page dtor.  This is needed in case someone takes an additional
+        * temporary ref to the page, and freeing is delayed until they drop
+        * their reference.
+        *
+        * For gigantic pages set the destructor to the null dtor.  This
+        * destructor will never be called.  Before freeing the gigantic
+        * page destroy_compound_gigantic_folio will turn the folio into a
+        * simple group of pages.  After this the destructor does not
+        * apply.
+        *
+        */
+       if (hstate_is_gigantic(h))
+               folio_set_compound_dtor(folio, NULL_COMPOUND_DTOR);
+       else
+               folio_set_compound_dtor(folio, COMPOUND_PAGE_DTOR);
+}
+
 /*
- * Remove hugetlb folio from lists, and update dtor so that the folio appears
- * as just a compound page.
+ * Remove hugetlb folio from lists.
+ * If vmemmap exists for the folio, update dtor so that the folio appears
+ * as just a compound page.  Otherwise, wait until after allocating vmemmap
+ * to update dtor.
  *
  * A reference is held on the folio, except in the case of demote.
  *
@@ -1612,31 +1640,19 @@ static void __remove_hugetlb_folio(struct hstate *h, struct folio *folio,
        }
 
        /*
-        * Very subtle
-        *
-        * For non-gigantic pages set the destructor to the normal compound
-        * page dtor.  This is needed in case someone takes an additional
-        * temporary ref to the page, and freeing is delayed until they drop
-        * their reference.
-        *
-        * For gigantic pages set the destructor to the null dtor.  This
-        * destructor will never be called.  Before freeing the gigantic
-        * page destroy_compound_gigantic_folio will turn the folio into a
-        * simple group of pages.  After this the destructor does not
-        * apply.
-        *
-        * This handles the case where more than one ref is held when and
-        * after update_and_free_hugetlb_folio is called.
-        *
-        * In the case of demote we do not ref count the page as it will soon
-        * be turned into a page of smaller size.
+        * We can only clear the hugetlb destructor after allocating vmemmap
+        * pages.  Otherwise, someone (memory error handling) may try to write
+        * to tail struct pages.
+        */
+       if (!folio_test_hugetlb_vmemmap_optimized(folio))
+               __clear_hugetlb_destructor(h, folio);
+
+        /*
+         * In the case of demote we do not ref count the page as it will soon
+         * be turned into a page of smaller size.
         */
        if (!demote)
                folio_ref_unfreeze(folio, 1);
-       if (hstate_is_gigantic(h))
-               folio_set_compound_dtor(folio, NULL_COMPOUND_DTOR);
-       else
-               folio_set_compound_dtor(folio, COMPOUND_PAGE_DTOR);
 
        h->nr_huge_pages--;
        h->nr_huge_pages_node[nid]--;
@@ -1705,6 +1721,7 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
 {
        int i;
        struct page *subpage;
+       bool clear_dtor = folio_test_hugetlb_vmemmap_optimized(folio);
 
        if (hstate_is_gigantic(h) && !gigantic_page_runtime_supported())
                return;
@@ -1735,6 +1752,16 @@ static void __update_and_free_hugetlb_folio(struct hstate *h,
        if (unlikely(folio_test_hwpoison(folio)))
                folio_clear_hugetlb_hwpoison(folio);
 
+       /*
+        * If vmemmap pages were allocated above, then we need to clear the
+        * hugetlb destructor under the hugetlb lock.
+        */
+       if (clear_dtor) {
+               spin_lock_irq(&hugetlb_lock);
+               __clear_hugetlb_destructor(h, folio);
+               spin_unlock_irq(&hugetlb_lock);
+       }
+
        for (i = 0; i < pages_per_huge_page(h); i++) {
                subpage = folio_page(folio, i);
                subpage->flags &= ~(1 << PG_locked | 1 << PG_error |
index ba26635..d20d766 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2784,6 +2784,8 @@ struct page *ksm_might_need_to_copy(struct page *page,
                        anon_vma->root == vma->anon_vma->root) {
                return page;            /* still no need to copy it */
        }
+       if (PageHWPoison(page))
+               return ERR_PTR(-EHWPOISON);
        if (!PageUptodate(page))
                return page;            /* let do_swap_page report the error */
 
index ece5d48..9a28503 100644 (file)
@@ -2466,7 +2466,7 @@ int unpoison_memory(unsigned long pfn)
 {
        struct folio *folio;
        struct page *p;
-       int ret = -EBUSY;
+       int ret = -EBUSY, ghp;
        unsigned long count = 1;
        bool huge = false;
        static DEFINE_RATELIMIT_STATE(unpoison_rs, DEFAULT_RATELIMIT_INTERVAL,
@@ -2499,6 +2499,13 @@ int unpoison_memory(unsigned long pfn)
                goto unlock_mutex;
        }
 
+       if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio))
+               goto unlock_mutex;
+
+       /*
+        * Note that folio->_mapcount is overloaded in SLAB, so the simple test
+        * in folio_mapped() has to be done after folio_test_slab() is checked.
+        */
        if (folio_mapped(folio)) {
                unpoison_pr_info("Unpoison: Someone maps the hwpoison page %#lx\n",
                                 pfn, &unpoison_rs);
@@ -2511,32 +2518,28 @@ int unpoison_memory(unsigned long pfn)
                goto unlock_mutex;
        }
 
-       if (folio_test_slab(folio) || PageTable(&folio->page) || folio_test_reserved(folio))
-               goto unlock_mutex;
-
-       ret = get_hwpoison_page(p, MF_UNPOISON);
-       if (!ret) {
+       ghp = get_hwpoison_page(p, MF_UNPOISON);
+       if (!ghp) {
                if (PageHuge(p)) {
                        huge = true;
                        count = folio_free_raw_hwp(folio, false);
-                       if (count == 0) {
-                               ret = -EBUSY;
+                       if (count == 0)
                                goto unlock_mutex;
-                       }
                }
                ret = folio_test_clear_hwpoison(folio) ? 0 : -EBUSY;
-       } else if (ret < 0) {
-               if (ret == -EHWPOISON) {
+       } else if (ghp < 0) {
+               if (ghp == -EHWPOISON) {
                        ret = put_page_back_buddy(p) ? 0 : -EBUSY;
-               } else
+               } else {
+                       ret = ghp;
                        unpoison_pr_info("Unpoison: failed to grab page %#lx\n",
                                         pfn, &unpoison_rs);
+               }
        } else {
                if (PageHuge(p)) {
                        huge = true;
                        count = folio_free_raw_hwp(folio, false);
                        if (count == 0) {
-                               ret = -EBUSY;
                                folio_put(folio);
                                goto unlock_mutex;
                        }
index 8e6dde6..b15112b 100644 (file)
@@ -1746,7 +1746,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        struct page *swapcache;
        spinlock_t *ptl;
        pte_t *pte, new_pte, old_pte;
-       bool hwposioned = false;
+       bool hwpoisoned = PageHWPoison(page);
        int ret = 1;
 
        swapcache = page;
@@ -1754,7 +1754,7 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
        if (unlikely(!page))
                return -ENOMEM;
        else if (unlikely(PTR_ERR(page) == -EHWPOISON))
-               hwposioned = true;
+               hwpoisoned = true;
 
        pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
        if (unlikely(!pte || !pte_same_as_swp(ptep_get(pte),
@@ -1765,11 +1765,11 @@ static int unuse_pte(struct vm_area_struct *vma, pmd_t *pmd,
 
        old_pte = ptep_get(pte);
 
-       if (unlikely(hwposioned || !PageUptodate(page))) {
+       if (unlikely(hwpoisoned || !PageUptodate(page))) {
                swp_entry_t swp_entry;
 
                dec_mm_counter(vma->vm_mm, MM_SWAPENTS);
-               if (hwposioned) {
+               if (hwpoisoned) {
                        swp_entry = make_hwpoison_entry(swapcache);
                        page = swapcache;
                } else {
index 3f05797..32916d2 100644 (file)
@@ -1798,6 +1798,7 @@ static void replace_sub_page(struct size_class *class, struct zspage *zspage,
 
 static bool zs_page_isolate(struct page *page, isolate_mode_t mode)
 {
+       struct zs_pool *pool;
        struct zspage *zspage;
 
        /*
@@ -1807,9 +1808,10 @@ static bool zs_page_isolate(struct page *page, isolate_mode_t mode)
        VM_BUG_ON_PAGE(PageIsolated(page), page);
 
        zspage = get_zspage(page);
-       migrate_write_lock(zspage);
+       pool = zspage->pool;
+       spin_lock(&pool->lock);
        inc_zspage_isolation(zspage);
-       migrate_write_unlock(zspage);
+       spin_unlock(&pool->lock);
 
        return true;
 }
@@ -1875,12 +1877,12 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
        kunmap_atomic(s_addr);
 
        replace_sub_page(class, zspage, newpage, page);
+       dec_zspage_isolation(zspage);
        /*
         * Since we complete the data copy and set up new zspage structure,
         * it's okay to release the pool's lock.
         */
        spin_unlock(&pool->lock);
-       dec_zspage_isolation(zspage);
        migrate_write_unlock(zspage);
 
        get_page(newpage);
@@ -1897,14 +1899,16 @@ static int zs_page_migrate(struct page *newpage, struct page *page,
 
 static void zs_page_putback(struct page *page)
 {
+       struct zs_pool *pool;
        struct zspage *zspage;
 
        VM_BUG_ON_PAGE(!PageIsolated(page), page);
 
        zspage = get_zspage(page);
-       migrate_write_lock(zspage);
+       pool = zspage->pool;
+       spin_lock(&pool->lock);
        dec_zspage_isolation(zspage);
-       migrate_write_unlock(zspage);
+       spin_unlock(&pool->lock);
 }
 
 static const struct movable_operations zsmalloc_mops = {
index b366211..e40aa3e 100644 (file)
@@ -384,7 +384,8 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
                        dev->name);
                vlan_vid_add(dev, htons(ETH_P_8021Q), 0);
        }
-       if (event == NETDEV_DOWN)
+       if (event == NETDEV_DOWN &&
+           (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER))
                vlan_vid_del(dev, htons(ETH_P_8021Q), 0);
 
        vlan_info = rtnl_dereference(dev->vlan_info);
index 828fb39..74b49c3 100644 (file)
@@ -2516,6 +2516,7 @@ static struct batadv_algo_ops batadv_batman_iv __read_mostly = {
        },
        .gw = {
                .init_sel_class = batadv_iv_init_sel_class,
+               .sel_class_max = BATADV_TQ_MAX_VALUE,
                .get_best_gw_node = batadv_iv_gw_get_best_gw_node,
                .is_eligible = batadv_iv_gw_is_eligible,
                .dump = batadv_iv_gw_dump,
index 54e41fc..ac11f1f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/kref.h>
+#include <linux/limits.h>
 #include <linux/list.h>
 #include <linux/minmax.h>
 #include <linux/netdevice.h>
@@ -34,7 +35,6 @@
 #include "bat_v_elp.h"
 #include "bat_v_ogm.h"
 #include "gateway_client.h"
-#include "gateway_common.h"
 #include "hard-interface.h"
 #include "hash.h"
 #include "log.h"
@@ -512,25 +512,6 @@ static void batadv_v_init_sel_class(struct batadv_priv *bat_priv)
        atomic_set(&bat_priv->gw.sel_class, 50);
 }
 
-static ssize_t batadv_v_store_sel_class(struct batadv_priv *bat_priv,
-                                       char *buff, size_t count)
-{
-       u32 old_class, class;
-
-       if (!batadv_parse_throughput(bat_priv->soft_iface, buff,
-                                    "B.A.T.M.A.N. V GW selection class",
-                                    &class))
-               return -EINVAL;
-
-       old_class = atomic_read(&bat_priv->gw.sel_class);
-       atomic_set(&bat_priv->gw.sel_class, class);
-
-       if (old_class != class)
-               batadv_gw_reselect(bat_priv);
-
-       return count;
-}
-
 /**
  * batadv_v_gw_throughput_get() - retrieve the GW-bandwidth for a given GW
  * @gw_node: the GW to retrieve the metric for
@@ -818,7 +799,7 @@ static struct batadv_algo_ops batadv_batman_v __read_mostly = {
        },
        .gw = {
                .init_sel_class = batadv_v_init_sel_class,
-               .store_sel_class = batadv_v_store_sel_class,
+               .sel_class_max = U32_MAX,
                .get_best_gw_node = batadv_v_gw_get_best_gw_node,
                .is_eligible = batadv_v_gw_is_eligible,
                .dump = batadv_v_gw_dump,
index 6a964a7..2dd36ef 100644 (file)
 
 #include <linux/atomic.h>
 #include <linux/byteorder/generic.h>
-#include <linux/errno.h>
-#include <linux/kstrtox.h>
-#include <linux/limits.h>
-#include <linux/math64.h>
-#include <linux/netdevice.h>
 #include <linux/stddef.h>
-#include <linux/string.h>
+#include <linux/types.h>
 #include <uapi/linux/batadv_packet.h>
 #include <uapi/linux/batman_adv.h>
 
 #include "gateway_client.h"
-#include "log.h"
 #include "tvlv.h"
 
 /**
- * batadv_parse_throughput() - parse supplied string buffer to extract
- *  throughput information
- * @net_dev: the soft interface net device
- * @buff: string buffer to parse
- * @description: text shown when throughput string cannot be parsed
- * @throughput: pointer holding the returned throughput information
- *
- * Return: false on parse error and true otherwise.
- */
-bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
-                            const char *description, u32 *throughput)
-{
-       enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT;
-       u64 lthroughput;
-       char *tmp_ptr;
-       int ret;
-
-       if (strlen(buff) > 4) {
-               tmp_ptr = buff + strlen(buff) - 4;
-
-               if (strncasecmp(tmp_ptr, "mbit", 4) == 0)
-                       bw_unit_type = BATADV_BW_UNIT_MBIT;
-
-               if (strncasecmp(tmp_ptr, "kbit", 4) == 0 ||
-                   bw_unit_type == BATADV_BW_UNIT_MBIT)
-                       *tmp_ptr = '\0';
-       }
-
-       ret = kstrtou64(buff, 10, &lthroughput);
-       if (ret) {
-               batadv_err(net_dev,
-                          "Invalid throughput speed for %s: %s\n",
-                          description, buff);
-               return false;
-       }
-
-       switch (bw_unit_type) {
-       case BATADV_BW_UNIT_MBIT:
-               /* prevent overflow */
-               if (U64_MAX / 10 < lthroughput) {
-                       batadv_err(net_dev,
-                                  "Throughput speed for %s too large: %s\n",
-                                  description, buff);
-                       return false;
-               }
-
-               lthroughput *= 10;
-               break;
-       case BATADV_BW_UNIT_KBIT:
-       default:
-               lthroughput = div_u64(lthroughput, 100);
-               break;
-       }
-
-       if (lthroughput > U32_MAX) {
-               batadv_err(net_dev,
-                          "Throughput speed for %s too large: %s\n",
-                          description, buff);
-               return false;
-       }
-
-       *throughput = lthroughput;
-
-       return true;
-}
-
-/**
- * batadv_parse_gw_bandwidth() - parse supplied string buffer to extract
- *  download and upload bandwidth information
- * @net_dev: the soft interface net device
- * @buff: string buffer to parse
- * @down: pointer holding the returned download bandwidth information
- * @up: pointer holding the returned upload bandwidth information
- *
- * Return: false on parse error and true otherwise.
- */
-static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff,
-                                     u32 *down, u32 *up)
-{
-       char *slash_ptr;
-       bool ret;
-
-       slash_ptr = strchr(buff, '/');
-       if (slash_ptr)
-               *slash_ptr = 0;
-
-       ret = batadv_parse_throughput(net_dev, buff, "download gateway speed",
-                                     down);
-       if (!ret)
-               return false;
-
-       /* we also got some upload info */
-       if (slash_ptr) {
-               ret = batadv_parse_throughput(net_dev, slash_ptr + 1,
-                                             "upload gateway speed", up);
-               if (!ret)
-                       return false;
-       }
-
-       return true;
-}
-
-/**
  * batadv_gw_tvlv_container_update() - update the gw tvlv container after
  *  gateway setting change
  * @bat_priv: the bat priv with all the soft interface information
@@ -156,57 +47,6 @@ void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv)
 }
 
 /**
- * batadv_gw_bandwidth_set() - Parse and set download/upload gateway bandwidth
- *  from supplied string buffer
- * @net_dev: netdev struct of the soft interface
- * @buff: the buffer containing the user data
- * @count: number of bytes in the buffer
- *
- * Return: 'count' on success or a negative error code in case of failure
- */
-ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
-                               size_t count)
-{
-       struct batadv_priv *bat_priv = netdev_priv(net_dev);
-       u32 down_curr;
-       u32 up_curr;
-       u32 down_new = 0;
-       u32 up_new = 0;
-       bool ret;
-
-       down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down);
-       up_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_up);
-
-       ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new);
-       if (!ret)
-               return -EINVAL;
-
-       if (!down_new)
-               down_new = 1;
-
-       if (!up_new)
-               up_new = down_new / 5;
-
-       if (!up_new)
-               up_new = 1;
-
-       if (down_curr == down_new && up_curr == up_new)
-               return count;
-
-       batadv_gw_reselect(bat_priv);
-       batadv_info(net_dev,
-                   "Changing gateway bandwidth from: '%u.%u/%u.%u MBit' to: '%u.%u/%u.%u MBit'\n",
-                   down_curr / 10, down_curr % 10, up_curr / 10, up_curr % 10,
-                   down_new / 10, down_new % 10, up_new / 10, up_new % 10);
-
-       atomic_set(&bat_priv->gw.bandwidth_down, down_new);
-       atomic_set(&bat_priv->gw.bandwidth_up, up_new);
-       batadv_gw_tvlv_container_update(bat_priv);
-
-       return count;
-}
-
-/**
  * batadv_gw_tvlv_ogm_handler_v1() - process incoming gateway tvlv container
  * @bat_priv: the bat priv with all the soft interface information
  * @orig: the orig_node of the ogm
index 87c37f9..5d097d6 100644 (file)
@@ -9,9 +9,6 @@
 
 #include "main.h"
 
-#include <linux/netdevice.h>
-#include <linux/types.h>
-
 /**
  * enum batadv_bandwidth_units - bandwidth unit types
  */
@@ -27,12 +24,8 @@ enum batadv_bandwidth_units {
 #define BATADV_GW_MODE_CLIENT_NAME     "client"
 #define BATADV_GW_MODE_SERVER_NAME     "server"
 
-ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff,
-                               size_t count);
 void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv);
 void batadv_gw_init(struct batadv_priv *bat_priv);
 void batadv_gw_free(struct batadv_priv *bat_priv);
-bool batadv_parse_throughput(struct net_device *net_dev, char *buff,
-                            const char *description, u32 *throughput);
 
 #endif /* _NET_BATMAN_ADV_GATEWAY_COMMON_H_ */
index 41c1ad3..5a4ff9a 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/atomic.h>
 #include <linux/byteorder/generic.h>
+#include <linux/compiler.h>
 #include <linux/container_of.h>
 #include <linux/errno.h>
 #include <linux/gfp.h>
@@ -699,9 +700,14 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
        struct batadv_priv *bat_priv;
        __be16 ethertype = htons(ETH_P_BATMAN);
        int max_header_len = batadv_max_header_len();
+       unsigned int required_mtu;
+       unsigned int hardif_mtu;
        int ret;
 
-       if (hard_iface->net_dev->mtu < ETH_MIN_MTU + max_header_len)
+       hardif_mtu = READ_ONCE(hard_iface->net_dev->mtu);
+       required_mtu = READ_ONCE(soft_iface->mtu) + max_header_len;
+
+       if (hardif_mtu < ETH_MIN_MTU + max_header_len)
                return -EINVAL;
 
        if (hard_iface->if_status != BATADV_IF_NOT_IN_USE)
@@ -734,18 +740,18 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface,
                    hard_iface->net_dev->name);
 
        if (atomic_read(&bat_priv->fragmentation) &&
-           hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len)
+           hardif_mtu < required_mtu)
                batadv_info(hard_iface->soft_iface,
                            "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. Packets going over this interface will be fragmented on layer2 which could impact the performance. Setting the MTU to %i would solve the problem.\n",
-                           hard_iface->net_dev->name, hard_iface->net_dev->mtu,
-                           ETH_DATA_LEN + max_header_len);
+                           hard_iface->net_dev->name, hardif_mtu,
+                           required_mtu);
 
        if (!atomic_read(&bat_priv->fragmentation) &&
-           hard_iface->net_dev->mtu < ETH_DATA_LEN + max_header_len)
+           hardif_mtu < required_mtu)
                batadv_info(hard_iface->soft_iface,
                            "The MTU of interface %s is too small (%i) to handle the transport of batman-adv packets. If you experience problems getting traffic through try increasing the MTU to %i.\n",
-                           hard_iface->net_dev->name, hard_iface->net_dev->mtu,
-                           ETH_DATA_LEN + max_header_len);
+                           hard_iface->net_dev->name, hardif_mtu,
+                           required_mtu);
 
        if (batadv_hardif_is_iface_up(hard_iface))
                batadv_hardif_activate_interface(hard_iface);
index 156ed39..10007c5 100644 (file)
@@ -13,7 +13,7 @@
 #define BATADV_DRIVER_DEVICE "batman-adv"
 
 #ifndef BATADV_SOURCE_VERSION
-#define BATADV_SOURCE_VERSION "2023.1"
+#define BATADV_SOURCE_VERSION "2023.3"
 #endif
 
 /* B.A.T.M.A.N. parameters */
index ad5714f..d37872b 100644 (file)
@@ -377,7 +377,7 @@ nla_put_failure:
  *
  * Return: 0 on success, < 0 on error
  */
-int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv)
+static int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv)
 {
        struct sk_buff *msg;
        int ret;
@@ -548,15 +548,12 @@ static int batadv_netlink_set_mesh(struct sk_buff *skb, struct genl_info *info)
                 * algorithm in use implements the GW API
                 */
 
-               u32 sel_class_max = 0xffffffffu;
+               u32 sel_class_max = bat_priv->algo_ops->gw.sel_class_max;
                u32 sel_class;
 
                attr = info->attrs[BATADV_ATTR_GW_SEL_CLASS];
                sel_class = nla_get_u32(attr);
 
-               if (!bat_priv->algo_ops->gw.store_sel_class)
-                       sel_class_max = BATADV_TQ_MAX_VALUE;
-
                if (sel_class >= 1 && sel_class <= sel_class_max) {
                        atomic_set(&bat_priv->gw.sel_class, sel_class);
                        batadv_gw_reselect(bat_priv);
@@ -858,8 +855,8 @@ nla_put_failure:
  *
  * Return: 0 on success, < 0 on error
  */
-int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv,
-                                struct batadv_hard_iface *hard_iface)
+static int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv,
+                                       struct batadv_hard_iface *hard_iface)
 {
        struct sk_buff *msg;
        int ret;
@@ -1073,8 +1070,8 @@ nla_put_failure:
  *
  * Return: 0 on success, < 0 on error
  */
-int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv,
-                              struct batadv_softif_vlan *vlan)
+static int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv,
+                                     struct batadv_softif_vlan *vlan)
 {
        struct sk_buff *msg;
        int ret;
index 48102cc..876d280 100644 (file)
@@ -21,12 +21,6 @@ int batadv_netlink_tpmeter_notify(struct batadv_priv *bat_priv, const u8 *dst,
                                  u8 result, u32 test_time, u64 total_bytes,
                                  u32 cookie);
 
-int batadv_netlink_notify_mesh(struct batadv_priv *bat_priv);
-int batadv_netlink_notify_hardif(struct batadv_priv *bat_priv,
-                                struct batadv_hard_iface *hard_iface);
-int batadv_netlink_notify_vlan(struct batadv_priv *bat_priv,
-                              struct batadv_softif_vlan *vlan);
-
 extern struct genl_family batadv_netlink_family;
 
 #endif /* _NET_BATMAN_ADV_NETLINK_H_ */
index 5f38778..afd15b3 100644 (file)
@@ -27,10 +27,6 @@ int batadv_recv_frag_packet(struct sk_buff *skb,
                            struct batadv_hard_iface *iface);
 int batadv_recv_bcast_packet(struct sk_buff *skb,
                             struct batadv_hard_iface *recv_if);
-int batadv_recv_tt_query(struct sk_buff *skb,
-                        struct batadv_hard_iface *recv_if);
-int batadv_recv_roam_adv(struct sk_buff *skb,
-                        struct batadv_hard_iface *recv_if);
 int batadv_recv_unicast_tvlv(struct sk_buff *skb,
                             struct batadv_hard_iface *recv_if);
 int batadv_recv_unhandled_unicast_packet(struct sk_buff *skb,
index d3fdf82..f7947fa 100644 (file)
@@ -154,7 +154,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p)
 static int batadv_interface_change_mtu(struct net_device *dev, int new_mtu)
 {
        /* check ranges */
-       if (new_mtu < 68 || new_mtu > batadv_hardif_min_mtu(dev))
+       if (new_mtu < ETH_MIN_MTU || new_mtu > batadv_hardif_min_mtu(dev))
                return -EINVAL;
 
        dev->mtu = new_mtu;
index ca9449e..54c2b8f 100644 (file)
@@ -2191,11 +2191,10 @@ struct batadv_algo_gw_ops {
        void (*init_sel_class)(struct batadv_priv *bat_priv);
 
        /**
-        * @store_sel_class: parse and stores a new GW selection class
-        *  (optional)
+        * @sel_class_max: maximum allowed GW selection class
         */
-       ssize_t (*store_sel_class)(struct batadv_priv *bat_priv, char *buff,
-                                  size_t count);
+       u32 sel_class_max;
+
        /**
         * @get_best_gw_node: select the best GW from the list of available
         *  nodes (optional)
index 33fdf04..9b5bc62 100644 (file)
@@ -4795,12 +4795,23 @@ static void skb_extensions_init(void)
 static void skb_extensions_init(void) {}
 #endif
 
+/* The SKB kmem_cache slab is critical for network performance.  Never
+ * merge/alias the slab with similar sized objects.  This avoids fragmentation
+ * that hurts performance of kmem_cache_{alloc,free}_bulk APIs.
+ */
+#ifndef CONFIG_SLUB_TINY
+#define FLAG_SKB_NO_MERGE      SLAB_NO_MERGE
+#else /* CONFIG_SLUB_TINY - simple loop in kmem_cache_alloc_bulk */
+#define FLAG_SKB_NO_MERGE      0
+#endif
+
 void __init skb_init(void)
 {
        skbuff_cache = kmem_cache_create_usercopy("skbuff_head_cache",
                                              sizeof(struct sk_buff),
                                              0,
-                                             SLAB_HWCACHE_ALIGN|SLAB_PANIC,
+                                             SLAB_HWCACHE_ALIGN|SLAB_PANIC|
+                                               FLAG_SKB_NO_MERGE,
                                              offsetof(struct sk_buff, cb),
                                              sizeof_field(struct sk_buff, cb),
                                              NULL);
index 22d9439..a072295 100644 (file)
@@ -3160,7 +3160,7 @@ void __sk_mem_reduce_allocated(struct sock *sk, int amount)
        if (mem_cgroup_sockets_enabled && sk->sk_memcg)
                mem_cgroup_uncharge_skmem(sk->sk_memcg, amount);
 
-       if (sk_under_memory_pressure(sk) &&
+       if (sk_under_global_memory_pressure(sk) &&
            (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)))
                sk_leave_memory_pressure(sk);
 }
index 53bfd8a..d1e7d0c 100644 (file)
@@ -287,12 +287,12 @@ static netdev_tx_t vti_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 
        switch (skb->protocol) {
        case htons(ETH_P_IP):
-               xfrm_decode_session(skb, &fl, AF_INET);
                memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET);
                break;
        case htons(ETH_P_IPV6):
-               xfrm_decode_session(skb, &fl, AF_INET6);
                memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET6);
                break;
        default:
                goto tx_err;
index 74c70fc..984ab4a 100644 (file)
@@ -618,7 +618,9 @@ out_reset_timer:
            tcp_stream_is_thin(tp) &&
            icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) {
                icsk->icsk_backoff = 0;
-               icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX);
+               icsk->icsk_rto = clamp(__tcp_set_rto(tp),
+                                      tcp_rto_min(sk),
+                                      TCP_RTO_MAX);
        } else if (sk->sk_state != TCP_SYN_SENT ||
                   icsk->icsk_backoff >
                   READ_ONCE(net->ipv4.sysctl_tcp_syn_linear_timeouts)) {
index 658bfed..08d4b71 100644 (file)
@@ -152,7 +152,7 @@ config INET6_TUNNEL
        default n
 
 config IPV6_VTI
-tristate "Virtual (secure) IPv6: tunneling"
+       tristate "Virtual (secure) IPv6: tunneling"
        select IPV6_TUNNEL
        select NET_IP_TUNNEL
        select XFRM
index 10b2228..73c85d4 100644 (file)
@@ -568,12 +568,12 @@ vti6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
                    vti6_addr_conflict(t, ipv6_hdr(skb)))
                        goto tx_err;
 
-               xfrm_decode_session(skb, &fl, AF_INET6);
                memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET6);
                break;
        case htons(ETH_P_IP):
-               xfrm_decode_session(skb, &fl, AF_INET);
                memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET);
                break;
        default:
                goto tx_err;
index 542439b..d68d018 100644 (file)
@@ -1847,9 +1847,9 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_ms
        if (ext_hdrs[SADB_X_EXT_FILTER - 1]) {
                struct sadb_x_filter *xfilter = ext_hdrs[SADB_X_EXT_FILTER - 1];
 
-               if ((xfilter->sadb_x_filter_splen >=
+               if ((xfilter->sadb_x_filter_splen >
                        (sizeof(xfrm_address_t) << 3)) ||
-                   (xfilter->sadb_x_filter_dplen >=
+                   (xfilter->sadb_x_filter_dplen >
                        (sizeof(xfrm_address_t) << 3))) {
                        mutex_unlock(&pfk->dump_lock);
                        return -EINVAL;
index 5a0a84a..8a16672 100644 (file)
@@ -19,3 +19,18 @@ struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
 
        return NULL;
 }
+
+BTF_SET8_START(bpf_mptcp_fmodret_ids)
+BTF_ID_FLAGS(func, update_socket_protocol)
+BTF_SET8_END(bpf_mptcp_fmodret_ids)
+
+static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
+       .owner = THIS_MODULE,
+       .set   = &bpf_mptcp_fmodret_ids,
+};
+
+static int __init bpf_mptcp_kfunc_init(void)
+{
+       return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
+}
+late_initcall(bpf_mptcp_kfunc_init);
index 62606fb..4bb0d90 100644 (file)
@@ -1876,6 +1876,7 @@ static int
 proc_do_sync_threshold(struct ctl_table *table, int write,
                       void *buffer, size_t *lenp, loff_t *ppos)
 {
+       struct netns_ipvs *ipvs = table->extra2;
        int *valp = table->data;
        int val[2];
        int rc;
@@ -1885,6 +1886,7 @@ proc_do_sync_threshold(struct ctl_table *table, int write,
                .mode = table->mode,
        };
 
+       mutex_lock(&ipvs->sync_mutex);
        memcpy(val, valp, sizeof(val));
        rc = proc_dointvec(&tmp, write, buffer, lenp, ppos);
        if (write) {
@@ -1894,6 +1896,7 @@ proc_do_sync_threshold(struct ctl_table *table, int write,
                else
                        memcpy(valp, val, sizeof(val));
        }
+       mutex_unlock(&ipvs->sync_mutex);
        return rc;
 }
 
@@ -4321,6 +4324,7 @@ static int __net_init ip_vs_control_net_init_sysctl(struct netns_ipvs *ipvs)
        ipvs->sysctl_sync_threshold[0] = DEFAULT_SYNC_THRESHOLD;
        ipvs->sysctl_sync_threshold[1] = DEFAULT_SYNC_PERIOD;
        tbl[idx].data = &ipvs->sysctl_sync_threshold;
+       tbl[idx].extra2 = ipvs;
        tbl[idx++].maxlen = sizeof(ipvs->sysctl_sync_threshold);
        ipvs->sysctl_sync_refresh_period = DEFAULT_SYNC_REFRESH_PERIOD;
        tbl[idx++].data = &ipvs->sysctl_sync_refresh_period;
index 91eacc9..b6bcc8f 100644 (file)
@@ -49,8 +49,8 @@ static const unsigned int sctp_timeouts[SCTP_CONNTRACK_MAX] = {
        [SCTP_CONNTRACK_COOKIE_WAIT]            = 3 SECS,
        [SCTP_CONNTRACK_COOKIE_ECHOED]          = 3 SECS,
        [SCTP_CONNTRACK_ESTABLISHED]            = 210 SECS,
-       [SCTP_CONNTRACK_SHUTDOWN_SENT]          = 300 SECS / 1000,
-       [SCTP_CONNTRACK_SHUTDOWN_RECD]          = 300 SECS / 1000,
+       [SCTP_CONNTRACK_SHUTDOWN_SENT]          = 3 SECS,
+       [SCTP_CONNTRACK_SHUTDOWN_RECD]          = 3 SECS,
        [SCTP_CONNTRACK_SHUTDOWN_ACK_SENT]      = 3 SECS,
        [SCTP_CONNTRACK_HEARTBEAT_SENT]         = 30 SECS,
 };
@@ -105,7 +105,7 @@ static const u8 sctp_conntracks[2][11][SCTP_CONNTRACK_MAX] = {
        {
 /*     ORIGINAL        */
 /*                  sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA, sHS */
-/* init         */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCW},
+/* init         */ {sCL, sCL, sCW, sCE, sES, sCL, sCL, sSA, sCW},
 /* init_ack     */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA, sCL},
 /* abort        */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},
 /* shutdown     */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA, sCL},
index c62227a..3e841e4 100644 (file)
@@ -7091,6 +7091,7 @@ static int nft_set_catchall_flush(const struct nft_ctx *ctx,
                ret = __nft_set_catchall_flush(ctx, set, &elem);
                if (ret < 0)
                        break;
+               nft_set_elem_change_active(ctx->net, set, ext);
        }
 
        return ret;
@@ -9480,9 +9481,14 @@ struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set,
        if (!trans)
                return NULL;
 
+       trans->net = maybe_get_net(net);
+       if (!trans->net) {
+               kfree(trans);
+               return NULL;
+       }
+
        refcount_inc(&set->refs);
        trans->set = set;
-       trans->net = get_net(net);
        trans->seq = gc_seq;
 
        return trans;
@@ -9738,6 +9744,22 @@ static void nft_set_commit_update(struct list_head *set_update_list)
        }
 }
 
+static unsigned int nft_gc_seq_begin(struct nftables_pernet *nft_net)
+{
+       unsigned int gc_seq;
+
+       /* Bump gc counter, it becomes odd, this is the busy mark. */
+       gc_seq = READ_ONCE(nft_net->gc_seq);
+       WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
+
+       return gc_seq;
+}
+
+static void nft_gc_seq_end(struct nftables_pernet *nft_net, unsigned int gc_seq)
+{
+       WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
+}
+
 static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
@@ -9823,9 +9845,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
 
        WRITE_ONCE(nft_net->base_seq, base_seq);
 
-       /* Bump gc counter, it becomes odd, this is the busy mark. */
-       gc_seq = READ_ONCE(nft_net->gc_seq);
-       WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
+       gc_seq = nft_gc_seq_begin(nft_net);
 
        /* step 3. Start new generation, rules_gen_X now in use. */
        net->nft.gencursor = nft_gencursor_next(net);
@@ -10038,7 +10058,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
        nf_tables_gen_notify(net, skb, NFT_MSG_NEWGEN);
        nf_tables_commit_audit_log(&adl, nft_net->base_seq);
 
-       WRITE_ONCE(nft_net->gc_seq, ++gc_seq);
+       nft_gc_seq_end(nft_net, gc_seq);
        nf_tables_commit_release(net);
 
        return 0;
@@ -11039,6 +11059,7 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
        struct net *net = n->net;
        unsigned int deleted;
        bool restart = false;
+       unsigned int gc_seq;
 
        if (event != NETLINK_URELEASE || n->protocol != NETLINK_NETFILTER)
                return NOTIFY_DONE;
@@ -11046,6 +11067,9 @@ static int nft_rcv_nl_event(struct notifier_block *this, unsigned long event,
        nft_net = nft_pernet(net);
        deleted = 0;
        mutex_lock(&nft_net->commit_mutex);
+
+       gc_seq = nft_gc_seq_begin(nft_net);
+
        if (!list_empty(&nf_tables_destroy_list))
                rcu_barrier();
 again:
@@ -11068,6 +11092,8 @@ again:
                if (restart)
                        goto again;
        }
+       nft_gc_seq_end(nft_net, gc_seq);
+
        mutex_unlock(&nft_net->commit_mutex);
 
        return NOTIFY_DONE;
@@ -11105,12 +11131,20 @@ static void __net_exit nf_tables_pre_exit_net(struct net *net)
 static void __net_exit nf_tables_exit_net(struct net *net)
 {
        struct nftables_pernet *nft_net = nft_pernet(net);
+       unsigned int gc_seq;
 
        mutex_lock(&nft_net->commit_mutex);
+
+       gc_seq = nft_gc_seq_begin(nft_net);
+
        if (!list_empty(&nft_net->commit_list) ||
            !list_empty(&nft_net->module_list))
                __nf_tables_abort(net, NFNL_ABORT_NONE);
+
        __nft_release_tables(net);
+
+       nft_gc_seq_end(nft_net, gc_seq);
+
        mutex_unlock(&nft_net->commit_mutex);
        WARN_ON_ONCE(!list_empty(&nft_net->tables));
        WARN_ON_ONCE(!list_empty(&nft_net->module_list));
index 4fb34d7..5c5cc01 100644 (file)
@@ -191,6 +191,9 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
        if (IS_ERR(set))
                return PTR_ERR(set);
 
+       if (set->flags & NFT_SET_OBJECT)
+               return -EOPNOTSUPP;
+
        if (set->ops->update == NULL)
                return -EOPNOTSUPP;
 
index a5b8301..3757fcc 100644 (file)
@@ -566,6 +566,8 @@ next_match:
                        goto out;
 
                if (last) {
+                       if (nft_set_elem_expired(&f->mt[b].e->ext))
+                               goto next_match;
                        if ((genmask &&
                             !nft_set_elem_active(&f->mt[b].e->ext, genmask)))
                                goto next_match;
@@ -600,17 +602,8 @@ out:
 static void *nft_pipapo_get(const struct net *net, const struct nft_set *set,
                            const struct nft_set_elem *elem, unsigned int flags)
 {
-       struct nft_pipapo_elem *ret;
-
-       ret = pipapo_get(net, set, (const u8 *)elem->key.val.data,
+       return pipapo_get(net, set, (const u8 *)elem->key.val.data,
                         nft_genmask_cur(net));
-       if (IS_ERR(ret))
-               return ret;
-
-       if (nft_set_elem_expired(&ret->ext))
-               return ERR_PTR(-ENOENT);
-
-       return ret;
 }
 
 /**
@@ -1549,7 +1542,7 @@ static void nft_pipapo_gc_deactivate(struct net *net, struct nft_set *set,
 
 /**
  * pipapo_gc() - Drop expired entries from set, destroy start and end elements
- * @set:       nftables API set representation
+ * @_set:      nftables API set representation
  * @m:         Matching data
  */
 static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
@@ -1697,6 +1690,17 @@ static void nft_pipapo_commit(const struct nft_set *set)
        priv->clone = new_clone;
 }
 
+static bool nft_pipapo_transaction_mutex_held(const struct nft_set *set)
+{
+#ifdef CONFIG_PROVE_LOCKING
+       const struct net *net = read_pnet(&set->net);
+
+       return lockdep_is_held(&nft_pernet(net)->commit_mutex);
+#else
+       return true;
+#endif
+}
+
 static void nft_pipapo_abort(const struct nft_set *set)
 {
        struct nft_pipapo *priv = nft_set_priv(set);
@@ -1705,7 +1709,7 @@ static void nft_pipapo_abort(const struct nft_set *set)
        if (!priv->dirty)
                return;
 
-       m = rcu_dereference(priv->match);
+       m = rcu_dereference_protected(priv->match, nft_pipapo_transaction_mutex_held(set));
 
        new_clone = pipapo_clone(m);
        if (IS_ERR(new_clone))
@@ -1732,11 +1736,7 @@ static void nft_pipapo_activate(const struct net *net,
                                const struct nft_set *set,
                                const struct nft_set_elem *elem)
 {
-       struct nft_pipapo_elem *e;
-
-       e = pipapo_get(net, set, (const u8 *)elem->key.val.data, 0);
-       if (IS_ERR(e))
-               return;
+       struct nft_pipapo_elem *e = elem->priv;
 
        nft_set_elem_change_active(net, set, &e->ext);
 }
@@ -1950,10 +1950,6 @@ static void nft_pipapo_remove(const struct net *net, const struct nft_set *set,
 
        data = (const u8 *)nft_set_ext_key(&e->ext);
 
-       e = pipapo_get(net, set, data, 0);
-       if (IS_ERR(e))
-               return;
-
        while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
                union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
                const u8 *match_start, *match_end;
index 0a974ee..11c6941 100644 (file)
@@ -1830,7 +1830,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        parms.port_no = OVSP_LOCAL;
        parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
        parms.desired_ifindex = a[OVS_DP_ATTR_IFINDEX]
-               ? nla_get_u32(a[OVS_DP_ATTR_IFINDEX]) : 0;
+               ? nla_get_s32(a[OVS_DP_ATTR_IFINDEX]) : 0;
 
        /* So far only local changes have been made, now need the lock. */
        ovs_lock();
@@ -2053,7 +2053,7 @@ static const struct nla_policy datapath_policy[OVS_DP_ATTR_MAX + 1] = {
        [OVS_DP_ATTR_USER_FEATURES] = { .type = NLA_U32 },
        [OVS_DP_ATTR_MASKS_CACHE_SIZE] =  NLA_POLICY_RANGE(NLA_U32, 0,
                PCPU_MIN_UNIT_SIZE / sizeof(struct mask_cache_entry)),
-       [OVS_DP_ATTR_IFINDEX] = {.type = NLA_U32 },
+       [OVS_DP_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
 };
 
 static const struct genl_small_ops dp_datapath_genl_ops[] = {
@@ -2306,7 +2306,7 @@ restart:
        parms.port_no = port_no;
        parms.upcall_portids = a[OVS_VPORT_ATTR_UPCALL_PID];
        parms.desired_ifindex = a[OVS_VPORT_ATTR_IFINDEX]
-               ? nla_get_u32(a[OVS_VPORT_ATTR_IFINDEX]) : 0;
+               ? nla_get_s32(a[OVS_VPORT_ATTR_IFINDEX]) : 0;
 
        vport = new_vport(&parms);
        err = PTR_ERR(vport);
@@ -2543,7 +2543,7 @@ static const struct nla_policy vport_policy[OVS_VPORT_ATTR_MAX + 1] = {
        [OVS_VPORT_ATTR_TYPE] = { .type = NLA_U32 },
        [OVS_VPORT_ATTR_UPCALL_PID] = { .type = NLA_UNSPEC },
        [OVS_VPORT_ATTR_OPTIONS] = { .type = NLA_NESTED },
-       [OVS_VPORT_ATTR_IFINDEX] = { .type = NLA_U32 },
+       [OVS_VPORT_ATTR_IFINDEX] = NLA_POLICY_MIN(NLA_S32, 0),
        [OVS_VPORT_ATTR_NETNSID] = { .type = NLA_S32 },
        [OVS_VPORT_ATTR_UPCALL_STATS] = { .type = NLA_NESTED },
 };
index 38d9aa0..4ad39a4 100644 (file)
@@ -105,6 +105,11 @@ struct netem_sched_data {
                u32 rho;
        } delay_cor, loss_cor, dup_cor, reorder_cor, corrupt_cor;
 
+       struct prng  {
+               u64 seed;
+               struct rnd_state prng_state;
+       } prng;
+
        struct disttable *delay_dist;
 
        enum  {
@@ -179,15 +184,16 @@ static void init_crandom(struct crndstate *state, unsigned long rho)
  * Next number depends on last value.
  * rho is scaled to avoid floating point.
  */
-static u32 get_crandom(struct crndstate *state)
+static u32 get_crandom(struct crndstate *state, struct prng *p)
 {
        u64 value, rho;
        unsigned long answer;
+       struct rnd_state *s = &p->prng_state;
 
        if (!state || state->rho == 0)  /* no correlation */
-               return get_random_u32();
+               return prandom_u32_state(s);
 
-       value = get_random_u32();
+       value = prandom_u32_state(s);
        rho = (u64)state->rho + 1;
        answer = (value * ((1ull<<32) - rho) + state->last * rho) >> 32;
        state->last = answer;
@@ -201,7 +207,7 @@ static u32 get_crandom(struct crndstate *state)
 static bool loss_4state(struct netem_sched_data *q)
 {
        struct clgstate *clg = &q->clg;
-       u32 rnd = get_random_u32();
+       u32 rnd = prandom_u32_state(&q->prng.prng_state);
 
        /*
         * Makes a comparison between rnd and the transition
@@ -266,18 +272,19 @@ static bool loss_4state(struct netem_sched_data *q)
 static bool loss_gilb_ell(struct netem_sched_data *q)
 {
        struct clgstate *clg = &q->clg;
+       struct rnd_state *s = &q->prng.prng_state;
 
        switch (clg->state) {
        case GOOD_STATE:
-               if (get_random_u32() < clg->a1)
+               if (prandom_u32_state(s) < clg->a1)
                        clg->state = BAD_STATE;
-               if (get_random_u32() < clg->a4)
+               if (prandom_u32_state(s) < clg->a4)
                        return true;
                break;
        case BAD_STATE:
-               if (get_random_u32() < clg->a2)
+               if (prandom_u32_state(s) < clg->a2)
                        clg->state = GOOD_STATE;
-               if (get_random_u32() > clg->a3)
+               if (prandom_u32_state(s) > clg->a3)
                        return true;
        }
 
@@ -289,7 +296,7 @@ static bool loss_event(struct netem_sched_data *q)
        switch (q->loss_model) {
        case CLG_RANDOM:
                /* Random packet drop 0 => none, ~0 => all */
-               return q->loss && q->loss >= get_crandom(&q->loss_cor);
+               return q->loss && q->loss >= get_crandom(&q->loss_cor, &q->prng);
 
        case CLG_4_STATES:
                /* 4state loss model algorithm (used also for GI model)
@@ -318,6 +325,7 @@ static bool loss_event(struct netem_sched_data *q)
  */
 static s64 tabledist(s64 mu, s32 sigma,
                     struct crndstate *state,
+                    struct prng *prng,
                     const struct disttable *dist)
 {
        s64 x;
@@ -327,7 +335,7 @@ static s64 tabledist(s64 mu, s32 sigma,
        if (sigma == 0)
                return mu;
 
-       rnd = get_crandom(state);
+       rnd = get_crandom(state, prng);
 
        /* default uniform distribution */
        if (dist == NULL)
@@ -449,7 +457,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
        skb->prev = NULL;
 
        /* Random duplication */
-       if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor))
+       if (q->duplicate && q->duplicate >= get_crandom(&q->dup_cor, &q->prng))
                ++count;
 
        /* Drop packet? */
@@ -492,7 +500,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
         * If packet is going to be hardware checksummed, then
         * do it now in software before we mangle it.
         */
-       if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor)) {
+       if (q->corrupt && q->corrupt >= get_crandom(&q->corrupt_cor, &q->prng)) {
                if (skb_is_gso(skb)) {
                        skb = netem_segment(skb, sch, to_free);
                        if (!skb)
@@ -530,12 +538,12 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
        cb = netem_skb_cb(skb);
        if (q->gap == 0 ||              /* not doing reordering */
            q->counter < q->gap - 1 ||  /* inside last reordering gap */
-           q->reorder < get_crandom(&q->reorder_cor)) {
+           q->reorder < get_crandom(&q->reorder_cor, &q->prng)) {
                u64 now;
                s64 delay;
 
                delay = tabledist(q->latency, q->jitter,
-                                 &q->delay_cor, q->delay_dist);
+                                 &q->delay_cor, &q->prng, q->delay_dist);
 
                now = ktime_get_ns();
 
@@ -639,7 +647,7 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)
        else
                next_delay = tabledist(q->slot_config.dist_delay,
                                       (s32)(q->slot_config.dist_jitter),
-                                      NULL, q->slot_dist);
+                                      NULL, &q->prng, q->slot_dist);
 
        q->slot.slot_next = now + next_delay;
        q->slot.packets_left = q->slot_config.max_packets;
@@ -922,6 +930,7 @@ static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = {
        [TCA_NETEM_LATENCY64]   = { .type = NLA_S64 },
        [TCA_NETEM_JITTER64]    = { .type = NLA_S64 },
        [TCA_NETEM_SLOT]        = { .len = sizeof(struct tc_netem_slot) },
+       [TCA_NETEM_PRNG_SEED]   = { .type = NLA_U64 },
 };
 
 static int parse_attr(struct nlattr *tb[], int maxtype, struct nlattr *nla,
@@ -1040,6 +1049,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
        /* capping jitter to the range acceptable by tabledist() */
        q->jitter = min_t(s64, abs(q->jitter), INT_MAX);
 
+       if (tb[TCA_NETEM_PRNG_SEED])
+               q->prng.seed = nla_get_u64(tb[TCA_NETEM_PRNG_SEED]);
+       else
+               q->prng.seed = get_random_u64();
+       prandom_seed_state(&q->prng.prng_state, q->prng.seed);
+
 unlock:
        sch_tree_unlock(sch);
 
@@ -1203,6 +1218,10 @@ static int netem_dump(struct Qdisc *sch, struct sk_buff *skb)
                        goto nla_put_failure;
        }
 
+       if (nla_put_u64_64bit(skb, TCA_NETEM_PRNG_SEED, q->prng.seed,
+                             TCA_NETEM_PAD))
+               goto nla_put_failure;
+
        return nla_nest_end(skb, nla);
 
 nla_put_failure:
index 5d4e375..fdb5233 100644 (file)
@@ -1657,12 +1657,36 @@ struct file *__sys_socket_file(int family, int type, int protocol)
        return sock_alloc_file(sock, flags, NULL);
 }
 
+/*     A hook for bpf progs to attach to and update socket protocol.
+ *
+ *     A static noinline declaration here could cause the compiler to
+ *     optimize away the function. A global noinline declaration will
+ *     keep the definition, but may optimize away the callsite.
+ *     Therefore, __weak is needed to ensure that the call is still
+ *     emitted, by telling the compiler that we don't know what the
+ *     function might eventually be.
+ *
+ *     __diag_* below are needed to dismiss the missing prototype warning.
+ */
+
+__diag_push();
+__diag_ignore_all("-Wmissing-prototypes",
+                 "A fmod_ret entry point for BPF programs");
+
+__weak noinline int update_socket_protocol(int family, int type, int protocol)
+{
+       return protocol;
+}
+
+__diag_pop();
+
 int __sys_socket(int family, int type, int protocol)
 {
        struct socket *sock;
        int flags;
 
-       sock = __sys_socket_create(family, type, protocol);
+       sock = __sys_socket_create(family, type,
+                                  update_socket_protocol(family, type, protocol));
        if (IS_ERR(sock))
                return PTR_ERR(sock);
 
index 2ed29e4..8c9a8ee 100644 (file)
@@ -1248,6 +1248,9 @@ static int svc_tcp_sendmsg(struct socket *sock, struct xdr_buf *xdr,
        if (ret != head->iov_len)
                goto out;
 
+       if (xdr_buf_pagecount(xdr))
+               xdr->bvec[0].bv_offset = offset_in_page(xdr->page_base);
+
        msg.msg_flags = MSG_SPLICE_PAGES;
        iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, xdr->bvec,
                      xdr_buf_pagecount(xdr), xdr->page_len);
index 8cbf45a..655fe4f 100644 (file)
@@ -108,7 +108,7 @@ static const struct nla_policy compat_policy[XFRMA_MAX+1] = {
        [XFRMA_ALG_COMP]        = { .len = sizeof(struct xfrm_algo) },
        [XFRMA_ENCAP]           = { .len = sizeof(struct xfrm_encap_tmpl) },
        [XFRMA_TMPL]            = { .len = sizeof(struct xfrm_user_tmpl) },
-       [XFRMA_SEC_CTX]         = { .len = sizeof(struct xfrm_sec_ctx) },
+       [XFRMA_SEC_CTX]         = { .len = sizeof(struct xfrm_user_sec_ctx) },
        [XFRMA_LTIME_VAL]       = { .len = sizeof(struct xfrm_lifetime_cur) },
        [XFRMA_REPLAY_VAL]      = { .len = sizeof(struct xfrm_replay_state) },
        [XFRMA_REPLAY_THRESH]   = { .type = NLA_U32 },
index 815b380..d5ee967 100644 (file)
@@ -180,6 +180,8 @@ static int xfrm4_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
        int optlen = 0;
        int err = -EINVAL;
 
+       skb->protocol = htons(ETH_P_IP);
+
        if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) {
                struct ip_beet_phdr *ph;
                int phlen;
@@ -232,6 +234,8 @@ static int xfrm4_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err = -EINVAL;
 
+       skb->protocol = htons(ETH_P_IP);
+
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
                goto out;
 
@@ -267,6 +271,8 @@ static int xfrm6_remove_tunnel_encap(struct xfrm_state *x, struct sk_buff *skb)
 {
        int err = -EINVAL;
 
+       skb->protocol = htons(ETH_P_IPV6);
+
        if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
                goto out;
 
@@ -296,6 +302,8 @@ static int xfrm6_remove_beet_encap(struct xfrm_state *x, struct sk_buff *skb)
        int size = sizeof(struct ipv6hdr);
        int err;
 
+       skb->protocol = htons(ETH_P_IPV6);
+
        err = skb_cow_head(skb, size + skb->mac_len);
        if (err)
                goto out;
@@ -346,6 +354,7 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
                        return xfrm6_remove_tunnel_encap(x, skb);
                break;
                }
+               return -EINVAL;
        }
 
        WARN_ON_ONCE(1);
@@ -366,19 +375,6 @@ static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
                return -EAFNOSUPPORT;
        }
 
-       switch (XFRM_MODE_SKB_CB(skb)->protocol) {
-       case IPPROTO_IPIP:
-       case IPPROTO_BEETPH:
-               skb->protocol = htons(ETH_P_IP);
-               break;
-       case IPPROTO_IPV6:
-               skb->protocol = htons(ETH_P_IPV6);
-               break;
-       default:
-               WARN_ON_ONCE(1);
-               break;
-       }
-
        return xfrm_inner_mode_encap_remove(x, skb);
 }
 
index a331996..b864740 100644 (file)
@@ -537,8 +537,8 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
 
        switch (skb->protocol) {
        case htons(ETH_P_IPV6):
-               xfrm_decode_session(skb, &fl, AF_INET6);
                memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET6);
                if (!dst) {
                        fl.u.ip6.flowi6_oif = dev->ifindex;
                        fl.u.ip6.flowi6_flags |= FLOWI_FLAG_ANYSRC;
@@ -552,8 +552,8 @@ static netdev_tx_t xfrmi_xmit(struct sk_buff *skb, struct net_device *dev)
                }
                break;
        case htons(ETH_P_IP):
-               xfrm_decode_session(skb, &fl, AF_INET);
                memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
+               xfrm_decode_session(skb, &fl, AF_INET);
                if (!dst) {
                        struct rtable *rt;
 
index 49e63ee..bda5327 100644 (file)
@@ -1324,12 +1324,8 @@ found:
                        struct xfrm_dev_offload *xso = &x->xso;
 
                        if (xso->type == XFRM_DEV_OFFLOAD_PACKET) {
-                               xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
-                               xso->dir = 0;
-                               netdev_put(xso->dev, &xso->dev_tracker);
-                               xso->dev = NULL;
-                               xso->real_dev = NULL;
-                               xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
+                               xfrm_dev_state_delete(x);
+                               xfrm_dev_state_free(x);
                        }
 #endif
                        x->km.state = XFRM_STATE_DEAD;
index c34a2a0..ad01997 100644 (file)
@@ -628,7 +628,7 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs,
        struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH];
        struct nlattr *mt = attrs[XFRMA_MTIMER_THRESH];
 
-       if (re) {
+       if (re && x->replay_esn && x->preplay_esn) {
                struct xfrm_replay_state_esn *replay_esn;
                replay_esn = nla_data(re);
                memcpy(x->replay_esn, replay_esn,
@@ -1267,6 +1267,15 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
                                         sizeof(*filter), GFP_KERNEL);
                        if (filter == NULL)
                                return -ENOMEM;
+
+                       /* see addr_match(), (prefix length >> 5) << 2
+                        * will be used to compare xfrm_address_t
+                        */
+                       if (filter->splen > (sizeof(xfrm_address_t) << 3) ||
+                           filter->dplen > (sizeof(xfrm_address_t) << 3)) {
+                               kfree(filter);
+                               return -EINVAL;
+                       }
                }
 
                if (attrs[XFRMA_PROTO])
@@ -2336,6 +2345,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh,
                                            NETLINK_CB(skb).portid);
                }
        } else {
+               xfrm_dev_policy_delete(xp);
                xfrm_audit_policy_delete(xp, err ? 0 : 1, true);
 
                if (err != 0)
@@ -3015,7 +3025,7 @@ const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
        [XFRMA_ALG_COMP]        = { .len = sizeof(struct xfrm_algo) },
        [XFRMA_ENCAP]           = { .len = sizeof(struct xfrm_encap_tmpl) },
        [XFRMA_TMPL]            = { .len = sizeof(struct xfrm_user_tmpl) },
-       [XFRMA_SEC_CTX]         = { .len = sizeof(struct xfrm_sec_ctx) },
+       [XFRMA_SEC_CTX]         = { .len = sizeof(struct xfrm_user_sec_ctx) },
        [XFRMA_LTIME_VAL]       = { .len = sizeof(struct xfrm_lifetime_cur) },
        [XFRMA_REPLAY_VAL]      = { .len = sizeof(struct xfrm_replay_state) },
        [XFRMA_REPLAY_THRESH]   = { .type = NLA_U32 },
@@ -3035,6 +3045,7 @@ const struct nla_policy xfrma_policy[XFRMA_MAX+1] = {
        [XFRMA_SET_MARK]        = { .type = NLA_U32 },
        [XFRMA_SET_MARK_MASK]   = { .type = NLA_U32 },
        [XFRMA_IF_ID]           = { .type = NLA_U32 },
+       [XFRMA_MTIMER_THRESH]   = { .type = NLA_U32 },
 };
 EXPORT_SYMBOL_GPL(xfrma_policy);
 
index 16c8793..653b92f 100644 (file)
@@ -129,6 +129,7 @@ static struct sym_entry *read_symbol(FILE *in, char **buf, size_t *buf_len)
        ssize_t readlen;
        struct sym_entry *sym;
 
+       errno = 0;
        readlen = getline(buf, buf_len, in);
        if (readlen < 0) {
                if (errno) {
index 65a168d..0b214f6 100644 (file)
@@ -150,6 +150,18 @@ static void show_link_attach_type_json(__u32 attach_type, json_writer_t *wtr)
                jsonw_uint_field(wtr, "attach_type", attach_type);
 }
 
+static void show_link_ifindex_json(__u32 ifindex, json_writer_t *wtr)
+{
+       char devname[IF_NAMESIZE] = "(unknown)";
+
+       if (ifindex)
+               if_indextoname(ifindex, devname);
+       else
+               snprintf(devname, sizeof(devname), "(detached)");
+       jsonw_string_field(wtr, "devname", devname);
+       jsonw_uint_field(wtr, "ifindex", ifindex);
+}
+
 static bool is_iter_map_target(const char *target_name)
 {
        return strcmp(target_name, "bpf_map_elem") == 0 ||
@@ -433,6 +445,13 @@ static int show_link_close_json(int fd, struct bpf_link_info *info)
        case BPF_LINK_TYPE_NETFILTER:
                netfilter_dump_json(info, json_wtr);
                break;
+       case BPF_LINK_TYPE_TCX:
+               show_link_ifindex_json(info->tcx.ifindex, json_wtr);
+               show_link_attach_type_json(info->tcx.attach_type, json_wtr);
+               break;
+       case BPF_LINK_TYPE_XDP:
+               show_link_ifindex_json(info->xdp.ifindex, json_wtr);
+               break;
        case BPF_LINK_TYPE_STRUCT_OPS:
                jsonw_uint_field(json_wtr, "map_id",
                                 info->struct_ops.map_id);
@@ -509,6 +528,22 @@ static void show_link_attach_type_plain(__u32 attach_type)
                printf("attach_type %u  ", attach_type);
 }
 
+static void show_link_ifindex_plain(__u32 ifindex)
+{
+       char devname[IF_NAMESIZE * 2] = "(unknown)";
+       char tmpname[IF_NAMESIZE];
+       char *ret = NULL;
+
+       if (ifindex)
+               ret = if_indextoname(ifindex, tmpname);
+       else
+               snprintf(devname, sizeof(devname), "(detached)");
+       if (ret)
+               snprintf(devname, sizeof(devname), "%s(%d)",
+                        tmpname, ifindex);
+       printf("ifindex %s  ", devname);
+}
+
 static void show_iter_plain(struct bpf_link_info *info)
 {
        const char *target_name = u64_to_ptr(info->iter.target_name);
@@ -745,6 +780,15 @@ static int show_link_close_plain(int fd, struct bpf_link_info *info)
        case BPF_LINK_TYPE_NETFILTER:
                netfilter_dump_plain(info);
                break;
+       case BPF_LINK_TYPE_TCX:
+               printf("\n\t");
+               show_link_ifindex_plain(info->tcx.ifindex);
+               show_link_attach_type_plain(info->tcx.attach_type);
+               break;
+       case BPF_LINK_TYPE_XDP:
+               printf("\n\t");
+               show_link_ifindex_plain(info->xdp.ifindex);
+               break;
        case BPF_LINK_TYPE_KPROBE_MULTI:
                show_kprobe_multi_plain(info);
                break;
index 9174344..80de287 100644 (file)
@@ -236,7 +236,7 @@ static int do_help(int argc, char **argv)
 {
        fprintf(stderr,
                "Usage: %1$s %2$s { show | list }\n"
-               "       %1$s %2$s help }\n"
+               "       %1$s %2$s help\n"
                "\n"
                "       " HELP_SPEC_OPTIONS " }\n"
                "",
index a0f4cab..b2c2946 100644 (file)
@@ -40,7 +40,8 @@ $(OUTPUT)counter_example: $(COUNTER_EXAMPLE)
 clean:
        rm -f $(ALL_PROGRAMS)
        rm -rf $(OUTPUT)include/linux/counter.h
-       rmdir -p $(OUTPUT)include/linux
+       rm -df $(OUTPUT)include/linux
+       rm -df $(OUTPUT)include
        find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
 
 install: $(ALL_PROGRAMS)
index 17883f5..b14a437 100644 (file)
@@ -1978,9 +1978,9 @@ static int bpf_object__read_kconfig_file(struct bpf_object *obj, void *data)
                return -ENAMETOOLONG;
 
        /* gzopen also accepts uncompressed files. */
-       file = gzopen(buf, "r");
+       file = gzopen(buf, "re");
        if (!file)
-               file = gzopen("/proc/config.gz", "r");
+               file = gzopen("/proc/config.gz", "re");
 
        if (!file) {
                pr_warn("failed to open system Kconfig\n");
index a61c7bc..63f468b 100644 (file)
@@ -177,7 +177,7 @@ void regression1_test(void)
        nr_threads = 2;
        pthread_barrier_init(&worker_barrier, NULL, nr_threads);
 
-       threads = malloc(nr_threads * sizeof(pthread_t *));
+       threads = malloc(nr_threads * sizeof(*threads));
 
        for (i = 0; i < nr_threads; i++) {
                arg = i;
index 3b61e8b..7f768d3 100644 (file)
@@ -12,3 +12,6 @@ kprobe_multi_test/skel_api                       # libbpf: failed to load BPF sk
 module_attach                                    # prog 'kprobe_multi': failed to auto-attach: -95
 fentry_test/fentry_many_args                     # fentry_many_args:FAIL:fentry_many_args_attach unexpected error: -524
 fexit_test/fexit_many_args                       # fexit_many_args:FAIL:fexit_many_args_attach unexpected error: -524
+fill_link_info/kprobe_multi_link_info            # bpf_program__attach_kprobe_multi_opts unexpected error: -95
+fill_link_info/kretprobe_multi_link_info         # bpf_program__attach_kprobe_multi_opts unexpected error: -95
+fill_link_info/kprobe_multi_invalid_ubuff        # bpf_program__attach_kprobe_multi_opts unexpected error: -95
index 16f774b..7b281db 100755 (executable)
@@ -2,7 +2,7 @@
 
 set -eufo pipefail
 
-for i in base kprobe kretprobe rawtp fentry fexit fmodret
+for i in base kprobe kretprobe rawtp fentry fexit
 do
        summary=$(sudo ./bench -w2 -d5 -a rename-$i | tail -n1 | cut -d'(' -f1 | cut -d' ' -f3-)
        printf "%-10s: %s\n" $i "$summary"
diff --git a/tools/testing/selftests/bpf/prog_tests/fill_link_info.c b/tools/testing/selftests/bpf/prog_tests/fill_link_info.c
new file mode 100644 (file)
index 0000000..9d768e0
--- /dev/null
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023 Yafang Shao <laoar.shao@gmail.com> */
+
+#include <string.h>
+#include <linux/bpf.h>
+#include <linux/limits.h>
+#include <test_progs.h>
+#include "trace_helpers.h"
+#include "test_fill_link_info.skel.h"
+
+#define TP_CAT "sched"
+#define TP_NAME "sched_switch"
+
+static const char *kmulti_syms[] = {
+       "bpf_fentry_test2",
+       "bpf_fentry_test1",
+       "bpf_fentry_test3",
+};
+#define KMULTI_CNT ARRAY_SIZE(kmulti_syms)
+static __u64 kmulti_addrs[KMULTI_CNT];
+
+#define KPROBE_FUNC "bpf_fentry_test1"
+static __u64 kprobe_addr;
+
+#define UPROBE_FILE "/proc/self/exe"
+static ssize_t uprobe_offset;
+/* uprobe attach point */
+static noinline void uprobe_func(void)
+{
+       asm volatile ("");
+}
+
+static int verify_perf_link_info(int fd, enum bpf_perf_event_type type, long addr,
+                                ssize_t offset, ssize_t entry_offset)
+{
+       struct bpf_link_info info;
+       __u32 len = sizeof(info);
+       char buf[PATH_MAX];
+       int err;
+
+       memset(&info, 0, sizeof(info));
+       buf[0] = '\0';
+
+again:
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       if (!ASSERT_OK(err, "get_link_info"))
+               return -1;
+
+       if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_PERF_EVENT, "link_type"))
+               return -1;
+       if (!ASSERT_EQ(info.perf_event.type, type, "perf_type_match"))
+               return -1;
+
+       switch (info.perf_event.type) {
+       case BPF_PERF_EVENT_KPROBE:
+       case BPF_PERF_EVENT_KRETPROBE:
+               ASSERT_EQ(info.perf_event.kprobe.offset, offset, "kprobe_offset");
+
+               /* In case kernel.kptr_restrict is not permitted or MAX_SYMS is reached */
+               if (addr)
+                       ASSERT_EQ(info.perf_event.kprobe.addr, addr + entry_offset,
+                                 "kprobe_addr");
+
+               if (!info.perf_event.kprobe.func_name) {
+                       ASSERT_EQ(info.perf_event.kprobe.name_len, 0, "name_len");
+                       info.perf_event.kprobe.func_name = ptr_to_u64(&buf);
+                       info.perf_event.kprobe.name_len = sizeof(buf);
+                       goto again;
+               }
+
+               err = strncmp(u64_to_ptr(info.perf_event.kprobe.func_name), KPROBE_FUNC,
+                             strlen(KPROBE_FUNC));
+               ASSERT_EQ(err, 0, "cmp_kprobe_func_name");
+               break;
+       case BPF_PERF_EVENT_TRACEPOINT:
+               if (!info.perf_event.tracepoint.tp_name) {
+                       ASSERT_EQ(info.perf_event.tracepoint.name_len, 0, "name_len");
+                       info.perf_event.tracepoint.tp_name = ptr_to_u64(&buf);
+                       info.perf_event.tracepoint.name_len = sizeof(buf);
+                       goto again;
+               }
+
+               err = strncmp(u64_to_ptr(info.perf_event.tracepoint.tp_name), TP_NAME,
+                             strlen(TP_NAME));
+               ASSERT_EQ(err, 0, "cmp_tp_name");
+               break;
+       case BPF_PERF_EVENT_UPROBE:
+       case BPF_PERF_EVENT_URETPROBE:
+               ASSERT_EQ(info.perf_event.uprobe.offset, offset, "uprobe_offset");
+
+               if (!info.perf_event.uprobe.file_name) {
+                       ASSERT_EQ(info.perf_event.uprobe.name_len, 0, "name_len");
+                       info.perf_event.uprobe.file_name = ptr_to_u64(&buf);
+                       info.perf_event.uprobe.name_len = sizeof(buf);
+                       goto again;
+               }
+
+               err = strncmp(u64_to_ptr(info.perf_event.uprobe.file_name), UPROBE_FILE,
+                             strlen(UPROBE_FILE));
+                       ASSERT_EQ(err, 0, "cmp_file_name");
+               break;
+       default:
+               err = -1;
+               break;
+       }
+       return err;
+}
+
+static void kprobe_fill_invalid_user_buffer(int fd)
+{
+       struct bpf_link_info info;
+       __u32 len = sizeof(info);
+       int err;
+
+       memset(&info, 0, sizeof(info));
+
+       info.perf_event.kprobe.func_name = 0x1; /* invalid address */
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EINVAL, "invalid_buff_and_len");
+
+       info.perf_event.kprobe.name_len = 64;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EFAULT, "invalid_buff");
+
+       info.perf_event.kprobe.func_name = 0;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EINVAL, "invalid_len");
+
+       ASSERT_EQ(info.perf_event.kprobe.addr, 0, "func_addr");
+       ASSERT_EQ(info.perf_event.kprobe.offset, 0, "func_offset");
+       ASSERT_EQ(info.perf_event.type, 0, "type");
+}
+
+static void test_kprobe_fill_link_info(struct test_fill_link_info *skel,
+                                      enum bpf_perf_event_type type,
+                                      bool invalid)
+{
+       DECLARE_LIBBPF_OPTS(bpf_kprobe_opts, opts,
+               .attach_mode = PROBE_ATTACH_MODE_LINK,
+               .retprobe = type == BPF_PERF_EVENT_KRETPROBE,
+       );
+       ssize_t entry_offset = 0;
+       int link_fd, err;
+
+       skel->links.kprobe_run = bpf_program__attach_kprobe_opts(skel->progs.kprobe_run,
+                                                                KPROBE_FUNC, &opts);
+       if (!ASSERT_OK_PTR(skel->links.kprobe_run, "attach_kprobe"))
+               return;
+
+       link_fd = bpf_link__fd(skel->links.kprobe_run);
+       if (!invalid) {
+               /* See also arch_adjust_kprobe_addr(). */
+               if (skel->kconfig->CONFIG_X86_KERNEL_IBT)
+                       entry_offset = 4;
+               err = verify_perf_link_info(link_fd, type, kprobe_addr, 0, entry_offset);
+               ASSERT_OK(err, "verify_perf_link_info");
+       } else {
+               kprobe_fill_invalid_user_buffer(link_fd);
+       }
+       bpf_link__detach(skel->links.kprobe_run);
+}
+
+static void test_tp_fill_link_info(struct test_fill_link_info *skel)
+{
+       int link_fd, err;
+
+       skel->links.tp_run = bpf_program__attach_tracepoint(skel->progs.tp_run, TP_CAT, TP_NAME);
+       if (!ASSERT_OK_PTR(skel->links.tp_run, "attach_tp"))
+               return;
+
+       link_fd = bpf_link__fd(skel->links.tp_run);
+       err = verify_perf_link_info(link_fd, BPF_PERF_EVENT_TRACEPOINT, 0, 0, 0);
+       ASSERT_OK(err, "verify_perf_link_info");
+       bpf_link__detach(skel->links.tp_run);
+}
+
+static void test_uprobe_fill_link_info(struct test_fill_link_info *skel,
+                                      enum bpf_perf_event_type type)
+{
+       int link_fd, err;
+
+       skel->links.uprobe_run = bpf_program__attach_uprobe(skel->progs.uprobe_run,
+                                                           type == BPF_PERF_EVENT_URETPROBE,
+                                                           0, /* self pid */
+                                                           UPROBE_FILE, uprobe_offset);
+       if (!ASSERT_OK_PTR(skel->links.uprobe_run, "attach_uprobe"))
+               return;
+
+       link_fd = bpf_link__fd(skel->links.uprobe_run);
+       err = verify_perf_link_info(link_fd, type, 0, uprobe_offset, 0);
+       ASSERT_OK(err, "verify_perf_link_info");
+       bpf_link__detach(skel->links.uprobe_run);
+}
+
+static int verify_kmulti_link_info(int fd, bool retprobe)
+{
+       struct bpf_link_info info;
+       __u32 len = sizeof(info);
+       __u64 addrs[KMULTI_CNT];
+       int flags, i, err;
+
+       memset(&info, 0, sizeof(info));
+
+again:
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       if (!ASSERT_OK(err, "get_link_info"))
+               return -1;
+
+       if (!ASSERT_EQ(info.type, BPF_LINK_TYPE_KPROBE_MULTI, "kmulti_type"))
+               return -1;
+
+       ASSERT_EQ(info.kprobe_multi.count, KMULTI_CNT, "func_cnt");
+       flags = info.kprobe_multi.flags & BPF_F_KPROBE_MULTI_RETURN;
+       if (!retprobe)
+               ASSERT_EQ(flags, 0, "kmulti_flags");
+       else
+               ASSERT_NEQ(flags, 0, "kretmulti_flags");
+
+       if (!info.kprobe_multi.addrs) {
+               info.kprobe_multi.addrs = ptr_to_u64(addrs);
+               goto again;
+       }
+       for (i = 0; i < KMULTI_CNT; i++)
+               ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
+       return 0;
+}
+
+static void verify_kmulti_invalid_user_buffer(int fd)
+{
+       struct bpf_link_info info;
+       __u32 len = sizeof(info);
+       __u64 addrs[KMULTI_CNT];
+       int err, i;
+
+       memset(&info, 0, sizeof(info));
+
+       info.kprobe_multi.count = KMULTI_CNT;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EINVAL, "no_addr");
+
+       info.kprobe_multi.addrs = ptr_to_u64(addrs);
+       info.kprobe_multi.count = 0;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EINVAL, "no_cnt");
+
+       for (i = 0; i < KMULTI_CNT; i++)
+               addrs[i] = 0;
+       info.kprobe_multi.count = KMULTI_CNT - 1;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -ENOSPC, "smaller_cnt");
+       for (i = 0; i < KMULTI_CNT - 1; i++)
+               ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
+       ASSERT_EQ(addrs[i], 0, "kmulti_addrs");
+
+       for (i = 0; i < KMULTI_CNT; i++)
+               addrs[i] = 0;
+       info.kprobe_multi.count = KMULTI_CNT + 1;
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, 0, "bigger_cnt");
+       for (i = 0; i < KMULTI_CNT; i++)
+               ASSERT_EQ(addrs[i], kmulti_addrs[i], "kmulti_addrs");
+
+       info.kprobe_multi.count = KMULTI_CNT;
+       info.kprobe_multi.addrs = 0x1; /* invalid addr */
+       err = bpf_link_get_info_by_fd(fd, &info, &len);
+       ASSERT_EQ(err, -EFAULT, "invalid_buff");
+}
+
+static int symbols_cmp_r(const void *a, const void *b)
+{
+       const char **str_a = (const char **) a;
+       const char **str_b = (const char **) b;
+
+       return strcmp(*str_a, *str_b);
+}
+
+static void test_kprobe_multi_fill_link_info(struct test_fill_link_info *skel,
+                                            bool retprobe, bool invalid)
+{
+       LIBBPF_OPTS(bpf_kprobe_multi_opts, opts);
+       int link_fd, err;
+
+       opts.syms = kmulti_syms;
+       opts.cnt = KMULTI_CNT;
+       opts.retprobe = retprobe;
+       skel->links.kmulti_run = bpf_program__attach_kprobe_multi_opts(skel->progs.kmulti_run,
+                                                                      NULL, &opts);
+       if (!ASSERT_OK_PTR(skel->links.kmulti_run, "attach_kprobe_multi"))
+               return;
+
+       link_fd = bpf_link__fd(skel->links.kmulti_run);
+       if (!invalid) {
+               err = verify_kmulti_link_info(link_fd, retprobe);
+               ASSERT_OK(err, "verify_kmulti_link_info");
+       } else {
+               verify_kmulti_invalid_user_buffer(link_fd);
+       }
+       bpf_link__detach(skel->links.kmulti_run);
+}
+
+void test_fill_link_info(void)
+{
+       struct test_fill_link_info *skel;
+       int i;
+
+       skel = test_fill_link_info__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel_open"))
+               return;
+
+       /* load kallsyms to compare the addr */
+       if (!ASSERT_OK(load_kallsyms_refresh(), "load_kallsyms_refresh"))
+               goto cleanup;
+
+       kprobe_addr = ksym_get_addr(KPROBE_FUNC);
+       if (test__start_subtest("kprobe_link_info"))
+               test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, false);
+       if (test__start_subtest("kretprobe_link_info"))
+               test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KRETPROBE, false);
+       if (test__start_subtest("kprobe_invalid_ubuff"))
+               test_kprobe_fill_link_info(skel, BPF_PERF_EVENT_KPROBE, true);
+       if (test__start_subtest("tracepoint_link_info"))
+               test_tp_fill_link_info(skel);
+
+       uprobe_offset = get_uprobe_offset(&uprobe_func);
+       if (test__start_subtest("uprobe_link_info"))
+               test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_UPROBE);
+       if (test__start_subtest("uretprobe_link_info"))
+               test_uprobe_fill_link_info(skel, BPF_PERF_EVENT_URETPROBE);
+
+       qsort(kmulti_syms, KMULTI_CNT, sizeof(kmulti_syms[0]), symbols_cmp_r);
+       for (i = 0; i < KMULTI_CNT; i++)
+               kmulti_addrs[i] = ksym_get_addr(kmulti_syms[i]);
+       if (test__start_subtest("kprobe_multi_link_info"))
+               test_kprobe_multi_fill_link_info(skel, false, false);
+       if (test__start_subtest("kretprobe_multi_link_info"))
+               test_kprobe_multi_fill_link_info(skel, true, false);
+       if (test__start_subtest("kprobe_multi_invalid_ubuff"))
+               test_kprobe_multi_fill_link_info(skel, true, true);
+
+cleanup:
+       test_fill_link_info__destroy(skel);
+}
index a543742..2eb7155 100644 (file)
@@ -173,8 +173,8 @@ static void verify_fail(struct kfunc_test_params *param)
        case tc_test:
                topts.data_in = &pkt_v4;
                topts.data_size_in = sizeof(pkt_v4);
-               break;
                topts.repeat = 1;
+               break;
        }
 
        skel = kfunc_call_fail__open_opts(&opts);
index cd0c42f..7c0be7c 100644 (file)
@@ -2,17 +2,59 @@
 /* Copyright (c) 2020, Tessares SA. */
 /* Copyright (c) 2022, SUSE. */
 
+#include <linux/const.h>
+#include <netinet/in.h>
 #include <test_progs.h>
 #include "cgroup_helpers.h"
 #include "network_helpers.h"
 #include "mptcp_sock.skel.h"
+#include "mptcpify.skel.h"
 
 #define NS_TEST "mptcp_ns"
 
+#ifndef IPPROTO_MPTCP
+#define IPPROTO_MPTCP 262
+#endif
+
+#ifndef SOL_MPTCP
+#define SOL_MPTCP 284
+#endif
+#ifndef MPTCP_INFO
+#define MPTCP_INFO             1
+#endif
+#ifndef MPTCP_INFO_FLAG_FALLBACK
+#define MPTCP_INFO_FLAG_FALLBACK               _BITUL(0)
+#endif
+#ifndef MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED
+#define MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED    _BITUL(1)
+#endif
+
 #ifndef TCP_CA_NAME_MAX
 #define TCP_CA_NAME_MAX        16
 #endif
 
+struct __mptcp_info {
+       __u8    mptcpi_subflows;
+       __u8    mptcpi_add_addr_signal;
+       __u8    mptcpi_add_addr_accepted;
+       __u8    mptcpi_subflows_max;
+       __u8    mptcpi_add_addr_signal_max;
+       __u8    mptcpi_add_addr_accepted_max;
+       __u32   mptcpi_flags;
+       __u32   mptcpi_token;
+       __u64   mptcpi_write_seq;
+       __u64   mptcpi_snd_una;
+       __u64   mptcpi_rcv_nxt;
+       __u8    mptcpi_local_addr_used;
+       __u8    mptcpi_local_addr_max;
+       __u8    mptcpi_csum_enabled;
+       __u32   mptcpi_retransmits;
+       __u64   mptcpi_bytes_retrans;
+       __u64   mptcpi_bytes_sent;
+       __u64   mptcpi_bytes_received;
+       __u64   mptcpi_bytes_acked;
+};
+
 struct mptcp_storage {
        __u32 invoked;
        __u32 is_mptcp;
@@ -22,6 +64,24 @@ struct mptcp_storage {
        char ca_name[TCP_CA_NAME_MAX];
 };
 
+static struct nstoken *create_netns(void)
+{
+       SYS(fail, "ip netns add %s", NS_TEST);
+       SYS(fail, "ip -net %s link set dev lo up", NS_TEST);
+
+       return open_netns(NS_TEST);
+fail:
+       return NULL;
+}
+
+static void cleanup_netns(struct nstoken *nstoken)
+{
+       if (nstoken)
+               close_netns(nstoken);
+
+       SYS_NOFAIL("ip netns del %s &> /dev/null", NS_TEST);
+}
+
 static int verify_tsk(int map_fd, int client_fd)
 {
        int err, cfd = client_fd;
@@ -100,24 +160,14 @@ static int run_test(int cgroup_fd, int server_fd, bool is_mptcp)
 
        sock_skel = mptcp_sock__open_and_load();
        if (!ASSERT_OK_PTR(sock_skel, "skel_open_load"))
-               return -EIO;
+               return libbpf_get_error(sock_skel);
 
        err = mptcp_sock__attach(sock_skel);
        if (!ASSERT_OK(err, "skel_attach"))
                goto out;
 
        prog_fd = bpf_program__fd(sock_skel->progs._sockops);
-       if (!ASSERT_GE(prog_fd, 0, "bpf_program__fd")) {
-               err = -EIO;
-               goto out;
-       }
-
        map_fd = bpf_map__fd(sock_skel->maps.socket_storage_map);
-       if (!ASSERT_GE(map_fd, 0, "bpf_map__fd")) {
-               err = -EIO;
-               goto out;
-       }
-
        err = bpf_prog_attach(prog_fd, cgroup_fd, BPF_CGROUP_SOCK_OPS, 0);
        if (!ASSERT_OK(err, "bpf_prog_attach"))
                goto out;
@@ -147,11 +197,8 @@ static void test_base(void)
        if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))
                return;
 
-       SYS(fail, "ip netns add %s", NS_TEST);
-       SYS(fail, "ip -net %s link set dev lo up", NS_TEST);
-
-       nstoken = open_netns(NS_TEST);
-       if (!ASSERT_OK_PTR(nstoken, "open_netns"))
+       nstoken = create_netns();
+       if (!ASSERT_OK_PTR(nstoken, "create_netns"))
                goto fail;
 
        /* without MPTCP */
@@ -174,11 +221,104 @@ with_mptcp:
        close(server_fd);
 
 fail:
-       if (nstoken)
-               close_netns(nstoken);
+       cleanup_netns(nstoken);
+       close(cgroup_fd);
+}
 
-       SYS_NOFAIL("ip netns del " NS_TEST " &> /dev/null");
+static void send_byte(int fd)
+{
+       char b = 0x55;
+
+       ASSERT_EQ(write(fd, &b, sizeof(b)), 1, "send single byte");
+}
+
+static int verify_mptcpify(int server_fd, int client_fd)
+{
+       struct __mptcp_info info;
+       socklen_t optlen;
+       int protocol;
+       int err = 0;
+
+       optlen = sizeof(protocol);
+       if (!ASSERT_OK(getsockopt(server_fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &optlen),
+                      "getsockopt(SOL_PROTOCOL)"))
+               return -1;
+
+       if (!ASSERT_EQ(protocol, IPPROTO_MPTCP, "protocol isn't MPTCP"))
+               err++;
 
+       optlen = sizeof(info);
+       if (!ASSERT_OK(getsockopt(client_fd, SOL_MPTCP, MPTCP_INFO, &info, &optlen),
+                      "getsockopt(MPTCP_INFO)"))
+               return -1;
+
+       if (!ASSERT_GE(info.mptcpi_flags, 0, "unexpected mptcpi_flags"))
+               err++;
+       if (!ASSERT_FALSE(info.mptcpi_flags & MPTCP_INFO_FLAG_FALLBACK,
+                         "MPTCP fallback"))
+               err++;
+       if (!ASSERT_TRUE(info.mptcpi_flags & MPTCP_INFO_FLAG_REMOTE_KEY_RECEIVED,
+                        "no remote key received"))
+               err++;
+
+       return err;
+}
+
+static int run_mptcpify(int cgroup_fd)
+{
+       int server_fd, client_fd, err = 0;
+       struct mptcpify *mptcpify_skel;
+
+       mptcpify_skel = mptcpify__open_and_load();
+       if (!ASSERT_OK_PTR(mptcpify_skel, "skel_open_load"))
+               return libbpf_get_error(mptcpify_skel);
+
+       err = mptcpify__attach(mptcpify_skel);
+       if (!ASSERT_OK(err, "skel_attach"))
+               goto out;
+
+       /* without MPTCP */
+       server_fd = start_server(AF_INET, SOCK_STREAM, NULL, 0, 0);
+       if (!ASSERT_GE(server_fd, 0, "start_server")) {
+               err = -EIO;
+               goto out;
+       }
+
+       client_fd = connect_to_fd(server_fd, 0);
+       if (!ASSERT_GE(client_fd, 0, "connect to fd")) {
+               err = -EIO;
+               goto close_server;
+       }
+
+       send_byte(client_fd);
+
+       err = verify_mptcpify(server_fd, client_fd);
+
+       close(client_fd);
+close_server:
+       close(server_fd);
+out:
+       mptcpify__destroy(mptcpify_skel);
+       return err;
+}
+
+static void test_mptcpify(void)
+{
+       struct nstoken *nstoken = NULL;
+       int cgroup_fd;
+
+       cgroup_fd = test__join_cgroup("/mptcpify");
+       if (!ASSERT_GE(cgroup_fd, 0, "test__join_cgroup"))
+               return;
+
+       nstoken = create_netns();
+       if (!ASSERT_OK_PTR(nstoken, "create_netns"))
+               goto fail;
+
+       ASSERT_OK(run_mptcpify(cgroup_fd), "run_mptcpify");
+
+fail:
+       cleanup_netns(nstoken);
        close(cgroup_fd);
 }
 
@@ -186,4 +326,6 @@ void test_mptcp(void)
 {
        if (test__start_subtest("base"))
                test_base();
+       if (test__start_subtest("mptcpify"))
+               test_mptcpify();
 }
index 81eea5f..74fc1fe 100644 (file)
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /* Copyright (c) 2023 Isovalent */
 #include <uapi/linux/if_link.h>
+#include <uapi/linux/pkt_sched.h>
 #include <net/if.h>
 #include <test_progs.h>
 
@@ -1581,3 +1582,338 @@ void serial_test_tc_links_dev_cleanup(void)
        test_tc_links_dev_cleanup_target(BPF_TCX_INGRESS);
        test_tc_links_dev_cleanup_target(BPF_TCX_EGRESS);
 }
+
+static void test_tc_chain_mixed(int target)
+{
+       LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
+       LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
+       LIBBPF_OPTS(bpf_tcx_opts, optl);
+       struct test_tc_link *skel;
+       struct bpf_link *link;
+       __u32 pid1, pid2, pid3;
+       int err;
+
+       skel = test_tc_link__open();
+       if (!ASSERT_OK_PTR(skel, "skel_open"))
+               goto cleanup;
+
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
+                 0, "tc4_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc5, target),
+                 0, "tc5_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc6, target),
+                 0, "tc6_attach_type");
+
+       err = test_tc_link__load(skel);
+       if (!ASSERT_OK(err, "skel_load"))
+               goto cleanup;
+
+       pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
+       pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc5));
+       pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc6));
+
+       ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
+       ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
+
+       assert_mprog_count(target, 0);
+
+       tc_hook.attach_point = target == BPF_TCX_INGRESS ?
+                              BPF_TC_INGRESS : BPF_TC_EGRESS;
+       err = bpf_tc_hook_create(&tc_hook);
+       err = err == -EEXIST ? 0 : err;
+       if (!ASSERT_OK(err, "bpf_tc_hook_create"))
+               goto cleanup;
+
+       tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
+       err = bpf_tc_attach(&tc_hook, &tc_opts);
+       if (!ASSERT_OK(err, "bpf_tc_attach"))
+               goto cleanup;
+
+       link = bpf_program__attach_tcx(skel->progs.tc6, loopback, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc6 = link;
+
+       assert_mprog_count(target, 1);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
+
+       skel->bss->seen_tc4 = false;
+       skel->bss->seen_tc5 = false;
+       skel->bss->seen_tc6 = false;
+
+       err = bpf_link__update_program(skel->links.tc6, skel->progs.tc4);
+       if (!ASSERT_OK(err, "link_update"))
+               goto cleanup;
+
+       assert_mprog_count(target, 1);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
+
+       skel->bss->seen_tc4 = false;
+       skel->bss->seen_tc5 = false;
+       skel->bss->seen_tc6 = false;
+
+       err = bpf_link__detach(skel->links.tc6);
+       if (!ASSERT_OK(err, "prog_detach"))
+               goto cleanup;
+
+       __assert_mprog_count(target, 0, true, loopback);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
+
+cleanup:
+       tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
+       err = bpf_tc_detach(&tc_hook, &tc_opts);
+       ASSERT_OK(err, "bpf_tc_detach");
+
+       tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
+       bpf_tc_hook_destroy(&tc_hook);
+
+       test_tc_link__destroy(skel);
+}
+
+void serial_test_tc_links_chain_mixed(void)
+{
+       test_tc_chain_mixed(BPF_TCX_INGRESS);
+       test_tc_chain_mixed(BPF_TCX_EGRESS);
+}
+
+static void test_tc_links_ingress(int target, bool chain_tc_old,
+                                 bool tcx_teardown_first)
+{
+       LIBBPF_OPTS(bpf_tc_opts, tc_opts,
+               .handle         = 1,
+               .priority       = 1,
+       );
+       LIBBPF_OPTS(bpf_tc_hook, tc_hook,
+               .ifindex        = loopback,
+               .attach_point   = BPF_TC_CUSTOM,
+               .parent         = TC_H_INGRESS,
+       );
+       bool hook_created = false, tc_attached = false;
+       LIBBPF_OPTS(bpf_tcx_opts, optl);
+       __u32 pid1, pid2, pid3;
+       struct test_tc_link *skel;
+       struct bpf_link *link;
+       int err;
+
+       skel = test_tc_link__open();
+       if (!ASSERT_OK_PTR(skel, "skel_open"))
+               goto cleanup;
+
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
+                 0, "tc1_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
+                 0, "tc2_attach_type");
+
+       err = test_tc_link__load(skel);
+       if (!ASSERT_OK(err, "skel_load"))
+               goto cleanup;
+
+       pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
+       pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
+       pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
+
+       ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
+       ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
+
+       assert_mprog_count(target, 0);
+
+       if (chain_tc_old) {
+               ASSERT_OK(system("tc qdisc add dev lo ingress"), "add_ingress");
+               hook_created = true;
+
+               tc_opts.prog_fd = bpf_program__fd(skel->progs.tc3);
+               err = bpf_tc_attach(&tc_hook, &tc_opts);
+               if (!ASSERT_OK(err, "bpf_tc_attach"))
+                       goto cleanup;
+               tc_attached = true;
+       }
+
+       link = bpf_program__attach_tcx(skel->progs.tc1, loopback, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc1 = link;
+
+       link = bpf_program__attach_tcx(skel->progs.tc2, loopback, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc2 = link;
+
+       assert_mprog_count(target, 2);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
+       ASSERT_EQ(skel->bss->seen_tc2, true, "seen_tc2");
+       ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
+
+       skel->bss->seen_tc1 = false;
+       skel->bss->seen_tc2 = false;
+       skel->bss->seen_tc3 = false;
+
+       err = bpf_link__detach(skel->links.tc2);
+       if (!ASSERT_OK(err, "prog_detach"))
+               goto cleanup;
+
+       assert_mprog_count(target, 1);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc1, true, "seen_tc1");
+       ASSERT_EQ(skel->bss->seen_tc2, false, "seen_tc2");
+       ASSERT_EQ(skel->bss->seen_tc3, chain_tc_old, "seen_tc3");
+cleanup:
+       if (tc_attached) {
+               tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
+               err = bpf_tc_detach(&tc_hook, &tc_opts);
+               ASSERT_OK(err, "bpf_tc_detach");
+       }
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+       assert_mprog_count(target, 1);
+       if (hook_created && tcx_teardown_first)
+               ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+       test_tc_link__destroy(skel);
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+       if (hook_created && !tcx_teardown_first)
+               ASSERT_OK(system("tc qdisc del dev lo ingress"), "del_ingress");
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+       assert_mprog_count(target, 0);
+}
+
+void serial_test_tc_links_ingress(void)
+{
+       test_tc_links_ingress(BPF_TCX_INGRESS, true, true);
+       test_tc_links_ingress(BPF_TCX_INGRESS, true, false);
+       test_tc_links_ingress(BPF_TCX_INGRESS, false, false);
+}
+
+static void test_tc_links_dev_mixed(int target)
+{
+       LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
+       LIBBPF_OPTS(bpf_tc_hook, tc_hook);
+       LIBBPF_OPTS(bpf_tcx_opts, optl);
+       __u32 pid1, pid2, pid3, pid4;
+       struct test_tc_link *skel;
+       struct bpf_link *link;
+       int err, ifindex;
+
+       ASSERT_OK(system("ip link add dev tcx_opts1 type veth peer name tcx_opts2"), "add veth");
+       ifindex = if_nametoindex("tcx_opts1");
+       ASSERT_NEQ(ifindex, 0, "non_zero_ifindex");
+
+       skel = test_tc_link__open();
+       if (!ASSERT_OK_PTR(skel, "skel_open"))
+               goto cleanup;
+
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc1, target),
+                 0, "tc1_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc2, target),
+                 0, "tc2_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc3, target),
+                 0, "tc3_attach_type");
+       ASSERT_EQ(bpf_program__set_expected_attach_type(skel->progs.tc4, target),
+                 0, "tc4_attach_type");
+
+       err = test_tc_link__load(skel);
+       if (!ASSERT_OK(err, "skel_load"))
+               goto cleanup;
+
+       pid1 = id_from_prog_fd(bpf_program__fd(skel->progs.tc1));
+       pid2 = id_from_prog_fd(bpf_program__fd(skel->progs.tc2));
+       pid3 = id_from_prog_fd(bpf_program__fd(skel->progs.tc3));
+       pid4 = id_from_prog_fd(bpf_program__fd(skel->progs.tc4));
+
+       ASSERT_NEQ(pid1, pid2, "prog_ids_1_2");
+       ASSERT_NEQ(pid3, pid4, "prog_ids_3_4");
+       ASSERT_NEQ(pid2, pid3, "prog_ids_2_3");
+
+       assert_mprog_count(target, 0);
+
+       link = bpf_program__attach_tcx(skel->progs.tc1, ifindex, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc1 = link;
+
+       assert_mprog_count_ifindex(ifindex, target, 1);
+
+       link = bpf_program__attach_tcx(skel->progs.tc2, ifindex, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc2 = link;
+
+       assert_mprog_count_ifindex(ifindex, target, 2);
+
+       link = bpf_program__attach_tcx(skel->progs.tc3, ifindex, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc3 = link;
+
+       assert_mprog_count_ifindex(ifindex, target, 3);
+
+       link = bpf_program__attach_tcx(skel->progs.tc4, ifindex, &optl);
+       if (!ASSERT_OK_PTR(link, "link_attach"))
+               goto cleanup;
+
+       skel->links.tc4 = link;
+
+       assert_mprog_count_ifindex(ifindex, target, 4);
+
+       tc_hook.ifindex = ifindex;
+       tc_hook.attach_point = target == BPF_TCX_INGRESS ?
+                              BPF_TC_INGRESS : BPF_TC_EGRESS;
+
+       err = bpf_tc_hook_create(&tc_hook);
+       err = err == -EEXIST ? 0 : err;
+       if (!ASSERT_OK(err, "bpf_tc_hook_create"))
+               goto cleanup;
+
+       tc_opts.prog_fd = bpf_program__fd(skel->progs.tc5);
+       err = bpf_tc_attach(&tc_hook, &tc_opts);
+       if (!ASSERT_OK(err, "bpf_tc_attach"))
+               goto cleanup;
+
+       ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
+       ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
+       ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
+
+       ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc1)), 0, "tc1_ifindex");
+       ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc2)), 0, "tc2_ifindex");
+       ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc3)), 0, "tc3_ifindex");
+       ASSERT_EQ(ifindex_from_link_fd(bpf_link__fd(skel->links.tc4)), 0, "tc4_ifindex");
+
+       test_tc_link__destroy(skel);
+       return;
+cleanup:
+       test_tc_link__destroy(skel);
+
+       ASSERT_OK(system("ip link del dev tcx_opts1"), "del veth");
+       ASSERT_EQ(if_nametoindex("tcx_opts1"), 0, "dev1_removed");
+       ASSERT_EQ(if_nametoindex("tcx_opts2"), 0, "dev2_removed");
+}
+
+void serial_test_tc_links_dev_mixed(void)
+{
+       test_tc_links_dev_mixed(BPF_TCX_INGRESS);
+       test_tc_links_dev_mixed(BPF_TCX_EGRESS);
+}
index 39bd253..7a2ecd4 100644 (file)
@@ -2268,3 +2268,113 @@ void serial_test_tc_opts_delete_empty(void)
        test_tc_opts_delete_empty(BPF_TCX_INGRESS, true);
        test_tc_opts_delete_empty(BPF_TCX_EGRESS, true);
 }
+
+static void test_tc_chain_mixed(int target)
+{
+       LIBBPF_OPTS(bpf_tc_opts, tc_opts, .handle = 1, .priority = 1);
+       LIBBPF_OPTS(bpf_tc_hook, tc_hook, .ifindex = loopback);
+       LIBBPF_OPTS(bpf_prog_attach_opts, opta);
+       LIBBPF_OPTS(bpf_prog_detach_opts, optd);
+       __u32 fd1, fd2, fd3, id1, id2, id3;
+       struct test_tc_link *skel;
+       int err, detach_fd;
+
+       skel = test_tc_link__open_and_load();
+       if (!ASSERT_OK_PTR(skel, "skel_load"))
+               goto cleanup;
+
+       fd1 = bpf_program__fd(skel->progs.tc4);
+       fd2 = bpf_program__fd(skel->progs.tc5);
+       fd3 = bpf_program__fd(skel->progs.tc6);
+
+       id1 = id_from_prog_fd(fd1);
+       id2 = id_from_prog_fd(fd2);
+       id3 = id_from_prog_fd(fd3);
+
+       ASSERT_NEQ(id1, id2, "prog_ids_1_2");
+       ASSERT_NEQ(id2, id3, "prog_ids_2_3");
+
+       assert_mprog_count(target, 0);
+
+       tc_hook.attach_point = target == BPF_TCX_INGRESS ?
+                              BPF_TC_INGRESS : BPF_TC_EGRESS;
+       err = bpf_tc_hook_create(&tc_hook);
+       err = err == -EEXIST ? 0 : err;
+       if (!ASSERT_OK(err, "bpf_tc_hook_create"))
+               goto cleanup;
+
+       tc_opts.prog_fd = fd2;
+       err = bpf_tc_attach(&tc_hook, &tc_opts);
+       if (!ASSERT_OK(err, "bpf_tc_attach"))
+               goto cleanup_hook;
+
+       err = bpf_prog_attach_opts(fd3, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup_filter;
+
+       detach_fd = fd3;
+
+       assert_mprog_count(target, 1);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, false, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, true, "seen_tc6");
+
+       skel->bss->seen_tc4 = false;
+       skel->bss->seen_tc5 = false;
+       skel->bss->seen_tc6 = false;
+
+       LIBBPF_OPTS_RESET(opta,
+               .flags = BPF_F_REPLACE,
+               .replace_prog_fd = fd3,
+       );
+
+       err = bpf_prog_attach_opts(fd1, loopback, target, &opta);
+       if (!ASSERT_EQ(err, 0, "prog_attach"))
+               goto cleanup_opts;
+
+       detach_fd = fd1;
+
+       assert_mprog_count(target, 1);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, true, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
+
+       skel->bss->seen_tc4 = false;
+       skel->bss->seen_tc5 = false;
+       skel->bss->seen_tc6 = false;
+
+cleanup_opts:
+       err = bpf_prog_detach_opts(detach_fd, loopback, target, &optd);
+       ASSERT_OK(err, "prog_detach");
+       __assert_mprog_count(target, 0, true, loopback);
+
+       ASSERT_OK(system(ping_cmd), ping_cmd);
+
+       ASSERT_EQ(skel->bss->seen_tc4, false, "seen_tc4");
+       ASSERT_EQ(skel->bss->seen_tc5, true, "seen_tc5");
+       ASSERT_EQ(skel->bss->seen_tc6, false, "seen_tc6");
+
+cleanup_filter:
+       tc_opts.flags = tc_opts.prog_fd = tc_opts.prog_id = 0;
+       err = bpf_tc_detach(&tc_hook, &tc_opts);
+       ASSERT_OK(err, "bpf_tc_detach");
+
+cleanup_hook:
+       tc_hook.attach_point = BPF_TC_INGRESS | BPF_TC_EGRESS;
+       bpf_tc_hook_destroy(&tc_hook);
+
+cleanup:
+       test_tc_link__destroy(skel);
+}
+
+void serial_test_tc_opts_chain_mixed(void)
+{
+       test_tc_chain_mixed(BPF_TCX_INGRESS);
+       test_tc_chain_mixed(BPF_TCX_EGRESS);
+}
diff --git a/tools/testing/selftests/bpf/progs/mptcpify.c b/tools/testing/selftests/bpf/progs/mptcpify.c
new file mode 100644 (file)
index 0000000..53301ae
--- /dev/null
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023, SUSE. */
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include "bpf_tracing_net.h"
+
+char _license[] SEC("license") = "GPL";
+
+SEC("fmod_ret/update_socket_protocol")
+int BPF_PROG(mptcpify, int family, int type, int protocol)
+{
+       if ((family == AF_INET || family == AF_INET6) &&
+           type == SOCK_STREAM &&
+           (!protocol || protocol == IPPROTO_TCP)) {
+               return IPPROTO_MPTCP;
+       }
+
+       return protocol;
+}
diff --git a/tools/testing/selftests/bpf/progs/test_fill_link_info.c b/tools/testing/selftests/bpf/progs/test_fill_link_info.c
new file mode 100644 (file)
index 0000000..564f402
--- /dev/null
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2023 Yafang Shao <laoar.shao@gmail.com> */
+
+#include "vmlinux.h"
+#include <bpf/bpf_tracing.h>
+#include <stdbool.h>
+
+extern bool CONFIG_X86_KERNEL_IBT __kconfig __weak;
+
+/* This function is here to have CONFIG_X86_KERNEL_IBT
+ * used and added to object BTF.
+ */
+int unused(void)
+{
+       return CONFIG_X86_KERNEL_IBT ? 0 : 1;
+}
+
+SEC("kprobe")
+int BPF_PROG(kprobe_run)
+{
+       return 0;
+}
+
+SEC("uprobe")
+int BPF_PROG(uprobe_run)
+{
+       return 0;
+}
+
+SEC("tracepoint")
+int BPF_PROG(tp_run)
+{
+       return 0;
+}
+
+SEC("kprobe.multi")
+int BPF_PROG(kmulti_run)
+{
+       return 0;
+}
+
+char _license[] SEC("license") = "GPL";
index ed1fd0e..30e7124 100644 (file)
@@ -10,6 +10,8 @@ bool seen_tc1;
 bool seen_tc2;
 bool seen_tc3;
 bool seen_tc4;
+bool seen_tc5;
+bool seen_tc6;
 
 SEC("tc/ingress")
 int tc1(struct __sk_buff *skb)
@@ -38,3 +40,17 @@ int tc4(struct __sk_buff *skb)
        seen_tc4 = true;
        return TCX_NEXT;
 }
+
+SEC("tc/egress")
+int tc5(struct __sk_buff *skb)
+{
+       seen_tc5 = true;
+       return TCX_PASS;
+}
+
+SEC("tc/egress")
+int tc6(struct __sk_buff *skb)
+{
+       seen_tc6 = true;
+       return TCX_PASS;
+}
index 258ddc5..1b2cec9 100644 (file)
@@ -70,6 +70,10 @@ static int test_kmem_basic(const char *root)
                goto cleanup;
 
        cg_write(cg, "memory.high", "1M");
+
+       /* wait for RCU freeing */
+       sleep(1);
+
        slab1 = cg_read_key_long(cg, "memory.stat", "slab ");
        if (slab1 <= 0)
                goto cleanup;
index 435aceb..380b691 100644 (file)
@@ -831,6 +831,7 @@ int main(int argc, char *argv[])
                                printf("Size must be greater than 0\n");
                                return KSFT_FAIL;
                        }
+                       break;
                case 't':
                        {
                                int tmp = atoi(optarg);
index aff88f7..5ea9d63 100755 (executable)
@@ -72,7 +72,8 @@ test_span_gre_ttl()
 
        RET=0
 
-       mirror_install $swp1 ingress $tundev "matchall $tcflags"
+       mirror_install $swp1 ingress $tundev \
+               "prot ip flower $tcflags ip_prot icmp"
        tc filter add dev $h3 ingress pref 77 prot $prot \
                flower skip_hw ip_ttl 50 action pass