summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap3
-rw-r--r--CREDITS8
-rw-r--r--Documentation/ABI/testing/sysfs-driver-uniwill-laptop10
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt13
-rw-r--r--Documentation/admin-guide/laptops/uniwill-laptop.rst2
-rw-r--r--Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml1
-rw-r--r--Documentation/devicetree/bindings/net/can/nxp,sja1000.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml1
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml1
-rw-r--r--Documentation/hwmon/emc1403.rst2
-rw-r--r--Documentation/hwmon/index.rst1
-rw-r--r--Documentation/hwmon/sa67.rst41
-rw-r--r--Documentation/netlink/specs/nfsd.yaml4
-rw-r--r--Documentation/sound/alsa-configuration.rst4
-rw-r--r--MAINTAINERS37
-rw-r--r--Makefile10
-rw-r--r--arch/alpha/kernel/vmlinux.lds.S1
-rw-r--r--arch/arc/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.S1
-rw-r--r--arch/arm/kernel/vmlinux-xip.lds.S1
-rw-r--r--arch/arm/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm64/include/asm/cmpxchg.h12
-rw-r--r--arch/arm64/include/asm/pgtable-prot.h10
-rw-r--r--arch/arm64/include/asm/runtime-const.h4
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S1
-rw-r--r--arch/arm64/mm/contpte.c53
-rw-r--r--arch/csky/kernel/vmlinux.lds.S1
-rw-r--r--arch/hexagon/kernel/vmlinux.lds.S1
-rw-r--r--arch/loongarch/kernel/vmlinux.lds.S1
-rw-r--r--arch/m68k/kernel/vmlinux-nommu.lds1
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds1
-rw-r--r--arch/m68k/kernel/vmlinux-sun3.lds1
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/nios2/kernel/vmlinux.lds.S1
-rw-r--r--arch/openrisc/kernel/vmlinux.lds.S1
-rw-r--r--arch/parisc/boot/compressed/vmlinux.lds.S1
-rw-r--r--arch/parisc/include/asm/pgtable.h2
-rw-r--r--arch/parisc/kernel/head.S7
-rw-r--r--arch/parisc/kernel/setup.c20
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S1
-rw-r--r--arch/powerpc/kernel/pci_of_scan.c7
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S1
-rw-r--r--arch/riscv/kernel/vmlinux.lds.S1
-rw-r--r--arch/s390/include/asm/processor.h2
-rw-r--r--arch/s390/kernel/vmlinux.lds.S1
-rw-r--r--arch/s390/lib/xor.c11
-rw-r--r--arch/sh/kernel/vmlinux.lds.S1
-rw-r--r--arch/sparc/kernel/pci.c7
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S1
-rw-r--r--arch/um/kernel/dyn.lds.S1
-rw-r--r--arch/um/kernel/uml.lds.S1
-rw-r--r--arch/x86/boot/compressed/Makefile1
-rw-r--r--arch/x86/boot/compressed/sev.c9
-rw-r--r--arch/x86/boot/compressed/vmlinux.lds.S2
-rw-r--r--arch/x86/boot/startup/sev-shared.c2
-rw-r--r--arch/x86/coco/sev/core.c1
-rw-r--r--arch/x86/entry/vdso/vdso32/sigreturn.S30
-rw-r--r--arch/x86/include/asm/efi.h2
-rw-r--r--arch/x86/include/asm/msr-index.h5
-rw-r--r--arch/x86/include/asm/numa.h6
-rw-r--r--arch/x86/include/asm/pgtable_64.h2
-rw-r--r--arch/x86/include/asm/topology.h6
-rw-r--r--arch/x86/kernel/cpu/common.c3
-rw-r--r--arch/x86/kernel/cpu/resctrl/monitor.c36
-rw-r--r--arch/x86/kernel/cpu/topology.c13
-rw-r--r--arch/x86/kernel/head_64.S28
-rw-r--r--arch/x86/kernel/smpboot.c201
-rw-r--r--arch/x86/kernel/vmlinux.lds.S1
-rw-r--r--arch/x86/mm/numa.c8
-rw-r--r--arch/x86/mm/srat.c2
-rw-r--r--arch/x86/platform/efi/efi.c2
-rw-r--r--arch/x86/platform/efi/quirks.c55
-rw-r--r--arch/x86/platform/pvh/enlighten.c7
-rw-r--r--arch/x86/xen/enlighten_pv.c2
-rw-r--r--arch/x86/xen/mmu_pv.c9
-rw-r--r--block/blk-map.c3
-rw-r--r--block/blk-mq.c45
-rw-r--r--block/blk-sysfs.c8
-rw-r--r--block/elevator.c12
-rw-r--r--crypto/Kconfig9
-rw-r--r--crypto/testmgr.c4
-rw-r--r--drivers/accel/amdxdna/aie2_ctx.c23
-rw-r--r--drivers/accel/amdxdna/aie2_message.c36
-rw-r--r--drivers/accel/amdxdna/aie2_pci.c66
-rw-r--r--drivers/accel/amdxdna/aie2_pci.h1
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.c27
-rw-r--r--drivers/accel/amdxdna/amdxdna_ctx.h3
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.c91
-rw-r--r--drivers/accel/amdxdna/amdxdna_mailbox.h31
-rw-r--r--drivers/accel/amdxdna/npu1_regs.c2
-rw-r--r--drivers/accel/ethosu/ethosu_gem.c12
-rw-r--r--drivers/accel/ethosu/ethosu_job.c26
-rw-r--r--drivers/acpi/acpica/acpredef.h5
-rw-r--r--drivers/acpi/device_pm.c9
-rw-r--r--drivers/ata/libata-core.c2
-rw-r--r--drivers/ata/libata-eh.c3
-rw-r--r--drivers/ata/libata-scsi.c1
-rw-r--r--drivers/base/base.h11
-rw-r--r--drivers/base/dd.c2
-rw-r--r--drivers/crypto/atmel-sha204a.c5
-rw-r--r--drivers/crypto/ccp/sev-dev-tsm.c2
-rw-r--r--drivers/crypto/ccp/sev-dev.c10
-rw-r--r--drivers/firmware/efi/mokvar-table.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c6
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c116
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c42
-rw-r--r--drivers/gpu/drm/amd/amdgpu/psp_v15_0.c20
-rw-r--r--drivers/gpu/drm/amd/amdgpu/soc21.c4
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c3
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c16
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c6
-rw-r--r--drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h18
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c8
-rw-r--r--drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c3
-rw-r--r--drivers/gpu/drm/drm_pagemap.c14
-rw-r--r--drivers/gpu/drm/i915/display/intel_psr.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c3
-rw-r--r--drivers/gpu/drm/panthor/panthor_sched.c9
-rw-r--r--drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c16
-rw-r--r--drivers/gpu/drm/scheduler/sched_main.c1
-rw-r--r--drivers/gpu/drm/solomon/ssd130x.c6
-rw-r--r--drivers/gpu/drm/ttm/tests/ttm_bo_test.c4
-rw-r--r--drivers/gpu/drm/ttm/ttm_bo.c11
-rw-r--r--drivers/gpu/drm/ttm/ttm_pool_internal.h2
-rw-r--r--drivers/gpu/drm/xe/xe_configfs.c1
-rw-r--r--drivers/gpu/drm/xe/xe_exec_queue.c23
-rw-r--r--drivers/gpu/drm/xe/xe_gsc_proxy.c43
-rw-r--r--drivers/gpu/drm/xe/xe_gsc_types.h2
-rw-r--r--drivers/gpu/drm/xe/xe_lrc.h3
-rw-r--r--drivers/gpu/drm/xe/xe_reg_sr.c4
-rw-r--r--drivers/gpu/drm/xe/xe_ring_ops.c9
-rw-r--r--drivers/gpu/drm/xe/xe_vm_madvise.c3
-rw-r--r--drivers/gpu/drm/xe/xe_wa.c13
-rw-r--r--drivers/hid/hid-apple.c7
-rw-r--r--drivers/hid/hid-asus.c18
-rw-r--r--drivers/hid/hid-cmedia.c2
-rw-r--r--drivers/hid/hid-creative-sb0540.c2
-rw-r--r--drivers/hid/hid-ids.h1
-rw-r--r--drivers/hid/hid-magicmouse.c6
-rw-r--r--drivers/hid/hid-mcp2221.c2
-rw-r--r--drivers/hid/hid-multitouch.c43
-rw-r--r--drivers/hid/hid-zydacron.c2
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish.h2
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c12
-rw-r--r--drivers/hid/usbhid/hid-pidff.c11
-rw-r--r--drivers/hwmon/Kconfig10
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/aht10.c6
-rw-r--r--drivers/hwmon/it87.c5
-rw-r--r--drivers/hwmon/macsmc-hwmon.c53
-rw-r--r--drivers/hwmon/max6639.c2
-rw-r--r--drivers/hwmon/pmbus/q54sj108a2.c19
-rw-r--r--drivers/hwmon/sa67mcu-hwmon.c161
-rw-r--r--drivers/i2c/busses/i2c-i801.c14
-rw-r--r--drivers/media/dvb-core/dvb_net.c3
-rw-r--r--drivers/net/bonding/bond_main.c9
-rw-r--r--drivers/net/bonding/bond_options.c2
-rw-r--r--drivers/net/can/dummy_can.c1
-rw-r--r--drivers/net/can/spi/mcp251x.c15
-rw-r--r--drivers/net/can/usb/ems_usb.c7
-rw-r--r--drivers/net/can/usb/esd_usb.c30
-rw-r--r--drivers/net/can/usb/etas_es58x/es58x_core.c8
-rw-r--r--drivers/net/can/usb/f81604.c45
-rw-r--r--drivers/net/can/usb/gs_usb.c22
-rw-r--r--drivers/net/can/usb/ucan.c2
-rw-r--r--drivers/net/dsa/realtek/rtl8365mb.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-common.h2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c10
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c1
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h3
-rw-r--r--drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c3
-rw-r--r--drivers/net/ethernet/freescale/enetc/enetc.c2
-rw-r--r--drivers/net/ethernet/intel/e1000e/defines.h1
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h4
-rw-r--r--drivers/net/ethernet/intel/e1000e/hw.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/ich8lan.c31
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c15
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c41
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_trace.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c5
-rw-r--r--drivers/net/ethernet/intel/iavf/iavf_main.c17
-rw-r--r--drivers/net/ethernet/intel/ice/ice.h1
-rw-r--r--drivers/net/ethernet/intel/ice/ice_base.c38
-rw-r--r--drivers/net/ethernet/intel/ice/ice_common.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_ethtool.c51
-rw-r--r--drivers/net/ethernet/intel/ice/ice_idc.c44
-rw-r--r--drivers/net/ethernet/intel/ice/ice_lib.c15
-rw-r--r--drivers/net/ethernet/intel/ice/ice_main.c7
-rw-r--r--drivers/net/ethernet/intel/ice/ice_txrx.c4
-rw-r--r--drivers/net/ethernet/intel/ice/ice_xsk.c3
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_lib.c1
-rw-r--r--drivers/net/ethernet/intel/idpf/idpf_txrx.c14
-rw-r--r--drivers/net/ethernet/intel/idpf/xdp.c6
-rw-r--r--drivers/net/ethernet/intel/idpf/xsk.c1
-rw-r--r--drivers/net/ethernet/intel/igb/igb_xsk.c38
-rw-r--r--drivers/net/ethernet/intel/igc/igc_main.c34
-rw-r--r--drivers/net/ethernet/intel/igc/igc_ptp.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/vf.c3
-rw-r--r--drivers/net/ethernet/intel/libeth/xsk.c1
-rw-r--r--drivers/net/ethernet/intel/libie/fwlog.c4
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_main.c40
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep/octep_rx.c27
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c38
-rw-r--r--drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c28
-rw-r--r--drivers/net/ethernet/mediatek/mtk_eth_soc.c15
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c23
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c53
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c60
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c2
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c9
-rw-r--r--drivers/net/ethernet/ti/icssg/icssg_prueth.c8
-rw-r--r--drivers/net/netconsole.c2
-rw-r--r--drivers/net/usb/r8152.c1
-rw-r--r--drivers/net/vxlan/vxlan_core.c5
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c6
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c36
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mac.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c1
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_mac80211.c2
-rw-r--r--drivers/net/wireless/st/cw1200/pm.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c4
-rw-r--r--drivers/net/xen-netfront.c34
-rw-r--r--drivers/nvme/host/core.c28
-rw-r--r--drivers/nvme/host/fabrics.c4
-rw-r--r--drivers/nvme/host/multipath.c14
-rw-r--r--drivers/nvme/host/nvme.h57
-rw-r--r--drivers/nvme/host/pci.c186
-rw-r--r--drivers/nvme/host/pr.c4
-rw-r--r--drivers/nvme/host/sysfs.c23
-rw-r--r--drivers/nvme/host/tcp.c5
-rw-r--r--drivers/nvme/target/fcloop.c15
-rw-r--r--drivers/pci/xen-pcifront.c8
-rw-r--r--drivers/pinctrl/cirrus/pinctrl-cs42l43.c5
-rw-r--r--drivers/pinctrl/cix/pinctrl-sky1.c3
-rw-r--r--drivers/pinctrl/meson/pinctrl-amlogic-a4.c3
-rw-r--r--drivers/pinctrl/pinconf-generic.c4
-rw-r--r--drivers/pinctrl/pinctrl-amdisp.c2
-rw-r--r--drivers/pinctrl/pinctrl-cy8c95x0.c4
-rw-r--r--drivers/pinctrl/pinctrl-equilibrium.c31
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c12
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qcs615.c1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c4
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.c51
-rw-r--r--drivers/platform/x86/asus-armoury.h75
-rw-r--r--drivers/platform/x86/dell/alienware-wmi-wmax.c2
-rw-r--r--drivers/platform/x86/dell/dell-wmi-base.c6
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c1
-rw-r--r--drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c9
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c12
-rw-r--r--drivers/platform/x86/intel/hid.c19
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c7
-rw-r--r--drivers/platform/x86/lenovo/thinkpad_acpi.c6
-rw-r--r--drivers/platform/x86/oxpec.c30
-rw-r--r--drivers/platform/x86/redmi-wmi.c25
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c18
-rw-r--r--drivers/platform/x86/uniwill/uniwill-acpi.c110
-rw-r--r--drivers/platform/x86/uniwill/uniwill-wmi.h6
-rw-r--r--drivers/pmdomain/bcm/bcm2835-power.c6
-rw-r--r--drivers/pmdomain/rockchip/pm-domains.c2
-rw-r--r--drivers/regulator/mt6363-regulator.c4
-rw-r--r--drivers/regulator/pf9453-regulator.c2
-rw-r--r--drivers/scsi/mpi3mr/mpi3mr_fw.c10
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/scsi/scsi_scan.c1
-rw-r--r--drivers/scsi/xen-scsifront.c2
-rw-r--r--drivers/spi/spi-dw-dma.c2
-rw-r--r--drivers/target/target_core_configfs.c15
-rw-r--r--drivers/xen/xen-acpi-processor.c7
-rw-r--r--drivers/xen/xen-pciback/xenbus.c10
-rw-r--r--drivers/xen/xenbus/xenbus_client.c17
-rw-r--r--drivers/xen/xenbus/xenbus_probe.c42
-rw-r--r--drivers/xen/xenbus/xenbus_probe_frontend.c2
-rw-r--r--fs/btrfs/block-group.c1
-rw-r--r--fs/btrfs/delayed-inode.c2
-rw-r--r--fs/btrfs/disk-io.c36
-rw-r--r--fs/btrfs/extent-tree.c8
-rw-r--r--fs/btrfs/inode.c19
-rw-r--r--fs/btrfs/ioctl.c7
-rw-r--r--fs/btrfs/qgroup.c2
-rw-r--r--fs/btrfs/relocation.c6
-rw-r--r--fs/btrfs/scrub.c2
-rw-r--r--fs/btrfs/tree-checker.c4
-rw-r--r--fs/btrfs/volumes.c8
-rw-r--r--fs/iomap/buffered-io.c15
-rw-r--r--fs/iomap/direct-io.c15
-rw-r--r--fs/iomap/ioend.c13
-rw-r--r--fs/netfs/direct_write.c228
-rw-r--r--fs/netfs/internal.h4
-rw-r--r--fs/netfs/write_collect.c21
-rw-r--r--fs/netfs/write_issue.c41
-rw-r--r--fs/nfsd/nfsctl.c22
-rw-r--r--fs/nfsd/nfssvc.c7
-rw-r--r--fs/nsfs.c15
-rw-r--r--fs/smb/client/Makefile2
-rw-r--r--fs/smb/client/cifsfs.c7
-rw-r--r--fs/smb/client/cifsproto.h1
-rw-r--r--fs/smb/client/file.c11
-rw-r--r--fs/smb/client/misc.c42
-rw-r--r--fs/smb/client/smb1encrypt.c3
-rw-r--r--fs/smb/client/smb2glob.h12
-rw-r--r--fs/smb/client/smb2inode.c8
-rw-r--r--fs/smb/client/smb2maperror.c28
-rw-r--r--fs/smb/client/smb2maperror_test.c12
-rw-r--r--fs/smb/client/smb2pdu.c18
-rw-r--r--fs/smb/client/smb2pdu.h7
-rw-r--r--fs/smb/client/smb2proto.h3
-rw-r--r--fs/smb/client/smb2transport.c4
-rw-r--r--fs/smb/client/trace.h2
-rw-r--r--fs/smb/server/smb2pdu.h5
-rw-r--r--fs/verity/Kconfig3
-rw-r--r--include/asm-generic/vmlinux.lds.h4
-rw-r--r--include/drm/display/drm_dp.h2
-rw-r--r--include/kunit/run-in-irq-context.h44
-rw-r--r--include/linux/device/bus.h2
-rw-r--r--include/linux/eventpoll.h11
-rw-r--r--include/linux/hid.h6
-rw-r--r--include/linux/indirect_call_wrapper.h18
-rw-r--r--include/linux/kthread.h21
-rw-r--r--include/linux/migrate.h10
-rw-r--r--include/linux/netdevice.h27
-rw-r--r--include/linux/ns_common.h2
-rw-r--r--include/linux/platform_data/mlxreg.h14
-rw-r--r--include/linux/platform_data/x86/int3472.h5
-rw-r--r--include/linux/ring_buffer.h1
-rw-r--r--include/linux/uaccess.h54
-rw-r--r--include/linux/usb/r8152.h1
-rw-r--r--include/net/act_api.h1
-rw-r--r--include/net/bonding.h1
-rw-r--r--include/net/inet6_hashtables.h2
-rw-r--r--include/net/inet_hashtables.h2
-rw-r--r--include/net/ip.h2
-rw-r--r--include/net/ip_fib.h2
-rw-r--r--include/net/libeth/xsk.h3
-rw-r--r--include/net/netfilter/nf_tables.h7
-rw-r--r--include/net/sch_generic.h10
-rw-r--r--include/net/secure_seq.h45
-rw-r--r--include/net/tc_act/tc_gate.h33
-rw-r--r--include/net/tc_act/tc_ife.h4
-rw-r--r--include/net/tcp.h6
-rw-r--r--include/net/xdp_sock_drv.h16
-rw-r--r--include/sound/cs35l56.h1
-rw-r--r--include/sound/tas2781.h1
-rw-r--r--include/trace/events/netfs.h4
-rw-r--r--include/uapi/linux/dma-buf.h1
-rw-r--r--include/uapi/linux/io_uring.h3
-rw-r--r--include/xen/xenbus.h4
-rw-r--r--init/Kconfig2
-rw-r--r--io_uring/net.c2
-rw-r--r--io_uring/zcrx.c8
-rw-r--r--kernel/bpf/trampoline.c4
-rw-r--r--kernel/bpf/verifier.c38
-rw-r--r--kernel/cgroup/cgroup.c1
-rw-r--r--kernel/cgroup/cpuset.c222
-rw-r--r--kernel/exit.c6
-rw-r--r--kernel/kthread.c41
-rw-r--r--kernel/module/Kconfig23
-rw-r--r--kernel/module/main.c13
-rw-r--r--kernel/nscommon.c6
-rw-r--r--kernel/nstree.c29
-rw-r--r--kernel/sched/ext.c101
-rw-r--r--kernel/sched/ext_idle.c5
-rw-r--r--kernel/sched/ext_internal.h2
-rw-r--r--kernel/sched/isolation.c4
-rw-r--r--kernel/sched/syscalls.c30
-rw-r--r--kernel/time/jiffies.c2
-rw-r--r--kernel/time/timekeeping.c6
-rw-r--r--kernel/time/timer_migration.c4
-rw-r--r--kernel/trace/blktrace.c3
-rw-r--r--kernel/trace/ftrace.c4
-rw-r--r--kernel/trace/ring_buffer.c21
-rw-r--r--kernel/trace/trace.c19
-rw-r--r--kernel/trace/trace_events.c60
-rw-r--r--kernel/trace/trace_events_trigger.c3
-rw-r--r--kernel/trace/trace_functions_graph.c19
-rw-r--r--lib/crypto/.kunitconfig34
-rw-r--r--lib/crypto/tests/Kconfig35
-rw-r--r--lib/kunit/test.c231
-rw-r--r--mm/filemap.c15
-rw-r--r--mm/madvise.c2
-rw-r--r--mm/memory.c3
-rw-r--r--mm/migrate.c8
-rw-r--r--mm/migrate_device.c2
-rw-r--r--mm/slab.h10
-rw-r--r--mm/slub.c69
-rw-r--r--net/atm/lec.c26
-rw-r--r--net/batman-adv/bat_v_elp.c10
-rw-r--r--net/batman-adv/hard-interface.c8
-rw-r--r--net/batman-adv/hard-interface.h1
-rw-r--r--net/bridge/br_device.c2
-rw-r--r--net/bridge/br_input.c2
-rw-r--r--net/bridge/br_private.h10
-rw-r--r--net/bridge/br_vlan_options.c26
-rw-r--r--net/can/bcm.c1
-rw-r--r--net/core/dev.c24
-rw-r--r--net/core/devmem.c6
-rw-r--r--net/core/filter.c6
-rw-r--r--net/core/netpoll.c2
-rw-r--r--net/core/secure_seq.c80
-rw-r--r--net/core/skmsg.c14
-rw-r--r--net/ipv4/Kconfig2
-rw-r--r--net/ipv4/inet_hashtables.c8
-rw-r--r--net/ipv4/syncookies.c11
-rw-r--r--net/ipv4/sysctl_net_ipv4.c5
-rw-r--r--net/ipv4/tcp.c7
-rw-r--r--net/ipv4/tcp_ao.c3
-rw-r--r--net/ipv4/tcp_bpf.c2
-rw-r--r--net/ipv4/tcp_diag.c2
-rw-r--r--net/ipv4/tcp_input.c38
-rw-r--r--net/ipv4/tcp_ipv4.c40
-rw-r--r--net/ipv4/tcp_minisocks.c2
-rw-r--r--net/ipv4/udp.c27
-rw-r--r--net/ipv4/udp_bpf.c2
-rw-r--r--net/ipv6/inet6_hashtables.c3
-rw-r--r--net/ipv6/route.c11
-rw-r--r--net/ipv6/syncookies.c11
-rw-r--r--net/ipv6/tcp_ipv6.c40
-rw-r--r--net/mac80211/eht.c1
-rw-r--r--net/mptcp/pm.c55
-rw-r--r--net/mptcp/pm_kernel.c9
-rw-r--r--net/netfilter/nf_tables_api.c45
-rw-r--r--net/netfilter/nft_set_hash.c1
-rw-r--r--net/netfilter/nft_set_pipapo.c62
-rw-r--r--net/netfilter/nft_set_pipapo.h2
-rw-r--r--net/netfilter/nft_set_rbtree.c8
-rw-r--r--net/nfc/digital_core.c8
-rw-r--r--net/nfc/nci/core.c30
-rw-r--r--net/nfc/nci/data.c12
-rw-r--r--net/nfc/rawsock.c11
-rw-r--r--net/rds/tcp.c14
-rw-r--r--net/sched/act_ct.c6
-rw-r--r--net/sched/act_gate.c265
-rw-r--r--net/sched/act_ife.c93
-rw-r--r--net/sched/cls_api.c7
-rw-r--r--net/sched/sch_cake.c53
-rw-r--r--net/sched/sch_ets.c12
-rw-r--r--net/sched/sch_fq.c1
-rw-r--r--net/unix/af_unix.c8
-rw-r--r--net/xdp/xsk.c26
-rw-r--r--rust/kernel/kunit.rs8
-rw-r--r--scripts/genksyms/parse.y4
-rwxr-xr-xscripts/package/install-extmod-build4
-rw-r--r--sound/firewire/dice/dice.c2
-rw-r--r--sound/hda/codecs/ca0132.c9
-rw-r--r--sound/hda/codecs/hdmi/tegrahdmi.c1
-rw-r--r--sound/hda/codecs/realtek/alc269.c1
-rw-r--r--sound/hda/codecs/senarytech.c14
-rw-r--r--sound/hda/codecs/side-codecs/tas2781_hda_i2c.c15
-rw-r--r--sound/soc/amd/acp/amd-acp63-acpi-match.c413
-rw-r--r--sound/soc/amd/yc/acp6x-mach.c7
-rw-r--r--sound/soc/codecs/cs35l56-shared.c16
-rw-r--r--sound/soc/codecs/cs35l56.c12
-rw-r--r--sound/soc/codecs/rt1320-sdw.c5
-rw-r--r--sound/soc/codecs/tas2781-fmwlib.c94
-rw-r--r--sound/soc/fsl/fsl_easrc.c14
-rw-r--r--sound/soc/intel/boards/sof_sdw.c8
-rw-r--r--sound/soc/sdca/sdca_functions.c5
-rw-r--r--sound/usb/quirks.c2
-rw-r--r--sound/usb/usx2y/us122l.c12
-rw-r--r--tools/bpf/resolve_btfids/Makefile9
-rw-r--r--tools/objtool/Makefile8
-rw-r--r--tools/sched_ext/Kconfig61
-rw-r--r--tools/sched_ext/Makefile2
-rw-r--r--tools/sched_ext/README.md6
-rw-r--r--tools/sched_ext/include/scx/compat.h7
-rw-r--r--tools/sched_ext/scx_central.c2
-rw-r--r--tools/sched_ext/scx_sdt.c2
-rw-r--r--tools/testing/kunit/kunit_kernel.py6
-rwxr-xr-xtools/testing/kunit/kunit_tool_test.py26
-rw-r--r--tools/testing/selftests/arm64/abi/hwcap.c4
-rw-r--r--tools/testing/selftests/bpf/Makefile1
-rw-r--r--tools/testing/selftests/bpf/prog_tests/reg_bounds.c76
-rw-r--r--tools/testing/selftests/bpf/prog_tests/xdp_bonding.c58
-rw-r--r--tools/testing/selftests/bpf/progs/exceptions_assert.c34
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_bounds.c39
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_linked_scalars.c64
-rw-r--r--tools/testing/selftests/bpf/progs/verifier_scalar_ids.c56
-rw-r--r--tools/testing/selftests/bpf/verifier/precise.c8
-rwxr-xr-xtools/testing/selftests/cgroup/test_cpuset_prs.sh224
-rw-r--r--tools/testing/selftests/filesystems/nsfs/iterate_mntns.c25
-rw-r--r--tools/testing/selftests/hid/tests/test_wacom_generic.py34
-rw-r--r--tools/testing/selftests/kselftest_harness.h7
-rw-r--r--tools/testing/selftests/net/Makefile1
-rwxr-xr-xtools/testing/selftests/net/bridge_vlan_dump.sh204
-rwxr-xr-xtools/testing/selftests/net/fib_nexthops.sh11
-rwxr-xr-xtools/testing/selftests/net/mptcp/mptcp_join.sh49
-rwxr-xr-xtools/testing/selftests/net/mptcp/simult_flows.sh11
-rw-r--r--tools/testing/selftests/net/netfilter/nf_queue.c10
-rwxr-xr-xtools/testing/selftests/net/netfilter/nft_queue.sh13
-rw-r--r--tools/testing/selftests/net/packetdrill/tcp_rcv_big_endseq.pkt2
-rw-r--r--tools/testing/selftests/net/packetdrill/tcp_rcv_toobig.pkt33
-rw-r--r--tools/testing/selftests/net/tun.c12
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-N4
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-T3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/SRCU-U4
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TASKS023
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY014
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY023
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TRACE013
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE044
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE054
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE065
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE101
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL4
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuscale/TINY3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcuscale/TRACE013
-rw-r--r--tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT3
-rw-r--r--tools/testing/selftests/rcutorture/configs/refscale/TINY3
-rw-r--r--tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT3
-rw-r--r--tools/testing/selftests/sched_ext/Makefile2
-rw-r--r--tools/testing/selftests/sched_ext/init_enable_count.c3
-rw-r--r--tools/testing/selftests/sched_ext/peek_dsq.bpf.c4
-rw-r--r--tools/testing/selftests/sched_ext/rt_stall.c1
-rw-r--r--tools/testing/selftests/sched_ext/runner.c3
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/ct.json159
-rw-r--r--tools/testing/selftests/tc-testing/tc-tests/actions/ife.json99
-rw-r--r--tools/testing/selftests/tc-testing/tdc_helper.py10
522 files changed, 6499 insertions, 2735 deletions
diff --git a/.mailmap b/.mailmap
index 7d5a6cc3909f..5ac7074c455f 100644
--- a/.mailmap
+++ b/.mailmap
@@ -219,6 +219,7 @@ Daniele Alessandrelli <daniele.alessandrelli@gmail.com> <daniele.alessandrelli@i
Danilo Krummrich <dakr@kernel.org> <dakr@redhat.com>
David Brownell <david-b@pacbell.net>
David Collins <quic_collinsd@quicinc.com> <collinsd@codeaurora.org>
+David Gow <david@davidgow.net> <davidgow@google.com>
David Heidelberg <david@ixit.cz> <d.okias@gmail.com>
David Hildenbrand <david@kernel.org> <david@redhat.com>
David Rheinsberg <david@readahead.eu> <dh.herrmann@gmail.com>
@@ -353,6 +354,7 @@ Jarkko Sakkinen <jarkko@kernel.org> <jarkko.sakkinen@opinsys.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@mellanox.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgg@nvidia.com>
Jason Gunthorpe <jgg@ziepe.ca> <jgunthorpe@obsidianresearch.com>
+Jason Xing <kerneljasonxing@gmail.com> <kernelxing@tencent.com>
<javier@osg.samsung.com> <javier.martinez@collabora.co.uk>
Javi Merino <javi.merino@kernel.org> <javi.merino@arm.com>
Jayachandran C <c.jayachandran@gmail.com> <jayachandranc@netlogicmicro.com>
@@ -401,6 +403,7 @@ Jiri Slaby <jirislaby@kernel.org> <xslaby@fi.muni.cz>
Jisheng Zhang <jszhang@kernel.org> <jszhang@marvell.com>
Jisheng Zhang <jszhang@kernel.org> <Jisheng.Zhang@synaptics.com>
Jishnu Prakash <quic_jprakash@quicinc.com> <jprakash@codeaurora.org>
+Joe Damato <joe@dama.to> <jdamato@fastly.com>
Joel Granados <joel.granados@kernel.org> <j.granados@samsung.com>
Johan Hovold <johan@kernel.org> <jhovold@gmail.com>
Johan Hovold <johan@kernel.org> <johan@hovoldconsulting.com>
diff --git a/CREDITS b/CREDITS
index d74c8b2b7ed3..9091bac3d2da 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1242,6 +1242,10 @@ N: Veaceslav Falico
E: vfalico@gmail.com
D: Co-maintainer and co-author of the network bonding driver.
+N: Thomas Falcon
+E: tlfalcon@linux.ibm.com
+D: Initial author of the IBM ibmvnic network driver
+
N: János Farkas
E: chexum@shadow.banki.hu
D: romfs, various (mostly networking) fixes
@@ -2415,6 +2419,10 @@ S: Am Muehlenweg 38
S: D53424 Remagen
S: Germany
+N: Jonathan Lemon
+E: jonathan.lemon@gmail.com
+D: OpenCompute PTP clock driver (ptp_ocp)
+
N: Colin Leroy
E: colin@colino.net
W: http://www.geekounet.org/
diff --git a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
index eaeb659793d2..2df70792968f 100644
--- a/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
+++ b/Documentation/ABI/testing/sysfs-driver-uniwill-laptop
@@ -1,4 +1,4 @@
-What: /sys/bus/platform/devices/INOU0000:XX/fn_lock_toggle_enable
+What: /sys/bus/platform/devices/INOU0000:XX/fn_lock
Date: November 2025
KernelVersion: 6.19
Contact: Armin Wolf <W_Armin@gmx.de>
@@ -8,15 +8,15 @@ Description:
Reading this file returns the current enable status of the FN lock functionality.
-What: /sys/bus/platform/devices/INOU0000:XX/super_key_toggle_enable
+What: /sys/bus/platform/devices/INOU0000:XX/super_key_enable
Date: November 2025
KernelVersion: 6.19
Contact: Armin Wolf <W_Armin@gmx.de>
Description:
- Allows userspace applications to enable/disable the super key functionality
- of the integrated keyboard by writing "1"/"0" into this file.
+ Allows userspace applications to enable/disable the super key of the integrated
+ keyboard by writing "1"/"0" into this file.
- Reading this file returns the current enable status of the super key functionality.
+ Reading this file returns the current enable status of the super key.
What: /sys/bus/platform/devices/INOU0000:XX/touchpad_toggle_enable
Date: November 2025
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index cb850e5290c2..55ffc0f8858a 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -74,6 +74,7 @@
TPM TPM drivers are enabled.
UMS USB Mass Storage support is enabled.
USB USB support is enabled.
+ NVME NVMe support is enabled
USBHID USB Human Interface Device support is enabled.
V4L Video For Linux support is enabled.
VGA The VGA console has been enabled.
@@ -4787,6 +4788,18 @@ Kernel parameters
This can be set from sysctl after boot.
See Documentation/admin-guide/sysctl/vm.rst for details.
+ nvme.quirks= [NVME] A list of quirk entries to augment the built-in
+ nvme quirk list. List entries are separated by a
+ '-' character.
+ Each entry has the form VendorID:ProductID:quirk_names.
+ The IDs are 4-digits hex numbers and quirk_names is a
+ list of quirk names separated by commas. A quirk name
+ can be prefixed by '^', meaning that the specified
+ quirk must be disabled.
+
+ Example:
+ nvme.quirks=7710:2267:bogus_nid,^identify_cns-9900:7711:broken_msi
+
ohci1394_dma=early [HW,EARLY] enable debugging via the ohci1394 driver.
See Documentation/core-api/debugging-via-ohci1394.rst for more
info.
diff --git a/Documentation/admin-guide/laptops/uniwill-laptop.rst b/Documentation/admin-guide/laptops/uniwill-laptop.rst
index a16baf15516b..aff5f57a6bd4 100644
--- a/Documentation/admin-guide/laptops/uniwill-laptop.rst
+++ b/Documentation/admin-guide/laptops/uniwill-laptop.rst
@@ -24,7 +24,7 @@ Keyboard settings
The ``uniwill-laptop`` driver allows the user to enable/disable:
- - the FN and super key lock functionality of the integrated keyboard
+ - the FN lock and super key of the integrated keyboard
- the touchpad toggle functionality of the integrated touchpad
See Documentation/ABI/testing/sysfs-driver-uniwill-laptop for details.
diff --git a/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml b/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
index 966b221b6caa..5803a1770cad 100644
--- a/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
+++ b/Documentation/devicetree/bindings/hwmon/kontron,sl28cpld-hwmon.yaml
@@ -16,7 +16,6 @@ description: |
properties:
compatible:
enum:
- - kontron,sa67mcu-hwmon
- kontron,sl28cpld-fan
reg:
diff --git a/Documentation/devicetree/bindings/net/can/nxp,sja1000.yaml b/Documentation/devicetree/bindings/net/can/nxp,sja1000.yaml
index ec0c2168e4b9..6bcfff970117 100644
--- a/Documentation/devicetree/bindings/net/can/nxp,sja1000.yaml
+++ b/Documentation/devicetree/bindings/net/can/nxp,sja1000.yaml
@@ -87,6 +87,7 @@ required:
allOf:
- $ref: can-controller.yaml#
+ - $ref: /schemas/memory-controllers/mc-peripheral-props.yaml
- if:
properties:
compatible:
diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
index da89523ccf5f..92bc3ef56f2c 100644
--- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
+++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-graph-card.yaml
@@ -23,6 +23,7 @@ properties:
enum:
- nvidia,tegra210-audio-graph-card
- nvidia,tegra186-audio-graph-card
+ - nvidia,tegra238-audio-graph-card
- nvidia,tegra264-audio-graph-card
clocks:
diff --git a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
index e4cdbf2202b9..1394f78281fc 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
+++ b/Documentation/devicetree/bindings/sound/renesas,rz-ssi.yaml
@@ -20,6 +20,7 @@ properties:
- renesas,r9a07g044-ssi # RZ/G2{L,LC}
- renesas,r9a07g054-ssi # RZ/V2L
- renesas,r9a08g045-ssi # RZ/G3S
+ - renesas,r9a08g046-ssi # RZ/G3L
- const: renesas,rz-ssi
reg:
diff --git a/Documentation/hwmon/emc1403.rst b/Documentation/hwmon/emc1403.rst
index 57f833b1a800..77060d515323 100644
--- a/Documentation/hwmon/emc1403.rst
+++ b/Documentation/hwmon/emc1403.rst
@@ -57,7 +57,7 @@ Supported chips:
- https://ww1.microchip.com/downloads/en/DeviceDoc/EMC1438%20DS%20Rev.%201.0%20(04-29-10).pdf
Author:
- Kalhan Trisal <kalhan.trisal@intel.com
+ Kalhan Trisal <kalhan.trisal@intel.com>
Description
diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index d91dbb20c7dc..b2ca8513cfcd 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -220,7 +220,6 @@ Hardware Monitoring Kernel Drivers
q54sj108a2
qnap-mcu-hwmon
raspberrypi-hwmon
- sa67
sbrmi
sbtsi_temp
sch5627
diff --git a/Documentation/hwmon/sa67.rst b/Documentation/hwmon/sa67.rst
deleted file mode 100644
index 029c7c169b7f..000000000000
--- a/Documentation/hwmon/sa67.rst
+++ /dev/null
@@ -1,41 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0-only
-
-Kernel driver sa67mcu
-=====================
-
-Supported chips:
-
- * Kontron sa67mcu
-
- Prefix: 'sa67mcu'
-
- Datasheet: not available
-
-Authors: Michael Walle <mwalle@kernel.org>
-
-Description
------------
-
-The sa67mcu is a board management controller which also exposes a hardware
-monitoring controller.
-
-The controller has two voltage and one temperature sensor. The values are
-hold in two 8 bit registers to form one 16 bit value. Reading the lower byte
-will also capture the high byte to make the access atomic. The unit of the
-volatge sensors are 1mV and the unit of the temperature sensor is 0.1degC.
-
-Sysfs entries
--------------
-
-The following attributes are supported.
-
-======================= ========================================================
-in0_label "VDDIN"
-in0_input Measured VDDIN voltage.
-
-in1_label "VDD_RTC"
-in1_input Measured VDD_RTC voltage.
-
-temp1_input MCU temperature. Roughly the board temperature.
-======================= ========================================================
-
diff --git a/Documentation/netlink/specs/nfsd.yaml b/Documentation/netlink/specs/nfsd.yaml
index badb2fe57c98..f87b5a05e5e9 100644
--- a/Documentation/netlink/specs/nfsd.yaml
+++ b/Documentation/netlink/specs/nfsd.yaml
@@ -152,7 +152,7 @@ operations:
- compound-ops
-
name: threads-set
- doc: set the number of running threads
+ doc: set the maximum number of running threads
attribute-set: server
flags: [admin-perm]
do:
@@ -165,7 +165,7 @@ operations:
- min-threads
-
name: threads-get
- doc: get the number of running threads
+ doc: get the maximum number of running threads
attribute-set: server
do:
reply:
diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst
index 0a4eaa7d66dd..55b845d38236 100644
--- a/Documentation/sound/alsa-configuration.rst
+++ b/Documentation/sound/alsa-configuration.rst
@@ -2372,6 +2372,10 @@ quirk_flags
audible volume
* bit 25: ``mixer_capture_min_mute``
Similar to bit 24 but for capture streams
+ * bit 26: ``skip_iface_setup``
+ Skip the probe-time interface setup (usb_set_interface,
+ init_pitch, init_sample_rate); redundant with
+ snd_usb_endpoint_prepare() at stream-open time
This module supports multiple devices, autoprobe and hotplugging.
diff --git a/MAINTAINERS b/MAINTAINERS
index 61bf550fd37c..77fdfcb55f06 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -993,10 +993,8 @@ F: Documentation/devicetree/bindings/thermal/amazon,al-thermal.yaml
F: drivers/thermal/thermal_mmio.c
AMAZON ETHERNET DRIVERS
-M: Shay Agroskin <shayagr@amazon.com>
M: Arthur Kiyanovski <akiyano@amazon.com>
-R: David Arinzon <darinzon@amazon.com>
-R: Saeed Bishara <saeedb@amazon.com>
+M: David Arinzon <darinzon@amazon.com>
L: netdev@vger.kernel.org
S: Maintained
F: Documentation/networking/device_drivers/ethernet/amazon/ena.rst
@@ -4617,7 +4615,6 @@ F: drivers/bluetooth/
BLUETOOTH SUBSYSTEM
M: Marcel Holtmann <marcel@holtmann.org>
-M: Johan Hedberg <johan.hedberg@gmail.com>
M: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
L: linux-bluetooth@vger.kernel.org
S: Supported
@@ -10171,8 +10168,8 @@ F: drivers/i2c/busses/i2c-cpm.c
FREESCALE IMX / MXC FEC DRIVER
M: Wei Fang <wei.fang@nxp.com>
+R: Frank Li <frank.li@nxp.com>
R: Shenwei Wang <shenwei.wang@nxp.com>
-R: Clark Wang <xiaoning.wang@nxp.com>
L: imx@lists.linux.dev
L: netdev@vger.kernel.org
S: Maintained
@@ -10484,7 +10481,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace.git
F: Documentation/trace/ftrace*
F: arch/*/*/*/*ftrace*
F: arch/*/*/*ftrace*
-F: include/*/ftrace.h
+F: include/*/*ftrace*
F: kernel/trace/fgraph.c
F: kernel/trace/ftrace*
F: samples/ftrace
@@ -12216,7 +12213,6 @@ IBM Power SRIOV Virtual NIC Device Driver
M: Haren Myneni <haren@linux.ibm.com>
M: Rick Lindsley <ricklind@linux.ibm.com>
R: Nick Child <nnac123@linux.ibm.com>
-R: Thomas Falcon <tlfalcon@linux.ibm.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/ibm/ibmvnic.*
@@ -13942,7 +13938,7 @@ F: fs/smb/server/
KERNEL UNIT TESTING FRAMEWORK (KUnit)
M: Brendan Higgins <brendan.higgins@linux.dev>
-M: David Gow <davidgow@google.com>
+M: David Gow <david@davidgow.net>
R: Rae Moar <raemoar63@gmail.com>
L: linux-kselftest@vger.kernel.org
L: kunit-dev@googlegroups.com
@@ -14762,7 +14758,7 @@ F: drivers/misc/lis3lv02d/
F: drivers/platform/x86/hp/hp_accel.c
LIST KUNIT TEST
-M: David Gow <davidgow@google.com>
+M: David Gow <david@davidgow.net>
L: linux-kselftest@vger.kernel.org
L: kunit-dev@googlegroups.com
S: Maintained
@@ -15375,10 +15371,8 @@ F: drivers/crypto/marvell/
F: include/linux/soc/marvell/octeontx2/
MARVELL GIGABIT ETHERNET DRIVERS (skge/sky2)
-M: Mirko Lindner <mlindner@marvell.com>
-M: Stephen Hemminger <stephen@networkplumber.org>
L: netdev@vger.kernel.org
-S: Odd fixes
+S: Orphan
F: drivers/net/ethernet/marvell/sk*
MARVELL LIBERTAS WIRELESS DRIVER
@@ -15475,7 +15469,6 @@ MARVELL OCTEONTX2 RVU ADMIN FUNCTION DRIVER
M: Sunil Goutham <sgoutham@marvell.com>
M: Linu Cherian <lcherian@marvell.com>
M: Geetha sowjanya <gakula@marvell.com>
-M: Jerin Jacob <jerinj@marvell.com>
M: hariprasad <hkelam@marvell.com>
M: Subbaraya Sundeep <sbhatta@marvell.com>
L: netdev@vger.kernel.org
@@ -15490,7 +15483,7 @@ S: Supported
F: drivers/perf/marvell_pem_pmu.c
MARVELL PRESTERA ETHERNET SWITCH DRIVER
-M: Taras Chornyi <taras.chornyi@plvision.eu>
+M: Elad Nachman <enachman@marvell.com>
S: Supported
W: https://github.com/Marvell-switching/switchdev-prestera
F: drivers/net/ethernet/marvell/prestera/
@@ -16164,7 +16157,6 @@ F: drivers/dma/mediatek/
MEDIATEK ETHERNET DRIVER
M: Felix Fietkau <nbd@nbd.name>
-M: Sean Wang <sean.wang@mediatek.com>
M: Lorenzo Bianconi <lorenzo@kernel.org>
L: netdev@vger.kernel.org
S: Maintained
@@ -16357,8 +16349,6 @@ F: include/soc/mediatek/smi.h
MEDIATEK SWITCH DRIVER
M: Chester A. Unal <chester.a.unal@arinc9.com>
M: Daniel Golle <daniel@makrotopia.org>
-M: DENG Qingfang <dqfext@gmail.com>
-M: Sean Wang <sean.wang@mediatek.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/dsa/mt7530-mdio.c
@@ -19226,8 +19216,6 @@ F: tools/objtool/
OCELOT ETHERNET SWITCH DRIVER
M: Vladimir Oltean <vladimir.oltean@nxp.com>
-M: Claudiu Manoil <claudiu.manoil@nxp.com>
-M: Alexandre Belloni <alexandre.belloni@bootlin.com>
M: UNGLinuxDriver@microchip.com
L: netdev@vger.kernel.org
S: Supported
@@ -19813,7 +19801,6 @@ F: arch/*/boot/dts/
F: include/dt-bindings/
OPENCOMPUTE PTP CLOCK DRIVER
-M: Jonathan Lemon <jonathan.lemon@gmail.com>
M: Vadim Fedorenko <vadim.fedorenko@linux.dev>
L: netdev@vger.kernel.org
S: Maintained
@@ -20121,9 +20108,8 @@ F: Documentation/devicetree/bindings/pci/marvell,armada-3700-pcie.yaml
F: drivers/pci/controller/pci-aardvark.c
PCI DRIVER FOR ALTERA PCIE IP
-M: Joyce Ooi <joyce.ooi@intel.com>
L: linux-pci@vger.kernel.org
-S: Supported
+S: Orphan
F: Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
F: drivers/pci/controller/pcie-altera.c
@@ -20368,9 +20354,8 @@ S: Supported
F: Documentation/PCI/pci-error-recovery.rst
PCI MSI DRIVER FOR ALTERA MSI IP
-M: Joyce Ooi <joyce.ooi@intel.com>
L: linux-pci@vger.kernel.org
-S: Supported
+S: Orphan
F: Documentation/devicetree/bindings/interrupt-controller/altr,msi-controller.yaml
F: drivers/pci/controller/pcie-altera-msi.c
@@ -21457,9 +21442,8 @@ S: Supported
F: drivers/scsi/qedi/
QLOGIC QL4xxx ETHERNET DRIVER
-M: Manish Chopra <manishc@marvell.com>
L: netdev@vger.kernel.org
-S: Maintained
+S: Orphan
F: drivers/net/ethernet/qlogic/qed/
F: drivers/net/ethernet/qlogic/qede/
F: include/linux/qed/
@@ -24336,7 +24320,6 @@ F: Documentation/devicetree/bindings/interrupt-controller/kontron,sl28cpld-intc.
F: Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
F: Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
F: drivers/gpio/gpio-sl28cpld.c
-F: drivers/hwmon/sa67mcu-hwmon.c
F: drivers/hwmon/sl28cpld-hwmon.c
F: drivers/irqchip/irq-sl28cpld.c
F: drivers/pwm/pwm-sl28cpld.c
diff --git a/Makefile b/Makefile
index 2446085983f7..2b15f0b4a0cb 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
VERSION = 7
PATCHLEVEL = 0
SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
NAME = Baby Opossum Posse
# *DOCUMENTATION*
@@ -1497,13 +1497,13 @@ ifneq ($(wildcard $(resolve_btfids_O)),)
$(Q)$(MAKE) -sC $(srctree)/tools/bpf/resolve_btfids O=$(resolve_btfids_O) clean
endif
-PHONY += objtool_clean
+PHONY += objtool_clean objtool_mrproper
objtool_O = $(abspath $(objtree))/tools/objtool
-objtool_clean:
+objtool_clean objtool_mrproper:
ifneq ($(wildcard $(objtool_O)),)
- $(Q)$(MAKE) -sC $(abs_srctree)/tools/objtool O=$(objtool_O) srctree=$(abs_srctree) clean
+ $(Q)$(MAKE) -sC $(abs_srctree)/tools/objtool O=$(objtool_O) srctree=$(abs_srctree) $(patsubst objtool_%,%,$@)
endif
tools/: FORCE
@@ -1686,7 +1686,7 @@ PHONY += $(mrproper-dirs) mrproper
$(mrproper-dirs):
$(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@)
-mrproper: clean $(mrproper-dirs)
+mrproper: clean objtool_mrproper $(mrproper-dirs)
$(call cmd,rmfiles)
@find . $(RCS_FIND_IGNORE) \
\( -name '*.rmeta' \) \
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index 2efa7dfc798a..2d136c63db16 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -71,6 +71,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index 61a1b2b96e1d..6af63084ff28 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -123,6 +123,7 @@ SECTIONS
_end = . ;
STABS_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index d411abd4310e..2d916647df03 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -21,6 +21,7 @@ SECTIONS
COMMON_DISCARDS
*(.ARM.exidx*)
*(.ARM.extab*)
+ *(.modinfo)
*(.note.*)
*(.rel.*)
*(.printk_index)
diff --git a/arch/arm/kernel/vmlinux-xip.lds.S b/arch/arm/kernel/vmlinux-xip.lds.S
index f2e8d4fac068..5afb725998ec 100644
--- a/arch/arm/kernel/vmlinux-xip.lds.S
+++ b/arch/arm/kernel/vmlinux-xip.lds.S
@@ -154,6 +154,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ARM_DETAILS
ARM_ASSERTS
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index d592a203f9c6..c07843c3c53d 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -153,6 +153,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ARM_DETAILS
ARM_ASSERTS
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index d7a540736741..6cf3cd6873f5 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -91,8 +91,9 @@ __XCHG_GEN(_mb)
#define __xchg_wrapper(sfx, ptr, x) \
({ \
__typeof__(*(ptr)) __ret; \
- __ret = (__typeof__(*(ptr))) \
- __arch_xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \
+ __ret = (__force __typeof__(*(ptr))) \
+ __arch_xchg##sfx((__force unsigned long)(x), (ptr), \
+ sizeof(*(ptr))); \
__ret; \
})
@@ -175,9 +176,10 @@ __CMPXCHG_GEN(_mb)
#define __cmpxchg_wrapper(sfx, ptr, o, n) \
({ \
__typeof__(*(ptr)) __ret; \
- __ret = (__typeof__(*(ptr))) \
- __cmpxchg##sfx((ptr), (unsigned long)(o), \
- (unsigned long)(n), sizeof(*(ptr))); \
+ __ret = (__force __typeof__(*(ptr))) \
+ __cmpxchg##sfx((ptr), (__force unsigned long)(o), \
+ (__force unsigned long)(n), \
+ sizeof(*(ptr))); \
__ret; \
})
diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h
index 2b32639160de..f560e6420267 100644
--- a/arch/arm64/include/asm/pgtable-prot.h
+++ b/arch/arm64/include/asm/pgtable-prot.h
@@ -50,11 +50,11 @@
#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
-#define _PAGE_KERNEL (PROT_NORMAL)
-#define _PAGE_KERNEL_RO ((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY)
-#define _PAGE_KERNEL_ROX ((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY)
-#define _PAGE_KERNEL_EXEC (PROT_NORMAL & ~PTE_PXN)
-#define _PAGE_KERNEL_EXEC_CONT ((PROT_NORMAL & ~PTE_PXN) | PTE_CONT)
+#define _PAGE_KERNEL (PROT_NORMAL | PTE_DIRTY)
+#define _PAGE_KERNEL_RO ((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY | PTE_DIRTY)
+#define _PAGE_KERNEL_ROX ((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY | PTE_DIRTY)
+#define _PAGE_KERNEL_EXEC ((PROT_NORMAL & ~PTE_PXN) | PTE_DIRTY)
+#define _PAGE_KERNEL_EXEC_CONT ((PROT_NORMAL & ~PTE_PXN) | PTE_CONT | PTE_DIRTY)
#define _PAGE_SHARED (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
#define _PAGE_SHARED_EXEC (_PAGE_DEFAULT | PTE_USER | PTE_RDONLY | PTE_NG | PTE_PXN | PTE_WRITE)
diff --git a/arch/arm64/include/asm/runtime-const.h b/arch/arm64/include/asm/runtime-const.h
index be5915669d23..c3dbd3ae68f6 100644
--- a/arch/arm64/include/asm/runtime-const.h
+++ b/arch/arm64/include/asm/runtime-const.h
@@ -2,6 +2,10 @@
#ifndef _ASM_RUNTIME_CONST_H
#define _ASM_RUNTIME_CONST_H
+#ifdef MODULE
+ #error "Cannot use runtime-const infrastructure from modules"
+#endif
+
#include <asm/cacheflush.h>
/* Sigh. You can still run arm64 in BE mode */
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index ad6133b89e7a..2964aad0362e 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -349,6 +349,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
HEAD_SYMBOLS
diff --git a/arch/arm64/mm/contpte.c b/arch/arm64/mm/contpte.c
index b929a455103f..1519d090d5ea 100644
--- a/arch/arm64/mm/contpte.c
+++ b/arch/arm64/mm/contpte.c
@@ -599,6 +599,27 @@ void contpte_clear_young_dirty_ptes(struct vm_area_struct *vma,
}
EXPORT_SYMBOL_GPL(contpte_clear_young_dirty_ptes);
+static bool contpte_all_subptes_match_access_flags(pte_t *ptep, pte_t entry)
+{
+ pte_t *cont_ptep = contpte_align_down(ptep);
+ /*
+ * PFNs differ per sub-PTE. Match only bits consumed by
+ * __ptep_set_access_flags(): AF, DIRTY and write permission.
+ */
+ const pteval_t cmp_mask = PTE_RDONLY | PTE_AF | PTE_WRITE | PTE_DIRTY;
+ pteval_t entry_cmp = pte_val(entry) & cmp_mask;
+ int i;
+
+ for (i = 0; i < CONT_PTES; i++) {
+ pteval_t pte_cmp = pte_val(__ptep_get(cont_ptep + i)) & cmp_mask;
+
+ if (pte_cmp != entry_cmp)
+ return false;
+ }
+
+ return true;
+}
+
int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
unsigned long addr, pte_t *ptep,
pte_t entry, int dirty)
@@ -608,14 +629,38 @@ int contpte_ptep_set_access_flags(struct vm_area_struct *vma,
int i;
/*
- * Gather the access/dirty bits for the contiguous range. If nothing has
- * changed, its a noop.
+ * Check whether all sub-PTEs in the CONT block already match the
+ * requested access flags/write permission, using raw per-PTE values
+ * rather than the gathered ptep_get() view.
+ *
+ * __ptep_set_access_flags() can update AF, dirty and write
+ * permission, but only to make the mapping more permissive.
+ *
+ * ptep_get() gathers AF/dirty state across the whole CONT block,
+ * which is correct for a CPU with FEAT_HAFDBS. But page-table
+ * walkers that evaluate each descriptor individually (e.g. a CPU
+ * without DBM support, or an SMMU without HTTU, or with HA/HD
+ * disabled in CD.TCR) can keep faulting on the target sub-PTE if
+ * only a sibling has been updated. Gathering can therefore cause
+ * false no-ops when only a sibling has been updated:
+ * - write faults: target still has PTE_RDONLY (needs PTE_RDONLY cleared)
+ * - read faults: target still lacks PTE_AF
+ *
+ * Per Arm ARM (DDI 0487) D8.7.1, any sub-PTE in a CONT range may
+ * become the effective cached translation, so all entries must have
+ * consistent attributes. Check the full CONT block before returning
+ * no-op, and when any sub-PTE mismatches, proceed to update the whole
+ * range.
*/
- orig_pte = pte_mknoncont(ptep_get(ptep));
- if (pte_val(orig_pte) == pte_val(entry))
+ if (contpte_all_subptes_match_access_flags(ptep, entry))
return 0;
/*
+ * Use raw target pte (not gathered) for write-bit unfold decision.
+ */
+ orig_pte = pte_mknoncont(__ptep_get(ptep));
+
+ /*
* We can fix up access/dirty bits without having to unfold the contig
* range. But if the write bit is changing, we must unfold.
*/
diff --git a/arch/csky/kernel/vmlinux.lds.S b/arch/csky/kernel/vmlinux.lds.S
index d718961786d2..81943981b3af 100644
--- a/arch/csky/kernel/vmlinux.lds.S
+++ b/arch/csky/kernel/vmlinux.lds.S
@@ -109,6 +109,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/hexagon/kernel/vmlinux.lds.S b/arch/hexagon/kernel/vmlinux.lds.S
index 1150b77fa281..aae22283b5e0 100644
--- a/arch/hexagon/kernel/vmlinux.lds.S
+++ b/arch/hexagon/kernel/vmlinux.lds.S
@@ -62,6 +62,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
.hexagon.attributes 0 : { *(.hexagon.attributes) }
diff --git a/arch/loongarch/kernel/vmlinux.lds.S b/arch/loongarch/kernel/vmlinux.lds.S
index 08ea921cdec1..d0e1377a041d 100644
--- a/arch/loongarch/kernel/vmlinux.lds.S
+++ b/arch/loongarch/kernel/vmlinux.lds.S
@@ -147,6 +147,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
#ifdef CONFIG_EFI_STUB
diff --git a/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds
index 2624fc18c131..45d7f4b0177b 100644
--- a/arch/m68k/kernel/vmlinux-nommu.lds
+++ b/arch/m68k/kernel/vmlinux-nommu.lds
@@ -85,6 +85,7 @@ SECTIONS {
_end = .;
STABS_DEBUG
+ MODINFO
ELF_DETAILS
/* Sections to be discarded */
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 1ccdd04ae462..7326586afe15 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -58,6 +58,7 @@ SECTIONS
_end = . ;
STABS_DEBUG
+ MODINFO
ELF_DETAILS
/* Sections to be discarded */
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index f13ddcc2af5c..1b19fef201fb 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -51,6 +51,7 @@ __init_begin = .;
_end = . ;
STABS_DEBUG
+ MODINFO
ELF_DETAILS
/* Sections to be discarded */
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 2b708fac8d2c..579b2cc1995a 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -217,6 +217,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
/* These must appear regardless of . */
diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S
index 37b958055064..206f92445bfa 100644
--- a/arch/nios2/kernel/vmlinux.lds.S
+++ b/arch/nios2/kernel/vmlinux.lds.S
@@ -57,6 +57,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/openrisc/kernel/vmlinux.lds.S b/arch/openrisc/kernel/vmlinux.lds.S
index 049bff45f612..9b29c3211774 100644
--- a/arch/openrisc/kernel/vmlinux.lds.S
+++ b/arch/openrisc/kernel/vmlinux.lds.S
@@ -101,6 +101,7 @@ SECTIONS
/* Throw in the debugging sections */
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
/* Sections to be discarded -- must be last */
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
index ab7b43990857..87d24cc824b6 100644
--- a/arch/parisc/boot/compressed/vmlinux.lds.S
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -90,6 +90,7 @@ SECTIONS
/* Sections to be discarded */
DISCARDS
/DISCARD/ : {
+ *(.modinfo)
#ifdef CONFIG_64BIT
/* temporary hack until binutils is fixed to not emit these
* for static binaries
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index 2c139a4dbf4b..17afe7a59edf 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -85,7 +85,7 @@ extern void __update_cache(pte_t pte);
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
/* This is the size of the initially mapped kernel memory */
-#if defined(CONFIG_64BIT)
+#if defined(CONFIG_64BIT) || defined(CONFIG_KALLSYMS)
#define KERNEL_INITIAL_ORDER 26 /* 1<<26 = 64MB */
#else
#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 96e0264ac961..9188c8d87437 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -56,6 +56,7 @@ ENTRY(parisc_kernel_start)
.import __bss_start,data
.import __bss_stop,data
+ .import __end,data
load32 PA(__bss_start),%r3
load32 PA(__bss_stop),%r4
@@ -149,7 +150,11 @@ $cpu_ok:
* everything ... it will get remapped correctly later */
ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
load32 (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
- load32 PA(pg0),%r1
+ load32 PA(_end),%r1
+ SHRREG %r1,PAGE_SHIFT,%r1 /* %r1 is PFN count for _end symbol */
+ cmpb,<<,n %r11,%r1,1f
+ copy %r1,%r11 /* %r1 PFN count smaller than %r11 */
+1: load32 PA(pg0),%r1
$pgt_fill_loop:
STREGM %r3,ASM_PTE_ENTRY_SIZE(%r1)
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index ace483b6f19a..d3e17a7a8901 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -120,14 +120,6 @@ void __init setup_arch(char **cmdline_p)
#endif
printk(KERN_CONT ".\n");
- /*
- * Check if initial kernel page mappings are sufficient.
- * panic early if not, else we may access kernel functions
- * and variables which can't be reached.
- */
- if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
- panic("KERNEL_INITIAL_ORDER too small!");
-
#ifdef CONFIG_64BIT
if(parisc_narrow_firmware) {
printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
@@ -279,6 +271,18 @@ void __init start_parisc(void)
int ret, cpunum;
struct pdc_coproc_cfg coproc_cfg;
+ /*
+ * Check if initial kernel page mapping is sufficient.
+ * Print warning if not, because we may access kernel functions and
+ * variables which can't be reached yet through the initial mappings.
+ * Note that the panic() and printk() functions are not functional
+ * yet, so we need to use direct iodc() firmware calls instead.
+ */
+ const char warn1[] = "CRITICAL: Kernel may crash because "
+ "KERNEL_INITIAL_ORDER is too small.\n";
+ if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
+ pdc_iodc_print(warn1, sizeof(warn1) - 1);
+
/* check QEMU/SeaBIOS marker in PAGE0 */
running_on_qemu = (memcmp(&PAGE0->pad0, "SeaBIOS", 8) == 0);
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index b445e47903cf..0ca93d6d7235 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -165,6 +165,7 @@ SECTIONS
_end = . ;
STABS_DEBUG
+ MODINFO
ELF_DETAILS
.note 0 : { *(.note) }
diff --git a/arch/powerpc/kernel/pci_of_scan.c b/arch/powerpc/kernel/pci_of_scan.c
index 756043dd06e9..fb9fbf0d1796 100644
--- a/arch/powerpc/kernel/pci_of_scan.c
+++ b/arch/powerpc/kernel/pci_of_scan.c
@@ -212,6 +212,13 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
dev->error_state = pci_channel_io_normal;
dev->dma_mask = 0xffffffff;
+ /*
+ * Assume 64-bit addresses for MSI initially. Will be changed to 32-bit
+ * if MSI (rather than MSI-X) capability does not have
+ * PCI_MSI_FLAGS_64BIT. Can also be overridden by driver.
+ */
+ dev->msi_addr_mask = DMA_BIT_MASK(64);
+
/* Early fixups, before probing the BARs */
pci_fixup_device(pci_fixup_early, dev);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 15850296c0a9..8fc11d6565bf 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -397,6 +397,7 @@ SECTIONS
_end = . ;
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index 61bd5ba6680a..997f9eb3b22b 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -170,6 +170,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
.riscv.attributes 0 : { *(.riscv.attributes) }
diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h
index cc187afa07b3..78195ee5e99f 100644
--- a/arch/s390/include/asm/processor.h
+++ b/arch/s390/include/asm/processor.h
@@ -159,7 +159,7 @@ static __always_inline void __stackleak_poison(unsigned long erase_low,
" j 4f\n"
"3: mvc 8(1,%[addr]),0(%[addr])\n"
"4:"
- : [addr] "+&a" (erase_low), [count] "+&d" (count), [tmp] "=&a" (tmp)
+ : [addr] "+&a" (erase_low), [count] "+&a" (count), [tmp] "=&a" (tmp)
: [poison] "d" (poison)
: "memory", "cc"
);
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index 53bcbb91bb9b..2b62395e35bf 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -221,6 +221,7 @@ SECTIONS
/* Debugging sections. */
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
/*
diff --git a/arch/s390/lib/xor.c b/arch/s390/lib/xor.c
index 1721b73b7803..5363e4c2462d 100644
--- a/arch/s390/lib/xor.c
+++ b/arch/s390/lib/xor.c
@@ -28,8 +28,8 @@ static void xor_xc_2(unsigned long bytes, unsigned long * __restrict p1,
" j 3f\n"
"2: xc 0(1,%1),0(%2)\n"
"3:"
- : : "d" (bytes), "a" (p1), "a" (p2)
- : "0", "cc", "memory");
+ : "+a" (bytes), "+a" (p1), "+a" (p2)
+ : : "0", "cc", "memory");
}
static void xor_xc_3(unsigned long bytes, unsigned long * __restrict p1,
@@ -54,7 +54,7 @@ static void xor_xc_3(unsigned long bytes, unsigned long * __restrict p1,
"2: xc 0(1,%1),0(%2)\n"
"3: xc 0(1,%1),0(%3)\n"
"4:"
- : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3)
+ : "+a" (bytes), "+a" (p1), "+a" (p2), "+a" (p3)
: : "0", "cc", "memory");
}
@@ -85,7 +85,7 @@ static void xor_xc_4(unsigned long bytes, unsigned long * __restrict p1,
"3: xc 0(1,%1),0(%3)\n"
"4: xc 0(1,%1),0(%4)\n"
"5:"
- : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4)
+ : "+a" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4)
: : "0", "cc", "memory");
}
@@ -96,7 +96,6 @@ static void xor_xc_5(unsigned long bytes, unsigned long * __restrict p1,
const unsigned long * __restrict p5)
{
asm volatile(
- " larl 1,2f\n"
" aghi %0,-1\n"
" jm 6f\n"
" srlg 0,%0,8\n"
@@ -122,7 +121,7 @@ static void xor_xc_5(unsigned long bytes, unsigned long * __restrict p1,
"4: xc 0(1,%1),0(%4)\n"
"5: xc 0(1,%1),0(%5)\n"
"6:"
- : "+d" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4),
+ : "+a" (bytes), "+a" (p1), "+a" (p2), "+a" (p3), "+a" (p4),
"+a" (p5)
: : "0", "cc", "memory");
}
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 008c30289eaa..169c63fb3c1d 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -89,6 +89,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 7e41574634b3..1603d50fdcad 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -355,6 +355,13 @@ static struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->error_state = pci_channel_io_normal;
dev->dma_mask = 0xffffffff;
+ /*
+ * Assume 64-bit addresses for MSI initially. Will be changed to 32-bit
+ * if MSI (rather than MSI-X) capability does not have
+ * PCI_MSI_FLAGS_64BIT. Can also be overridden by driver.
+ */
+ dev->msi_addr_mask = DMA_BIT_MASK(64);
+
if (of_node_name_eq(node, "pci")) {
/* a PCI-PCI bridge */
dev->hdr_type = PCI_HEADER_TYPE_BRIDGE;
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index f1b86eb30340..7ea510d9b42f 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -191,6 +191,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index a36b7918a011..ad3cefeff2ac 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -172,6 +172,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index a409d4b66114..30aa24348d60 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -113,6 +113,7 @@ SECTIONS
STABS_DEBUG
DWARF_DEBUG
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 68f9d7a1683b..b8b2b7bea1d3 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -113,6 +113,7 @@ vmlinux-objs-$(CONFIG_EFI_SBAT) += $(obj)/sbat.o
ifdef CONFIG_EFI_SBAT
$(obj)/sbat.o: $(CONFIG_EFI_SBAT_FILE)
+AFLAGS_sbat.o += -I $(srctree)
endif
$(obj)/vmlinux: $(vmlinux-objs-y) $(vmlinux-libs-y) FORCE
diff --git a/arch/x86/boot/compressed/sev.c b/arch/x86/boot/compressed/sev.c
index c8c1464b3a56..e468476e9e4a 100644
--- a/arch/x86/boot/compressed/sev.c
+++ b/arch/x86/boot/compressed/sev.c
@@ -28,17 +28,17 @@
#include "sev.h"
static struct ghcb boot_ghcb_page __aligned(PAGE_SIZE);
-struct ghcb *boot_ghcb;
+struct ghcb *boot_ghcb __section(".data");
#undef __init
#define __init
#define __BOOT_COMPRESSED
-u8 snp_vmpl;
-u16 ghcb_version;
+u8 snp_vmpl __section(".data");
+u16 ghcb_version __section(".data");
-u64 boot_svsm_caa_pa;
+u64 boot_svsm_caa_pa __section(".data");
/* Include code for early handlers */
#include "../../boot/startup/sev-shared.c"
@@ -188,6 +188,7 @@ bool sev_es_check_ghcb_fault(unsigned long address)
MSR_AMD64_SNP_RESERVED_BIT13 | \
MSR_AMD64_SNP_RESERVED_BIT15 | \
MSR_AMD64_SNP_SECURE_AVIC | \
+ MSR_AMD64_SNP_RESERVED_BITS19_22 | \
MSR_AMD64_SNP_RESERVED_MASK)
#ifdef CONFIG_AMD_SECURE_AVIC
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 587ce3e7c504..e0b152715d9c 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -88,7 +88,7 @@ SECTIONS
/DISCARD/ : {
*(.dynamic) *(.dynsym) *(.dynstr) *(.dynbss)
*(.hash) *(.gnu.hash)
- *(.note.*)
+ *(.note.*) *(.modinfo)
}
.got.plt (INFO) : {
diff --git a/arch/x86/boot/startup/sev-shared.c b/arch/x86/boot/startup/sev-shared.c
index a0fa8bb2b945..d9ac3a929d33 100644
--- a/arch/x86/boot/startup/sev-shared.c
+++ b/arch/x86/boot/startup/sev-shared.c
@@ -31,7 +31,7 @@ static u32 cpuid_std_range_max __ro_after_init;
static u32 cpuid_hyp_range_max __ro_after_init;
static u32 cpuid_ext_range_max __ro_after_init;
-bool sev_snp_needs_sfw;
+bool sev_snp_needs_sfw __section(".data");
void __noreturn
sev_es_terminate(unsigned int set, unsigned int reason)
diff --git a/arch/x86/coco/sev/core.c b/arch/x86/coco/sev/core.c
index 907981b94c40..7ed3da998489 100644
--- a/arch/x86/coco/sev/core.c
+++ b/arch/x86/coco/sev/core.c
@@ -89,6 +89,7 @@ static const char * const sev_status_feat_names[] = {
[MSR_AMD64_SNP_VMSA_REG_PROT_BIT] = "VMSARegProt",
[MSR_AMD64_SNP_SMT_PROT_BIT] = "SMTProt",
[MSR_AMD64_SNP_SECURE_AVIC_BIT] = "SecureAVIC",
+ [MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT] = "IBPBOnEntry",
};
/*
diff --git a/arch/x86/entry/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S
index b433353bc8e3..b33fcc501ba3 100644
--- a/arch/x86/entry/vdso/vdso32/sigreturn.S
+++ b/arch/x86/entry/vdso/vdso32/sigreturn.S
@@ -35,9 +35,38 @@
#endif
.endm
+/*
+ * WARNING:
+ *
+ * A bug in the libgcc unwinder as of at least gcc 15.2 (2026) means that
+ * the unwinder fails to recognize the signal frame flag.
+ *
+ * There is a hacky legacy fallback path in libgcc which ends up
+ * getting invoked instead. It happens to work as long as BOTH of the
+ * following conditions are true:
+ *
+ * 1. There is at least one byte before the each of the sigreturn
+ * functions which falls outside any function. This is enforced by
+ * an explicit nop instruction before the ALIGN.
+ * 2. The code sequences between the entry point up to and including
+ * the int $0x80 below need to match EXACTLY. Do not change them
+ * in any way. The exact byte sequences are:
+ *
+ * __kernel_sigreturn:
+ * 0: 58 pop %eax
+ * 1: b8 77 00 00 00 mov $0x77,%eax
+ * 6: cd 80 int $0x80
+ *
+ * __kernel_rt_sigreturn:
+ * 0: b8 ad 00 00 00 mov $0xad,%eax
+ * 5: cd 80 int $0x80
+ *
+ * For details, see: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124050
+ */
.text
.globl __kernel_sigreturn
.type __kernel_sigreturn,@function
+ nop /* libgcc hack: see comment above */
ALIGN
__kernel_sigreturn:
STARTPROC_SIGNAL_FRAME IA32_SIGFRAME_sigcontext
@@ -52,6 +81,7 @@ SYM_INNER_LABEL(vdso32_sigreturn_landing_pad, SYM_L_GLOBAL)
.globl __kernel_rt_sigreturn
.type __kernel_rt_sigreturn,@function
+ nop /* libgcc hack: see comment above */
ALIGN
__kernel_rt_sigreturn:
STARTPROC_SIGNAL_FRAME IA32_RT_SIGFRAME_sigcontext
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index f227a70ac91f..51b4cdbea061 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -138,7 +138,7 @@ extern void __init efi_apply_memmap_quirks(void);
extern int __init efi_reuse_config(u64 tables, int nr_tables);
extern void efi_delete_dummy_variable(void);
extern void efi_crash_gracefully_on_page_fault(unsigned long phys_addr);
-extern void efi_free_boot_services(void);
+extern void efi_unmap_boot_services(void);
void arch_efi_call_virt_setup(void);
void arch_efi_call_virt_teardown(void);
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index da5275d8eda6..6673601246b3 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -740,7 +740,10 @@
#define MSR_AMD64_SNP_SMT_PROT BIT_ULL(MSR_AMD64_SNP_SMT_PROT_BIT)
#define MSR_AMD64_SNP_SECURE_AVIC_BIT 18
#define MSR_AMD64_SNP_SECURE_AVIC BIT_ULL(MSR_AMD64_SNP_SECURE_AVIC_BIT)
-#define MSR_AMD64_SNP_RESV_BIT 19
+#define MSR_AMD64_SNP_RESERVED_BITS19_22 GENMASK_ULL(22, 19)
+#define MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT 23
+#define MSR_AMD64_SNP_IBPB_ON_ENTRY BIT_ULL(MSR_AMD64_SNP_IBPB_ON_ENTRY_BIT)
+#define MSR_AMD64_SNP_RESV_BIT 24
#define MSR_AMD64_SNP_RESERVED_MASK GENMASK_ULL(63, MSR_AMD64_SNP_RESV_BIT)
#define MSR_AMD64_SAVIC_CONTROL 0xc0010138
#define MSR_AMD64_SAVIC_EN_BIT 0
diff --git a/arch/x86/include/asm/numa.h b/arch/x86/include/asm/numa.h
index 53ba39ce010c..a9063f332fa6 100644
--- a/arch/x86/include/asm/numa.h
+++ b/arch/x86/include/asm/numa.h
@@ -22,6 +22,7 @@ extern int numa_off;
*/
extern s16 __apicid_to_node[MAX_LOCAL_APIC];
extern nodemask_t numa_nodes_parsed __initdata;
+extern nodemask_t numa_phys_nodes_parsed __initdata;
static inline void set_apicid_to_node(int apicid, s16 node)
{
@@ -48,6 +49,7 @@ extern void __init init_cpu_to_node(void);
extern void numa_add_cpu(unsigned int cpu);
extern void numa_remove_cpu(unsigned int cpu);
extern void init_gi_nodes(void);
+extern int num_phys_nodes(void);
#else /* CONFIG_NUMA */
static inline void numa_set_node(int cpu, int node) { }
static inline void numa_clear_node(int cpu) { }
@@ -55,6 +57,10 @@ static inline void init_cpu_to_node(void) { }
static inline void numa_add_cpu(unsigned int cpu) { }
static inline void numa_remove_cpu(unsigned int cpu) { }
static inline void init_gi_nodes(void) { }
+static inline int num_phys_nodes(void)
+{
+ return 1;
+}
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DEBUG_PER_CPU_MAPS
diff --git a/arch/x86/include/asm/pgtable_64.h b/arch/x86/include/asm/pgtable_64.h
index f06e5d6a2747..ce45882ccd07 100644
--- a/arch/x86/include/asm/pgtable_64.h
+++ b/arch/x86/include/asm/pgtable_64.h
@@ -19,10 +19,8 @@
extern p4d_t level4_kernel_pgt[512];
extern p4d_t level4_ident_pgt[512];
extern pud_t level3_kernel_pgt[512];
-extern pud_t level3_ident_pgt[512];
extern pmd_t level2_kernel_pgt[512];
extern pmd_t level2_fixmap_pgt[512];
-extern pmd_t level2_ident_pgt[512];
extern pte_t level1_fixmap_pgt[512 * FIXMAP_PMD_NUM];
extern pgd_t init_top_pgt[];
diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index 1fadf0cf520c..0ba9bdb99871 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -155,6 +155,7 @@ extern unsigned int __max_logical_packages;
extern unsigned int __max_threads_per_core;
extern unsigned int __num_threads_per_package;
extern unsigned int __num_cores_per_package;
+extern unsigned int __num_nodes_per_package;
const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c);
enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c);
@@ -179,6 +180,11 @@ static inline unsigned int topology_num_threads_per_package(void)
return __num_threads_per_package;
}
+static inline unsigned int topology_num_nodes_per_package(void)
+{
+ return __num_nodes_per_package;
+}
+
#ifdef CONFIG_X86_LOCAL_APIC
int topology_get_logical_id(u32 apicid, enum x86_topology_domains at_level);
#else
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 1c3261cae40c..a8ff4376c286 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -95,6 +95,9 @@ EXPORT_SYMBOL(__max_dies_per_package);
unsigned int __max_logical_packages __ro_after_init = 1;
EXPORT_SYMBOL(__max_logical_packages);
+unsigned int __num_nodes_per_package __ro_after_init = 1;
+EXPORT_SYMBOL(__num_nodes_per_package);
+
unsigned int __num_cores_per_package __ro_after_init = 1;
EXPORT_SYMBOL(__num_cores_per_package);
diff --git a/arch/x86/kernel/cpu/resctrl/monitor.c b/arch/x86/kernel/cpu/resctrl/monitor.c
index e6a154240b8d..9bd87bae4983 100644
--- a/arch/x86/kernel/cpu/resctrl/monitor.c
+++ b/arch/x86/kernel/cpu/resctrl/monitor.c
@@ -364,7 +364,7 @@ void arch_mon_domain_online(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
msr_clear_bit(MSR_RMID_SNC_CONFIG, 0);
}
-/* CPU models that support MSR_RMID_SNC_CONFIG */
+/* CPU models that support SNC and MSR_RMID_SNC_CONFIG */
static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
X86_MATCH_VFM(INTEL_ICELAKE_X, 0),
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, 0),
@@ -375,40 +375,14 @@ static const struct x86_cpu_id snc_cpu_ids[] __initconst = {
{}
};
-/*
- * There isn't a simple hardware bit that indicates whether a CPU is running
- * in Sub-NUMA Cluster (SNC) mode. Infer the state by comparing the
- * number of CPUs sharing the L3 cache with CPU0 to the number of CPUs in
- * the same NUMA node as CPU0.
- * It is not possible to accurately determine SNC state if the system is
- * booted with a maxcpus=N parameter. That distorts the ratio of SNC nodes
- * to L3 caches. It will be OK if system is booted with hyperthreading
- * disabled (since this doesn't affect the ratio).
- */
static __init int snc_get_config(void)
{
- struct cacheinfo *ci = get_cpu_cacheinfo_level(0, RESCTRL_L3_CACHE);
- const cpumask_t *node0_cpumask;
- int cpus_per_node, cpus_per_l3;
- int ret;
-
- if (!x86_match_cpu(snc_cpu_ids) || !ci)
- return 1;
+ int ret = topology_num_nodes_per_package();
- cpus_read_lock();
- if (num_online_cpus() != num_present_cpus())
- pr_warn("Some CPUs offline, SNC detection may be incorrect\n");
- cpus_read_unlock();
-
- node0_cpumask = cpumask_of_node(cpu_to_node(0));
-
- cpus_per_node = cpumask_weight(node0_cpumask);
- cpus_per_l3 = cpumask_weight(&ci->shared_cpu_map);
-
- if (!cpus_per_node || !cpus_per_l3)
+ if (ret > 1 && !x86_match_cpu(snc_cpu_ids)) {
+ pr_warn("CoD enabled system? Resctrl not supported\n");
return 1;
-
- ret = cpus_per_l3 / cpus_per_node;
+ }
/* sanity check: Only valid results are 1, 2, 3, 4, 6 */
switch (ret) {
diff --git a/arch/x86/kernel/cpu/topology.c b/arch/x86/kernel/cpu/topology.c
index 23190a786d31..eafcb1fc185a 100644
--- a/arch/x86/kernel/cpu/topology.c
+++ b/arch/x86/kernel/cpu/topology.c
@@ -31,6 +31,7 @@
#include <asm/mpspec.h>
#include <asm/msr.h>
#include <asm/smp.h>
+#include <asm/numa.h>
#include "cpu.h"
@@ -492,11 +493,19 @@ void __init topology_init_possible_cpus(void)
set_nr_cpu_ids(allowed);
cnta = domain_weight(TOPO_PKG_DOMAIN);
- cntb = domain_weight(TOPO_DIE_DOMAIN);
__max_logical_packages = cnta;
+
+ pr_info("Max. logical packages: %3u\n", __max_logical_packages);
+
+ cntb = num_phys_nodes();
+ __num_nodes_per_package = DIV_ROUND_UP(cntb, cnta);
+
+ pr_info("Max. logical nodes: %3u\n", cntb);
+ pr_info("Num. nodes per package:%3u\n", __num_nodes_per_package);
+
+ cntb = domain_weight(TOPO_DIE_DOMAIN);
__max_dies_per_package = 1U << (get_count_order(cntb) - get_count_order(cnta));
- pr_info("Max. logical packages: %3u\n", cnta);
pr_info("Max. logical dies: %3u\n", cntb);
pr_info("Max. dies per package: %3u\n", __max_dies_per_package);
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 21816b48537c..85d4a5094f6b 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -616,38 +616,10 @@ SYM_DATA(early_recursion_flag, .long 0)
.data
-#if defined(CONFIG_XEN_PV) || defined(CONFIG_PVH)
-SYM_DATA_START_PTI_ALIGNED(init_top_pgt)
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
- .org init_top_pgt + L4_PAGE_OFFSET*8, 0
- .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
- .org init_top_pgt + L4_START_KERNEL*8, 0
- /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE_NOENC
- .fill PTI_USER_PGD_FILL,8,0
-SYM_DATA_END(init_top_pgt)
-
-SYM_DATA_START_PAGE_ALIGNED(level3_ident_pgt)
- .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE_NOENC
- .fill 511, 8, 0
-SYM_DATA_END(level3_ident_pgt)
-SYM_DATA_START_PAGE_ALIGNED(level2_ident_pgt)
- /*
- * Since I easily can, map the first 1G.
- * Don't set NX because code runs from these pages.
- *
- * Note: This sets _PAGE_GLOBAL despite whether
- * the CPU supports it or it is enabled. But,
- * the CPU should ignore the bit.
- */
- PMDS(0, __PAGE_KERNEL_IDENT_LARGE_EXEC, PTRS_PER_PMD)
-SYM_DATA_END(level2_ident_pgt)
-#else
SYM_DATA_START_PTI_ALIGNED(init_top_pgt)
.fill 512,8,0
.fill PTI_USER_PGD_FILL,8,0
SYM_DATA_END(init_top_pgt)
-#endif
SYM_DATA_START_PAGE_ALIGNED(level4_kernel_pgt)
.fill 511,8,0
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 5cd6950ab672..294a8ea60298 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -468,13 +468,6 @@ static int x86_cluster_flags(void)
}
#endif
-/*
- * Set if a package/die has multiple NUMA nodes inside.
- * AMD Magny-Cours, Intel Cluster-on-Die, and Intel
- * Sub-NUMA Clustering have this.
- */
-static bool x86_has_numa_in_package;
-
static struct sched_domain_topology_level x86_topology[] = {
SDTL_INIT(tl_smt_mask, cpu_smt_flags, SMT),
#ifdef CONFIG_SCHED_CLUSTER
@@ -496,7 +489,7 @@ static void __init build_sched_topology(void)
* PKG domain since the NUMA domains will auto-magically create the
* right spanning domains based on the SLIT.
*/
- if (x86_has_numa_in_package) {
+ if (topology_num_nodes_per_package() > 1) {
unsigned int pkgdom = ARRAY_SIZE(x86_topology) - 2;
memset(&x86_topology[pkgdom], 0, sizeof(x86_topology[pkgdom]));
@@ -513,33 +506,149 @@ static void __init build_sched_topology(void)
}
#ifdef CONFIG_NUMA
-static int sched_avg_remote_distance;
-static int avg_remote_numa_distance(void)
+/*
+ * Test if the on-trace cluster at (N,N) is symmetric.
+ * Uses upper triangle iteration to avoid obvious duplicates.
+ */
+static bool slit_cluster_symmetric(int N)
{
- int i, j;
- int distance, nr_remote, total_distance;
-
- if (sched_avg_remote_distance > 0)
- return sched_avg_remote_distance;
-
- nr_remote = 0;
- total_distance = 0;
- for_each_node_state(i, N_CPU) {
- for_each_node_state(j, N_CPU) {
- distance = node_distance(i, j);
-
- if (distance >= REMOTE_DISTANCE) {
- nr_remote++;
- total_distance += distance;
- }
+ int u = topology_num_nodes_per_package();
+
+ for (int k = 0; k < u; k++) {
+ for (int l = k; l < u; l++) {
+ if (node_distance(N + k, N + l) !=
+ node_distance(N + l, N + k))
+ return false;
}
}
- if (nr_remote)
- sched_avg_remote_distance = total_distance / nr_remote;
- else
- sched_avg_remote_distance = REMOTE_DISTANCE;
- return sched_avg_remote_distance;
+ return true;
+}
+
+/*
+ * Return the package-id of the cluster, or ~0 if indeterminate.
+ * Each node in the on-trace cluster should have the same package-id.
+ */
+static u32 slit_cluster_package(int N)
+{
+ int u = topology_num_nodes_per_package();
+ u32 pkg_id = ~0;
+
+ for (int n = 0; n < u; n++) {
+ const struct cpumask *cpus = cpumask_of_node(N + n);
+ int cpu;
+
+ for_each_cpu(cpu, cpus) {
+ u32 id = topology_logical_package_id(cpu);
+
+ if (pkg_id == ~0)
+ pkg_id = id;
+ if (pkg_id != id)
+ return ~0;
+ }
+ }
+
+ return pkg_id;
+}
+
+/*
+ * Validate the SLIT table is of the form expected for SNC, specifically:
+ *
+ * - each on-trace cluster should be symmetric,
+ * - each on-trace cluster should have a unique package-id.
+ *
+ * If you NUMA_EMU on top of SNC, you get to keep the pieces.
+ */
+static bool slit_validate(void)
+{
+ int u = topology_num_nodes_per_package();
+ u32 pkg_id, prev_pkg_id = ~0;
+
+ for (int pkg = 0; pkg < topology_max_packages(); pkg++) {
+ int n = pkg * u;
+
+ /*
+ * Ensure the on-trace cluster is symmetric and each cluster
+ * has a different package id.
+ */
+ if (!slit_cluster_symmetric(n))
+ return false;
+ pkg_id = slit_cluster_package(n);
+ if (pkg_id == ~0)
+ return false;
+ if (pkg && pkg_id == prev_pkg_id)
+ return false;
+
+ prev_pkg_id = pkg_id;
+ }
+
+ return true;
+}
+
+/*
+ * Compute a sanitized SLIT table for SNC; notably SNC-3 can end up with
+ * asymmetric off-trace clusters, reflecting physical assymmetries. However
+ * this leads to 'unfortunate' sched_domain configurations.
+ *
+ * For example dual socket GNR with SNC-3:
+ *
+ * node distances:
+ * node 0 1 2 3 4 5
+ * 0: 10 15 17 21 28 26
+ * 1: 15 10 15 23 26 23
+ * 2: 17 15 10 26 23 21
+ * 3: 21 28 26 10 15 17
+ * 4: 23 26 23 15 10 15
+ * 5: 26 23 21 17 15 10
+ *
+ * Fix things up by averaging out the off-trace clusters; resulting in:
+ *
+ * node 0 1 2 3 4 5
+ * 0: 10 15 17 24 24 24
+ * 1: 15 10 15 24 24 24
+ * 2: 17 15 10 24 24 24
+ * 3: 24 24 24 10 15 17
+ * 4: 24 24 24 15 10 15
+ * 5: 24 24 24 17 15 10
+ */
+static int slit_cluster_distance(int i, int j)
+{
+ static int slit_valid = -1;
+ int u = topology_num_nodes_per_package();
+ long d = 0;
+ int x, y;
+
+ if (slit_valid < 0) {
+ slit_valid = slit_validate();
+ if (!slit_valid)
+ pr_err(FW_BUG "SLIT table doesn't have the expected form for SNC -- fixup disabled!\n");
+ else
+ pr_info("Fixing up SNC SLIT table.\n");
+ }
+
+ /*
+ * Is this a unit cluster on the trace?
+ */
+ if ((i / u) == (j / u) || !slit_valid)
+ return node_distance(i, j);
+
+ /*
+ * Off-trace cluster.
+ *
+ * Notably average out the symmetric pair of off-trace clusters to
+ * ensure the resulting SLIT table is symmetric.
+ */
+ x = i - (i % u);
+ y = j - (j % u);
+
+ for (i = x; i < x + u; i++) {
+ for (j = y; j < y + u; j++) {
+ d += node_distance(i, j);
+ d += node_distance(j, i);
+ }
+ }
+
+ return d / (2*u*u);
}
int arch_sched_node_distance(int from, int to)
@@ -549,34 +658,14 @@ int arch_sched_node_distance(int from, int to)
switch (boot_cpu_data.x86_vfm) {
case INTEL_GRANITERAPIDS_X:
case INTEL_ATOM_DARKMONT_X:
-
- if (!x86_has_numa_in_package || topology_max_packages() == 1 ||
- d < REMOTE_DISTANCE)
+ if (topology_max_packages() == 1 ||
+ topology_num_nodes_per_package() < 3)
return d;
/*
- * With SNC enabled, there could be too many levels of remote
- * NUMA node distances, creating NUMA domain levels
- * including local nodes and partial remote nodes.
- *
- * Trim finer distance tuning for NUMA nodes in remote package
- * for the purpose of building sched domains. Group NUMA nodes
- * in the remote package in the same sched group.
- * Simplify NUMA domains and avoid extra NUMA levels including
- * different remote NUMA nodes and local nodes.
- *
- * GNR and CWF don't expect systems with more than 2 packages
- * and more than 2 hops between packages. Single average remote
- * distance won't be appropriate if there are more than 2
- * packages as average distance to different remote packages
- * could be different.
+ * Handle SNC-3 asymmetries.
*/
- WARN_ONCE(topology_max_packages() > 2,
- "sched: Expect only up to 2 packages for GNR or CWF, "
- "but saw %d packages when building sched domains.",
- topology_max_packages());
-
- d = avg_remote_numa_distance();
+ return slit_cluster_distance(from, to);
}
return d;
}
@@ -606,7 +695,7 @@ void set_cpu_sibling_map(int cpu)
o = &cpu_data(i);
if (match_pkg(c, o) && !topology_same_node(c, o))
- x86_has_numa_in_package = true;
+ WARN_ON_ONCE(topology_num_nodes_per_package() == 1);
if ((i == cpu) || (has_smt && match_smt(c, o)))
link_mask(topology_sibling_cpumask, cpu, i);
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 3a24a3fc55f5..4711a35e706c 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -427,6 +427,7 @@ SECTIONS
.llvm_bb_addr_map : { *(.llvm_bb_addr_map) }
#endif
+ MODINFO
ELF_DETAILS
DISCARDS
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 7a97327140df..99d0a9332c14 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -48,6 +48,8 @@ s16 __apicid_to_node[MAX_LOCAL_APIC] = {
[0 ... MAX_LOCAL_APIC-1] = NUMA_NO_NODE
};
+nodemask_t numa_phys_nodes_parsed __initdata;
+
int numa_cpu_node(int cpu)
{
u32 apicid = early_per_cpu(x86_cpu_to_apicid, cpu);
@@ -57,6 +59,11 @@ int numa_cpu_node(int cpu)
return NUMA_NO_NODE;
}
+int __init num_phys_nodes(void)
+{
+ return bitmap_weight(numa_phys_nodes_parsed.bits, MAX_NUMNODES);
+}
+
cpumask_var_t node_to_cpumask_map[MAX_NUMNODES];
EXPORT_SYMBOL(node_to_cpumask_map);
@@ -210,6 +217,7 @@ static int __init dummy_numa_init(void)
0LLU, PFN_PHYS(max_pfn) - 1);
node_set(0, numa_nodes_parsed);
+ node_set(0, numa_phys_nodes_parsed);
numa_add_memblk(0, 0, PFN_PHYS(max_pfn));
return 0;
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index 6f8e0f21c710..44ca66651756 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -57,6 +57,7 @@ acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa)
}
set_apicid_to_node(apic_id, node);
node_set(node, numa_nodes_parsed);
+ node_set(node, numa_phys_nodes_parsed);
pr_debug("SRAT: PXM %u -> APIC 0x%04x -> Node %u\n", pxm, apic_id, node);
}
@@ -97,6 +98,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
set_apicid_to_node(apic_id, node);
node_set(node, numa_nodes_parsed);
+ node_set(node, numa_phys_nodes_parsed);
pr_debug("SRAT: PXM %u -> APIC 0x%02x -> Node %u\n", pxm, apic_id, node);
}
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index d00c6de7f3b7..d84c6020dda1 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -836,7 +836,7 @@ static void __init __efi_enter_virtual_mode(void)
}
efi_check_for_embedded_firmwares();
- efi_free_boot_services();
+ efi_unmap_boot_services();
if (!efi_is_mixed())
efi_native_runtime_setup();
diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c
index 553f330198f2..35caa5746115 100644
--- a/arch/x86/platform/efi/quirks.c
+++ b/arch/x86/platform/efi/quirks.c
@@ -341,7 +341,7 @@ void __init efi_reserve_boot_services(void)
/*
* Because the following memblock_reserve() is paired
- * with memblock_free_late() for this region in
+ * with free_reserved_area() for this region in
* efi_free_boot_services(), we must be extremely
* careful not to reserve, and subsequently free,
* critical regions of memory (like the kernel image) or
@@ -404,17 +404,33 @@ static void __init efi_unmap_pages(efi_memory_desc_t *md)
pr_err("Failed to unmap VA mapping for 0x%llx\n", va);
}
-void __init efi_free_boot_services(void)
+struct efi_freeable_range {
+ u64 start;
+ u64 end;
+};
+
+static struct efi_freeable_range *ranges_to_free;
+
+void __init efi_unmap_boot_services(void)
{
struct efi_memory_map_data data = { 0 };
efi_memory_desc_t *md;
int num_entries = 0;
+ int idx = 0;
+ size_t sz;
void *new, *new_md;
/* Keep all regions for /sys/kernel/debug/efi */
if (efi_enabled(EFI_DBG))
return;
+ sz = sizeof(*ranges_to_free) * efi.memmap.nr_map + 1;
+ ranges_to_free = kzalloc(sz, GFP_KERNEL);
+ if (!ranges_to_free) {
+ pr_err("Failed to allocate storage for freeable EFI regions\n");
+ return;
+ }
+
for_each_efi_memory_desc(md) {
unsigned long long start = md->phys_addr;
unsigned long long size = md->num_pages << EFI_PAGE_SHIFT;
@@ -471,7 +487,15 @@ void __init efi_free_boot_services(void)
start = SZ_1M;
}
- memblock_free_late(start, size);
+ /*
+ * With CONFIG_DEFERRED_STRUCT_PAGE_INIT parts of the memory
+ * map are still not initialized and we can't reliably free
+ * memory here.
+ * Queue the ranges to free at a later point.
+ */
+ ranges_to_free[idx].start = start;
+ ranges_to_free[idx].end = start + size;
+ idx++;
}
if (!num_entries)
@@ -512,6 +536,31 @@ void __init efi_free_boot_services(void)
}
}
+static int __init efi_free_boot_services(void)
+{
+ struct efi_freeable_range *range = ranges_to_free;
+ unsigned long freed = 0;
+
+ if (!ranges_to_free)
+ return 0;
+
+ while (range->start) {
+ void *start = phys_to_virt(range->start);
+ void *end = phys_to_virt(range->end);
+
+ free_reserved_area(start, end, -1, NULL);
+ freed += (end - start);
+ range++;
+ }
+ kfree(ranges_to_free);
+
+ if (freed)
+ pr_info("Freeing EFI boot services memory: %ldK\n", freed / SZ_1K);
+
+ return 0;
+}
+arch_initcall(efi_free_boot_services);
+
/*
* A number of config table entries get remapped to virtual addresses
* after entering EFI virtual mode. However, the kexec kernel requires
diff --git a/arch/x86/platform/pvh/enlighten.c b/arch/x86/platform/pvh/enlighten.c
index 2263885d16ba..f2053cbe9b0c 100644
--- a/arch/x86/platform/pvh/enlighten.c
+++ b/arch/x86/platform/pvh/enlighten.c
@@ -25,11 +25,6 @@ struct hvm_start_info __initdata pvh_start_info;
const unsigned int __initconst pvh_start_info_sz = sizeof(pvh_start_info);
-static u64 __init pvh_get_root_pointer(void)
-{
- return pvh_start_info.rsdp_paddr;
-}
-
/*
* Xen guests are able to obtain the memory map from the hypervisor via the
* HYPERVISOR_memory_op hypercall.
@@ -95,7 +90,7 @@ static void __init init_pvh_bootparams(bool xen_guest)
pvh_bootparams.hdr.version = (2 << 8) | 12;
pvh_bootparams.hdr.type_of_loader = ((xen_guest ? 0x9 : 0xb) << 4) | 0;
- x86_init.acpi.get_root_pointer = pvh_get_root_pointer;
+ pvh_bootparams.acpi_rsdp_addr = pvh_start_info.rsdp_paddr;
}
/*
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 6e459e47cafd..eaad22b47206 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -392,7 +392,7 @@ static void __init xen_init_capabilities(void)
/*
* Xen PV would need some work to support PCID: CR3 handling as well
- * as xen_flush_tlb_others() would need updating.
+ * as xen_flush_tlb_multi() would need updating.
*/
setup_clear_cpu_cap(X86_FEATURE_PCID);
diff --git a/arch/x86/xen/mmu_pv.c b/arch/x86/xen/mmu_pv.c
index 3254eaa88471..c80d0058efd1 100644
--- a/arch/x86/xen/mmu_pv.c
+++ b/arch/x86/xen/mmu_pv.c
@@ -105,6 +105,9 @@ pte_t xen_make_pte_init(pteval_t pte);
static pud_t level3_user_vsyscall[PTRS_PER_PUD] __page_aligned_bss;
#endif
+static pud_t level3_ident_pgt[PTRS_PER_PUD] __page_aligned_bss;
+static pmd_t level2_ident_pgt[PTRS_PER_PMD] __page_aligned_bss;
+
/*
* Protects atomic reservation decrease/increase against concurrent increases.
* Also protects non-atomic updates of current_pages and balloon lists.
@@ -1777,6 +1780,12 @@ void __init xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn)
/* Zap identity mapping */
init_top_pgt[0] = __pgd(0);
+ init_top_pgt[pgd_index(__PAGE_OFFSET_BASE_L4)].pgd =
+ __pa_symbol(level3_ident_pgt) + _KERNPG_TABLE_NOENC;
+ init_top_pgt[pgd_index(__START_KERNEL_map)].pgd =
+ __pa_symbol(level3_kernel_pgt) + _PAGE_TABLE_NOENC;
+ level3_ident_pgt[0].pud = __pa_symbol(level2_ident_pgt) + _KERNPG_TABLE_NOENC;
+
/* Pre-constructed entries are in pfn, so convert to mfn */
/* L4[273] -> level3_ident_pgt */
/* L4[511] -> level3_kernel_pgt */
diff --git a/block/blk-map.c b/block/blk-map.c
index 53bdd100aa4b..768549f19f97 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -398,8 +398,7 @@ static struct bio *bio_copy_kern(struct request *rq, void *data, unsigned int le
if (op_is_write(op))
memcpy(page_address(page), p, bytes);
- if (bio_add_page(bio, page, bytes, 0) < bytes)
- break;
+ __bio_add_page(bio, page, bytes, 0);
len -= bytes;
p += bytes;
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 9af8c3dec3f6..3da2215b2912 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -4793,38 +4793,45 @@ static void blk_mq_update_queue_map(struct blk_mq_tag_set *set)
}
}
-static int blk_mq_realloc_tag_set_tags(struct blk_mq_tag_set *set,
- int new_nr_hw_queues)
+static struct blk_mq_tags **blk_mq_prealloc_tag_set_tags(
+ struct blk_mq_tag_set *set,
+ int new_nr_hw_queues)
{
struct blk_mq_tags **new_tags;
int i;
if (set->nr_hw_queues >= new_nr_hw_queues)
- goto done;
+ return NULL;
new_tags = kcalloc_node(new_nr_hw_queues, sizeof(struct blk_mq_tags *),
GFP_KERNEL, set->numa_node);
if (!new_tags)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
if (set->tags)
memcpy(new_tags, set->tags, set->nr_hw_queues *
sizeof(*set->tags));
- kfree(set->tags);
- set->tags = new_tags;
for (i = set->nr_hw_queues; i < new_nr_hw_queues; i++) {
- if (!__blk_mq_alloc_map_and_rqs(set, i)) {
- while (--i >= set->nr_hw_queues)
- __blk_mq_free_map_and_rqs(set, i);
- return -ENOMEM;
+ if (blk_mq_is_shared_tags(set->flags)) {
+ new_tags[i] = set->shared_tags;
+ } else {
+ new_tags[i] = blk_mq_alloc_map_and_rqs(set, i,
+ set->queue_depth);
+ if (!new_tags[i])
+ goto out_unwind;
}
cond_resched();
}
-done:
- set->nr_hw_queues = new_nr_hw_queues;
- return 0;
+ return new_tags;
+out_unwind:
+ while (--i >= set->nr_hw_queues) {
+ if (!blk_mq_is_shared_tags(set->flags))
+ blk_mq_free_map_and_rqs(set, new_tags[i], i);
+ }
+ kfree(new_tags);
+ return ERR_PTR(-ENOMEM);
}
/*
@@ -5113,6 +5120,7 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
unsigned int memflags;
int i;
struct xarray elv_tbl;
+ struct blk_mq_tags **new_tags;
bool queues_frozen = false;
lockdep_assert_held(&set->tag_list_lock);
@@ -5147,11 +5155,18 @@ static void __blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set,
if (blk_mq_elv_switch_none(q, &elv_tbl))
goto switch_back;
+ new_tags = blk_mq_prealloc_tag_set_tags(set, nr_hw_queues);
+ if (IS_ERR(new_tags))
+ goto switch_back;
+
list_for_each_entry(q, &set->tag_list, tag_set_list)
blk_mq_freeze_queue_nomemsave(q);
queues_frozen = true;
- if (blk_mq_realloc_tag_set_tags(set, nr_hw_queues) < 0)
- goto switch_back;
+ if (new_tags) {
+ kfree(set->tags);
+ set->tags = new_tags;
+ }
+ set->nr_hw_queues = nr_hw_queues;
fallback:
blk_mq_update_queue_map(set);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index f3b1968c80ce..55a1bbfef7d4 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -78,8 +78,14 @@ queue_requests_store(struct gendisk *disk, const char *page, size_t count)
/*
* Serialize updating nr_requests with concurrent queue_requests_store()
* and switching elevator.
+ *
+ * Use trylock to avoid circular lock dependency with kernfs active
+ * reference during concurrent disk deletion:
+ * update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
+ * kn->active -> update_nr_hwq_lock (via this sysfs write path)
*/
- down_write(&set->update_nr_hwq_lock);
+ if (!down_write_trylock(&set->update_nr_hwq_lock))
+ return -EBUSY;
if (nr == q->nr_requests)
goto unlock;
diff --git a/block/elevator.c b/block/elevator.c
index ebe2a1fcf011..3bcd37c2aa34 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -807,7 +807,16 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
elv_iosched_load_module(ctx.name);
ctx.type = elevator_find_get(ctx.name);
- down_read(&set->update_nr_hwq_lock);
+ /*
+ * Use trylock to avoid circular lock dependency with kernfs active
+ * reference during concurrent disk deletion:
+ * update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
+ * kn->active -> update_nr_hwq_lock (via this sysfs write path)
+ */
+ if (!down_read_trylock(&set->update_nr_hwq_lock)) {
+ ret = -EBUSY;
+ goto out;
+ }
if (!blk_queue_no_elv_switch(q)) {
ret = elevator_change(q, &ctx);
if (!ret)
@@ -817,6 +826,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
}
up_read(&set->update_nr_hwq_lock);
+out:
if (ctx.type)
elevator_put(ctx.type);
return ret;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index e2b4106ac961..b4bb85e8e226 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -876,8 +876,6 @@ config CRYPTO_BLAKE2B
- blake2b-384
- blake2b-512
- Used by the btrfs filesystem.
-
See https://blake2.net for further information.
config CRYPTO_CMAC
@@ -965,7 +963,6 @@ config CRYPTO_SHA256
10118-3), including HMAC support.
This is required for IPsec AH (XFRM_AH) and IPsec ESP (XFRM_ESP).
- Used by the btrfs filesystem, Ceph, NFS, and SMB.
config CRYPTO_SHA512
tristate "SHA-384 and SHA-512"
@@ -1039,8 +1036,6 @@ config CRYPTO_XXHASH
Extremely fast, working at speeds close to RAM limits.
- Used by the btrfs filesystem.
-
endmenu
menu "CRCs (cyclic redundancy checks)"
@@ -1058,8 +1053,6 @@ config CRYPTO_CRC32C
on Communications, Vol. 41, No. 6, June 1993, selected for use with
iSCSI.
- Used by btrfs, ext4, jbd2, NVMeoF/TCP, and iSCSI.
-
config CRYPTO_CRC32
tristate "CRC32"
select CRYPTO_HASH
@@ -1067,8 +1060,6 @@ config CRYPTO_CRC32
help
CRC32 CRC algorithm (IEEE 802.3)
- Used by RoCEv2 and f2fs.
-
endmenu
menu "Compression"
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 49b607f65f63..4985411dedae 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -4132,7 +4132,7 @@ static const struct alg_test_desc alg_test_descs[] = {
.fips_allowed = 1,
}, {
.alg = "authenc(hmac(sha224),cbc(aes))",
- .generic_driver = "authenc(hmac-sha224-lib,cbc(aes-generic))",
+ .generic_driver = "authenc(hmac-sha224-lib,cbc(aes-lib))",
.test = alg_test_aead,
.suite = {
.aead = __VECS(hmac_sha224_aes_cbc_tv_temp)
@@ -4194,7 +4194,7 @@ static const struct alg_test_desc alg_test_descs[] = {
.fips_allowed = 1,
}, {
.alg = "authenc(hmac(sha384),cbc(aes))",
- .generic_driver = "authenc(hmac-sha384-lib,cbc(aes-generic))",
+ .generic_driver = "authenc(hmac-sha384-lib,cbc(aes-lib))",
.test = alg_test_aead,
.suite = {
.aead = __VECS(hmac_sha384_aes_cbc_tv_temp)
diff --git a/drivers/accel/amdxdna/aie2_ctx.c b/drivers/accel/amdxdna/aie2_ctx.c
index 25845bd5e507..afee5e667f77 100644
--- a/drivers/accel/amdxdna/aie2_ctx.c
+++ b/drivers/accel/amdxdna/aie2_ctx.c
@@ -186,13 +186,13 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
cmd_abo = job->cmd_bo;
if (unlikely(job->job_timeout)) {
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
+ amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
ret = -EINVAL;
goto out;
}
if (unlikely(!data) || unlikely(size != sizeof(u32))) {
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
+ amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
ret = -EINVAL;
goto out;
}
@@ -202,7 +202,7 @@ aie2_sched_resp_handler(void *handle, void __iomem *data, size_t size)
if (status == AIE2_STATUS_SUCCESS)
amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_COMPLETED);
else
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR);
+ amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ERROR);
out:
aie2_sched_notify(job);
@@ -244,13 +244,13 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
cmd_abo = job->cmd_bo;
if (unlikely(job->job_timeout)) {
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_TIMEOUT);
+ amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_TIMEOUT);
ret = -EINVAL;
goto out;
}
if (unlikely(!data) || unlikely(size != sizeof(u32) * 3)) {
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
+ amdxdna_cmd_set_error(cmd_abo, job, 0, ERT_CMD_STATE_ABORT);
ret = -EINVAL;
goto out;
}
@@ -270,19 +270,12 @@ aie2_sched_cmdlist_resp_handler(void *handle, void __iomem *data, size_t size)
fail_cmd_idx, fail_cmd_status);
if (fail_cmd_status == AIE2_STATUS_SUCCESS) {
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ABORT);
+ amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ABORT);
ret = -EINVAL;
- goto out;
+ } else {
+ amdxdna_cmd_set_error(cmd_abo, job, fail_cmd_idx, ERT_CMD_STATE_ERROR);
}
- amdxdna_cmd_set_state(cmd_abo, ERT_CMD_STATE_ERROR);
- if (amdxdna_cmd_get_op(cmd_abo) == ERT_CMD_CHAIN) {
- struct amdxdna_cmd_chain *cc = amdxdna_cmd_get_payload(cmd_abo, NULL);
-
- cc->error_index = fail_cmd_idx;
- if (cc->error_index >= cc->command_count)
- cc->error_index = 0;
- }
out:
aie2_sched_notify(job);
return ret;
diff --git a/drivers/accel/amdxdna/aie2_message.c b/drivers/accel/amdxdna/aie2_message.c
index 277a27bce850..ffcf3be79e23 100644
--- a/drivers/accel/amdxdna/aie2_message.c
+++ b/drivers/accel/amdxdna/aie2_message.c
@@ -40,11 +40,8 @@ static int aie2_send_mgmt_msg_wait(struct amdxdna_dev_hdl *ndev,
return -ENODEV;
ret = xdna_send_msg_wait(xdna, ndev->mgmt_chann, msg);
- if (ret == -ETIME) {
- xdna_mailbox_stop_channel(ndev->mgmt_chann);
- xdna_mailbox_destroy_channel(ndev->mgmt_chann);
- ndev->mgmt_chann = NULL;
- }
+ if (ret == -ETIME)
+ aie2_destroy_mgmt_chann(ndev);
if (!ret && *hdl->status != AIE2_STATUS_SUCCESS) {
XDNA_ERR(xdna, "command opcode 0x%x failed, status 0x%x",
@@ -296,13 +293,20 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
}
intr_reg = i2x.mb_head_ptr_reg + 4;
- hwctx->priv->mbox_chann = xdna_mailbox_create_channel(ndev->mbox, &x2i, &i2x,
- intr_reg, ret);
+ hwctx->priv->mbox_chann = xdna_mailbox_alloc_channel(ndev->mbox);
if (!hwctx->priv->mbox_chann) {
XDNA_ERR(xdna, "Not able to create channel");
ret = -EINVAL;
goto del_ctx_req;
}
+
+ ret = xdna_mailbox_start_channel(hwctx->priv->mbox_chann, &x2i, &i2x,
+ intr_reg, ret);
+ if (ret) {
+ XDNA_ERR(xdna, "Not able to create channel");
+ ret = -EINVAL;
+ goto free_channel;
+ }
ndev->hwctx_num++;
XDNA_DBG(xdna, "Mailbox channel irq: %d, msix_id: %d", ret, resp.msix_id);
@@ -310,6 +314,8 @@ int aie2_create_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwct
return 0;
+free_channel:
+ xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
del_ctx_req:
aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
return ret;
@@ -325,7 +331,7 @@ int aie2_destroy_context(struct amdxdna_dev_hdl *ndev, struct amdxdna_hwctx *hwc
xdna_mailbox_stop_channel(hwctx->priv->mbox_chann);
ret = aie2_destroy_context_req(ndev, hwctx->fw_ctx_id);
- xdna_mailbox_destroy_channel(hwctx->priv->mbox_chann);
+ xdna_mailbox_free_channel(hwctx->priv->mbox_chann);
XDNA_DBG(xdna, "Destroyed fw ctx %d", hwctx->fw_ctx_id);
hwctx->priv->mbox_chann = NULL;
hwctx->fw_ctx_id = -1;
@@ -914,6 +920,20 @@ void aie2_msg_init(struct amdxdna_dev_hdl *ndev)
ndev->exec_msg_ops = &legacy_exec_message_ops;
}
+void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev)
+{
+ struct amdxdna_dev *xdna = ndev->xdna;
+
+ drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock));
+
+ if (!ndev->mgmt_chann)
+ return;
+
+ xdna_mailbox_stop_channel(ndev->mgmt_chann);
+ xdna_mailbox_free_channel(ndev->mgmt_chann);
+ ndev->mgmt_chann = NULL;
+}
+
static inline struct amdxdna_gem_obj *
aie2_cmdlist_get_cmd_buf(struct amdxdna_sched_job *job)
{
diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c
index 85079b6fc5d9..4924a9da55b6 100644
--- a/drivers/accel/amdxdna/aie2_pci.c
+++ b/drivers/accel/amdxdna/aie2_pci.c
@@ -330,9 +330,7 @@ static void aie2_hw_stop(struct amdxdna_dev *xdna)
aie2_runtime_cfg(ndev, AIE2_RT_CFG_CLK_GATING, NULL);
aie2_mgmt_fw_fini(ndev);
- xdna_mailbox_stop_channel(ndev->mgmt_chann);
- xdna_mailbox_destroy_channel(ndev->mgmt_chann);
- ndev->mgmt_chann = NULL;
+ aie2_destroy_mgmt_chann(ndev);
drmm_kfree(&xdna->ddev, ndev->mbox);
ndev->mbox = NULL;
aie2_psp_stop(ndev->psp_hdl);
@@ -363,10 +361,29 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
}
pci_set_master(pdev);
+ mbox_res.ringbuf_base = ndev->sram_base;
+ mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
+ mbox_res.mbox_base = ndev->mbox_base;
+ mbox_res.mbox_size = MBOX_SIZE(ndev);
+ mbox_res.name = "xdna_mailbox";
+ ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
+ if (!ndev->mbox) {
+ XDNA_ERR(xdna, "failed to create mailbox device");
+ ret = -ENODEV;
+ goto disable_dev;
+ }
+
+ ndev->mgmt_chann = xdna_mailbox_alloc_channel(ndev->mbox);
+ if (!ndev->mgmt_chann) {
+ XDNA_ERR(xdna, "failed to alloc channel");
+ ret = -ENODEV;
+ goto disable_dev;
+ }
+
ret = aie2_smu_init(ndev);
if (ret) {
XDNA_ERR(xdna, "failed to init smu, ret %d", ret);
- goto disable_dev;
+ goto free_channel;
}
ret = aie2_psp_start(ndev->psp_hdl);
@@ -381,18 +398,6 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
goto stop_psp;
}
- mbox_res.ringbuf_base = ndev->sram_base;
- mbox_res.ringbuf_size = pci_resource_len(pdev, xdna->dev_info->sram_bar);
- mbox_res.mbox_base = ndev->mbox_base;
- mbox_res.mbox_size = MBOX_SIZE(ndev);
- mbox_res.name = "xdna_mailbox";
- ndev->mbox = xdnam_mailbox_create(&xdna->ddev, &mbox_res);
- if (!ndev->mbox) {
- XDNA_ERR(xdna, "failed to create mailbox device");
- ret = -ENODEV;
- goto stop_psp;
- }
-
mgmt_mb_irq = pci_irq_vector(pdev, ndev->mgmt_chan_idx);
if (mgmt_mb_irq < 0) {
ret = mgmt_mb_irq;
@@ -401,13 +406,13 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
}
xdna_mailbox_intr_reg = ndev->mgmt_i2x.mb_head_ptr_reg + 4;
- ndev->mgmt_chann = xdna_mailbox_create_channel(ndev->mbox,
- &ndev->mgmt_x2i,
- &ndev->mgmt_i2x,
- xdna_mailbox_intr_reg,
- mgmt_mb_irq);
- if (!ndev->mgmt_chann) {
- XDNA_ERR(xdna, "failed to create management mailbox channel");
+ ret = xdna_mailbox_start_channel(ndev->mgmt_chann,
+ &ndev->mgmt_x2i,
+ &ndev->mgmt_i2x,
+ xdna_mailbox_intr_reg,
+ mgmt_mb_irq);
+ if (ret) {
+ XDNA_ERR(xdna, "failed to start management mailbox channel");
ret = -EINVAL;
goto stop_psp;
}
@@ -415,38 +420,41 @@ static int aie2_hw_start(struct amdxdna_dev *xdna)
ret = aie2_mgmt_fw_init(ndev);
if (ret) {
XDNA_ERR(xdna, "initial mgmt firmware failed, ret %d", ret);
- goto destroy_mgmt_chann;
+ goto stop_fw;
}
ret = aie2_pm_init(ndev);
if (ret) {
XDNA_ERR(xdna, "failed to init pm, ret %d", ret);
- goto destroy_mgmt_chann;
+ goto stop_fw;
}
ret = aie2_mgmt_fw_query(ndev);
if (ret) {
XDNA_ERR(xdna, "failed to query fw, ret %d", ret);
- goto destroy_mgmt_chann;
+ goto stop_fw;
}
ret = aie2_error_async_events_alloc(ndev);
if (ret) {
XDNA_ERR(xdna, "Allocate async events failed, ret %d", ret);
- goto destroy_mgmt_chann;
+ goto stop_fw;
}
ndev->dev_status = AIE2_DEV_START;
return 0;
-destroy_mgmt_chann:
+stop_fw:
+ aie2_suspend_fw(ndev);
xdna_mailbox_stop_channel(ndev->mgmt_chann);
- xdna_mailbox_destroy_channel(ndev->mgmt_chann);
stop_psp:
aie2_psp_stop(ndev->psp_hdl);
fini_smu:
aie2_smu_fini(ndev);
+free_channel:
+ xdna_mailbox_free_channel(ndev->mgmt_chann);
+ ndev->mgmt_chann = NULL;
disable_dev:
pci_disable_device(pdev);
diff --git a/drivers/accel/amdxdna/aie2_pci.h b/drivers/accel/amdxdna/aie2_pci.h
index b20a3661078c..e72311c77996 100644
--- a/drivers/accel/amdxdna/aie2_pci.h
+++ b/drivers/accel/amdxdna/aie2_pci.h
@@ -303,6 +303,7 @@ int aie2_get_array_async_error(struct amdxdna_dev_hdl *ndev,
/* aie2_message.c */
void aie2_msg_init(struct amdxdna_dev_hdl *ndev);
+void aie2_destroy_mgmt_chann(struct amdxdna_dev_hdl *ndev);
int aie2_suspend_fw(struct amdxdna_dev_hdl *ndev);
int aie2_resume_fw(struct amdxdna_dev_hdl *ndev);
int aie2_set_runtime_cfg(struct amdxdna_dev_hdl *ndev, u32 type, u64 value);
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.c b/drivers/accel/amdxdna/amdxdna_ctx.c
index 263d36072540..666dfd7b2a80 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.c
+++ b/drivers/accel/amdxdna/amdxdna_ctx.c
@@ -135,6 +135,33 @@ u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo)
return INVALID_CU_IDX;
}
+int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo,
+ struct amdxdna_sched_job *job, u32 cmd_idx,
+ enum ert_cmd_state error_state)
+{
+ struct amdxdna_client *client = job->hwctx->client;
+ struct amdxdna_cmd *cmd = abo->mem.kva;
+ struct amdxdna_cmd_chain *cc = NULL;
+
+ cmd->header &= ~AMDXDNA_CMD_STATE;
+ cmd->header |= FIELD_PREP(AMDXDNA_CMD_STATE, error_state);
+
+ if (amdxdna_cmd_get_op(abo) == ERT_CMD_CHAIN) {
+ cc = amdxdna_cmd_get_payload(abo, NULL);
+ cc->error_index = (cmd_idx < cc->command_count) ? cmd_idx : 0;
+ abo = amdxdna_gem_get_obj(client, cc->data[0], AMDXDNA_BO_CMD);
+ if (!abo)
+ return -EINVAL;
+ cmd = abo->mem.kva;
+ }
+
+ memset(cmd->data, 0xff, abo->mem.size - sizeof(*cmd));
+ if (cc)
+ amdxdna_gem_put_obj(abo);
+
+ return 0;
+}
+
/*
* This should be called in close() and remove(). DO NOT call in other syscalls.
* This guarantee that when hwctx and resources will be released, if user
diff --git a/drivers/accel/amdxdna/amdxdna_ctx.h b/drivers/accel/amdxdna/amdxdna_ctx.h
index 16c85f08f03c..fbdf9d000871 100644
--- a/drivers/accel/amdxdna/amdxdna_ctx.h
+++ b/drivers/accel/amdxdna/amdxdna_ctx.h
@@ -167,6 +167,9 @@ amdxdna_cmd_get_state(struct amdxdna_gem_obj *abo)
void *amdxdna_cmd_get_payload(struct amdxdna_gem_obj *abo, u32 *size);
u32 amdxdna_cmd_get_cu_idx(struct amdxdna_gem_obj *abo);
+int amdxdna_cmd_set_error(struct amdxdna_gem_obj *abo,
+ struct amdxdna_sched_job *job, u32 cmd_idx,
+ enum ert_cmd_state error_state);
void amdxdna_sched_job_cleanup(struct amdxdna_sched_job *job);
void amdxdna_hwctx_remove_all(struct amdxdna_client *client);
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.c b/drivers/accel/amdxdna/amdxdna_mailbox.c
index 235a94047530..46d844a73a94 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.c
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.c
@@ -460,26 +460,49 @@ msg_id_failed:
return ret;
}
-struct mailbox_channel *
-xdna_mailbox_create_channel(struct mailbox *mb,
- const struct xdna_mailbox_chann_res *x2i,
- const struct xdna_mailbox_chann_res *i2x,
- u32 iohub_int_addr,
- int mb_irq)
+struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb)
{
struct mailbox_channel *mb_chann;
- int ret;
-
- if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
- pr_err("Ring buf size must be power of 2");
- return NULL;
- }
mb_chann = kzalloc_obj(*mb_chann);
if (!mb_chann)
return NULL;
+ INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
+ mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
+ if (!mb_chann->work_q) {
+ MB_ERR(mb_chann, "Create workqueue failed");
+ goto free_chann;
+ }
mb_chann->mb = mb;
+
+ return mb_chann;
+
+free_chann:
+ kfree(mb_chann);
+ return NULL;
+}
+
+void xdna_mailbox_free_channel(struct mailbox_channel *mb_chann)
+{
+ destroy_workqueue(mb_chann->work_q);
+ kfree(mb_chann);
+}
+
+int
+xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
+ const struct xdna_mailbox_chann_res *x2i,
+ const struct xdna_mailbox_chann_res *i2x,
+ u32 iohub_int_addr,
+ int mb_irq)
+{
+ int ret;
+
+ if (!is_power_of_2(x2i->rb_size) || !is_power_of_2(i2x->rb_size)) {
+ pr_err("Ring buf size must be power of 2");
+ return -EINVAL;
+ }
+
mb_chann->msix_irq = mb_irq;
mb_chann->iohub_int_addr = iohub_int_addr;
memcpy(&mb_chann->res[CHAN_RES_X2I], x2i, sizeof(*x2i));
@@ -489,61 +512,37 @@ xdna_mailbox_create_channel(struct mailbox *mb,
mb_chann->x2i_tail = mailbox_get_tailptr(mb_chann, CHAN_RES_X2I);
mb_chann->i2x_head = mailbox_get_headptr(mb_chann, CHAN_RES_I2X);
- INIT_WORK(&mb_chann->rx_work, mailbox_rx_worker);
- mb_chann->work_q = create_singlethread_workqueue(MAILBOX_NAME);
- if (!mb_chann->work_q) {
- MB_ERR(mb_chann, "Create workqueue failed");
- goto free_and_out;
- }
-
/* Everything look good. Time to enable irq handler */
ret = request_irq(mb_irq, mailbox_irq_handler, 0, MAILBOX_NAME, mb_chann);
if (ret) {
MB_ERR(mb_chann, "Failed to request irq %d ret %d", mb_irq, ret);
- goto destroy_wq;
+ return ret;
}
mb_chann->bad_state = false;
mailbox_reg_write(mb_chann, mb_chann->iohub_int_addr, 0);
- MB_DBG(mb_chann, "Mailbox channel created (irq: %d)", mb_chann->msix_irq);
- return mb_chann;
-
-destroy_wq:
- destroy_workqueue(mb_chann->work_q);
-free_and_out:
- kfree(mb_chann);
- return NULL;
+ MB_DBG(mb_chann, "Mailbox channel started (irq: %d)", mb_chann->msix_irq);
+ return 0;
}
-int xdna_mailbox_destroy_channel(struct mailbox_channel *mb_chann)
+void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
{
struct mailbox_msg *mb_msg;
unsigned long msg_id;
- MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
+ /* Disable an irq and wait. This might sleep. */
free_irq(mb_chann->msix_irq, mb_chann);
- destroy_workqueue(mb_chann->work_q);
- /* We can clean up and release resources */
+ /* Cancel RX work and wait for it to finish */
+ drain_workqueue(mb_chann->work_q);
+
+ /* We can clean up and release resources */
xa_for_each(&mb_chann->chan_xa, msg_id, mb_msg)
mailbox_release_msg(mb_chann, mb_msg);
-
xa_destroy(&mb_chann->chan_xa);
- MB_DBG(mb_chann, "Mailbox channel destroyed, irq: %d", mb_chann->msix_irq);
- kfree(mb_chann);
- return 0;
-}
-
-void xdna_mailbox_stop_channel(struct mailbox_channel *mb_chann)
-{
- /* Disable an irq and wait. This might sleep. */
- disable_irq(mb_chann->msix_irq);
-
- /* Cancel RX work and wait for it to finish */
- cancel_work_sync(&mb_chann->rx_work);
- MB_DBG(mb_chann, "IRQ disabled and RX work cancelled");
+ MB_DBG(mb_chann, "Mailbox channel stopped, irq: %d", mb_chann->msix_irq);
}
struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
diff --git a/drivers/accel/amdxdna/amdxdna_mailbox.h b/drivers/accel/amdxdna/amdxdna_mailbox.h
index ea367f2fb738..8b1e00945da4 100644
--- a/drivers/accel/amdxdna/amdxdna_mailbox.h
+++ b/drivers/accel/amdxdna/amdxdna_mailbox.h
@@ -74,9 +74,16 @@ struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
const struct xdna_mailbox_res *res);
/*
- * xdna_mailbox_create_channel() -- Create a mailbox channel instance
+ * xdna_mailbox_alloc_channel() -- alloc a mailbox channel
*
- * @mailbox: the handle return from xdna_mailbox_create()
+ * @mb: mailbox handle
+ */
+struct mailbox_channel *xdna_mailbox_alloc_channel(struct mailbox *mb);
+
+/*
+ * xdna_mailbox_start_channel() -- start a mailbox channel instance
+ *
+ * @mb_chann: the handle return from xdna_mailbox_alloc_channel()
* @x2i: host to firmware mailbox resources
* @i2x: firmware to host mailbox resources
* @xdna_mailbox_intr_reg: register addr of MSI-X interrupt
@@ -84,28 +91,24 @@ struct mailbox *xdnam_mailbox_create(struct drm_device *ddev,
*
* Return: If success, return a handle of mailbox channel. Otherwise, return NULL.
*/
-struct mailbox_channel *
-xdna_mailbox_create_channel(struct mailbox *mailbox,
- const struct xdna_mailbox_chann_res *x2i,
- const struct xdna_mailbox_chann_res *i2x,
- u32 xdna_mailbox_intr_reg,
- int mb_irq);
+int
+xdna_mailbox_start_channel(struct mailbox_channel *mb_chann,
+ const struct xdna_mailbox_chann_res *x2i,
+ const struct xdna_mailbox_chann_res *i2x,
+ u32 xdna_mailbox_intr_reg,
+ int mb_irq);
/*
- * xdna_mailbox_destroy_channel() -- destroy mailbox channel
+ * xdna_mailbox_free_channel() -- free mailbox channel
*
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
- *
- * Return: if success, return 0. otherwise return error code
*/
-int xdna_mailbox_destroy_channel(struct mailbox_channel *mailbox_chann);
+void xdna_mailbox_free_channel(struct mailbox_channel *mailbox_chann);
/*
* xdna_mailbox_stop_channel() -- stop mailbox channel
*
* @mailbox_chann: the handle return from xdna_mailbox_create_channel()
- *
- * Return: if success, return 0. otherwise return error code
*/
void xdna_mailbox_stop_channel(struct mailbox_channel *mailbox_chann);
diff --git a/drivers/accel/amdxdna/npu1_regs.c b/drivers/accel/amdxdna/npu1_regs.c
index 6e3d3ca69c04..1320e924e548 100644
--- a/drivers/accel/amdxdna/npu1_regs.c
+++ b/drivers/accel/amdxdna/npu1_regs.c
@@ -67,7 +67,7 @@ const struct dpm_clk_freq npu1_dpm_clk_table[] = {
static const struct aie2_fw_feature_tbl npu1_fw_feature_table[] = {
{ .major = 5, .min_minor = 7 },
- { .features = BIT_U64(AIE2_NPU_COMMAND), .min_minor = 8 },
+ { .features = BIT_U64(AIE2_NPU_COMMAND), .major = 5, .min_minor = 8 },
{ 0 }
};
diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c
index 668c71d5ff45..7994e7073903 100644
--- a/drivers/accel/ethosu/ethosu_gem.c
+++ b/drivers/accel/ethosu/ethosu_gem.c
@@ -245,11 +245,14 @@ static int calc_sizes(struct drm_device *ddev,
((st->ifm.stride_kernel >> 1) & 0x1) + 1;
u32 stride_x = ((st->ifm.stride_kernel >> 5) & 0x2) +
(st->ifm.stride_kernel & 0x1) + 1;
- u32 ifm_height = st->ofm.height[2] * stride_y +
+ s32 ifm_height = st->ofm.height[2] * stride_y +
st->ifm.height[2] - (st->ifm.pad_top + st->ifm.pad_bottom);
- u32 ifm_width = st->ofm.width * stride_x +
+ s32 ifm_width = st->ofm.width * stride_x +
st->ifm.width - (st->ifm.pad_left + st->ifm.pad_right);
+ if (ifm_height < 0 || ifm_width < 0)
+ return -EINVAL;
+
len = feat_matrix_length(info, &st->ifm, ifm_width,
ifm_height, st->ifm.depth);
dev_dbg(ddev->dev, "op %d: IFM:%d:0x%llx-0x%llx\n",
@@ -417,7 +420,10 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev,
return ret;
break;
case NPU_OP_ELEMENTWISE:
- use_ifm2 = !((st.ifm2.broadcast == 8) || (param == 5) ||
+ use_scale = ethosu_is_u65(edev) ?
+ (st.ifm2.broadcast & 0x80) :
+ (st.ifm2.broadcast == 8);
+ use_ifm2 = !(use_scale || (param == 5) ||
(param == 6) || (param == 7) || (param == 0x24));
use_ifm = st.ifm.broadcast != 8;
ret = calc_sizes_elemwise(ddev, info, cmd, &st, use_ifm, use_ifm2);
diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c
index 8598a3634340..ec85f4156744 100644
--- a/drivers/accel/ethosu/ethosu_job.c
+++ b/drivers/accel/ethosu/ethosu_job.c
@@ -143,23 +143,29 @@ out:
return ret;
}
+static void ethosu_job_err_cleanup(struct ethosu_job *job)
+{
+ unsigned int i;
+
+ for (i = 0; i < job->region_cnt; i++)
+ drm_gem_object_put(job->region_bo[i]);
+
+ drm_gem_object_put(job->cmd_bo);
+
+ kfree(job);
+}
+
static void ethosu_job_cleanup(struct kref *ref)
{
struct ethosu_job *job = container_of(ref, struct ethosu_job,
refcount);
- unsigned int i;
pm_runtime_put_autosuspend(job->dev->base.dev);
dma_fence_put(job->done_fence);
dma_fence_put(job->inference_done_fence);
- for (i = 0; i < job->region_cnt; i++)
- drm_gem_object_put(job->region_bo[i]);
-
- drm_gem_object_put(job->cmd_bo);
-
- kfree(job);
+ ethosu_job_err_cleanup(job);
}
static void ethosu_job_put(struct ethosu_job *job)
@@ -454,12 +460,16 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file
}
}
ret = ethosu_job_push(ejob);
+ if (!ret) {
+ ethosu_job_put(ejob);
+ return 0;
+ }
out_cleanup_job:
if (ret)
drm_sched_job_cleanup(&ejob->base);
out_put_job:
- ethosu_job_put(ejob);
+ ethosu_job_err_cleanup(ejob);
return ret;
}
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 5f70b196e0aa..6c9b5bf7d392 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -379,8 +379,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_CPC", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Ints/Bufs) */
- PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,
- 0, 0, 0),
+ PACKAGE_INFO(ACPI_PTYPE1_VAR,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER |
+ ACPI_RTYPE_PACKAGE, 0, 0, 0, 0),
{{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index f2579611e0a5..aa55ecfc2923 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1457,15 +1457,6 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on)
return 0;
/*
- * Skip devices whose ACPI companions don't support power management and
- * don't have a wakeup GPE.
- */
- if (!acpi_device_power_manageable(adev) && !acpi_device_can_wakeup(adev)) {
- dev_dbg(dev, "No ACPI power management or wakeup GPE\n");
- return 0;
- }
-
- /*
* Only attach the power domain to the first device if the
* companion is shared by multiple. This is to prevent doing power
* management twice.
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index ccbf320524da..6c4e567b6582 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4189,6 +4189,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
ATA_QUIRK_FIRMWARE_WARN },
/* Seagate disks with LPM issues */
+ { "ST1000DM010-2EP102", NULL, ATA_QUIRK_NOLPM },
{ "ST2000DM008-2FR102", NULL, ATA_QUIRK_NOLPM },
/* drives which fail FPDMA_AA activation (some may freeze afterwards)
@@ -4231,6 +4232,7 @@ static const struct ata_dev_quirks_entry __ata_dev_quirks[] = {
/* Devices that do not need bridging limits applied */
{ "MTRON MSP-SATA*", NULL, ATA_QUIRK_BRIDGE_OK },
{ "BUFFALO HD-QSU2/R5", NULL, ATA_QUIRK_BRIDGE_OK },
+ { "QEMU HARDDISK", "2.5+", ATA_QUIRK_BRIDGE_OK },
/* Devices which aren't very happy with higher link speeds */
{ "WD My Book", NULL, ATA_QUIRK_1_5_GBPS },
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index b373cceb95d2..23be85418b3b 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -647,7 +647,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
break;
}
- if (qc == ap->deferred_qc) {
+ if (i < ATA_MAX_QUEUE && qc == ap->deferred_qc) {
/*
* This is a deferred command that timed out while
* waiting for the command queue to drain. Since the qc
@@ -659,6 +659,7 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
*/
WARN_ON_ONCE(qc->flags & ATA_QCFLAG_ACTIVE);
ap->deferred_qc = NULL;
+ cancel_work(&ap->deferred_qc_work);
set_host_byte(scmd, DID_TIME_OUT);
scsi_eh_finish_cmd(scmd, &ap->eh_done_q);
} else if (i < ATA_MAX_QUEUE) {
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index c0dd75a0287c..ad798e5246b4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1699,6 +1699,7 @@ void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
scmd = qc->scsicmd;
ap->deferred_qc = NULL;
+ cancel_work(&ap->deferred_qc_work);
ata_qc_free(qc);
scmd->result = (DID_SOFT_ERROR << 16);
scsi_done(scmd);
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 79d031d2d845..1af95ac68b77 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -179,19 +179,10 @@ void device_release_driver_internal(struct device *dev, const struct device_driv
void driver_detach(const struct device_driver *drv);
void driver_deferred_probe_del(struct device *dev);
void device_set_deferred_probe_reason(const struct device *dev, struct va_format *vaf);
-static inline int driver_match_device_locked(const struct device_driver *drv,
- struct device *dev)
-{
- device_lock_assert(dev);
-
- return drv->bus->match ? drv->bus->match(dev, drv) : 1;
-}
-
static inline int driver_match_device(const struct device_driver *drv,
struct device *dev)
{
- guard(device)(dev);
- return driver_match_device_locked(drv, dev);
+ return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
static inline void dev_sync_state(struct device *dev)
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 0354f209529c..bea8da5f8a3a 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -928,7 +928,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
bool async_allowed;
int ret;
- ret = driver_match_device_locked(drv, dev);
+ ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
return 0;
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 8adc7fe71c04..98d1023007e3 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -52,9 +52,10 @@ static int atmel_sha204a_rng_read_nonblocking(struct hwrng *rng, void *data,
rng->priv = 0;
} else {
work_data = kmalloc_obj(*work_data, GFP_ATOMIC);
- if (!work_data)
+ if (!work_data) {
+ atomic_dec(&i2c_priv->tfm_count);
return -ENOMEM;
-
+ }
work_data->ctx = i2c_priv;
work_data->client = i2c_priv->client;
diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c
index adc9542ae806..b07ae529b591 100644
--- a/drivers/crypto/ccp/sev-dev-tsm.c
+++ b/drivers/crypto/ccp/sev-dev-tsm.c
@@ -378,9 +378,9 @@ void sev_tsm_init_locked(struct sev_device *sev, void *tio_status_page)
return;
error_exit:
- kfree(t);
pr_err("Failed to enable SEV-TIO: ret=%d en=%d initdone=%d SEV=%d\n",
ret, t->tio_en, t->tio_init_done, boot_cpu_has(X86_FEATURE_SEV));
+ kfree(t);
}
void sev_tsm_uninit(struct sev_device *sev)
diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c
index 096f993974d1..8b2dfc11289b 100644
--- a/drivers/crypto/ccp/sev-dev.c
+++ b/drivers/crypto/ccp/sev-dev.c
@@ -1105,15 +1105,12 @@ struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages)
{
struct psp_device *psp_master = psp_get_master_device();
struct snp_hv_fixed_pages_entry *entry;
- struct sev_device *sev;
unsigned int order;
struct page *page;
- if (!psp_master || !psp_master->sev_data)
+ if (!psp_master)
return NULL;
- sev = psp_master->sev_data;
-
order = get_order(PMD_SIZE * num_2mb_pages);
/*
@@ -1126,7 +1123,8 @@ struct page *snp_alloc_hv_fixed_pages(unsigned int num_2mb_pages)
* This API uses SNP_INIT_EX to transition allocated pages to HV_Fixed
* page state, fail if SNP is already initialized.
*/
- if (sev->snp_initialized)
+ if (psp_master->sev_data &&
+ ((struct sev_device *)psp_master->sev_data)->snp_initialized)
return NULL;
/* Re-use freed pages that match the request */
@@ -1162,7 +1160,7 @@ void snp_free_hv_fixed_pages(struct page *page)
struct psp_device *psp_master = psp_get_master_device();
struct snp_hv_fixed_pages_entry *entry, *nentry;
- if (!psp_master || !psp_master->sev_data)
+ if (!psp_master)
return;
/*
diff --git a/drivers/firmware/efi/mokvar-table.c b/drivers/firmware/efi/mokvar-table.c
index 4ff0c2926097..6842aa96d704 100644
--- a/drivers/firmware/efi/mokvar-table.c
+++ b/drivers/firmware/efi/mokvar-table.c
@@ -85,7 +85,7 @@ static struct kobject *mokvar_kobj;
* as an alternative to ordinary EFI variables, due to platform-dependent
* limitations. The memory occupied by this table is marked as reserved.
*
- * This routine must be called before efi_free_boot_services() in order
+ * This routine must be called before efi_unmap_boot_services() in order
* to guarantee that it can mark the table as reserved.
*
* Implicit inputs:
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
index 06c1913d5a3f..29b400cdd6d5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c
@@ -1439,7 +1439,10 @@ static int init_kfd_vm(struct amdgpu_vm *vm, void **process_info,
*process_info = info;
}
- vm->process_info = *process_info;
+ if (cmpxchg(&vm->process_info, NULL, *process_info) != NULL) {
+ ret = -EINVAL;
+ goto already_acquired;
+ }
/* Validate page directory and attach eviction fence */
ret = amdgpu_bo_reserve(vm->root.bo, true);
@@ -1479,6 +1482,7 @@ validate_pd_fail:
amdgpu_bo_unreserve(vm->root.bo);
reserve_pd_fail:
vm->process_info = NULL;
+already_acquired:
if (info) {
dma_fence_put(&info->eviction_fence->base);
*process_info = NULL;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
index 9d67b770bcc2..7c450350847d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c
@@ -446,8 +446,7 @@ static int amdgpu_userq_wait_for_last_fence(struct amdgpu_usermode_queue *queue)
return ret;
}
-static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
- int queue_id)
+static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
@@ -461,7 +460,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
uq_funcs->mqd_destroy(queue);
amdgpu_userq_fence_driver_free(queue);
/* Use interrupt-safe locking since IRQ handlers may access these XArrays */
- xa_erase_irq(&uq_mgr->userq_xa, (unsigned long)queue_id);
xa_erase_irq(&adev->userq_doorbell_xa, queue->doorbell_index);
queue->userq_mgr = NULL;
list_del(&queue->userq_va_list);
@@ -470,12 +468,6 @@ static void amdgpu_userq_cleanup(struct amdgpu_usermode_queue *queue,
up_read(&adev->reset_domain->sem);
}
-static struct amdgpu_usermode_queue *
-amdgpu_userq_find(struct amdgpu_userq_mgr *uq_mgr, int qid)
-{
- return xa_load(&uq_mgr->userq_xa, qid);
-}
-
void
amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *uq_mgr,
struct amdgpu_eviction_fence_mgr *evf_mgr)
@@ -625,22 +617,13 @@ unref_bo:
}
static int
-amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
+amdgpu_userq_destroy(struct amdgpu_userq_mgr *uq_mgr, struct amdgpu_usermode_queue *queue)
{
- struct amdgpu_fpriv *fpriv = filp->driver_priv;
- struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
struct amdgpu_device *adev = uq_mgr->adev;
- struct amdgpu_usermode_queue *queue;
int r = 0;
cancel_delayed_work_sync(&uq_mgr->resume_work);
mutex_lock(&uq_mgr->userq_mutex);
- queue = amdgpu_userq_find(uq_mgr, queue_id);
- if (!queue) {
- drm_dbg_driver(adev_to_drm(uq_mgr->adev), "Invalid queue id to destroy\n");
- mutex_unlock(&uq_mgr->userq_mutex);
- return -EINVAL;
- }
amdgpu_userq_wait_for_last_fence(queue);
/* Cancel any pending hang detection work and cleanup */
if (queue->hang_detect_fence) {
@@ -672,7 +655,7 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
drm_warn(adev_to_drm(uq_mgr->adev), "trying to destroy a HW mapping userq\n");
queue->state = AMDGPU_USERQ_STATE_HUNG;
}
- amdgpu_userq_cleanup(queue, queue_id);
+ amdgpu_userq_cleanup(queue);
mutex_unlock(&uq_mgr->userq_mutex);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
@@ -680,6 +663,37 @@ amdgpu_userq_destroy(struct drm_file *filp, int queue_id)
return r;
}
+static void amdgpu_userq_kref_destroy(struct kref *kref)
+{
+ int r;
+ struct amdgpu_usermode_queue *queue =
+ container_of(kref, struct amdgpu_usermode_queue, refcount);
+ struct amdgpu_userq_mgr *uq_mgr = queue->userq_mgr;
+
+ r = amdgpu_userq_destroy(uq_mgr, queue);
+ if (r)
+ drm_file_err(uq_mgr->file, "Failed to destroy usermode queue %d\n", r);
+}
+
+struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid)
+{
+ struct amdgpu_usermode_queue *queue;
+
+ xa_lock(&uq_mgr->userq_xa);
+ queue = xa_load(&uq_mgr->userq_xa, qid);
+ if (queue)
+ kref_get(&queue->refcount);
+ xa_unlock(&uq_mgr->userq_xa);
+
+ return queue;
+}
+
+void amdgpu_userq_put(struct amdgpu_usermode_queue *queue)
+{
+ if (queue)
+ kref_put(&queue->refcount, amdgpu_userq_kref_destroy);
+}
+
static int amdgpu_userq_priority_permit(struct drm_file *filp,
int priority)
{
@@ -834,6 +848,9 @@ amdgpu_userq_create(struct drm_file *filp, union drm_amdgpu_userq *args)
goto unlock;
}
+ /* drop this refcount during queue destroy */
+ kref_init(&queue->refcount);
+
/* Wait for mode-1 reset to complete */
down_read(&adev->reset_domain->sem);
r = xa_err(xa_store_irq(&adev->userq_doorbell_xa, index, queue, GFP_KERNEL));
@@ -985,7 +1002,9 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
struct drm_file *filp)
{
union drm_amdgpu_userq *args = data;
- int r;
+ struct amdgpu_fpriv *fpriv = filp->driver_priv;
+ struct amdgpu_usermode_queue *queue;
+ int r = 0;
if (!amdgpu_userq_enabled(dev))
return -ENOTSUPP;
@@ -1000,11 +1019,16 @@ int amdgpu_userq_ioctl(struct drm_device *dev, void *data,
drm_file_err(filp, "Failed to create usermode queue\n");
break;
- case AMDGPU_USERQ_OP_FREE:
- r = amdgpu_userq_destroy(filp, args->in.queue_id);
- if (r)
- drm_file_err(filp, "Failed to destroy usermode queue\n");
+ case AMDGPU_USERQ_OP_FREE: {
+ xa_lock(&fpriv->userq_mgr.userq_xa);
+ queue = __xa_erase(&fpriv->userq_mgr.userq_xa, args->in.queue_id);
+ xa_unlock(&fpriv->userq_mgr.userq_xa);
+ if (!queue)
+ return -ENOENT;
+
+ amdgpu_userq_put(queue);
break;
+ }
default:
drm_dbg_driver(dev, "Invalid user queue op specified: %d\n", args->in.op);
@@ -1023,16 +1047,23 @@ amdgpu_userq_restore_all(struct amdgpu_userq_mgr *uq_mgr)
/* Resume all the queues for this process */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
+
if (!amdgpu_userq_buffer_vas_mapped(queue)) {
drm_file_err(uq_mgr->file,
"trying restore queue without va mapping\n");
queue->state = AMDGPU_USERQ_STATE_INVALID_VA;
+ amdgpu_userq_put(queue);
continue;
}
r = amdgpu_userq_restore_helper(queue);
if (r)
ret = r;
+
+ amdgpu_userq_put(queue);
}
if (ret)
@@ -1266,9 +1297,13 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
amdgpu_userq_detect_and_reset_queues(uq_mgr);
/* Try to unmap all the queues in this process ctx */
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
r = amdgpu_userq_preempt_helper(queue);
if (r)
ret = r;
+ amdgpu_userq_put(queue);
}
if (ret)
@@ -1301,16 +1336,24 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
int ret;
xa_for_each(&uq_mgr->userq_xa, queue_id, queue) {
+ queue = amdgpu_userq_get(uq_mgr, queue_id);
+ if (!queue)
+ continue;
+
struct dma_fence *f = queue->last_fence;
- if (!f || dma_fence_is_signaled(f))
+ if (!f || dma_fence_is_signaled(f)) {
+ amdgpu_userq_put(queue);
continue;
+ }
ret = dma_fence_wait_timeout(f, true, msecs_to_jiffies(100));
if (ret <= 0) {
drm_file_err(uq_mgr->file, "Timed out waiting for fence=%llu:%llu\n",
f->context, f->seqno);
+ amdgpu_userq_put(queue);
return -ETIMEDOUT;
}
+ amdgpu_userq_put(queue);
}
return 0;
@@ -1361,20 +1404,23 @@ int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *f
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr)
{
struct amdgpu_usermode_queue *queue;
- unsigned long queue_id;
+ unsigned long queue_id = 0;
+
+ for (;;) {
+ xa_lock(&userq_mgr->userq_xa);
+ queue = xa_find(&userq_mgr->userq_xa, &queue_id, ULONG_MAX,
+ XA_PRESENT);
+ if (queue)
+ __xa_erase(&userq_mgr->userq_xa, queue_id);
+ xa_unlock(&userq_mgr->userq_xa);
- cancel_delayed_work_sync(&userq_mgr->resume_work);
+ if (!queue)
+ break;
- mutex_lock(&userq_mgr->userq_mutex);
- amdgpu_userq_detect_and_reset_queues(userq_mgr);
- xa_for_each(&userq_mgr->userq_xa, queue_id, queue) {
- amdgpu_userq_wait_for_last_fence(queue);
- amdgpu_userq_unmap_helper(queue);
- amdgpu_userq_cleanup(queue, queue_id);
+ amdgpu_userq_put(queue);
}
xa_destroy(&userq_mgr->userq_xa);
- mutex_unlock(&userq_mgr->userq_mutex);
mutex_destroy(&userq_mgr->userq_mutex);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
index 5845d8959034..736c1d38297c 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.h
@@ -74,6 +74,7 @@ struct amdgpu_usermode_queue {
struct dentry *debugfs_queue;
struct delayed_work hang_detect_work;
struct dma_fence *hang_detect_fence;
+ struct kref refcount;
struct list_head userq_va_list;
};
@@ -112,6 +113,9 @@ struct amdgpu_db_info {
struct amdgpu_userq_obj *db_obj;
};
+struct amdgpu_usermode_queue *amdgpu_userq_get(struct amdgpu_userq_mgr *uq_mgr, u32 qid);
+void amdgpu_userq_put(struct amdgpu_usermode_queue *queue);
+
int amdgpu_userq_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
int amdgpu_userq_mgr_init(struct amdgpu_userq_mgr *userq_mgr, struct drm_file *file_priv,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
index 7e9cf1868cc9..5239b06b9ab0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq_fence.c
@@ -466,7 +466,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
struct drm_amdgpu_userq_signal *args = data;
struct drm_gem_object **gobj_write = NULL;
struct drm_gem_object **gobj_read = NULL;
- struct amdgpu_usermode_queue *queue;
+ struct amdgpu_usermode_queue *queue = NULL;
struct amdgpu_userq_fence *userq_fence;
struct drm_syncobj **syncobj = NULL;
u32 *bo_handles_write, num_write_bo_handles;
@@ -553,7 +553,7 @@ int amdgpu_userq_signal_ioctl(struct drm_device *dev, void *data,
}
/* Retrieve the user queue */
- queue = xa_load(&userq_mgr->userq_xa, args->queue_id);
+ queue = amdgpu_userq_get(userq_mgr, args->queue_id);
if (!queue) {
r = -ENOENT;
goto put_gobj_write;
@@ -648,6 +648,9 @@ free_syncobj:
free_syncobj_handles:
kfree(syncobj_handles);
+ if (queue)
+ amdgpu_userq_put(queue);
+
return r;
}
@@ -660,7 +663,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
struct drm_amdgpu_userq_wait *wait_info = data;
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_userq_mgr *userq_mgr = &fpriv->userq_mgr;
- struct amdgpu_usermode_queue *waitq;
+ struct amdgpu_usermode_queue *waitq = NULL;
struct drm_gem_object **gobj_write;
struct drm_gem_object **gobj_read;
struct dma_fence **fences = NULL;
@@ -926,7 +929,7 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
*/
num_fences = dma_fence_dedup_array(fences, num_fences);
- waitq = xa_load(&userq_mgr->userq_xa, wait_info->waitq_id);
+ waitq = amdgpu_userq_get(userq_mgr, wait_info->waitq_id);
if (!waitq) {
r = -EINVAL;
goto free_fences;
@@ -983,32 +986,14 @@ int amdgpu_userq_wait_ioctl(struct drm_device *dev, void *data,
r = -EFAULT;
goto free_fences;
}
-
- kfree(fences);
- kfree(fence_info);
}
- drm_exec_fini(&exec);
- for (i = 0; i < num_read_bo_handles; i++)
- drm_gem_object_put(gobj_read[i]);
- kfree(gobj_read);
-
- for (i = 0; i < num_write_bo_handles; i++)
- drm_gem_object_put(gobj_write[i]);
- kfree(gobj_write);
-
- kfree(timeline_points);
- kfree(timeline_handles);
- kfree(syncobj_handles);
- kfree(bo_handles_write);
- kfree(bo_handles_read);
-
- return 0;
-
free_fences:
- while (num_fences-- > 0)
- dma_fence_put(fences[num_fences]);
- kfree(fences);
+ if (fences) {
+ while (num_fences-- > 0)
+ dma_fence_put(fences[num_fences]);
+ kfree(fences);
+ }
free_fence_info:
kfree(fence_info);
exec_fini:
@@ -1032,5 +1017,8 @@ free_bo_handles_write:
free_bo_handles_read:
kfree(bo_handles_read);
+ if (waitq)
+ amdgpu_userq_put(waitq);
+
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
index 723ddae17644..73a709773e85 100644
--- a/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/psp_v15_0.c
@@ -69,12 +69,12 @@ static int psp_v15_0_0_ring_stop(struct psp_context *psp,
0x80000000, 0x80000000, false);
} else {
/* Write the ring destroy command*/
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64,
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64,
GFX_CTRL_CMD_ID_DESTROY_RINGS);
/* there might be handshake issue with hardware which needs delay */
mdelay(20);
/* Wait for response flag (bit 31) */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x80000000, false);
}
@@ -116,7 +116,7 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
} else {
/* Wait for sOS ready for ring creation */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x80000000, false);
if (ret) {
DRM_ERROR("Failed to wait for trust OS ready for ring creation\n");
@@ -125,23 +125,23 @@ static int psp_v15_0_0_ring_create(struct psp_context *psp,
/* Write low address of the ring to C2PMSG_69 */
psp_ring_reg = lower_32_bits(ring->ring_mem_mc_addr);
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_69, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_69, psp_ring_reg);
/* Write high address of the ring to C2PMSG_70 */
psp_ring_reg = upper_32_bits(ring->ring_mem_mc_addr);
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_70, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_70, psp_ring_reg);
/* Write size of ring to C2PMSG_71 */
psp_ring_reg = ring->ring_size;
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_71, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_71, psp_ring_reg);
/* Write the ring initialization command to C2PMSG_64 */
psp_ring_reg = ring_type;
psp_ring_reg = psp_ring_reg << 16;
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_64, psp_ring_reg);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64, psp_ring_reg);
/* there might be handshake issue with hardware which needs delay */
mdelay(20);
/* Wait for response flag (bit 31) in C2PMSG_64 */
- ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_SMN_C2PMSG_64),
+ ret = psp_wait_for(psp, SOC15_REG_OFFSET(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_64),
0x80000000, 0x8000FFFF, false);
}
@@ -174,7 +174,7 @@ static uint32_t psp_v15_0_0_ring_get_wptr(struct psp_context *psp)
if (amdgpu_sriov_vf(adev))
data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_102);
else
- data = RREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67);
+ data = RREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67);
return data;
}
@@ -188,7 +188,7 @@ static void psp_v15_0_0_ring_set_wptr(struct psp_context *psp, uint32_t value)
WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_101,
GFX_CTRL_CMD_ID_CONSUME_CMD);
} else
- WREG32_SOC15(MP0, 0, regMPASP_SMN_C2PMSG_67, value);
+ WREG32_SOC15(MP0, 0, regMPASP_PCRU1_MPASP_C2PMSG_67, value);
}
static const struct psp_funcs psp_v15_0_0_funcs = {
diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c
index 8122a5cacf07..a0ad1f8a76f0 100644
--- a/drivers/gpu/drm/amd/amdgpu/soc21.c
+++ b/drivers/gpu/drm/amd/amdgpu/soc21.c
@@ -858,7 +858,9 @@ static int soc21_common_early_init(struct amdgpu_ip_block *ip_block)
AMD_CG_SUPPORT_IH_CG |
AMD_CG_SUPPORT_BIF_MGCG |
AMD_CG_SUPPORT_BIF_LS;
- adev->pg_flags = AMD_PG_SUPPORT_VCN |
+ adev->pg_flags = AMD_PG_SUPPORT_VCN_DPG |
+ AMD_PG_SUPPORT_VCN |
+ AMD_PG_SUPPORT_JPEG_DPG |
AMD_PG_SUPPORT_JPEG |
AMD_PG_SUPPORT_GFX_PG;
adev->external_rev_id = adev->rev_id + 0x1;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
index 2ba98f384685..cd1e58b8defc 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_color.c
@@ -1706,6 +1706,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
struct dc_transfer_func *tf = &dc_plane_state->in_shaper_func;
struct drm_atomic_state *state = plane_state->state;
const struct amdgpu_device *adev = drm_to_adev(colorop->dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
const struct drm_device *dev = colorop->dev;
const struct drm_color_lut32 *lut3d;
uint32_t lut3d_size;
@@ -1722,7 +1723,7 @@ __set_dm_plane_colorop_3dlut(struct drm_plane_state *plane_state,
}
if (colorop_state && !colorop_state->bypass && colorop->type == DRM_COLOROP_3D_LUT) {
- if (!adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (!has_3dlut) {
drm_dbg(dev, "3D LUT is not supported by hardware\n");
return -EINVAL;
}
@@ -1875,6 +1876,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
struct drm_colorop *colorop = plane_state->color_pipeline;
struct drm_device *dev = plane_state->plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
/* 1D Curve - DEGAM TF */
@@ -1907,7 +1909,7 @@ amdgpu_dm_plane_set_colorop_properties(struct drm_plane_state *plane_state,
if (ret)
return ret;
- if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (has_3dlut) {
/* 1D Curve & LUT - SHAPER TF & LUT */
colorop = colorop->next;
if (!colorop) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
index f25c0ede7199..d59ba82d3d7c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_colorop.c
@@ -60,6 +60,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
struct drm_colorop *ops[MAX_COLOR_PIPELINE_OPS];
struct drm_device *dev = plane->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
+ bool has_3dlut = adev->dm.dc->caps.color.dpp.hw_3d_lut || adev->dm.dc->caps.color.mpc.preblend;
int ret;
int i = 0;
@@ -112,7 +113,7 @@ int amdgpu_dm_initialize_default_pipeline(struct drm_plane *plane, struct drm_pr
i++;
- if (adev->dm.dc->caps.color.dpp.hw_3d_lut) {
+ if (has_3dlut) {
/* 1D curve - SHAPER TF */
ops[i] = kzalloc_obj(*ops[0]);
if (!ops[i]) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index 130190e8a1b2..304437c2284d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -765,15 +765,15 @@ int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
dm->adev->mode_info.crtcs[crtc_index] = acrtc;
/* Don't enable DRM CRTC degamma property for
- * 1. Degamma is replaced by color pipeline.
- * 2. DCE since it doesn't support programmable degamma anywhere.
- * 3. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
+ * 1. DCE since it doesn't support programmable degamma anywhere.
+ * 2. DCN401 since pre-blending degamma LUT doesn't apply to cursor.
+ * Note: DEGAMMA properties are created even if the primary plane has the
+ * COLOR_PIPELINE property. User space can use either the DEGAMMA properties
+ * or the COLOR_PIPELINE property. An atomic commit which attempts to enable
+ * both is rejected.
*/
- if (plane->color_pipeline_property)
- has_degamma = false;
- else
- has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
- dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
+ has_degamma = dm->adev->dm.dc->caps.color.dpp.dcn_arch &&
+ dm->adev->dm.dc->ctx->dce_version != DCN_VERSION_4_01;
drm_crtc_enable_color_mgmt(&acrtc->base, has_degamma ? MAX_COLOR_LUT_ENTRIES : 0,
true, MAX_COLOR_LUT_ENTRIES);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
index 70587e5a8d46..127207e18dcb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c
@@ -1256,6 +1256,14 @@ static int amdgpu_dm_plane_atomic_check(struct drm_plane *plane,
if (ret)
return ret;
+ /* Reject commits that attempt to use both COLOR_PIPELINE and CRTC DEGAMMA_LUT */
+ if (new_plane_state->color_pipeline && new_crtc_state->degamma_lut) {
+ drm_dbg_atomic(plane->dev,
+ "[PLANE:%d:%s] COLOR_PIPELINE and CRTC DEGAMMA_LUT cannot be enabled simultaneously\n",
+ plane->base.id, plane->name);
+ return -EINVAL;
+ }
+
ret = amdgpu_dm_plane_fill_dc_scaling_info(adev, new_plane_state, &scaling_info);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
index b91517b9fedc..eb198d52a115 100644
--- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
@@ -72,7 +72,11 @@ void dcn401_initialize_min_clocks(struct dc *dc)
* audio corruption. Read current DISPCLK from DENTIST and request the same
* freq to ensure that the timing is valid and unchanged.
*/
- clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
+ if (dc->clk_mgr->funcs->get_dispclk_from_dentist) {
+ clocks->dispclk_khz = dc->clk_mgr->funcs->get_dispclk_from_dentist(dc->clk_mgr);
+ } else {
+ clocks->dispclk_khz = dc->clk_mgr->boot_snapshot.dispclk * 1000;
+ }
}
clocks->ref_dtbclk_khz = dc->clk_mgr->bw_params->clk_table.entries[0].dtbclk_mhz * 1000;
clocks->fclk_p_state_change_support = true;
diff --git a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
index 0e4c195297a4..fe97943b9b97 100644
--- a/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
+++ b/drivers/gpu/drm/amd/include/asic_reg/mp/mp_15_0_0_offset.h
@@ -82,6 +82,24 @@
#define regMPASP_SMN_IH_SW_INT_CTRL 0x0142
#define regMPASP_SMN_IH_SW_INT_CTRL_BASE_IDX 0
+// addressBlock: mp_SmuMpASPPub_PcruDec
+// base address: 0x3800000
+#define regMPASP_PCRU1_MPASP_C2PMSG_64 0x4280
+#define regMPASP_PCRU1_MPASP_C2PMSG_64_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_65 0x4281
+#define regMPASP_PCRU1_MPASP_C2PMSG_65_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_66 0x4282
+#define regMPASP_PCRU1_MPASP_C2PMSG_66_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_67 0x4283
+#define regMPASP_PCRU1_MPASP_C2PMSG_67_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_68 0x4284
+#define regMPASP_PCRU1_MPASP_C2PMSG_68_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_69 0x4285
+#define regMPASP_PCRU1_MPASP_C2PMSG_69_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_70 0x4286
+#define regMPASP_PCRU1_MPASP_C2PMSG_70_BASE_IDX 3
+#define regMPASP_PCRU1_MPASP_C2PMSG_71 0x4287
+#define regMPASP_PCRU1_MPASP_C2PMSG_71_BASE_IDX 3
// addressBlock: mp_SmuMp1_SmnDec
// base address: 0x0
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
index e030f1e186cb..b32c053950c9 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c
@@ -2034,6 +2034,7 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
smu, SMU_DRIVER_TABLE_GPU_METRICS);
SmuMetricsExternal_t metrics_ext;
SmuMetrics_t *metrics = &metrics_ext.SmuMetrics;
+ uint32_t mp1_ver = amdgpu_ip_version(smu->adev, MP1_HWIP, 0);
int ret = 0;
ret = smu_cmn_get_metrics_table(smu,
@@ -2058,7 +2059,12 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+
+ if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) ||
+ (mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800))
+ gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ else
+ gpu_metrics->energy_accumulator = UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
index af0482c9caa7..f08cfa510a8a 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c
@@ -2065,7 +2065,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
metrics->Vcn1ActivityPercentage);
gpu_metrics->average_socket_power = metrics->AverageSocketPower;
- gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
+ gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ?
+ metrics->EnergyAccumulator : UINT_MAX;
if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD)
gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c
index bdc79140875c..862675ac5bb2 100644
--- a/drivers/gpu/drm/drm_pagemap.c
+++ b/drivers/gpu/drm/drm_pagemap.c
@@ -480,18 +480,8 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
.start = start,
.end = end,
.pgmap_owner = pagemap->owner,
- /*
- * FIXME: MIGRATE_VMA_SELECT_DEVICE_PRIVATE intermittently
- * causes 'xe_exec_system_allocator --r *race*no*' to trigger aa
- * engine reset and a hard hang due to getting stuck on a folio
- * lock. This should work and needs to be root-caused. The only
- * downside of not selecting MIGRATE_VMA_SELECT_DEVICE_PRIVATE
- * is that device-to-device migrations won’t work; instead,
- * memory will bounce through system memory. This path should be
- * rare and only occur when the madvise attributes of memory are
- * changed or atomics are being used.
- */
- .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT,
+ .flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT |
+ MIGRATE_VMA_SELECT_DEVICE_PRIVATE,
};
unsigned long i, npages = npages_in_range(start, end);
unsigned long own_pages = 0, migrated_pages = 0;
diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index 62208ffc5101..4ce1173a2e91 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1307,9 +1307,14 @@ static bool psr2_granularity_check(struct intel_crtc_state *crtc_state,
u16 sink_y_granularity = crtc_state->has_panel_replay ?
connector->dp.panel_replay_caps.su_y_granularity :
connector->dp.psr_caps.su_y_granularity;
- u16 sink_w_granularity = crtc_state->has_panel_replay ?
- connector->dp.panel_replay_caps.su_w_granularity :
- connector->dp.psr_caps.su_w_granularity;
+ u16 sink_w_granularity;
+
+ if (crtc_state->has_panel_replay)
+ sink_w_granularity = connector->dp.panel_replay_caps.su_w_granularity ==
+ DP_PANEL_REPLAY_FULL_LINE_GRANULARITY ?
+ crtc_hdisplay : connector->dp.panel_replay_caps.su_w_granularity;
+ else
+ sink_w_granularity = connector->dp.psr_caps.su_w_granularity;
/* PSR2 HW only send full lines so we only need to validate the width */
if (crtc_hdisplay % sink_w_granularity)
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 00d4530aea71..cc239492c7f0 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -1230,6 +1230,9 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg)
u8 size = msg->size;
int ret;
+ if (pm_runtime_suspended(nv_connector->base.dev->dev))
+ return -EBUSY;
+
nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
if (!nv_encoder)
return -ENODEV;
diff --git a/drivers/gpu/drm/panthor/panthor_sched.c b/drivers/gpu/drm/panthor/panthor_sched.c
index bd703a2904a1..a70f1db0764e 100644
--- a/drivers/gpu/drm/panthor/panthor_sched.c
+++ b/drivers/gpu/drm/panthor/panthor_sched.c
@@ -893,14 +893,15 @@ panthor_queue_get_syncwait_obj(struct panthor_group *group, struct panthor_queue
out_sync:
/* Make sure the CPU caches are invalidated before the seqno is read.
- * drm_gem_shmem_sync() is a NOP if map_wc=true, so no need to check
+ * panthor_gem_sync() is a NOP if map_wc=true, so no need to check
* it here.
*/
- panthor_gem_sync(&bo->base.base, queue->syncwait.offset,
+ panthor_gem_sync(&bo->base.base,
+ DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE,
+ queue->syncwait.offset,
queue->syncwait.sync64 ?
sizeof(struct panthor_syncobj_64b) :
- sizeof(struct panthor_syncobj_32b),
- DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE);
+ sizeof(struct panthor_syncobj_32b));
return queue->syncwait.kmap + queue->syncwait.offset;
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index f74a0aa85ba8..29f2b7d24fe5 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -1122,6 +1122,7 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *device)
{
struct rzg2l_mipi_dsi *dsi = host_to_rzg2l_mipi_dsi(host);
+ int bpp;
int ret;
if (device->lanes > dsi->num_data_lanes) {
@@ -1131,7 +1132,8 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
return -EINVAL;
}
- switch (mipi_dsi_pixel_format_to_bpp(device->format)) {
+ bpp = mipi_dsi_pixel_format_to_bpp(device->format);
+ switch (bpp) {
case 24:
break;
case 18:
@@ -1162,6 +1164,18 @@ static int rzg2l_mipi_dsi_host_attach(struct mipi_dsi_host *host,
drm_bridge_add(&dsi->bridge);
+ /*
+ * Report the required division ratio setting for the MIPI clock dividers.
+ *
+ * vclk * bpp = hsclk * 8 * num_lanes
+ *
+ * vclk * DSI_AB_divider = hsclk * 16
+ *
+ * which simplifies to...
+ * DSI_AB_divider = bpp * 2 / num_lanes
+ */
+ rzg2l_cpg_dsi_div_set_divider(bpp * 2 / dsi->lanes, PLL5_TARGET_DSI);
+
return 0;
}
diff --git a/drivers/gpu/drm/scheduler/sched_main.c b/drivers/gpu/drm/scheduler/sched_main.c
index e6ee35406165..2d5cb21a05b6 100644
--- a/drivers/gpu/drm/scheduler/sched_main.c
+++ b/drivers/gpu/drm/scheduler/sched_main.c
@@ -361,6 +361,7 @@ static void drm_sched_run_free_queue(struct drm_gpu_scheduler *sched)
/**
* drm_sched_job_done - complete a job
* @s_job: pointer to the job which is done
+ * @result: 0 on success, -ERRNO on error
*
* Finish the job's fence and resubmit the work items.
*/
diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
index 6ecf9e2ff61b..c77455b1834d 100644
--- a/drivers/gpu/drm/solomon/ssd130x.c
+++ b/drivers/gpu/drm/solomon/ssd130x.c
@@ -737,6 +737,7 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
unsigned int height = drm_rect_height(rect);
unsigned int line_length = DIV_ROUND_UP(width, 8);
unsigned int page_height = SSD130X_PAGE_HEIGHT;
+ u8 page_start = ssd130x->page_offset + y / page_height;
unsigned int pages = DIV_ROUND_UP(height, page_height);
struct drm_device *drm = &ssd130x->drm;
u32 array_idx = 0;
@@ -774,14 +775,11 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
*/
if (!ssd130x->page_address_mode) {
- u8 page_start;
-
/* Set address range for horizontal addressing mode */
ret = ssd130x_set_col_range(ssd130x, ssd130x->col_offset + x, width);
if (ret < 0)
return ret;
- page_start = ssd130x->page_offset + y / page_height;
ret = ssd130x_set_page_range(ssd130x, page_start, pages);
if (ret < 0)
return ret;
@@ -813,7 +811,7 @@ static int ssd130x_update_rect(struct ssd130x_device *ssd130x,
*/
if (ssd130x->page_address_mode) {
ret = ssd130x_set_page_pos(ssd130x,
- ssd130x->page_offset + i,
+ page_start + i,
ssd130x->col_offset + x);
if (ret < 0)
return ret;
diff --git a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c
index d468f8322072..f3103307b5df 100644
--- a/drivers/gpu/drm/ttm/tests/ttm_bo_test.c
+++ b/drivers/gpu/drm/ttm/tests/ttm_bo_test.c
@@ -222,13 +222,13 @@ static void ttm_bo_reserve_interrupted(struct kunit *test)
KUNIT_FAIL(test, "Couldn't create ttm bo reserve task\n");
/* Take a lock so the threaded reserve has to wait */
- mutex_lock(&bo->base.resv->lock.base);
+ dma_resv_lock(bo->base.resv, NULL);
wake_up_process(task);
msleep(20);
err = kthread_stop(task);
- mutex_unlock(&bo->base.resv->lock.base);
+ dma_resv_unlock(bo->base.resv);
KUNIT_ASSERT_EQ(test, err, -ERESTARTSYS);
}
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index acb9197db879..0765d69423d2 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -1107,8 +1107,7 @@ struct ttm_bo_swapout_walk {
static s64
ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
{
- struct ttm_resource *res = bo->resource;
- struct ttm_place place = { .mem_type = res->mem_type };
+ struct ttm_place place = { .mem_type = bo->resource->mem_type };
struct ttm_bo_swapout_walk *swapout_walk =
container_of(walk, typeof(*swapout_walk), walk);
struct ttm_operation_ctx *ctx = walk->arg.ctx;
@@ -1148,7 +1147,7 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
/*
* Move to system cached
*/
- if (res->mem_type != TTM_PL_SYSTEM) {
+ if (bo->resource->mem_type != TTM_PL_SYSTEM) {
struct ttm_resource *evict_mem;
struct ttm_place hop;
@@ -1180,15 +1179,15 @@ ttm_bo_swapout_cb(struct ttm_lru_walk *walk, struct ttm_buffer_object *bo)
if (ttm_tt_is_populated(tt)) {
spin_lock(&bdev->lru_lock);
- ttm_resource_del_bulk_move(res, bo);
+ ttm_resource_del_bulk_move(bo->resource, bo);
spin_unlock(&bdev->lru_lock);
ret = ttm_tt_swapout(bdev, tt, swapout_walk->gfp_flags);
spin_lock(&bdev->lru_lock);
if (ret)
- ttm_resource_add_bulk_move(res, bo);
- ttm_resource_move_to_lru_tail(res);
+ ttm_resource_add_bulk_move(bo->resource, bo);
+ ttm_resource_move_to_lru_tail(bo->resource);
spin_unlock(&bdev->lru_lock);
}
diff --git a/drivers/gpu/drm/ttm/ttm_pool_internal.h b/drivers/gpu/drm/ttm/ttm_pool_internal.h
index 82c4b7e56a99..24c179fd69d1 100644
--- a/drivers/gpu/drm/ttm/ttm_pool_internal.h
+++ b/drivers/gpu/drm/ttm/ttm_pool_internal.h
@@ -17,7 +17,7 @@ static inline bool ttm_pool_uses_dma32(struct ttm_pool *pool)
return pool->alloc_flags & TTM_ALLOCATION_POOL_USE_DMA32;
}
-static inline bool ttm_pool_beneficial_order(struct ttm_pool *pool)
+static inline unsigned int ttm_pool_beneficial_order(struct ttm_pool *pool)
{
return pool->alloc_flags & 0xff;
}
diff --git a/drivers/gpu/drm/xe/xe_configfs.c b/drivers/gpu/drm/xe/xe_configfs.c
index c59b1414df22..7fd07d1280bb 100644
--- a/drivers/gpu/drm/xe/xe_configfs.c
+++ b/drivers/gpu/drm/xe/xe_configfs.c
@@ -830,6 +830,7 @@ static void xe_config_device_release(struct config_item *item)
mutex_destroy(&dev->lock);
+ kfree(dev->config.ctx_restore_mid_bb[0].cs);
kfree(dev->config.ctx_restore_post_bb[0].cs);
kfree(dev);
}
diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c
index 0ddae7fcfc97..8ecdf949f9e4 100644
--- a/drivers/gpu/drm/xe/xe_exec_queue.c
+++ b/drivers/gpu/drm/xe/xe_exec_queue.c
@@ -266,6 +266,16 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe,
return q;
}
+static void __xe_exec_queue_fini(struct xe_exec_queue *q)
+{
+ int i;
+
+ q->ops->fini(q);
+
+ for (i = 0; i < q->width; ++i)
+ xe_lrc_put(q->lrc[i]);
+}
+
static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
{
int i, err;
@@ -320,21 +330,10 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags)
return 0;
err_lrc:
- for (i = i - 1; i >= 0; --i)
- xe_lrc_put(q->lrc[i]);
+ __xe_exec_queue_fini(q);
return err;
}
-static void __xe_exec_queue_fini(struct xe_exec_queue *q)
-{
- int i;
-
- q->ops->fini(q);
-
- for (i = 0; i < q->width; ++i)
- xe_lrc_put(q->lrc[i]);
-}
-
struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *vm,
u32 logical_mask, u16 width,
struct xe_hw_engine *hwe, u32 flags,
diff --git a/drivers/gpu/drm/xe/xe_gsc_proxy.c b/drivers/gpu/drm/xe/xe_gsc_proxy.c
index 42438b21f235..707db650a2ae 100644
--- a/drivers/gpu/drm/xe/xe_gsc_proxy.c
+++ b/drivers/gpu/drm/xe/xe_gsc_proxy.c
@@ -435,15 +435,11 @@ static int proxy_channel_alloc(struct xe_gsc *gsc)
return 0;
}
-static void xe_gsc_proxy_remove(void *arg)
+static void xe_gsc_proxy_stop(struct xe_gsc *gsc)
{
- struct xe_gsc *gsc = arg;
struct xe_gt *gt = gsc_to_gt(gsc);
struct xe_device *xe = gt_to_xe(gt);
- if (!gsc->proxy.component_added)
- return;
-
/* disable HECI2 IRQs */
scoped_guard(xe_pm_runtime, xe) {
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);
@@ -455,6 +451,30 @@ static void xe_gsc_proxy_remove(void *arg)
}
xe_gsc_wait_for_worker_completion(gsc);
+ gsc->proxy.started = false;
+}
+
+static void xe_gsc_proxy_remove(void *arg)
+{
+ struct xe_gsc *gsc = arg;
+ struct xe_gt *gt = gsc_to_gt(gsc);
+ struct xe_device *xe = gt_to_xe(gt);
+
+ if (!gsc->proxy.component_added)
+ return;
+
+ /*
+ * GSC proxy start is an async process that can be ongoing during
+ * Xe module load/unload. Using devm managed action to register
+ * xe_gsc_proxy_stop could cause issues if Xe module unload has
+ * already started when the action is registered, potentially leading
+ * to the cleanup being called at the wrong time. Therefore, instead
+ * of registering a separate devm action to undo what is done in
+ * proxy start, we call it from here, but only if the start has
+ * completed successfully (tracked with the 'started' flag).
+ */
+ if (gsc->proxy.started)
+ xe_gsc_proxy_stop(gsc);
component_del(xe->drm.dev, &xe_gsc_proxy_component_ops);
gsc->proxy.component_added = false;
@@ -510,6 +530,7 @@ int xe_gsc_proxy_init(struct xe_gsc *gsc)
*/
int xe_gsc_proxy_start(struct xe_gsc *gsc)
{
+ struct xe_gt *gt = gsc_to_gt(gsc);
int err;
/* enable the proxy interrupt in the GSC shim layer */
@@ -521,12 +542,18 @@ int xe_gsc_proxy_start(struct xe_gsc *gsc)
*/
err = xe_gsc_proxy_request_handler(gsc);
if (err)
- return err;
+ goto err_irq_disable;
if (!xe_gsc_proxy_init_done(gsc)) {
- xe_gt_err(gsc_to_gt(gsc), "GSC FW reports proxy init not completed\n");
- return -EIO;
+ xe_gt_err(gt, "GSC FW reports proxy init not completed\n");
+ err = -EIO;
+ goto err_irq_disable;
}
+ gsc->proxy.started = true;
return 0;
+
+err_irq_disable:
+ gsc_proxy_irq_toggle(gsc, false);
+ return err;
}
diff --git a/drivers/gpu/drm/xe/xe_gsc_types.h b/drivers/gpu/drm/xe/xe_gsc_types.h
index 97c056656df0..5aaa2a75861f 100644
--- a/drivers/gpu/drm/xe/xe_gsc_types.h
+++ b/drivers/gpu/drm/xe/xe_gsc_types.h
@@ -58,6 +58,8 @@ struct xe_gsc {
struct mutex mutex;
/** @proxy.component_added: whether the component has been added */
bool component_added;
+ /** @proxy.started: whether the proxy has been started */
+ bool started;
/** @proxy.bo: object to store message to and from the GSC */
struct xe_bo *bo;
/** @proxy.to_gsc: map of the memory used to send messages to the GSC */
diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h
index c307a3fd9ea2..c1c615447c85 100644
--- a/drivers/gpu/drm/xe/xe_lrc.h
+++ b/drivers/gpu/drm/xe/xe_lrc.h
@@ -75,7 +75,8 @@ static inline struct xe_lrc *xe_lrc_get(struct xe_lrc *lrc)
*/
static inline void xe_lrc_put(struct xe_lrc *lrc)
{
- kref_put(&lrc->refcount, xe_lrc_destroy);
+ if (lrc)
+ kref_put(&lrc->refcount, xe_lrc_destroy);
}
/**
diff --git a/drivers/gpu/drm/xe/xe_reg_sr.c b/drivers/gpu/drm/xe/xe_reg_sr.c
index 2e5c78940b41..a07be161cfa2 100644
--- a/drivers/gpu/drm/xe/xe_reg_sr.c
+++ b/drivers/gpu/drm/xe/xe_reg_sr.c
@@ -98,10 +98,12 @@ int xe_reg_sr_add(struct xe_reg_sr *sr,
*pentry = *e;
ret = xa_err(xa_store(&sr->xa, idx, pentry, GFP_KERNEL));
if (ret)
- goto fail;
+ goto fail_free;
return 0;
+fail_free:
+ kfree(pentry);
fail:
xe_gt_err(gt,
"discarding save-restore reg %04lx (clear: %08x, set: %08x, masked: %s, mcr: %s): ret=%d\n",
diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c
index 248620b0901d..53d420d72164 100644
--- a/drivers/gpu/drm/xe/xe_ring_ops.c
+++ b/drivers/gpu/drm/xe/xe_ring_ops.c
@@ -280,6 +280,9 @@ static void __emit_job_gen12_simple(struct xe_sched_job *job, struct xe_lrc *lrc
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
if (job->user_fence.used) {
i = emit_flush_dw(dw, i);
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
@@ -345,6 +348,9 @@ static void __emit_job_gen12_video(struct xe_sched_job *job, struct xe_lrc *lrc,
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
if (job->user_fence.used) {
i = emit_flush_dw(dw, i);
i = emit_store_imm_ppgtt_posted(job->user_fence.addr,
@@ -397,6 +403,9 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job,
i = emit_bb_start(batch_addr, ppgtt_flag, dw, i);
+ /* Don't preempt fence signaling */
+ dw[i++] = MI_ARB_ON_OFF | MI_ARB_DISABLE;
+
i = emit_render_cache_flush(job, dw, i);
if (job->user_fence.used)
diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c
index 95bf53cc29e3..bc39a9a9790c 100644
--- a/drivers/gpu/drm/xe/xe_vm_madvise.c
+++ b/drivers/gpu/drm/xe/xe_vm_madvise.c
@@ -453,7 +453,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
madvise_range.num_vmas,
args->atomic.val)) {
err = -EINVAL;
- goto madv_fini;
+ goto free_vmas;
}
}
@@ -490,6 +490,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil
err_fini:
if (madvise_range.has_bo_vmas)
drm_exec_fini(&exec);
+free_vmas:
kfree(madvise_range.vmas);
madvise_range.vmas = NULL;
madv_fini:
diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c
index c7b1bd79ab17..462c2fa712e0 100644
--- a/drivers/gpu/drm/xe/xe_wa.c
+++ b/drivers/gpu/drm/xe/xe_wa.c
@@ -241,12 +241,13 @@ static const struct xe_rtp_entry_sr gt_was[] = {
{ XE_RTP_NAME("16025250150"),
XE_RTP_RULES(GRAPHICS_VERSION(2001)),
- XE_RTP_ACTIONS(SET(LSN_VC_REG2,
- LSN_LNI_WGT(1) |
- LSN_LNE_WGT(1) |
- LSN_DIM_X_WGT(1) |
- LSN_DIM_Y_WGT(1) |
- LSN_DIM_Z_WGT(1)))
+ XE_RTP_ACTIONS(FIELD_SET(LSN_VC_REG2,
+ LSN_LNI_WGT_MASK | LSN_LNE_WGT_MASK |
+ LSN_DIM_X_WGT_MASK | LSN_DIM_Y_WGT_MASK |
+ LSN_DIM_Z_WGT_MASK,
+ LSN_LNI_WGT(1) | LSN_LNE_WGT(1) |
+ LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) |
+ LSN_DIM_Z_WGT(1)))
},
/* Xe2_HPM */
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index b949b767cf08..fc5897a6bb53 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -365,6 +365,9 @@ static const struct apple_non_apple_keyboard non_apple_keyboards[] = {
{ "A3R" },
{ "hfd.cn" },
{ "WKB603" },
+ { "TH87" }, /* EPOMAKER TH87 BT mode */
+ { "HFD Epomaker TH87" }, /* EPOMAKER TH87 USB mode */
+ { "2.4G Wireless Receiver" }, /* EPOMAKER TH87 dongle */
};
static bool apple_is_non_apple_keyboard(struct hid_device *hdev)
@@ -686,9 +689,7 @@ static const __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
hid_info(hdev,
"fixing up Magic Keyboard battery report descriptor\n");
*rsize = *rsize - 1;
- rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ rdesc = rdesc + 1;
rdesc[0] = 0x05;
rdesc[1] = 0x01;
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c
index 8ffcd12038e8..687b785e2d0c 100644
--- a/drivers/hid/hid-asus.c
+++ b/drivers/hid/hid-asus.c
@@ -1399,14 +1399,21 @@ static const __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
if (*rsize == rsize_orig &&
rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
- *rsize = rsize_orig + 1;
- rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ __u8 *new_rdesc;
+
+ new_rdesc = devm_kzalloc(&hdev->dev, rsize_orig + 1,
+ GFP_KERNEL);
+ if (!new_rdesc)
+ return rdesc;
hid_info(hdev, "Fixing up %s keyb report descriptor\n",
drvdata->quirks & QUIRK_T100CHI ?
"T100CHI" : "T90CHI");
+
+ memcpy(new_rdesc, rdesc, rsize_orig);
+ *rsize = rsize_orig + 1;
+ rdesc = new_rdesc;
+
memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
rdesc[offs] = 0x19;
rdesc[offs + 1] = 0x00;
@@ -1491,6 +1498,9 @@ static const struct hid_device_id asus_devices[] = {
USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD | QUIRK_ROG_ALLY_XPAD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
+ USB_DEVICE_ID_ASUSTEK_XGM_2023),
+ },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
QUIRK_ROG_CLAYMORE_II_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c
index 6bc50df9b3e1..7b3dd4197875 100644
--- a/drivers/hid/hid-cmedia.c
+++ b/drivers/hid/hid-cmedia.c
@@ -99,7 +99,7 @@ static int cmhid_raw_event(struct hid_device *hid, struct hid_report *report,
{
struct cmhid *cm = hid_get_drvdata(hid);
- if (len != CM6533_JD_RAWEV_LEN)
+ if (len != CM6533_JD_RAWEV_LEN || !(hid->claimed & HID_CLAIMED_INPUT))
goto out;
if (memcmp(data+CM6533_JD_SFX_OFFSET, ji_sfx, sizeof(ji_sfx)))
goto out;
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
index b4c8e7a5d3e0..dfd6add353d1 100644
--- a/drivers/hid/hid-creative-sb0540.c
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -153,7 +153,7 @@ static int creative_sb0540_raw_event(struct hid_device *hid,
u64 code, main_code;
int key;
- if (len != 6)
+ if (len != 6 || !(hid->claimed & HID_CLAIMED_INPUT))
return 0;
/* From daemons/hw_hiddev.c sb0540_rec() in lirc */
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3e299a30dcde..4ab7640b119a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -229,6 +229,7 @@
#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X 0x1b4c
#define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b
#define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869
+#define USB_DEVICE_ID_ASUSTEK_XGM_2023 0x1a9a
#define USB_VENDOR_ID_ATEN 0x0557
#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 91f621ceb924..9eadf3252d0d 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -990,13 +990,11 @@ static const __u8 *magicmouse_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*/
if ((is_usb_magicmouse2(hdev->vendor, hdev->product) ||
is_usb_magictrackpad2(hdev->vendor, hdev->product)) &&
- *rsize == 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
+ *rsize >= 83 && rdesc[46] == 0x84 && rdesc[58] == 0x85) {
hid_info(hdev,
"fixing up magicmouse battery report descriptor\n");
*rsize = *rsize - 1;
- rdesc = kmemdup(rdesc + 1, *rsize, GFP_KERNEL);
- if (!rdesc)
- return NULL;
+ rdesc = rdesc + 1;
rdesc[0] = 0x05;
rdesc[1] = 0x01;
diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c
index 33603b019f97..ef3b5c77c38e 100644
--- a/drivers/hid/hid-mcp2221.c
+++ b/drivers/hid/hid-mcp2221.c
@@ -353,6 +353,8 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp,
usleep_range(90, 100);
retries++;
} else {
+ usleep_range(980, 1000);
+ mcp_cancel_last_cmd(mcp);
return ret;
}
} else {
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 7daa8f6d8187..b8a748bbf0fd 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -77,6 +77,7 @@ MODULE_LICENSE("GPL");
#define MT_QUIRK_ORIENTATION_INVERT BIT(22)
#define MT_QUIRK_APPLE_TOUCHBAR BIT(23)
#define MT_QUIRK_YOGABOOK9I BIT(24)
+#define MT_QUIRK_KEEP_LATENCY_ON_CLOSE BIT(25)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -214,6 +215,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016
#define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017
#define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018
+#define MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE 0x0019
/* vendor specific classes */
#define MT_CLS_3M 0x0101
@@ -233,6 +235,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_SMART_TECH 0x0113
#define MT_CLS_APPLE_TOUCHBAR 0x0114
#define MT_CLS_YOGABOOK9I 0x0115
+#define MT_CLS_EGALAX_P80H84 0x0116
#define MT_CLS_SIS 0x0457
#define MT_DEFAULT_MAXCONTACT 10
@@ -334,6 +337,15 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_WIN8_PTP_BUTTONS,
.export_all_inputs = true },
+ { .name = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_HOVERING |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_STICKY_FINGERS |
+ MT_QUIRK_WIN8_PTP_BUTTONS |
+ MT_QUIRK_KEEP_LATENCY_ON_CLOSE,
+ .export_all_inputs = true },
/*
* vendor specific classes
@@ -438,6 +450,11 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_YOGABOOK9I,
.export_all_inputs = true
},
+ { .name = MT_CLS_EGALAX_P80H84,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_CONTACT_CNT_ACCURATE,
+ },
{ }
};
@@ -849,7 +866,8 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
if ((cls->name == MT_CLS_WIN_8 ||
cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT ||
cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU ||
- cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP) &&
+ cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP ||
+ cls->name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE) &&
(field->application == HID_DG_TOUCHPAD ||
field->application == HID_DG_TOUCHSCREEN))
app->quirks |= MT_QUIRK_CONFIDENCE;
@@ -1762,7 +1780,8 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
int ret;
if (td->is_haptic_touchpad && (td->mtclass.name == MT_CLS_WIN_8 ||
- td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT)) {
+ td->mtclass.name == MT_CLS_WIN_8_FORCE_MULTI_INPUT ||
+ td->mtclass.name == MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE)) {
if (hid_haptic_input_configured(hdev, td->haptic, hi) == 0)
td->is_haptic_touchpad = false;
} else {
@@ -2075,7 +2094,12 @@ static void mt_on_hid_hw_open(struct hid_device *hdev)
static void mt_on_hid_hw_close(struct hid_device *hdev)
{
- mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE);
+ struct mt_device *td = hid_get_drvdata(hdev);
+
+ if (td->mtclass.quirks & MT_QUIRK_KEEP_LATENCY_ON_CLOSE)
+ mt_set_modes(hdev, HID_LATENCY_NORMAL, TOUCHPAD_REPORT_NONE);
+ else
+ mt_set_modes(hdev, HID_LATENCY_HIGH, TOUCHPAD_REPORT_NONE);
}
/*
@@ -2215,8 +2239,9 @@ static const struct hid_device_id mt_devices[] = {
{ .driver_data = MT_CLS_EGALAX_SERIAL,
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C000) },
- { .driver_data = MT_CLS_EGALAX,
- MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ { .driver_data = MT_CLS_EGALAX_P80H84,
+ HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_DWAV,
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
/* Elan devices */
@@ -2461,6 +2486,14 @@ static const struct hid_device_id mt_devices[] = {
MT_USB_DEVICE(USB_VENDOR_ID_UNITEC,
USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) },
+ /* Uniwill touchpads */
+ { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_PIXART, 0x0255) },
+ { .driver_data = MT_CLS_WIN_8_KEEP_LATENCY_ON_CLOSE,
+ HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
+ USB_VENDOR_ID_PIXART, 0x0274) },
+
/* VTL panels */
{ .driver_data = MT_CLS_VTL,
MT_USB_DEVICE(USB_VENDOR_ID_VTL,
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index 3bdb26f45592..1aae80f848f5 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -114,7 +114,7 @@ static int zc_raw_event(struct hid_device *hdev, struct hid_report *report,
unsigned key;
unsigned short index;
- if (report->id == data[0]) {
+ if (report->id == data[0] && (hdev->claimed & HID_CLAIMED_INPUT)) {
/* break keys */
for (index = 0; index < 4; index++) {
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
index fa5d68c36313..27389971b96c 100644
--- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -39,6 +39,8 @@
#define PCI_DEVICE_ID_INTEL_ISH_PTL_H 0xE345
#define PCI_DEVICE_ID_INTEL_ISH_PTL_P 0xE445
#define PCI_DEVICE_ID_INTEL_ISH_WCL 0x4D45
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_H 0xD354
+#define PCI_DEVICE_ID_INTEL_ISH_NVL_S 0x6E78
#define REVISION_ID_CHT_A0 0x6
#define REVISION_ID_CHT_Ax_SI 0x0
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 1612e8cb23f0..ed3405c05e73 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -28,11 +28,15 @@ enum ishtp_driver_data_index {
ISHTP_DRIVER_DATA_LNL_M,
ISHTP_DRIVER_DATA_PTL,
ISHTP_DRIVER_DATA_WCL,
+ ISHTP_DRIVER_DATA_NVL_H,
+ ISHTP_DRIVER_DATA_NVL_S,
};
#define ISH_FW_GEN_LNL_M "lnlm"
#define ISH_FW_GEN_PTL "ptl"
#define ISH_FW_GEN_WCL "wcl"
+#define ISH_FW_GEN_NVL_H "nvlh"
+#define ISH_FW_GEN_NVL_S "nvls"
#define ISH_FIRMWARE_PATH(gen) "intel/ish/ish_" gen ".bin"
#define ISH_FIRMWARE_PATH_ALL "intel/ish/ish_*.bin"
@@ -47,6 +51,12 @@ static struct ishtp_driver_data ishtp_driver_data[] = {
[ISHTP_DRIVER_DATA_WCL] = {
.fw_generation = ISH_FW_GEN_WCL,
},
+ [ISHTP_DRIVER_DATA_NVL_H] = {
+ .fw_generation = ISH_FW_GEN_NVL_H,
+ },
+ [ISHTP_DRIVER_DATA_NVL_S] = {
+ .fw_generation = ISH_FW_GEN_NVL_S,
+ },
};
static const struct pci_device_id ish_pci_tbl[] = {
@@ -76,6 +86,8 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE_DATA(INTEL, ISH_PTL_H, ISHTP_DRIVER_DATA_PTL)},
{PCI_DEVICE_DATA(INTEL, ISH_PTL_P, ISHTP_DRIVER_DATA_PTL)},
{PCI_DEVICE_DATA(INTEL, ISH_WCL, ISHTP_DRIVER_DATA_WCL)},
+ {PCI_DEVICE_DATA(INTEL, ISH_NVL_H, ISHTP_DRIVER_DATA_NVL_H)},
+ {PCI_DEVICE_DATA(INTEL, ISH_NVL_S, ISHTP_DRIVER_DATA_NVL_S)},
{}
};
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index fdcf03408f47..fbf3dbc92e66 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -1452,10 +1452,13 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
hid_warn(pidff->hid, "unknown ramp effect layout\n");
if (PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- if (test_and_clear_bit(FF_SPRING, dev->ffbit) ||
- test_and_clear_bit(FF_DAMPER, dev->ffbit) ||
- test_and_clear_bit(FF_FRICTION, dev->ffbit) ||
- test_and_clear_bit(FF_INERTIA, dev->ffbit))
+ bool test = false;
+
+ test |= test_and_clear_bit(FF_SPRING, dev->ffbit);
+ test |= test_and_clear_bit(FF_DAMPER, dev->ffbit);
+ test |= test_and_clear_bit(FF_FRICTION, dev->ffbit);
+ test |= test_and_clear_bit(FF_INERTIA, dev->ffbit);
+ if (test)
hid_warn(pidff->hid, "unknown condition effect layout\n");
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 41c381764c2b..486152a8ea77 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1927,16 +1927,6 @@ config SENSORS_RASPBERRYPI_HWMON
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
-config SENSORS_SA67MCU
- tristate "Kontron sa67mcu hardware monitoring driver"
- depends on MFD_SL28CPLD || COMPILE_TEST
- help
- If you say yes here you get support for the voltage and temperature
- monitor of the sa67 board management controller.
-
- This driver can also be built as a module. If so, the module
- will be called sa67mcu-hwmon.
-
config SENSORS_SL28CPLD
tristate "Kontron sl28cpld hardware monitoring driver"
depends on MFD_SL28CPLD || COMPILE_TEST
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index eade8e3b1bde..5833c807c688 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -199,7 +199,6 @@ obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
-obj-$(CONFIG_SENSORS_SA67MCU) += sa67mcu-hwmon.o
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
diff --git a/drivers/hwmon/aht10.c b/drivers/hwmon/aht10.c
index 007befdba977..4ce019d2cc80 100644
--- a/drivers/hwmon/aht10.c
+++ b/drivers/hwmon/aht10.c
@@ -37,7 +37,9 @@
#define AHT10_CMD_MEAS 0b10101100
#define AHT10_CMD_RST 0b10111010
-#define DHT20_CMD_INIT 0x71
+#define AHT20_CMD_INIT 0b10111110
+
+#define DHT20_CMD_INIT 0b01110001
/*
* Flags in the answer byte/command
@@ -341,7 +343,7 @@ static int aht10_probe(struct i2c_client *client)
data->meas_size = AHT20_MEAS_SIZE;
data->crc8 = true;
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
- data->init_cmd = AHT10_CMD_INIT;
+ data->init_cmd = AHT20_CMD_INIT;
break;
case dht20:
data->meas_size = AHT20_MEAS_SIZE;
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e233aafa8856..5cfb98a0512f 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -3590,10 +3590,13 @@ static int it87_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct it87_data *data = dev_get_drvdata(dev);
+ int err;
it87_resume_sio(pdev);
- it87_lock(data);
+ err = it87_lock(data);
+ if (err)
+ return err;
it87_check_pwm(dev);
it87_check_limit_regs(data);
diff --git a/drivers/hwmon/macsmc-hwmon.c b/drivers/hwmon/macsmc-hwmon.c
index 1c0bbec7e8eb..1500ec2cc9f8 100644
--- a/drivers/hwmon/macsmc-hwmon.c
+++ b/drivers/hwmon/macsmc-hwmon.c
@@ -22,6 +22,7 @@
#include <linux/bitfield.h>
#include <linux/hwmon.h>
+#include <linux/math64.h>
#include <linux/mfd/macsmc.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -130,7 +131,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
if (ret < 0)
return ret;
- *p = mult_frac(val, scale, 65536);
+ *p = mul_u64_u32_div(val, scale, 65536);
return 0;
}
@@ -140,7 +141,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
* them.
*/
static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
- int *p, int scale)
+ long *p, int scale)
{
u32 fval;
u64 val;
@@ -162,21 +163,21 @@ static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
val = 0;
else if (exp < 0)
val >>= -exp;
- else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
+ else if (exp != 0 && (val & ~((1ULL << (64 - exp)) - 1))) /* overflow */
val = U64_MAX;
else
val <<= exp;
if (fval & FLT_SIGN_MASK) {
- if (val > (-(s64)INT_MIN))
- *p = INT_MIN;
+ if (val > (u64)LONG_MAX + 1)
+ *p = LONG_MIN;
else
- *p = -val;
+ *p = -(long)val;
} else {
- if (val > INT_MAX)
- *p = INT_MAX;
+ if (val > (u64)LONG_MAX)
+ *p = LONG_MAX;
else
- *p = val;
+ *p = (long)val;
}
return 0;
@@ -195,7 +196,7 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
switch (sensor->info.type_code) {
/* 32-bit IEEE 754 float */
case __SMC_KEY('f', 'l', 't', ' '): {
- u32 flt_ = 0;
+ long flt_ = 0;
ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
&flt_, scale);
@@ -214,7 +215,10 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
if (ret)
return ret;
- *val = (long)ioft;
+ if (ioft > LONG_MAX)
+ *val = LONG_MAX;
+ else
+ *val = (long)ioft;
break;
}
default:
@@ -224,29 +228,26 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
return 0;
}
-static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
+static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, long value)
{
u64 val;
u32 fval = 0;
- int exp = 0, neg;
+ int exp, neg;
+ neg = value < 0;
val = abs(value);
- neg = val != value;
if (val) {
- int msb = __fls(val) - exp;
-
- if (msb > 23) {
- val >>= msb - FLT_MANT_BIAS;
- exp -= msb - FLT_MANT_BIAS;
- } else if (msb < 23) {
- val <<= FLT_MANT_BIAS - msb;
- exp += msb;
- }
+ exp = __fls(val);
+
+ if (exp > 23)
+ val >>= exp - 23;
+ else
+ val <<= 23 - exp;
fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
- FIELD_PREP(FLT_MANT_MASK, val);
+ FIELD_PREP(FLT_MANT_MASK, val & FLT_MANT_MASK);
}
return apple_smc_write_u32(smc, key, fval);
@@ -663,8 +664,8 @@ static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
if (!hwmon->volt.sensors)
return -ENOMEM;
- for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
- sensor = &hwmon->temp.sensors[hwmon->temp.count];
+ for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
+ sensor = &hwmon->volt.sensors[hwmon->volt.count];
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
sensor->attrs = HWMON_I_INPUT;
diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c
index a0a1dbbda887..9a3c515efe2e 100644
--- a/drivers/hwmon/max6639.c
+++ b/drivers/hwmon/max6639.c
@@ -607,7 +607,7 @@ static int max6639_init_client(struct i2c_client *client,
return err;
/* Fans PWM polarity high by default */
- err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
+ err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
if (err)
return err;
diff --git a/drivers/hwmon/pmbus/q54sj108a2.c b/drivers/hwmon/pmbus/q54sj108a2.c
index fc030ca34480..d5d60a9af8c5 100644
--- a/drivers/hwmon/pmbus/q54sj108a2.c
+++ b/drivers/hwmon/pmbus/q54sj108a2.c
@@ -79,7 +79,8 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
int idx = *idxp;
struct q54sj108a2_data *psu = to_psu(idxp, idx);
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
- char data_char[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
+ char data_char[I2C_SMBUS_BLOCK_MAX * 2 + 2] = { 0 };
+ char *out = data;
char *res;
switch (idx) {
@@ -150,27 +151,27 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
if (rc < 0)
return rc;
- res = bin2hex(data, data_char, 32);
- rc = res - data;
-
+ res = bin2hex(data_char, data, rc);
+ rc = res - data_char;
+ out = data_char;
break;
case Q54SJ108A2_DEBUGFS_FLASH_KEY:
rc = i2c_smbus_read_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, data);
if (rc < 0)
return rc;
- res = bin2hex(data, data_char, 4);
- rc = res - data;
-
+ res = bin2hex(data_char, data, rc);
+ rc = res - data_char;
+ out = data_char;
break;
default:
return -EINVAL;
}
- data[rc] = '\n';
+ out[rc] = '\n';
rc += 2;
- return simple_read_from_buffer(buf, count, ppos, data, rc);
+ return simple_read_from_buffer(buf, count, ppos, out, rc);
}
static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,
diff --git a/drivers/hwmon/sa67mcu-hwmon.c b/drivers/hwmon/sa67mcu-hwmon.c
deleted file mode 100644
index 22f703b7b256..000000000000
--- a/drivers/hwmon/sa67mcu-hwmon.c
+++ /dev/null
@@ -1,161 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * sl67mcu hardware monitoring driver
- *
- * Copyright 2025 Kontron Europe GmbH
- */
-
-#include <linux/bitfield.h>
-#include <linux/hwmon.h>
-#include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/property.h>
-#include <linux/regmap.h>
-
-#define SA67MCU_VOLTAGE(n) (0x00 + ((n) * 2))
-#define SA67MCU_TEMP(n) (0x04 + ((n) * 2))
-
-struct sa67mcu_hwmon {
- struct regmap *regmap;
- u32 offset;
-};
-
-static int sa67mcu_hwmon_read(struct device *dev,
- enum hwmon_sensor_types type, u32 attr,
- int channel, long *input)
-{
- struct sa67mcu_hwmon *hwmon = dev_get_drvdata(dev);
- unsigned int offset;
- u8 reg[2];
- int ret;
-
- switch (type) {
- case hwmon_in:
- switch (attr) {
- case hwmon_in_input:
- offset = hwmon->offset + SA67MCU_VOLTAGE(channel);
- break;
- default:
- return -EOPNOTSUPP;
- }
- break;
- case hwmon_temp:
- switch (attr) {
- case hwmon_temp_input:
- offset = hwmon->offset + SA67MCU_TEMP(channel);
- break;
- default:
- return -EOPNOTSUPP;
- }
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- /* Reading the low byte will capture the value */
- ret = regmap_bulk_read(hwmon->regmap, offset, reg, ARRAY_SIZE(reg));
- if (ret)
- return ret;
-
- *input = reg[1] << 8 | reg[0];
-
- /* Temperatures are s16 and in 0.1degC steps. */
- if (type == hwmon_temp)
- *input = sign_extend32(*input, 15) * 100;
-
- return 0;
-}
-
-static const struct hwmon_channel_info * const sa67mcu_hwmon_info[] = {
- HWMON_CHANNEL_INFO(in,
- HWMON_I_INPUT | HWMON_I_LABEL,
- HWMON_I_INPUT | HWMON_I_LABEL),
- HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
- NULL
-};
-
-static const char *const sa67mcu_hwmon_in_labels[] = {
- "VDDIN",
- "VDD_RTC",
-};
-
-static int sa67mcu_hwmon_read_string(struct device *dev,
- enum hwmon_sensor_types type, u32 attr,
- int channel, const char **str)
-{
- switch (type) {
- case hwmon_in:
- switch (attr) {
- case hwmon_in_label:
- *str = sa67mcu_hwmon_in_labels[channel];
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static const struct hwmon_ops sa67mcu_hwmon_ops = {
- .visible = 0444,
- .read = sa67mcu_hwmon_read,
- .read_string = sa67mcu_hwmon_read_string,
-};
-
-static const struct hwmon_chip_info sa67mcu_hwmon_chip_info = {
- .ops = &sa67mcu_hwmon_ops,
- .info = sa67mcu_hwmon_info,
-};
-
-static int sa67mcu_hwmon_probe(struct platform_device *pdev)
-{
- struct sa67mcu_hwmon *hwmon;
- struct device *hwmon_dev;
- int ret;
-
- if (!pdev->dev.parent)
- return -ENODEV;
-
- hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
- if (!hwmon)
- return -ENOMEM;
-
- hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!hwmon->regmap)
- return -ENODEV;
-
- ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset);
- if (ret)
- return -EINVAL;
-
- hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
- "sa67mcu_hwmon", hwmon,
- &sa67mcu_hwmon_chip_info,
- NULL);
- if (IS_ERR(hwmon_dev))
- dev_err(&pdev->dev, "failed to register as hwmon device");
-
- return PTR_ERR_OR_ZERO(hwmon_dev);
-}
-
-static const struct of_device_id sa67mcu_hwmon_of_match[] = {
- { .compatible = "kontron,sa67mcu-hwmon", },
- {}
-};
-MODULE_DEVICE_TABLE(of, sa67mcu_hwmon_of_match);
-
-static struct platform_driver sa67mcu_hwmon_driver = {
- .probe = sa67mcu_hwmon_probe,
- .driver = {
- .name = "sa67mcu-hwmon",
- .of_match_table = sa67mcu_hwmon_of_match,
- },
-};
-module_platform_driver(sa67mcu_hwmon_driver);
-
-MODULE_DESCRIPTION("sa67mcu Hardware Monitoring Driver");
-MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 9e1789725edf..32a3cef02c7b 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -310,9 +310,10 @@ struct i801_priv {
/*
* If set to true the host controller registers are reserved for
- * ACPI AML use.
+ * ACPI AML use. Needs extra protection by acpi_lock.
*/
bool acpi_reserved;
+ struct mutex acpi_lock;
};
#define FEATURE_SMBUS_PEC BIT(0)
@@ -894,8 +895,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,
int hwpec, ret;
struct i801_priv *priv = i2c_get_adapdata(adap);
- if (priv->acpi_reserved)
+ mutex_lock(&priv->acpi_lock);
+ if (priv->acpi_reserved) {
+ mutex_unlock(&priv->acpi_lock);
return -EBUSY;
+ }
pm_runtime_get_sync(&priv->pci_dev->dev);
@@ -935,6 +939,7 @@ out:
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
pm_runtime_put_autosuspend(&priv->pci_dev->dev);
+ mutex_unlock(&priv->acpi_lock);
return ret;
}
@@ -1465,7 +1470,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
* further access from the driver itself. This device is now owned
* by the system firmware.
*/
- i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT);
+ mutex_lock(&priv->acpi_lock);
if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) {
priv->acpi_reserved = true;
@@ -1485,7 +1490,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits,
else
status = acpi_os_write_port(address, (u32)*value, bits);
- i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT);
+ mutex_unlock(&priv->acpi_lock);
return status;
}
@@ -1545,6 +1550,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->adapter.dev.parent = &dev->dev;
acpi_use_parent_companion(&priv->adapter.dev);
priv->adapter.retries = 3;
+ mutex_init(&priv->acpi_lock);
priv->pci_dev = dev;
priv->features = id->driver_data;
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 8bb8dd34c223..a2159b2bc176 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -228,6 +228,9 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
unsigned char htype = p->ule_sndu_type & 0x00FF;
+ if (htype >= ARRAY_SIZE(ule_mandatory_ext_handlers))
+ return -1;
+
/* Discriminate mandatory and optional extension headers. */
if (hlen == 0) {
/* Mandatory extension header */
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a1de08ee3815..14ed91391fcc 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -324,7 +324,7 @@ static bool bond_sk_check(struct bonding *bond)
}
}
-bool bond_xdp_check(struct bonding *bond, int mode)
+bool __bond_xdp_check(int mode, int xmit_policy)
{
switch (mode) {
case BOND_MODE_ROUNDROBIN:
@@ -335,7 +335,7 @@ bool bond_xdp_check(struct bonding *bond, int mode)
/* vlan+srcmac is not supported with XDP as in most cases the 802.1q
* payload is not in the packet due to hardware offload.
*/
- if (bond->params.xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
+ if (xmit_policy != BOND_XMIT_POLICY_VLAN_SRCMAC)
return true;
fallthrough;
default:
@@ -343,6 +343,11 @@ bool bond_xdp_check(struct bonding *bond, int mode)
}
}
+bool bond_xdp_check(struct bonding *bond, int mode)
+{
+ return __bond_xdp_check(mode, bond->params.xmit_policy);
+}
+
/*---------------------------------- VLAN -----------------------------------*/
/* In the following 2 functions, bond_vlan_rx_add_vid and bond_vlan_rx_kill_vid,
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index dcee384c2f06..7380cc4ee75a 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -1575,6 +1575,8 @@ static int bond_option_fail_over_mac_set(struct bonding *bond,
static int bond_option_xmit_hash_policy_set(struct bonding *bond,
const struct bond_opt_value *newval)
{
+ if (bond->xdp_prog && !__bond_xdp_check(BOND_MODE(bond), newval->value))
+ return -EOPNOTSUPP;
netdev_dbg(bond->dev, "Setting xmit hash policy to %s (%llu)\n",
newval->string, newval->value);
bond->params.xmit_policy = newval->value;
diff --git a/drivers/net/can/dummy_can.c b/drivers/net/can/dummy_can.c
index 41953655e3d3..cd23de488edc 100644
--- a/drivers/net/can/dummy_can.c
+++ b/drivers/net/can/dummy_can.c
@@ -241,6 +241,7 @@ static int __init dummy_can_init(void)
dev->netdev_ops = &dummy_can_netdev_ops;
dev->ethtool_ops = &dummy_can_ethtool_ops;
+ dev->flags |= IFF_ECHO; /* enable echo handling */
priv = netdev_priv(dev);
priv->can.bittiming_const = &dummy_can_bittiming_const;
priv->can.bitrate_max = 20 * MEGA /* BPS */;
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index fa97adf25b73..bb7782582f40 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -1214,6 +1214,7 @@ static int mcp251x_open(struct net_device *net)
{
struct mcp251x_priv *priv = netdev_priv(net);
struct spi_device *spi = priv->spi;
+ bool release_irq = false;
unsigned long flags = 0;
int ret;
@@ -1257,12 +1258,24 @@ static int mcp251x_open(struct net_device *net)
return 0;
out_free_irq:
- free_irq(spi->irq, priv);
+ /* The IRQ handler might be running, and if so it will be waiting
+ * for the lock. But free_irq() must wait for the handler to finish
+ * so calling it here would deadlock.
+ *
+ * Setting priv->force_quit will let the handler exit right away
+ * without any access to the hardware. This make it safe to call
+ * free_irq() after the lock is released.
+ */
+ priv->force_quit = 1;
+ release_irq = true;
+
mcp251x_hw_sleep(spi);
out_close:
mcp251x_power_enable(priv->transceiver, 0);
close_candev(net);
mutex_unlock(&priv->mcp_lock);
+ if (release_irq)
+ free_irq(spi->irq, priv);
return ret;
}
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 4c219a5b139b..9b25dda7c183 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -445,6 +445,11 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start = CPC_HEADER_SIZE;
while (msg_count) {
+ if (start + CPC_MSG_HEADER_LEN > urb->actual_length) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+
msg = (struct ems_cpc_msg *)&ibuf[start];
switch (msg->type) {
@@ -474,7 +479,7 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
start += CPC_MSG_HEADER_LEN + msg->length;
msg_count--;
- if (start > urb->transfer_buffer_length) {
+ if (start > urb->actual_length) {
netdev_err(netdev, "format error\n");
break;
}
diff --git a/drivers/net/can/usb/esd_usb.c b/drivers/net/can/usb/esd_usb.c
index 2892a68f510a..d257440fa01f 100644
--- a/drivers/net/can/usb/esd_usb.c
+++ b/drivers/net/can/usb/esd_usb.c
@@ -272,6 +272,9 @@ struct esd_usb {
struct usb_anchor rx_submitted;
+ unsigned int rx_pipe;
+ unsigned int tx_pipe;
+
int net_count;
u32 version;
int rxinitdone;
@@ -537,7 +540,7 @@ static void esd_usb_read_bulk_callback(struct urb *urb)
}
resubmit_urb:
- usb_fill_bulk_urb(urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
+ usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
urb->transfer_buffer, ESD_USB_RX_BUFFER_SIZE,
esd_usb_read_bulk_callback, dev);
@@ -626,9 +629,7 @@ static int esd_usb_send_msg(struct esd_usb *dev, union esd_usb_msg *msg)
{
int actual_length;
- return usb_bulk_msg(dev->udev,
- usb_sndbulkpipe(dev->udev, 2),
- msg,
+ return usb_bulk_msg(dev->udev, dev->tx_pipe, msg,
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
&actual_length,
1000);
@@ -639,12 +640,8 @@ static int esd_usb_wait_msg(struct esd_usb *dev,
{
int actual_length;
- return usb_bulk_msg(dev->udev,
- usb_rcvbulkpipe(dev->udev, 1),
- msg,
- sizeof(*msg),
- &actual_length,
- 1000);
+ return usb_bulk_msg(dev->udev, dev->rx_pipe, msg,
+ sizeof(*msg), &actual_length, 1000);
}
static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
@@ -677,8 +674,7 @@ static int esd_usb_setup_rx_urbs(struct esd_usb *dev)
urb->transfer_dma = buf_dma;
- usb_fill_bulk_urb(urb, dev->udev,
- usb_rcvbulkpipe(dev->udev, 1),
+ usb_fill_bulk_urb(urb, dev->udev, dev->rx_pipe,
buf, ESD_USB_RX_BUFFER_SIZE,
esd_usb_read_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -903,7 +899,7 @@ static netdev_tx_t esd_usb_start_xmit(struct sk_buff *skb,
/* hnd must not be 0 - MSB is stripped in txdone handling */
msg->tx.hnd = BIT(31) | i; /* returned in TX done message */
- usb_fill_bulk_urb(urb, dev->udev, usb_sndbulkpipe(dev->udev, 2), buf,
+ usb_fill_bulk_urb(urb, dev->udev, dev->tx_pipe, buf,
msg->hdr.len * sizeof(u32), /* convert to # of bytes */
esd_usb_write_bulk_callback, context);
@@ -1298,10 +1294,16 @@ done:
static int esd_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct usb_endpoint_descriptor *ep_in, *ep_out;
struct esd_usb *dev;
union esd_usb_msg *msg;
int i, err;
+ err = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out,
+ NULL, NULL);
+ if (err)
+ return err;
+
dev = kzalloc_obj(*dev);
if (!dev) {
err = -ENOMEM;
@@ -1309,6 +1311,8 @@ static int esd_usb_probe(struct usb_interface *intf,
}
dev->udev = interface_to_usbdev(intf);
+ dev->rx_pipe = usb_rcvbulkpipe(dev->udev, ep_in->bEndpointAddress);
+ dev->tx_pipe = usb_sndbulkpipe(dev->udev, ep_out->bEndpointAddress);
init_usb_anchor(&dev->rx_submitted);
diff --git a/drivers/net/can/usb/etas_es58x/es58x_core.c b/drivers/net/can/usb/etas_es58x/es58x_core.c
index 2d248deb69dc..b259f6109808 100644
--- a/drivers/net/can/usb/etas_es58x/es58x_core.c
+++ b/drivers/net/can/usb/etas_es58x/es58x_core.c
@@ -1461,12 +1461,18 @@ static void es58x_read_bulk_callback(struct urb *urb)
}
resubmit_urb:
+ usb_anchor_urb(urb, &es58x_dev->rx_urbs);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV) {
for (i = 0; i < es58x_dev->num_can_ch; i++)
if (es58x_dev->netdev[i])
netif_device_detach(es58x_dev->netdev[i]);
- } else if (ret)
+ } else
dev_err_ratelimited(dev,
"Failed resubmitting read bulk urb: %pe\n",
ERR_PTR(ret));
diff --git a/drivers/net/can/usb/f81604.c b/drivers/net/can/usb/f81604.c
index 76578063ac82..f12318268e46 100644
--- a/drivers/net/can/usb/f81604.c
+++ b/drivers/net/can/usb/f81604.c
@@ -413,6 +413,7 @@ static void f81604_read_bulk_callback(struct urb *urb)
{
struct f81604_can_frame *frame = urb->transfer_buffer;
struct net_device *netdev = urb->context;
+ struct f81604_port_priv *priv = netdev_priv(netdev);
int ret;
if (!netif_device_present(netdev))
@@ -445,10 +446,15 @@ static void f81604_read_bulk_callback(struct urb *urb)
f81604_process_rx_packet(netdev, frame);
resubmit_urb:
+ usb_anchor_urb(urb, &priv->urbs_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV)
netif_device_detach(netdev);
- else if (ret)
+ else
netdev_err(netdev,
"%s: failed to resubmit read bulk urb: %pe\n",
__func__, ERR_PTR(ret));
@@ -620,6 +626,12 @@ static void f81604_read_int_callback(struct urb *urb)
netdev_info(netdev, "%s: Int URB aborted: %pe\n", __func__,
ERR_PTR(urb->status));
+ if (urb->actual_length < sizeof(*data)) {
+ netdev_warn(netdev, "%s: short int URB: %u < %zu\n",
+ __func__, urb->actual_length, sizeof(*data));
+ goto resubmit_urb;
+ }
+
switch (urb->status) {
case 0: /* success */
break;
@@ -646,10 +658,15 @@ static void f81604_read_int_callback(struct urb *urb)
f81604_handle_tx(priv, data);
resubmit_urb:
+ usb_anchor_urb(urb, &priv->urbs_anchor);
ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (!ret)
+ return;
+ usb_unanchor_urb(urb);
+
if (ret == -ENODEV)
netif_device_detach(netdev);
- else if (ret)
+ else
netdev_err(netdev, "%s: failed to resubmit int urb: %pe\n",
__func__, ERR_PTR(ret));
}
@@ -874,9 +891,27 @@ static void f81604_write_bulk_callback(struct urb *urb)
if (!netif_device_present(netdev))
return;
- if (urb->status)
- netdev_info(netdev, "%s: Tx URB error: %pe\n", __func__,
- ERR_PTR(urb->status));
+ if (!urb->status)
+ return;
+
+ switch (urb->status) {
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ return;
+ default:
+ break;
+ }
+
+ if (net_ratelimit())
+ netdev_err(netdev, "%s: Tx URB error: %pe\n", __func__,
+ ERR_PTR(urb->status));
+
+ can_free_echo_skb(netdev, 0, NULL);
+ netdev->stats.tx_dropped++;
+ netdev->stats.tx_errors++;
+
+ netif_wake_queue(netdev);
}
static void f81604_clear_reg_work(struct work_struct *work)
diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c
index 9d27d6f0c0b5..ec9a7cbbbc69 100644
--- a/drivers/net/can/usb/gs_usb.c
+++ b/drivers/net/can/usb/gs_usb.c
@@ -772,9 +772,8 @@ device_detach:
}
}
-static int gs_usb_set_bittiming(struct net_device *netdev)
+static int gs_usb_set_bittiming(struct gs_can *dev)
{
- struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.bittiming;
struct gs_device_bittiming dbt = {
.prop_seg = cpu_to_le32(bt->prop_seg),
@@ -791,9 +790,8 @@ static int gs_usb_set_bittiming(struct net_device *netdev)
GFP_KERNEL);
}
-static int gs_usb_set_data_bittiming(struct net_device *netdev)
+static int gs_usb_set_data_bittiming(struct gs_can *dev)
{
- struct gs_can *dev = netdev_priv(netdev);
struct can_bittiming *bt = &dev->can.fd.data_bittiming;
struct gs_device_bittiming dbt = {
.prop_seg = cpu_to_le32(bt->prop_seg),
@@ -1057,6 +1055,20 @@ static int gs_can_open(struct net_device *netdev)
if (dev->feature & GS_CAN_FEATURE_HW_TIMESTAMP)
flags |= GS_CAN_MODE_HW_TIMESTAMP;
+ rc = gs_usb_set_bittiming(dev);
+ if (rc) {
+ netdev_err(netdev, "failed to set bittiming: %pe\n", ERR_PTR(rc));
+ goto out_usb_kill_anchored_urbs;
+ }
+
+ if (ctrlmode & CAN_CTRLMODE_FD) {
+ rc = gs_usb_set_data_bittiming(dev);
+ if (rc) {
+ netdev_err(netdev, "failed to set data bittiming: %pe\n", ERR_PTR(rc));
+ goto out_usb_kill_anchored_urbs;
+ }
+ }
+
/* finally start device */
dev->can.state = CAN_STATE_ERROR_ACTIVE;
dm.flags = cpu_to_le32(flags);
@@ -1370,7 +1382,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
dev->can.state = CAN_STATE_STOPPED;
dev->can.clock.freq = le32_to_cpu(bt_const.fclk_can);
dev->can.bittiming_const = &dev->bt_const;
- dev->can.do_set_bittiming = gs_usb_set_bittiming;
dev->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
@@ -1394,7 +1405,6 @@ static struct gs_can *gs_make_candev(unsigned int channel,
* GS_CAN_FEATURE_BT_CONST_EXT is set.
*/
dev->can.fd.data_bittiming_const = &dev->bt_const;
- dev->can.fd.do_set_data_bittiming = gs_usb_set_data_bittiming;
}
if (feature & GS_CAN_FEATURE_TERMINATION) {
diff --git a/drivers/net/can/usb/ucan.c b/drivers/net/can/usb/ucan.c
index c79508b1c43e..0ea0ac75e42f 100644
--- a/drivers/net/can/usb/ucan.c
+++ b/drivers/net/can/usb/ucan.c
@@ -748,7 +748,7 @@ static void ucan_read_bulk_callback(struct urb *urb)
len = le16_to_cpu(m->len);
/* check sanity (length of content) */
- if (urb->actual_length - pos < len) {
+ if ((len == 0) || (urb->actual_length - pos < len)) {
netdev_warn(up->netdev,
"invalid message (short; no data; l:%d)\n",
urb->actual_length);
diff --git a/drivers/net/dsa/realtek/rtl8365mb.c b/drivers/net/dsa/realtek/rtl8365mb.c
index c575e164368c..f938a3f701cc 100644
--- a/drivers/net/dsa/realtek/rtl8365mb.c
+++ b/drivers/net/dsa/realtek/rtl8365mb.c
@@ -769,7 +769,7 @@ static int rtl8365mb_phy_ocp_write(struct realtek_priv *priv, int phy,
out:
rtl83xx_unlock(priv);
- return 0;
+ return ret;
}
static int rtl8365mb_phy_read(struct realtek_priv *priv, int phy, int regnum)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
index 711f295eb777..80c2c27ac9dc 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h
@@ -431,7 +431,7 @@
#define MAC_SSIR_SSINC_INDEX 16
#define MAC_SSIR_SSINC_WIDTH 8
#define MAC_TCR_SS_INDEX 29
-#define MAC_TCR_SS_WIDTH 2
+#define MAC_TCR_SS_WIDTH 3
#define MAC_TCR_TE_INDEX 0
#define MAC_TCR_TE_WIDTH 1
#define MAC_TCR_VNE_INDEX 24
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 62bb4b8a68e1..8b79d88480db 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -1120,7 +1120,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerdown\n");
@@ -1131,8 +1130,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
if (caller == XGMAC_DRIVER_CONTEXT)
netif_device_detach(netdev);
@@ -1148,8 +1145,6 @@ int xgbe_powerdown(struct net_device *netdev, unsigned int caller)
pdata->power_down = 1;
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerdown\n");
return 0;
@@ -1159,7 +1154,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
{
struct xgbe_prv_data *pdata = netdev_priv(netdev);
struct xgbe_hw_if *hw_if = &pdata->hw_if;
- unsigned long flags;
DBGPR("-->xgbe_powerup\n");
@@ -1170,8 +1164,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
return -EINVAL;
}
- spin_lock_irqsave(&pdata->lock, flags);
-
pdata->power_down = 0;
xgbe_napi_enable(pdata, 0);
@@ -1186,8 +1178,6 @@ int xgbe_powerup(struct net_device *netdev, unsigned int caller)
xgbe_start_timers(pdata);
- spin_unlock_irqrestore(&pdata->lock, flags);
-
DBGPR("<--xgbe_powerup\n");
return 0;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index d1f0419edb23..7d45ea22a02e 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -76,7 +76,6 @@ struct xgbe_prv_data *xgbe_alloc_pdata(struct device *dev)
pdata->netdev = netdev;
pdata->dev = dev;
- spin_lock_init(&pdata->lock);
spin_lock_init(&pdata->xpcs_lock);
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index 1269b8ce9249..e1d7d7150e16 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -1004,9 +1004,6 @@ struct xgbe_prv_data {
unsigned int pp3;
unsigned int pp4;
- /* Overall device lock */
- spinlock_t lock;
-
/* XPCS indirect addressing lock */
spinlock_t xpcs_lock;
unsigned int xpcs_window_def_reg;
diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
index fc0e0f36186e..52c1cb9cb7e0 100644
--- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
+++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c
@@ -1533,7 +1533,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
if_id = (status & 0xFFFF0000) >> 16;
if (if_id >= ethsw->sw_attr.num_ifs) {
dev_err(dev, "Invalid if_id %d in IRQ status\n", if_id);
- goto out;
+ goto out_clear;
}
port_priv = ethsw->ports[if_id];
@@ -1553,6 +1553,7 @@ static irqreturn_t dpaa2_switch_irq0_handler_thread(int irq_num, void *arg)
dpaa2_switch_port_connect_mac(port_priv);
}
+out_clear:
err = dpsw_clear_irq_status(ethsw->mc_io, 0, ethsw->dpsw_handle,
DPSW_IRQ_INDEX_IF, status);
if (err)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c
index 70768392912c..a146ceaf2ed6 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc.c
@@ -3467,7 +3467,7 @@ static int enetc_int_vector_init(struct enetc_ndev_priv *priv, int i,
priv->rx_ring[i] = bdr;
err = __xdp_rxq_info_reg(&bdr->xdp.rxq, priv->ndev, i, 0,
- ENETC_RXB_DMA_SIZE_XDP);
+ ENETC_RXB_TRUESIZE);
if (err)
goto free_vector;
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h
index ba331899d186..d4a1041e456d 100644
--- a/drivers/net/ethernet/intel/e1000e/defines.h
+++ b/drivers/net/ethernet/intel/e1000e/defines.h
@@ -33,6 +33,7 @@
/* Extended Device Control */
#define E1000_CTRL_EXT_LPCD 0x00000004 /* LCD Power Cycle Done */
+#define E1000_CTRL_EXT_DPG_EN 0x00000008 /* Dynamic Power Gating Enable */
#define E1000_CTRL_EXT_SDP3_DATA 0x00000080 /* Value of SW Definable Pin 3 */
#define E1000_CTRL_EXT_FORCE_SMBUS 0x00000800 /* Force SMBus mode */
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index aa08f397988e..63ebe00376f5 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -117,7 +117,8 @@ enum e1000_boards {
board_pch_cnp,
board_pch_tgp,
board_pch_adp,
- board_pch_mtp
+ board_pch_mtp,
+ board_pch_ptp
};
struct e1000_ps_page {
@@ -527,6 +528,7 @@ extern const struct e1000_info e1000_pch_cnp_info;
extern const struct e1000_info e1000_pch_tgp_info;
extern const struct e1000_info e1000_pch_adp_info;
extern const struct e1000_info e1000_pch_mtp_info;
+extern const struct e1000_info e1000_pch_ptp_info;
extern const struct e1000_info e1000_es2_info;
void e1000e_ptp_init(struct e1000_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h
index fc8ed38aa095..c7ac599e5a7a 100644
--- a/drivers/net/ethernet/intel/e1000e/hw.h
+++ b/drivers/net/ethernet/intel/e1000e/hw.h
@@ -118,8 +118,6 @@ struct e1000_hw;
#define E1000_DEV_ID_PCH_ARL_I219_V24 0x57A1
#define E1000_DEV_ID_PCH_PTP_I219_LM25 0x57B3
#define E1000_DEV_ID_PCH_PTP_I219_V25 0x57B4
-#define E1000_DEV_ID_PCH_PTP_I219_LM26 0x57B5
-#define E1000_DEV_ID_PCH_PTP_I219_V26 0x57B6
#define E1000_DEV_ID_PCH_PTP_I219_LM27 0x57B7
#define E1000_DEV_ID_PCH_PTP_I219_V27 0x57B8
#define E1000_DEV_ID_PCH_NVL_I219_LM29 0x57B9
diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c
index 0ff8688ac3b8..dea208db1be5 100644
--- a/drivers/net/ethernet/intel/e1000e/ich8lan.c
+++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c
@@ -528,7 +528,7 @@ static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
phy->id = e1000_phy_unknown;
- if (hw->mac.type == e1000_pch_mtp) {
+ if (hw->mac.type == e1000_pch_mtp || hw->mac.type == e1000_pch_ptp) {
phy->retry_count = 2;
e1000e_enable_phy_retry(hw);
}
@@ -4932,6 +4932,15 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
reg |= E1000_KABGTXD_BGSQLBIAS;
ew32(KABGTXD, reg);
+ /* The hardware reset value of the DPG_EN bit is 1.
+ * Clear DPG_EN to prevent unexpected autonomous power gating.
+ */
+ if (hw->mac.type >= e1000_pch_ptp) {
+ reg = er32(CTRL_EXT);
+ reg &= ~E1000_CTRL_EXT_DPG_EN;
+ ew32(CTRL_EXT, reg);
+ }
+
return 0;
}
@@ -6208,3 +6217,23 @@ const struct e1000_info e1000_pch_mtp_info = {
.phy_ops = &ich8_phy_ops,
.nvm_ops = &spt_nvm_ops,
};
+
+const struct e1000_info e1000_pch_ptp_info = {
+ .mac = e1000_pch_ptp,
+ .flags = FLAG_IS_ICH
+ | FLAG_HAS_WOL
+ | FLAG_HAS_HW_TIMESTAMP
+ | FLAG_HAS_CTRLEXT_ON_LOAD
+ | FLAG_HAS_AMT
+ | FLAG_HAS_FLASH
+ | FLAG_HAS_JUMBO_FRAMES
+ | FLAG_APME_IN_WUC,
+ .flags2 = FLAG2_HAS_PHY_STATS
+ | FLAG2_HAS_EEE,
+ .pba = 26,
+ .max_hw_frame_size = 9022,
+ .get_variants = e1000_get_variants_ich8lan,
+ .mac_ops = &ich8_mac_ops,
+ .phy_ops = &ich8_phy_ops,
+ .nvm_ops = &spt_nvm_ops,
+};
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index fd4b117ed20f..35dab1e3132f 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -55,6 +55,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
[board_pch_tgp] = &e1000_pch_tgp_info,
[board_pch_adp] = &e1000_pch_adp_info,
[board_pch_mtp] = &e1000_pch_mtp_info,
+ [board_pch_ptp] = &e1000_pch_ptp_info,
};
struct e1000_reg_info {
@@ -7922,14 +7923,12 @@ static const struct pci_device_id e1000_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_LNP_I219_V21), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_LM24), board_pch_mtp },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_ARL_I219_V24), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V26), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_mtp },
- { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_mtp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM25), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V25), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_LM27), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_PTP_I219_V27), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_LM29), board_pch_ptp },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_PCH_NVL_I219_V29), board_pch_ptp },
{ 0, 0, 0, 0, 0, 0, 0 } /* terminate list */
};
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index 7b9e147d7365..926d001b2150 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -3569,6 +3569,7 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
u16 pf_q = vsi->base_queue + ring->queue_index;
struct i40e_hw *hw = &vsi->back->hw;
struct i40e_hmc_obj_rxq rx_ctx;
+ u32 xdp_frame_sz;
int err = 0;
bool ok;
@@ -3578,49 +3579,47 @@ static int i40e_configure_rx_ring(struct i40e_ring *ring)
memset(&rx_ctx, 0, sizeof(rx_ctx));
ring->rx_buf_len = vsi->rx_buf_len;
+ xdp_frame_sz = i40e_rx_pg_size(ring) / 2;
/* XDP RX-queue info only needed for RX rings exposed to XDP */
if (ring->vsi->type != I40E_VSI_MAIN)
goto skip;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->queue_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
ring->xsk_pool = i40e_xsk_pool(ring);
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
+ xdp_frame_sz = xsk_pool_get_rx_frag_step(ring->xsk_pool);
ring->rx_buf_len = xsk_pool_get_rx_frame_size(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->queue_index,
ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
+ xdp_frame_sz);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_XSK_BUFF_POOL,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
dev_info(&vsi->back->pdev->dev,
"Registered XDP mem model MEM_TYPE_XSK_BUFF_POOL on Rx ring %d\n",
ring->queue_index);
} else {
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->queue_index,
+ ring->q_vector->napi.napi_id,
+ xdp_frame_sz);
+ if (err)
+ return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
MEM_TYPE_PAGE_SHARED,
NULL);
if (err)
- return err;
+ goto unreg_xdp;
}
skip:
- xdp_init_buff(&ring->xdp, i40e_rx_pg_size(ring) / 2, &ring->xdp_rxq);
+ xdp_init_buff(&ring->xdp, xdp_frame_sz, &ring->xdp_rxq);
rx_ctx.dbuff = DIV_ROUND_UP(ring->rx_buf_len,
BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT));
@@ -3654,7 +3653,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to clear LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* set the context in the HMC */
@@ -3663,7 +3663,8 @@ skip:
dev_info(&vsi->back->pdev->dev,
"Failed to set LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
ring->queue_index, pf_q, err);
- return -ENOMEM;
+ err = -ENOMEM;
+ goto unreg_xdp;
}
/* configure Rx buffer alignment */
@@ -3671,7 +3672,8 @@ skip:
if (I40E_2K_TOO_SMALL_WITH_PADDING) {
dev_info(&vsi->back->pdev->dev,
"2k Rx buffer is too small to fit standard MTU and skb_shared_info\n");
- return -EOPNOTSUPP;
+ err = -EOPNOTSUPP;
+ goto unreg_xdp;
}
clear_ring_build_skb_enabled(ring);
} else {
@@ -3701,6 +3703,11 @@ skip:
}
return 0;
+unreg_xdp:
+ if (ring->vsi->type == I40E_VSI_MAIN)
+ xdp_rxq_info_unreg(&ring->xdp_rxq);
+
+ return err;
}
/**
diff --git a/drivers/net/ethernet/intel/i40e/i40e_trace.h b/drivers/net/ethernet/intel/i40e/i40e_trace.h
index 759f3d1c4c8f..dde0ccd789ed 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_trace.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_trace.h
@@ -88,7 +88,7 @@ TRACE_EVENT(i40e_napi_poll,
__entry->rx_clean_complete = rx_clean_complete;
__entry->tx_clean_complete = tx_clean_complete;
__entry->irq_num = q->irq_num;
- __entry->curr_cpu = get_cpu();
+ __entry->curr_cpu = smp_processor_id();
__assign_str(qname);
__assign_str(dev_name);
__assign_bitmask(irq_affinity, cpumask_bits(&q->affinity_mask),
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 34db7d8866b0..894f2d06d39d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -1470,6 +1470,9 @@ void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
if (!rx_ring->rx_bi)
return;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
if (rx_ring->xsk_pool) {
i40e_xsk_clean_rx_ring(rx_ring);
goto skip_free;
@@ -1527,8 +1530,6 @@ skip_free:
void i40e_free_rx_resources(struct i40e_ring *rx_ring)
{
i40e_clean_rx_ring(rx_ring);
- if (rx_ring->vsi->type == I40E_VSI_MAIN)
- xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
rx_ring->xdp_prog = NULL;
kfree(rx_ring->rx_bi);
rx_ring->rx_bi = NULL;
diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c
index bceaf4b1b85d..86c1964f42e1 100644
--- a/drivers/net/ethernet/intel/iavf/iavf_main.c
+++ b/drivers/net/ethernet/intel/iavf/iavf_main.c
@@ -2793,7 +2793,22 @@ static void iavf_init_config_adapter(struct iavf_adapter *adapter)
netdev->watchdog_timeo = 5 * HZ;
netdev->min_mtu = ETH_MIN_MTU;
- netdev->max_mtu = LIBIE_MAX_MTU;
+
+ /* PF/VF API: vf_res->max_mtu is max frame size (not MTU).
+ * Convert to MTU.
+ */
+ if (!adapter->vf_res->max_mtu) {
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else if (adapter->vf_res->max_mtu < LIBETH_RX_LL_LEN + ETH_MIN_MTU ||
+ adapter->vf_res->max_mtu >
+ LIBETH_RX_LL_LEN + LIBIE_MAX_MTU) {
+ netdev_warn_once(adapter->netdev,
+ "invalid max frame size %d from PF, using default MTU %d",
+ adapter->vf_res->max_mtu, LIBIE_MAX_MTU);
+ netdev->max_mtu = LIBIE_MAX_MTU;
+ } else {
+ netdev->max_mtu = adapter->vf_res->max_mtu - LIBETH_RX_LL_LEN;
+ }
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n",
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index def7efa15447..2b2b22af42be 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -987,6 +987,7 @@ int ice_schedule_reset(struct ice_pf *pf, enum ice_reset_req reset);
void ice_print_link_msg(struct ice_vsi *vsi, bool isup);
int ice_plug_aux_dev(struct ice_pf *pf);
void ice_unplug_aux_dev(struct ice_pf *pf);
+void ice_rdma_finalize_setup(struct ice_pf *pf);
int ice_init_rdma(struct ice_pf *pf);
void ice_deinit_rdma(struct ice_pf *pf);
bool ice_is_wol_supported(struct ice_hw *hw);
diff --git a/drivers/net/ethernet/intel/ice/ice_base.c b/drivers/net/ethernet/intel/ice/ice_base.c
index eb77dfa934aa..1667f686ff75 100644
--- a/drivers/net/ethernet/intel/ice/ice_base.c
+++ b/drivers/net/ethernet/intel/ice/ice_base.c
@@ -124,6 +124,8 @@ static int ice_vsi_alloc_q_vector(struct ice_vsi *vsi, u16 v_idx)
if (vsi->type == ICE_VSI_VF) {
ice_calc_vf_reg_idx(vsi->vf, q_vector);
goto out;
+ } else if (vsi->type == ICE_VSI_LB) {
+ goto skip_alloc;
} else if (vsi->type == ICE_VSI_CTRL && vsi->vf) {
struct ice_vsi *ctrl_vsi = ice_get_vf_ctrl_vsi(pf, vsi);
@@ -659,33 +661,22 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
{
struct device *dev = ice_pf_to_dev(ring->vsi->back);
u32 num_bufs = ICE_DESC_UNUSED(ring);
- u32 rx_buf_len;
int err;
- if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF) {
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- return err;
- }
-
+ if (ring->vsi->type == ICE_VSI_PF || ring->vsi->type == ICE_VSI_SF ||
+ ring->vsi->type == ICE_VSI_LB) {
ice_rx_xsk_pool(ring);
err = ice_realloc_rx_xdp_bufs(ring, ring->xsk_pool);
if (err)
return err;
if (ring->xsk_pool) {
- xdp_rxq_info_unreg(&ring->xdp_rxq);
-
- rx_buf_len =
- xsk_pool_get_rx_frame_size(ring->xsk_pool);
+ u32 frag_size =
+ xsk_pool_get_rx_frag_step(ring->xsk_pool);
err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
ring->q_index,
ring->q_vector->napi.napi_id,
- rx_buf_len);
+ frag_size);
if (err)
return err;
err = xdp_rxq_info_reg_mem_model(&ring->xdp_rxq,
@@ -702,14 +693,13 @@ static int ice_vsi_cfg_rxq(struct ice_rx_ring *ring)
if (err)
return err;
- if (!xdp_rxq_info_is_reg(&ring->xdp_rxq)) {
- err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
- ring->q_index,
- ring->q_vector->napi.napi_id,
- ring->rx_buf_len);
- if (err)
- goto err_destroy_fq;
- }
+ err = __xdp_rxq_info_reg(&ring->xdp_rxq, ring->netdev,
+ ring->q_index,
+ ring->q_vector->napi.napi_id,
+ ring->truesize);
+ if (err)
+ goto err_destroy_fq;
+
xdp_rxq_info_attach_page_pool(&ring->xdp_rxq,
ring->pp);
}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 6cd63190f55d..ce11fea122d0 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -1816,6 +1816,7 @@ static bool ice_should_retry_sq_send_cmd(u16 opcode)
case ice_aqc_opc_lldp_stop:
case ice_aqc_opc_lldp_start:
case ice_aqc_opc_lldp_filter_ctrl:
+ case ice_aqc_opc_sff_eeprom:
return true;
}
@@ -1841,6 +1842,7 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
{
struct libie_aq_desc desc_cpy;
bool is_cmd_for_retry;
+ u8 *buf_cpy = NULL;
u8 idx = 0;
u16 opcode;
int status;
@@ -1850,8 +1852,11 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
memset(&desc_cpy, 0, sizeof(desc_cpy));
if (is_cmd_for_retry) {
- /* All retryable cmds are direct, without buf. */
- WARN_ON(buf);
+ if (buf) {
+ buf_cpy = kmemdup(buf, buf_size, GFP_KERNEL);
+ if (!buf_cpy)
+ return -ENOMEM;
+ }
memcpy(&desc_cpy, desc, sizeof(desc_cpy));
}
@@ -1863,12 +1868,14 @@ ice_sq_send_cmd_retry(struct ice_hw *hw, struct ice_ctl_q_info *cq,
hw->adminq.sq_last_status != LIBIE_AQ_RC_EBUSY)
break;
+ if (buf_cpy)
+ memcpy(buf, buf_cpy, buf_size);
memcpy(desc, &desc_cpy, sizeof(desc_cpy));
-
msleep(ICE_SQ_SEND_DELAY_TIME_MS);
} while (++idx < ICE_SQ_SEND_MAX_EXECUTE);
+ kfree(buf_cpy);
return status;
}
@@ -6391,7 +6398,7 @@ int ice_lldp_fltr_add_remove(struct ice_hw *hw, struct ice_vsi *vsi, bool add)
struct ice_aqc_lldp_filter_ctrl *cmd;
struct libie_aq_desc desc;
- if (vsi->type != ICE_VSI_PF || !ice_fw_supports_lldp_fltr_ctrl(hw))
+ if (!ice_fw_supports_lldp_fltr_ctrl(hw))
return -EOPNOTSUPP;
cmd = libie_aq_raw(&desc);
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 0ea64b330614..301947d53ede 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -1289,6 +1289,10 @@ static u64 ice_loopback_test(struct net_device *netdev)
test_vsi->netdev = netdev;
tx_ring = test_vsi->tx_rings[0];
rx_ring = test_vsi->rx_rings[0];
+ /* Dummy q_vector and napi. Fill the minimum required for
+ * ice_rxq_pp_create().
+ */
+ rx_ring->q_vector->napi.dev = netdev;
if (ice_lbtest_prepare_rings(test_vsi)) {
ret = 2;
@@ -3328,7 +3332,7 @@ process_rx:
rx_rings = kzalloc_objs(*rx_rings, vsi->num_rxq);
if (!rx_rings) {
err = -ENOMEM;
- goto done;
+ goto free_xdp;
}
ice_for_each_rxq(vsi, i) {
@@ -3338,6 +3342,7 @@ process_rx:
rx_rings[i].cached_phctime = pf->ptp.cached_phc_time;
rx_rings[i].desc = NULL;
rx_rings[i].xdp_buf = NULL;
+ rx_rings[i].xdp_rxq = (struct xdp_rxq_info){ };
/* this is to allow wr32 to have something to write to
* during early allocation of Rx buffers
@@ -3355,7 +3360,7 @@ rx_unwind:
}
kfree(rx_rings);
err = -ENOMEM;
- goto free_tx;
+ goto free_xdp;
}
}
@@ -3407,6 +3412,13 @@ process_link:
}
goto done;
+free_xdp:
+ if (xdp_rings) {
+ ice_for_each_xdp_txq(vsi, i)
+ ice_free_tx_ring(&xdp_rings[i]);
+ kfree(xdp_rings);
+ }
+
free_tx:
/* error cleanup if the Rx allocations failed after getting Tx */
if (tx_rings) {
@@ -4505,7 +4517,7 @@ ice_get_module_eeprom(struct net_device *netdev,
u8 addr = ICE_I2C_EEPROM_DEV_ADDR;
struct ice_hw *hw = &pf->hw;
bool is_sfp = false;
- unsigned int i, j;
+ unsigned int i;
u16 offset = 0;
u8 page = 0;
int status;
@@ -4547,26 +4559,19 @@ ice_get_module_eeprom(struct net_device *netdev,
if (page == 0 || !(data[0x2] & 0x4)) {
u32 copy_len;
- /* If i2c bus is busy due to slow page change or
- * link management access, call can fail. This is normal.
- * So we retry this a few times.
- */
- for (j = 0; j < 4; j++) {
- status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
- !is_sfp, value,
- SFF_READ_BLOCK_SIZE,
- 0, NULL);
- netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%X)\n",
- addr, offset, page, is_sfp,
- value[0], value[1], value[2], value[3],
- value[4], value[5], value[6], value[7],
- status);
- if (status) {
- usleep_range(1500, 2500);
- memset(value, 0, SFF_READ_BLOCK_SIZE);
- continue;
- }
- break;
+ status = ice_aq_sff_eeprom(hw, 0, addr, offset, page,
+ !is_sfp, value,
+ SFF_READ_BLOCK_SIZE,
+ 0, NULL);
+ netdev_dbg(netdev, "SFF %02X %02X %02X %X = %02X%02X%02X%02X.%02X%02X%02X%02X (%pe)\n",
+ addr, offset, page, is_sfp,
+ value[0], value[1], value[2], value[3],
+ value[4], value[5], value[6], value[7],
+ ERR_PTR(status));
+ if (status) {
+ netdev_err(netdev, "%s: error reading module EEPROM: status %pe\n",
+ __func__, ERR_PTR(status));
+ return status;
}
/* Make sure we have enough room for the new block */
diff --git a/drivers/net/ethernet/intel/ice/ice_idc.c b/drivers/net/ethernet/intel/ice/ice_idc.c
index 3572b0e1d49f..102d63c3018b 100644
--- a/drivers/net/ethernet/intel/ice/ice_idc.c
+++ b/drivers/net/ethernet/intel/ice/ice_idc.c
@@ -361,6 +361,39 @@ void ice_unplug_aux_dev(struct ice_pf *pf)
}
/**
+ * ice_rdma_finalize_setup - Complete RDMA setup after VSI is ready
+ * @pf: ptr to ice_pf
+ *
+ * Sets VSI-dependent information and plugs aux device.
+ * Must be called after ice_init_rdma(), ice_vsi_rebuild(), and
+ * ice_dcb_rebuild() complete.
+ */
+void ice_rdma_finalize_setup(struct ice_pf *pf)
+{
+ struct device *dev = ice_pf_to_dev(pf);
+ struct iidc_rdma_priv_dev_info *privd;
+ int ret;
+
+ if (!ice_is_rdma_ena(pf) || !pf->cdev_info)
+ return;
+
+ privd = pf->cdev_info->iidc_priv;
+ if (!privd || !pf->vsi || !pf->vsi[0] || !pf->vsi[0]->netdev)
+ return;
+
+ /* Assign VSI info now that VSI is valid */
+ privd->netdev = pf->vsi[0]->netdev;
+ privd->vport_id = pf->vsi[0]->vsi_num;
+
+ /* Update QoS info after DCB has been rebuilt */
+ ice_setup_dcb_qos_info(pf, &privd->qos_info);
+
+ ret = ice_plug_aux_dev(pf);
+ if (ret)
+ dev_warn(dev, "Failed to plug RDMA aux device: %d\n", ret);
+}
+
+/**
* ice_init_rdma - initializes PF for RDMA use
* @pf: ptr to ice_pf
*/
@@ -398,22 +431,14 @@ int ice_init_rdma(struct ice_pf *pf)
}
cdev->iidc_priv = privd;
- privd->netdev = pf->vsi[0]->netdev;
privd->hw_addr = (u8 __iomem *)pf->hw.hw_addr;
cdev->pdev = pf->pdev;
- privd->vport_id = pf->vsi[0]->vsi_num;
pf->cdev_info->rdma_protocol |= IIDC_RDMA_PROTOCOL_ROCEV2;
- ice_setup_dcb_qos_info(pf, &privd->qos_info);
- ret = ice_plug_aux_dev(pf);
- if (ret)
- goto err_plug_aux_dev;
+
return 0;
-err_plug_aux_dev:
- pf->cdev_info->adev = NULL;
- xa_erase(&ice_aux_id, pf->aux_idx);
err_alloc_xa:
kfree(privd);
err_privd_alloc:
@@ -432,7 +457,6 @@ void ice_deinit_rdma(struct ice_pf *pf)
if (!ice_is_rdma_ena(pf))
return;
- ice_unplug_aux_dev(pf);
xa_erase(&ice_aux_id, pf->aux_idx);
kfree(pf->cdev_info->iidc_priv);
kfree(pf->cdev_info);
diff --git a/drivers/net/ethernet/intel/ice/ice_lib.c b/drivers/net/ethernet/intel/ice/ice_lib.c
index f91f8b672b02..689c6025ea82 100644
--- a/drivers/net/ethernet/intel/ice/ice_lib.c
+++ b/drivers/net/ethernet/intel/ice/ice_lib.c
@@ -107,10 +107,6 @@ static int ice_vsi_alloc_arrays(struct ice_vsi *vsi)
if (!vsi->rxq_map)
goto err_rxq_map;
- /* There is no need to allocate q_vectors for a loopback VSI. */
- if (vsi->type == ICE_VSI_LB)
- return 0;
-
/* allocate memory for q_vector pointers */
vsi->q_vectors = devm_kcalloc(dev, vsi->num_q_vectors,
sizeof(*vsi->q_vectors), GFP_KERNEL);
@@ -241,6 +237,8 @@ static void ice_vsi_set_num_qs(struct ice_vsi *vsi)
case ICE_VSI_LB:
vsi->alloc_txq = 1;
vsi->alloc_rxq = 1;
+ /* A dummy q_vector, no actual IRQ. */
+ vsi->num_q_vectors = 1;
break;
default:
dev_warn(ice_pf_to_dev(pf), "Unknown VSI type %d\n", vsi_type);
@@ -2426,14 +2424,21 @@ static int ice_vsi_cfg_def(struct ice_vsi *vsi)
}
break;
case ICE_VSI_LB:
- ret = ice_vsi_alloc_rings(vsi);
+ ret = ice_vsi_alloc_q_vectors(vsi);
if (ret)
goto unroll_vsi_init;
+ ret = ice_vsi_alloc_rings(vsi);
+ if (ret)
+ goto unroll_alloc_q_vector;
+
ret = ice_vsi_alloc_ring_stats(vsi);
if (ret)
goto unroll_vector_base;
+ /* Simply map the dummy q_vector to the only rx_ring */
+ vsi->rx_rings[0]->q_vector = vsi->q_vectors[0];
+
break;
default:
/* clean up the resources and exit */
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index ebf48feffb30..e7308e381e2f 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5138,6 +5138,9 @@ int ice_load(struct ice_pf *pf)
if (err)
goto err_init_rdma;
+ /* Finalize RDMA: VSI already created, assign info and plug device */
+ ice_rdma_finalize_setup(pf);
+
ice_service_task_restart(pf);
clear_bit(ICE_DOWN, pf->state);
@@ -5169,6 +5172,7 @@ void ice_unload(struct ice_pf *pf)
devl_assert_locked(priv_to_devlink(pf));
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
ice_deinit_features(pf);
ice_tc_indir_block_unregister(vsi);
@@ -5595,6 +5599,7 @@ static int ice_suspend(struct device *dev)
*/
disabled = ice_service_task_stop(pf);
+ ice_unplug_aux_dev(pf);
ice_deinit_rdma(pf);
/* Already suspended?, then there is nothing to do */
@@ -7859,7 +7864,7 @@ static void ice_rebuild(struct ice_pf *pf, enum ice_reset_req reset_type)
ice_health_clear(pf);
- ice_plug_aux_dev(pf);
+ ice_rdma_finalize_setup(pf);
if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG))
ice_lag_rebuild(pf);
diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c
index a5bbce68f76c..a2cd4cf37734 100644
--- a/drivers/net/ethernet/intel/ice/ice_txrx.c
+++ b/drivers/net/ethernet/intel/ice/ice_txrx.c
@@ -560,7 +560,9 @@ void ice_clean_rx_ring(struct ice_rx_ring *rx_ring)
i = 0;
}
- if (rx_ring->vsi->type == ICE_VSI_PF &&
+ if ((rx_ring->vsi->type == ICE_VSI_PF ||
+ rx_ring->vsi->type == ICE_VSI_SF ||
+ rx_ring->vsi->type == ICE_VSI_LB) &&
xdp_rxq_info_is_reg(&rx_ring->xdp_rxq)) {
xdp_rxq_info_detach_mem_model(&rx_ring->xdp_rxq);
xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
diff --git a/drivers/net/ethernet/intel/ice/ice_xsk.c b/drivers/net/ethernet/intel/ice/ice_xsk.c
index c673094663a3..0643017541c3 100644
--- a/drivers/net/ethernet/intel/ice/ice_xsk.c
+++ b/drivers/net/ethernet/intel/ice/ice_xsk.c
@@ -899,6 +899,9 @@ void ice_xsk_clean_rx_ring(struct ice_rx_ring *rx_ring)
u16 ntc = rx_ring->next_to_clean;
u16 ntu = rx_ring->next_to_use;
+ if (xdp_rxq_info_is_reg(&rx_ring->xdp_rxq))
+ xdp_rxq_info_unreg(&rx_ring->xdp_rxq);
+
while (ntc != ntu) {
struct xdp_buff *xdp = *ice_xdp_buf(rx_ring, ntc);
diff --git a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
index 40e08a71d2d3..bb99d9e7c65d 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_ethtool.c
@@ -307,9 +307,6 @@ static int idpf_del_flow_steer(struct net_device *netdev,
vport_config = vport->adapter->vport_config[np->vport_idx];
user_config = &vport_config->user_config;
- if (!idpf_sideband_action_ena(vport, fsp))
- return -EOPNOTSUPP;
-
rule = kzalloc_flex(*rule, rule_info, 1);
if (!rule)
return -ENOMEM;
diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c
index de3df705a7e6..cf966fe6c759 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_lib.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c
@@ -1318,6 +1318,7 @@ static struct idpf_vport *idpf_vport_alloc(struct idpf_adapter *adapter,
free_rss_key:
kfree(rss_data->rss_key);
+ rss_data->rss_key = NULL;
free_qreg_chunks:
idpf_vport_deinit_queue_reg_chunks(adapter->vport_config[idx]);
free_vector_idxs:
diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
index 05a162094d10..252259993022 100644
--- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c
+++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c
@@ -1314,6 +1314,9 @@ static void idpf_txq_group_rel(struct idpf_q_vec_rsrc *rsrc)
struct idpf_txq_group *txq_grp = &rsrc->txq_grps[i];
for (unsigned int j = 0; j < txq_grp->num_txq; j++) {
+ if (!txq_grp->txqs[j])
+ continue;
+
if (idpf_queue_has(FLOW_SCH_EN, txq_grp->txqs[j])) {
kfree(txq_grp->txqs[j]->refillq);
txq_grp->txqs[j]->refillq = NULL;
@@ -1339,6 +1342,9 @@ static void idpf_txq_group_rel(struct idpf_q_vec_rsrc *rsrc)
*/
static void idpf_rxq_sw_queue_rel(struct idpf_rxq_group *rx_qgrp)
{
+ if (!rx_qgrp->splitq.bufq_sets)
+ return;
+
for (unsigned int i = 0; i < rx_qgrp->splitq.num_bufq_sets; i++) {
struct idpf_bufq_set *bufq_set = &rx_qgrp->splitq.bufq_sets[i];
@@ -2336,7 +2342,7 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
do {
struct idpf_splitq_4b_tx_compl_desc *tx_desc;
- struct idpf_tx_queue *target;
+ struct idpf_tx_queue *target = NULL;
u32 ctype_gen, id;
tx_desc = flow ? &complq->comp[ntc].common :
@@ -2356,14 +2362,14 @@ void idpf_wait_for_sw_marker_completion(const struct idpf_tx_queue *txq)
target = complq->txq_grp->txqs[id];
idpf_queue_clear(SW_MARKER, target);
- if (target == txq)
- break;
next:
if (unlikely(++ntc == complq->desc_count)) {
ntc = 0;
gen_flag = !gen_flag;
}
+ if (target == txq)
+ break;
} while (time_before(jiffies, timeout));
idpf_queue_assign(GEN_CHK, complq, gen_flag);
@@ -4059,7 +4065,7 @@ static int idpf_vport_intr_req_irq(struct idpf_vport *vport,
continue;
name = kasprintf(GFP_KERNEL, "%s-%s-%s-%d", drv_name, if_name,
- vec_name, vidx);
+ vec_name, vector);
err = request_irq(irq_num, idpf_vport_intr_clean_queues, 0,
name, q_vector);
diff --git a/drivers/net/ethernet/intel/idpf/xdp.c b/drivers/net/ethernet/intel/idpf/xdp.c
index 6ac9c6624c2a..cbccd4546768 100644
--- a/drivers/net/ethernet/intel/idpf/xdp.c
+++ b/drivers/net/ethernet/intel/idpf/xdp.c
@@ -47,12 +47,16 @@ static int __idpf_xdp_rxq_info_init(struct idpf_rx_queue *rxq, void *arg)
{
const struct idpf_vport *vport = rxq->q_vector->vport;
const struct idpf_q_vec_rsrc *rsrc;
+ u32 frag_size = 0;
bool split;
int err;
+ if (idpf_queue_has(XSK, rxq))
+ frag_size = rxq->bufq_sets[0].bufq.truesize;
+
err = __xdp_rxq_info_reg(&rxq->xdp_rxq, vport->netdev, rxq->idx,
rxq->q_vector->napi.napi_id,
- rxq->rx_buf_size);
+ frag_size);
if (err)
return err;
diff --git a/drivers/net/ethernet/intel/idpf/xsk.c b/drivers/net/ethernet/intel/idpf/xsk.c
index 676cbd80774d..d95d3efdfd36 100644
--- a/drivers/net/ethernet/intel/idpf/xsk.c
+++ b/drivers/net/ethernet/intel/idpf/xsk.c
@@ -403,6 +403,7 @@ int idpf_xskfq_init(struct idpf_buf_queue *bufq)
bufq->pending = fq.pending;
bufq->thresh = fq.thresh;
bufq->rx_buf_size = fq.buf_len;
+ bufq->truesize = fq.truesize;
if (!idpf_xskfq_refill(bufq))
netdev_err(bufq->pool->netdev,
diff --git a/drivers/net/ethernet/intel/igb/igb_xsk.c b/drivers/net/ethernet/intel/igb/igb_xsk.c
index 30ce5fbb5b77..ce4a7b58cad2 100644
--- a/drivers/net/ethernet/intel/igb/igb_xsk.c
+++ b/drivers/net/ethernet/intel/igb/igb_xsk.c
@@ -524,6 +524,16 @@ bool igb_xmit_zc(struct igb_ring *tx_ring, struct xsk_buff_pool *xsk_pool)
return nb_pkts < budget;
}
+static u32 igb_sw_irq_prep(struct igb_q_vector *q_vector)
+{
+ u32 eics = 0;
+
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
+}
+
int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
{
struct igb_adapter *adapter = netdev_priv(dev);
@@ -542,20 +552,32 @@ int igb_xsk_wakeup(struct net_device *dev, u32 qid, u32 flags)
ring = adapter->tx_ring[qid];
- if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
- return -ENETDOWN;
-
if (!READ_ONCE(ring->xsk_pool))
return -EINVAL;
- if (!napi_if_scheduled_mark_missed(&ring->q_vector->napi)) {
+ if (flags & XDP_WAKEUP_TX) {
+ if (test_bit(IGB_RING_FLAG_TX_DISABLED, &ring->flags))
+ return -ENETDOWN;
+
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (flags & XDP_WAKEUP_RX) {
+ /* If IGB_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the TX path, making this RX call a NOP
+ */
+ ring = adapter->rx_ring[qid];
+ eics |= igb_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics) {
/* Cause software interrupt */
- if (adapter->flags & IGB_FLAG_HAS_MSIX) {
- eics |= ring->q_vector->eims_value;
+ if (adapter->flags & IGB_FLAG_HAS_MSIX)
wr32(E1000_EICS, eics);
- } else {
+ else
wr32(E1000_ICS, E1000_ICS_RXDMT0);
- }
}
return 0;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 27e5c2109138..b2e8d0c0f827 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -6906,28 +6906,29 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames,
return nxmit;
}
-static void igc_trigger_rxtxq_interrupt(struct igc_adapter *adapter,
- struct igc_q_vector *q_vector)
+static u32 igc_sw_irq_prep(struct igc_q_vector *q_vector)
{
- struct igc_hw *hw = &adapter->hw;
u32 eics = 0;
- eics |= q_vector->eims_value;
- wr32(IGC_EICS, eics);
+ if (!napi_if_scheduled_mark_missed(&q_vector->napi))
+ eics = q_vector->eims_value;
+
+ return eics;
}
int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
{
struct igc_adapter *adapter = netdev_priv(dev);
- struct igc_q_vector *q_vector;
+ struct igc_hw *hw = &adapter->hw;
struct igc_ring *ring;
+ u32 eics = 0;
if (test_bit(__IGC_DOWN, &adapter->state))
return -ENETDOWN;
if (!igc_xdp_is_enabled(adapter))
return -ENXIO;
-
+ /* Check if queue_id is valid. Tx and Rx queue numbers are always same */
if (queue_id >= adapter->num_rx_queues)
return -EINVAL;
@@ -6936,9 +6937,22 @@ int igc_xsk_wakeup(struct net_device *dev, u32 queue_id, u32 flags)
if (!ring->xsk_pool)
return -ENXIO;
- q_vector = adapter->q_vector[queue_id];
- if (!napi_if_scheduled_mark_missed(&q_vector->napi))
- igc_trigger_rxtxq_interrupt(adapter, q_vector);
+ if (flags & XDP_WAKEUP_RX)
+ eics |= igc_sw_irq_prep(ring->q_vector);
+
+ if (flags & XDP_WAKEUP_TX) {
+ /* If IGC_FLAG_QUEUE_PAIRS is active, the q_vector
+ * and NAPI is shared between RX and TX.
+ * If NAPI is already running it would be marked as missed
+ * from the RX path, making this TX call a NOP
+ */
+ ring = adapter->tx_ring[queue_id];
+ eics |= igc_sw_irq_prep(ring->q_vector);
+ }
+
+ if (eics)
+ /* Cause software interrupt */
+ wr32(IGC_EICS, eics);
return 0;
}
diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c
index 7aae83c108fd..44ee19386766 100644
--- a/drivers/net/ethernet/intel/igc/igc_ptp.c
+++ b/drivers/net/ethernet/intel/igc/igc_ptp.c
@@ -550,7 +550,8 @@ static void igc_ptp_free_tx_buffer(struct igc_adapter *adapter,
tstamp->buffer_type = 0;
/* Trigger txrx interrupt for transmit completion */
- igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index, 0);
+ igc_xsk_wakeup(adapter->netdev, tstamp->xsk_queue_index,
+ XDP_WAKEUP_TX);
return;
}
diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c
index 74d320879513..b67b580f7f1c 100644
--- a/drivers/net/ethernet/intel/ixgbevf/vf.c
+++ b/drivers/net/ethernet/intel/ixgbevf/vf.c
@@ -852,7 +852,8 @@ static s32 ixgbevf_check_mac_link_vf(struct ixgbe_hw *hw,
if (!mac->get_link_status)
goto out;
- if (hw->mac.type == ixgbe_mac_e610_vf) {
+ if (hw->mac.type == ixgbe_mac_e610_vf &&
+ hw->api_version >= ixgbe_mbox_api_16) {
ret_val = ixgbevf_get_pf_link_state(hw, speed, link_up);
if (ret_val)
goto out;
diff --git a/drivers/net/ethernet/intel/libeth/xsk.c b/drivers/net/ethernet/intel/libeth/xsk.c
index 846e902e31b6..4882951d5c9c 100644
--- a/drivers/net/ethernet/intel/libeth/xsk.c
+++ b/drivers/net/ethernet/intel/libeth/xsk.c
@@ -167,6 +167,7 @@ int libeth_xskfq_create(struct libeth_xskfq *fq)
fq->pending = fq->count;
fq->thresh = libeth_xdp_queue_threshold(fq->count);
fq->buf_len = xsk_pool_get_rx_frame_size(fq->pool);
+ fq->truesize = xsk_pool_get_rx_frag_step(fq->pool);
return 0;
}
diff --git a/drivers/net/ethernet/intel/libie/fwlog.c b/drivers/net/ethernet/intel/libie/fwlog.c
index 79020d990859..4d0c8370386b 100644
--- a/drivers/net/ethernet/intel/libie/fwlog.c
+++ b/drivers/net/ethernet/intel/libie/fwlog.c
@@ -1049,6 +1049,10 @@ void libie_fwlog_deinit(struct libie_fwlog *fwlog)
{
int status;
+ /* if FW logging isn't supported it means no configuration was done */
+ if (!libie_fwlog_supported(fwlog))
+ return;
+
/* make sure FW logging is disabled to not put the FW in a weird state
* for the next driver load
*/
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
index ec55eb2a6c04..028dd55604ea 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c
@@ -554,28 +554,43 @@ static void octep_clean_irqs(struct octep_device *oct)
}
/**
- * octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ * octep_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
-static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
+static void octep_update_pkt(struct octep_iq *iq, struct octep_oq *oq)
{
- u32 pkts_pend = oq->pkts_pending;
+ u32 pkts_pend = READ_ONCE(oq->pkts_pending);
+ u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ u32 pkts_processed = READ_ONCE(iq->pkts_processed);
+ u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
- if (iq->pkts_processed) {
- writel(iq->pkts_processed, iq->inst_cnt_reg);
- iq->pkt_in_done -= iq->pkts_processed;
- iq->pkts_processed = 0;
+ if (pkts_processed) {
+ writel(pkts_processed, iq->inst_cnt_reg);
+ readl(iq->inst_cnt_reg);
+ WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
+ WRITE_ONCE(iq->pkts_processed, 0);
}
- if (oq->last_pkt_count - pkts_pend) {
- writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
- oq->last_pkt_count = pkts_pend;
+ if (last_pkt_count - pkts_pend) {
+ writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
+ readl(oq->pkts_sent_reg);
+ WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
- wmb();
+ smp_wmb();
+}
+
+/**
+ * octep_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ *
+ * @iq: Octeon Tx queue data structure.
+ * @oq: Octeon Rx queue data structure.
+ */
+static void octep_enable_ioq_irq(struct octep_iq *iq, struct octep_oq *oq)
+{
writeq(1UL << OCTEP_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@@ -601,7 +616,8 @@ static int octep_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
- napi_complete(napi);
+ octep_update_pkt(ioq_vector->iq, ioq_vector->oq);
+ napi_complete_done(napi, rx_done);
octep_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
return rx_done;
}
diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
index f2a7c6a76c74..74de19166488 100644
--- a/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep/octep_rx.c
@@ -324,10 +324,16 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
struct octep_oq *oq)
{
u32 pkt_count, new_pkts;
+ u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
- new_pkts = pkt_count - oq->last_pkt_count;
+ last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ new_pkts = pkt_count - last_pkt_count;
+ if (pkt_count < last_pkt_count) {
+ dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
+ oq->q_no, pkt_count, last_pkt_count);
+ }
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
* reached half its max value.
@@ -338,8 +344,9 @@ static int octep_oq_check_hw_for_pkts(struct octep_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
- oq->last_pkt_count = pkt_count;
- oq->pkts_pending += new_pkts;
+ WRITE_ONCE(oq->last_pkt_count, pkt_count);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@@ -414,7 +421,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
u16 rx_ol_flags;
u32 read_idx;
- read_idx = oq->host_read_idx;
+ read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@@ -499,7 +506,7 @@ static int __octep_oq_process_rx(struct octep_device *oct,
napi_gro_receive(oq->napi, skb);
}
- oq->host_read_idx = read_idx;
+ WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@@ -522,22 +529,26 @@ int octep_oq_process_rx(struct octep_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_device *oct = oq->octep_dev;
+ u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
- if (oq->pkts_pending == 0)
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ if (pkts_pending == 0)
octep_oq_check_hw_for_pkts(oct, oq);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
- oq->pkts_pending);
+ pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_oq_process_rx(oct, oq,
pkts_available);
- oq->pkts_pending -= pkts_processed;
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
index 562fe945b422..7f1b93cffb98 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_main.c
@@ -286,28 +286,45 @@ static void octep_vf_clean_irqs(struct octep_vf_device *oct)
}
/**
- * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ * octep_vf_update_pkt() - Update IQ/OQ IN/OUT_CNT registers.
*
* @iq: Octeon Tx queue data structure.
* @oq: Octeon Rx queue data structure.
*/
-static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
+
+static void octep_vf_update_pkt(struct octep_vf_iq *iq, struct octep_vf_oq *oq)
{
- u32 pkts_pend = oq->pkts_pending;
+ u32 pkts_pend = READ_ONCE(oq->pkts_pending);
+ u32 last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ u32 pkts_processed = READ_ONCE(iq->pkts_processed);
+ u32 pkt_in_done = READ_ONCE(iq->pkt_in_done);
netdev_dbg(iq->netdev, "enabling intr for Q-%u\n", iq->q_no);
- if (iq->pkts_processed) {
- writel(iq->pkts_processed, iq->inst_cnt_reg);
- iq->pkt_in_done -= iq->pkts_processed;
- iq->pkts_processed = 0;
+ if (pkts_processed) {
+ writel(pkts_processed, iq->inst_cnt_reg);
+ readl(iq->inst_cnt_reg);
+ WRITE_ONCE(iq->pkt_in_done, (pkt_in_done - pkts_processed));
+ WRITE_ONCE(iq->pkts_processed, 0);
}
- if (oq->last_pkt_count - pkts_pend) {
- writel(oq->last_pkt_count - pkts_pend, oq->pkts_sent_reg);
- oq->last_pkt_count = pkts_pend;
+ if (last_pkt_count - pkts_pend) {
+ writel(last_pkt_count - pkts_pend, oq->pkts_sent_reg);
+ readl(oq->pkts_sent_reg);
+ WRITE_ONCE(oq->last_pkt_count, pkts_pend);
}
/* Flush the previous wrties before writing to RESEND bit */
smp_wmb();
+}
+
+/**
+ * octep_vf_enable_ioq_irq() - Enable MSI-x interrupt of a Tx/Rx queue.
+ *
+ * @iq: Octeon Tx queue data structure.
+ * @oq: Octeon Rx queue data structure.
+ */
+static void octep_vf_enable_ioq_irq(struct octep_vf_iq *iq,
+ struct octep_vf_oq *oq)
+{
writeq(1UL << OCTEP_VF_OQ_INTR_RESEND_BIT, oq->pkts_sent_reg);
writeq(1UL << OCTEP_VF_IQ_INTR_RESEND_BIT, iq->inst_cnt_reg);
}
@@ -333,6 +350,7 @@ static int octep_vf_napi_poll(struct napi_struct *napi, int budget)
if (tx_pending || rx_done >= budget)
return budget;
+ octep_vf_update_pkt(ioq_vector->iq, ioq_vector->oq);
if (likely(napi_complete_done(napi, rx_done)))
octep_vf_enable_ioq_irq(ioq_vector->iq, ioq_vector->oq);
diff --git a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
index 6f865dbbba6c..b579d5b545c4 100644
--- a/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
+++ b/drivers/net/ethernet/marvell/octeon_ep_vf/octep_vf_rx.c
@@ -325,9 +325,16 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
struct octep_vf_oq *oq)
{
u32 pkt_count, new_pkts;
+ u32 last_pkt_count, pkts_pending;
pkt_count = readl(oq->pkts_sent_reg);
- new_pkts = pkt_count - oq->last_pkt_count;
+ last_pkt_count = READ_ONCE(oq->last_pkt_count);
+ new_pkts = pkt_count - last_pkt_count;
+
+ if (pkt_count < last_pkt_count) {
+ dev_err(oq->dev, "OQ-%u pkt_count(%u) < oq->last_pkt_count(%u)\n",
+ oq->q_no, pkt_count, last_pkt_count);
+ }
/* Clear the hardware packets counter register if the rx queue is
* being processed continuously with-in a single interrupt and
@@ -339,8 +346,9 @@ static int octep_vf_oq_check_hw_for_pkts(struct octep_vf_device *oct,
pkt_count = readl(oq->pkts_sent_reg);
new_pkts += pkt_count;
}
- oq->last_pkt_count = pkt_count;
- oq->pkts_pending += new_pkts;
+ WRITE_ONCE(oq->last_pkt_count, pkt_count);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending + new_pkts));
return new_pkts;
}
@@ -369,7 +377,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
struct sk_buff *skb;
u32 read_idx;
- read_idx = oq->host_read_idx;
+ read_idx = READ_ONCE(oq->host_read_idx);
rx_bytes = 0;
desc_used = 0;
for (pkt = 0; pkt < pkts_to_process; pkt++) {
@@ -463,7 +471,7 @@ static int __octep_vf_oq_process_rx(struct octep_vf_device *oct,
napi_gro_receive(oq->napi, skb);
}
- oq->host_read_idx = read_idx;
+ WRITE_ONCE(oq->host_read_idx, read_idx);
oq->refill_count += desc_used;
oq->stats->packets += pkt;
oq->stats->bytes += rx_bytes;
@@ -486,22 +494,26 @@ int octep_vf_oq_process_rx(struct octep_vf_oq *oq, int budget)
{
u32 pkts_available, pkts_processed, total_pkts_processed;
struct octep_vf_device *oct = oq->octep_vf_dev;
+ u32 pkts_pending;
pkts_available = 0;
pkts_processed = 0;
total_pkts_processed = 0;
while (total_pkts_processed < budget) {
/* update pending count only when current one exhausted */
- if (oq->pkts_pending == 0)
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ if (pkts_pending == 0)
octep_vf_oq_check_hw_for_pkts(oct, oq);
+ pkts_pending = READ_ONCE(oq->pkts_pending);
pkts_available = min(budget - total_pkts_processed,
- oq->pkts_pending);
+ pkts_pending);
if (!pkts_available)
break;
pkts_processed = __octep_vf_oq_process_rx(oct, oq,
pkts_available);
- oq->pkts_pending -= pkts_processed;
+ pkts_pending = READ_ONCE(oq->pkts_pending);
+ WRITE_ONCE(oq->pkts_pending, (pkts_pending - pkts_processed));
total_pkts_processed += pkts_processed;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e5e2ffa9c542..ddc321a02fda 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -3748,12 +3748,21 @@ static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog,
mtk_stop(dev);
old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held());
+
+ if (netif_running(dev) && need_update) {
+ int err;
+
+ err = mtk_open(dev);
+ if (err) {
+ rcu_assign_pointer(eth->prog, old_prog);
+
+ return err;
+ }
+ }
+
if (old_prog)
bpf_prog_put(old_prog);
- if (netif_running(dev) && need_update)
- return mtk_open(dev);
-
return 0;
}
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 933e9d681ded..9017e806ecda 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1770,8 +1770,14 @@ static void mana_poll_tx_cq(struct mana_cq *cq)
ndev = txq->ndev;
apc = netdev_priv(ndev);
+ /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the
+ * doorbell can be rung in time for the hardware's requirement
+ * of at least one doorbell ring every 8 wraparounds.
+ */
comp_read = mana_gd_poll_cq(cq->gdma_cq, completions,
- CQE_POLLING_BUFFER);
+ min((cq->gdma_cq->queue_size /
+ COMP_ENTRY_SIZE) * 4,
+ CQE_POLLING_BUFFER));
if (comp_read < 1)
return;
@@ -2156,7 +2162,14 @@ static void mana_poll_rx_cq(struct mana_cq *cq)
struct mana_rxq *rxq = cq->rxq;
int comp_read, i;
- comp_read = mana_gd_poll_cq(cq->gdma_cq, comp, CQE_POLLING_BUFFER);
+ /* Limit CQEs polled to 4 wraparounds of the CQ to ensure the
+ * doorbell can be rung in time for the hardware's requirement
+ * of at least one doorbell ring every 8 wraparounds.
+ */
+ comp_read = mana_gd_poll_cq(cq->gdma_cq, comp,
+ min((cq->gdma_cq->queue_size /
+ COMP_ENTRY_SIZE) * 4,
+ CQE_POLLING_BUFFER));
WARN_ON_ONCE(comp_read > CQE_POLLING_BUFFER);
rxq->xdp_flush = false;
@@ -2201,11 +2214,11 @@ static int mana_cq_handler(void *context, struct gdma_queue *gdma_queue)
mana_gd_ring_cq(gdma_queue, SET_ARM_BIT);
cq->work_done_since_doorbell = 0;
napi_complete_done(&cq->napi, w);
- } else if (cq->work_done_since_doorbell >
- cq->gdma_cq->queue_size / COMP_ENTRY_SIZE * 4) {
+ } else if (cq->work_done_since_doorbell >=
+ (cq->gdma_cq->queue_size / COMP_ENTRY_SIZE) * 4) {
/* MANA hardware requires at least one doorbell ring every 8
* wraparounds of CQ even if there is no need to arm the CQ.
- * This driver rings the doorbell as soon as we have exceeded
+ * This driver rings the doorbell as soon as it has processed
* 4 wraparounds.
*/
mana_gd_ring_cq(gdma_queue, 0);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 51c96a738151..33667a26708c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -323,6 +323,7 @@ struct stmmac_priv {
void __iomem *ptpaddr;
void __iomem *estaddr;
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+ unsigned int num_double_vlans;
int sfty_irq;
int sfty_ce_irq;
int sfty_ue_irq;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index e00aa42a1961..6827c99bde8c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -156,6 +156,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue);
static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue);
static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
u32 rxmode, u32 chan);
+static int stmmac_vlan_restore(struct stmmac_priv *priv);
#ifdef CONFIG_DEBUG_FS
static const struct net_device_ops stmmac_netdev_ops;
@@ -4107,6 +4108,8 @@ static int __stmmac_open(struct net_device *dev,
phylink_start(priv->phylink);
+ stmmac_vlan_restore(priv);
+
ret = stmmac_request_irq(dev);
if (ret)
goto irq_error;
@@ -6766,6 +6769,9 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
hash = 0;
}
+ if (!netif_running(priv->dev))
+ return 0;
+
return stmmac_update_vlan_hash(priv, priv->hw, hash, pmatch, is_double);
}
@@ -6775,6 +6781,7 @@ static int stmmac_vlan_update(struct stmmac_priv *priv, bool is_double)
static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned int num_double_vlans;
bool is_double = false;
int ret;
@@ -6786,7 +6793,8 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
is_double = true;
set_bit(vid, priv->active_vlans);
- ret = stmmac_vlan_update(priv, is_double);
+ num_double_vlans = priv->num_double_vlans + is_double;
+ ret = stmmac_vlan_update(priv, num_double_vlans);
if (ret) {
clear_bit(vid, priv->active_vlans);
goto err_pm_put;
@@ -6794,9 +6802,15 @@ static int stmmac_vlan_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid
if (priv->hw->num_vlan) {
ret = stmmac_add_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
- if (ret)
+ if (ret) {
+ clear_bit(vid, priv->active_vlans);
+ stmmac_vlan_update(priv, priv->num_double_vlans);
goto err_pm_put;
+ }
}
+
+ priv->num_double_vlans = num_double_vlans;
+
err_pm_put:
pm_runtime_put(priv->device);
@@ -6809,6 +6823,7 @@ err_pm_put:
static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
{
struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned int num_double_vlans;
bool is_double = false;
int ret;
@@ -6820,14 +6835,23 @@ static int stmmac_vlan_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vi
is_double = true;
clear_bit(vid, priv->active_vlans);
+ num_double_vlans = priv->num_double_vlans - is_double;
+ ret = stmmac_vlan_update(priv, num_double_vlans);
+ if (ret) {
+ set_bit(vid, priv->active_vlans);
+ goto del_vlan_error;
+ }
if (priv->hw->num_vlan) {
ret = stmmac_del_hw_vlan_rx_fltr(priv, ndev, priv->hw, proto, vid);
- if (ret)
+ if (ret) {
+ set_bit(vid, priv->active_vlans);
+ stmmac_vlan_update(priv, priv->num_double_vlans);
goto del_vlan_error;
+ }
}
- ret = stmmac_vlan_update(priv, is_double);
+ priv->num_double_vlans = num_double_vlans;
del_vlan_error:
pm_runtime_put(priv->device);
@@ -6835,6 +6859,23 @@ del_vlan_error:
return ret;
}
+static int stmmac_vlan_restore(struct stmmac_priv *priv)
+{
+ int ret;
+
+ if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
+ return 0;
+
+ if (priv->hw->num_vlan)
+ stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw);
+
+ ret = stmmac_vlan_update(priv, priv->num_double_vlans);
+ if (ret)
+ netdev_err(priv->dev, "Failed to restore VLANs\n");
+
+ return ret;
+}
+
static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf)
{
struct stmmac_priv *priv = netdev_priv(dev);
@@ -8259,10 +8300,10 @@ int stmmac_resume(struct device *dev)
stmmac_init_coalesce(priv);
phylink_rx_clk_stop_block(priv->phylink);
stmmac_set_rx_mode(ndev);
-
- stmmac_restore_hw_vlan_rx_fltr(priv, ndev, priv->hw);
phylink_rx_clk_stop_unblock(priv->phylink);
+ stmmac_vlan_restore(priv);
+
stmmac_enable_all_queues(priv);
stmmac_enable_all_dma_irq(priv);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
index b18404dd5a8b..e24efe3bfedb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c
@@ -76,7 +76,9 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev,
}
hw->vlan_filter[0] = vid;
- vlan_write_single(dev, vid);
+
+ if (netif_running(dev))
+ vlan_write_single(dev, vid);
return 0;
}
@@ -97,12 +99,15 @@ static int vlan_add_hw_rx_fltr(struct net_device *dev,
return -EPERM;
}
- ret = vlan_write_filter(dev, hw, index, val);
+ if (netif_running(dev)) {
+ ret = vlan_write_filter(dev, hw, index, val);
+ if (ret)
+ return ret;
+ }
- if (!ret)
- hw->vlan_filter[index] = val;
+ hw->vlan_filter[index] = val;
- return ret;
+ return 0;
}
static int vlan_del_hw_rx_fltr(struct net_device *dev,
@@ -115,7 +120,9 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev,
if (hw->num_vlan == 1) {
if ((hw->vlan_filter[0] & VLAN_TAG_VID) == vid) {
hw->vlan_filter[0] = 0;
- vlan_write_single(dev, 0);
+
+ if (netif_running(dev))
+ vlan_write_single(dev, 0);
}
return 0;
}
@@ -124,25 +131,23 @@ static int vlan_del_hw_rx_fltr(struct net_device *dev,
for (i = 0; i < hw->num_vlan; i++) {
if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) &&
((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid)) {
- ret = vlan_write_filter(dev, hw, i, 0);
- if (!ret)
- hw->vlan_filter[i] = 0;
- else
- return ret;
+ if (netif_running(dev)) {
+ ret = vlan_write_filter(dev, hw, i, 0);
+ if (ret)
+ return ret;
+ }
+
+ hw->vlan_filter[i] = 0;
}
}
- return ret;
+ return 0;
}
static void vlan_restore_hw_rx_fltr(struct net_device *dev,
struct mac_device_info *hw)
{
- void __iomem *ioaddr = hw->pcsr;
- u32 value;
- u32 hash;
- u32 val;
int i;
/* Single Rx VLAN Filter */
@@ -152,19 +157,8 @@ static void vlan_restore_hw_rx_fltr(struct net_device *dev,
}
/* Extended Rx VLAN Filter Enable */
- for (i = 0; i < hw->num_vlan; i++) {
- if (hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) {
- val = hw->vlan_filter[i];
- vlan_write_filter(dev, hw, i, val);
- }
- }
-
- hash = readl(ioaddr + VLAN_HASH_TABLE);
- if (hash & VLAN_VLHT) {
- value = readl(ioaddr + VLAN_TAG);
- value |= VLAN_VTHM;
- writel(value, ioaddr + VLAN_TAG);
- }
+ for (i = 0; i < hw->num_vlan; i++)
+ vlan_write_filter(dev, hw, i, hw->vlan_filter[i]);
}
static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
@@ -183,6 +177,10 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
+ } else {
+ value &= ~VLAN_EDVLP;
+ value &= ~VLAN_ESVL;
+ value &= ~VLAN_DOVLTC;
}
writel(value, ioaddr + VLAN_TAG);
@@ -193,6 +191,10 @@ static void vlan_update_hash(struct mac_device_info *hw, u32 hash,
value |= VLAN_EDVLP;
value |= VLAN_ESVL;
value |= VLAN_DOVLTC;
+ } else {
+ value &= ~VLAN_EDVLP;
+ value &= ~VLAN_ESVL;
+ value &= ~VLAN_DOVLTC;
}
writel(value | perfect_match, ioaddr + VLAN_TAG);
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index 5924db6be3fe..967918050433 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -391,7 +391,7 @@ static void am65_cpsw_nuss_ndo_slave_set_rx_mode(struct net_device *ndev)
cpsw_ale_set_allmulti(common->ale,
ndev->flags & IFF_ALLMULTI, port->port_id);
- port_mask = ALE_PORT_HOST;
+ port_mask = BIT(port->port_id) | ALE_PORT_HOST;
/* Clear all mcast from ALE */
cpsw_ale_flush_multicast(common->ale, port_mask, -1);
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index bb969dd435b4..be7b69319221 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -450,14 +450,13 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
ale->port_mask_bits);
if ((mask & port_mask) == 0)
return; /* ports dont intersect, not interested */
- mask &= ~port_mask;
+ mask &= (~port_mask | ALE_PORT_HOST);
- /* free if only remaining port is host port */
- if (mask)
+ if (mask == 0x0 || mask == ALE_PORT_HOST)
+ cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+ else
cpsw_ale_set_port_mask(ale_entry, mask,
ale->port_mask_bits);
- else
- cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
}
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 0939994c932f..42a881bee109 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -273,6 +273,14 @@ static int prueth_emac_common_start(struct prueth *prueth)
if (ret)
goto disable_class;
+ /* Reset link state to force reconfiguration in
+ * emac_adjust_link(). Without this, if the link was already up
+ * before restart, emac_adjust_link() won't detect any state
+ * change and will skip critical configuration like writing
+ * speed to firmware.
+ */
+ emac->link = 0;
+
mutex_lock(&emac->ndev->phydev->lock);
emac_adjust_link(emac->ndev);
mutex_unlock(&emac->ndev->phydev->lock);
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 2db116fb1a7c..3c9acd6e49e8 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -617,7 +617,7 @@ static ssize_t sysdata_release_enabled_show(struct config_item *item,
bool release_enabled;
dynamic_netconsole_mutex_lock();
- release_enabled = !!(nt->sysdata_fields & SYSDATA_TASKNAME);
+ release_enabled = !!(nt->sysdata_fields & SYSDATA_RELEASE);
dynamic_netconsole_mutex_unlock();
return sysfs_emit(buf, "%d\n", release_enabled);
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 4af85728ac4f..0c83bbbea2e7 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -10054,6 +10054,7 @@ static const struct usb_device_id rtl8152_table[] = {
{ USB_DEVICE(VENDOR_ID_DLINK, 0xb301) },
{ USB_DEVICE(VENDOR_ID_DELL, 0xb097) },
{ USB_DEVICE(VENDOR_ID_ASUS, 0x1976) },
+ { USB_DEVICE(VENDOR_ID_TRENDNET, 0xe02b) },
{}
};
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 05558b6afecd..17c941aac32d 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2130,6 +2130,11 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
{
struct ipv6hdr *pip6;
+ /* check if nd_tbl is not initiliazed due to
+ * ipv6.disable=1 set during boot
+ */
+ if (!ipv6_stub->nd_tbl)
+ return false;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
return false;
pip6 = ipv6_hdr(skb);
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index c6b88909b6b7..b253d1e3f405 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5430,7 +5430,7 @@ int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw,
ar->last_tx_power_update))
goto send_tx_power;
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = arvif->vdev_id;
params.stats_id = WMI_REQUEST_PDEV_STAT;
ret = ath12k_mac_get_fw_stats(ar, &params);
@@ -13452,7 +13452,7 @@ void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
/* TODO: Use real NF instead of default one. */
signal = rate_info.rssi_comb;
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = 0;
params.stats_id = WMI_REQUEST_VDEV_STAT;
@@ -13580,7 +13580,7 @@ void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->ab->dp->dp_lock);
if (!signal && ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA) {
- params.pdev_id = ar->pdev->pdev_id;
+ params.pdev_id = ath12k_mac_get_target_pdev_id(ar);
params.vdev_id = 0;
params.stats_id = WMI_REQUEST_VDEV_STAT;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index eb7615a289f7..48fee9346de8 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -8241,8 +8241,6 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
struct ath12k_fw_stats *stats = parse->stats;
struct ath12k *ar;
struct ath12k_link_vif *arvif;
- struct ieee80211_sta *sta;
- struct ath12k_sta *ahsta;
struct ath12k_link_sta *arsta;
int i, ret = 0;
const void *data = ptr;
@@ -8278,21 +8276,19 @@ static int ath12k_wmi_tlv_fw_stats_data_parse(struct ath12k_base *ab,
arvif = ath12k_mac_get_arvif(ar, le32_to_cpu(src->vdev_id));
if (arvif) {
- sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
- arvif->bssid,
- NULL);
- if (sta) {
- ahsta = ath12k_sta_to_ahsta(sta);
- arsta = &ahsta->deflink;
+ spin_lock_bh(&ab->base_lock);
+ arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+ if (arsta) {
arsta->rssi_beacon = le32_to_cpu(src->beacon_snr);
ath12k_dbg(ab, ATH12K_DBG_WMI,
"wmi stats vdev id %d snr %d\n",
src->vdev_id, src->beacon_snr);
} else {
- ath12k_dbg(ab, ATH12K_DBG_WMI,
- "not found station bssid %pM for vdev stat\n",
- arvif->bssid);
+ ath12k_warn(ab,
+ "not found link sta with bssid %pM for vdev stat\n",
+ arvif->bssid);
}
+ spin_unlock_bh(&ab->base_lock);
}
data += sizeof(*src);
@@ -8363,8 +8359,6 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
struct ath12k_fw_stats *stats = parse->stats;
struct ath12k_link_vif *arvif;
struct ath12k_link_sta *arsta;
- struct ieee80211_sta *sta;
- struct ath12k_sta *ahsta;
struct ath12k *ar;
int vdev_id;
int j;
@@ -8400,19 +8394,15 @@ static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab,
"stats bssid %pM vif %p\n",
arvif->bssid, arvif->ahvif->vif);
- sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
- arvif->bssid,
- NULL);
- if (!sta) {
- ath12k_dbg(ab, ATH12K_DBG_WMI,
- "not found station of bssid %pM for rssi chain\n",
- arvif->bssid);
+ guard(spinlock_bh)(&ab->base_lock);
+ arsta = ath12k_link_sta_find_by_addr(ab, arvif->bssid);
+ if (!arsta) {
+ ath12k_warn(ab,
+ "not found link sta with bssid %pM for rssi chain\n",
+ arvif->bssid);
return -EPROTO;
}
- ahsta = ath12k_sta_to_ahsta(sta);
- arsta = &ahsta->deflink;
-
BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) >
ARRAY_SIZE(stats_rssi->rssi_avg_beacon));
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 3304b5971be0..b41ca1410da9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -413,6 +413,7 @@ mt76_connac2_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 + 1 + 2 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
u16 capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 871b67101976..0d9435900423 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -668,6 +668,7 @@ mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
tid = MT_TX_ADDBA;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 2560e2f46e89..d4f3ee943b47 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -800,6 +800,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
u32 val;
if (ieee80211_is_action(fc) &&
+ skb->len >= IEEE80211_MIN_ACTION_SIZE + 1 &&
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) {
if (is_mt7990(&dev->mt76))
diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
index 8c8e074a3a70..c7ae8031436a 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c
@@ -668,7 +668,7 @@ static int rsi_mac80211_config(struct ieee80211_hw *hw,
struct rsi_hw *adapter = hw->priv;
struct rsi_common *common = adapter->priv;
struct ieee80211_conf *conf = &hw->conf;
- int status = -EOPNOTSUPP;
+ int status = 0;
mutex_lock(&common->mutex);
diff --git a/drivers/net/wireless/st/cw1200/pm.c b/drivers/net/wireless/st/cw1200/pm.c
index 120f0379f81d..84eb15d729c7 100644
--- a/drivers/net/wireless/st/cw1200/pm.c
+++ b/drivers/net/wireless/st/cw1200/pm.c
@@ -264,12 +264,14 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
wiphy_err(priv->hw->wiphy,
"PM request failed: %d. WoW is disabled.\n", ret);
cw1200_wow_resume(hw);
+ mutex_unlock(&priv->conf_mutex);
return -EBUSY;
}
/* Force resume if event is coming from the device. */
if (atomic_read(&priv->bh_rx)) {
cw1200_wow_resume(hw);
+ mutex_unlock(&priv->conf_mutex);
return -EAGAIN;
}
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 17dd417756f2..1c340a4a0930 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -1875,6 +1875,8 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
wl->wow_enabled);
WARN_ON(!wl->wow_enabled);
+ mutex_lock(&wl->mutex);
+
ret = pm_runtime_force_resume(wl->dev);
if (ret < 0) {
wl1271_error("ELP wakeup failure!");
@@ -1891,8 +1893,6 @@ static int __maybe_unused wl1271_op_resume(struct ieee80211_hw *hw)
run_irq_work = true;
spin_unlock_irqrestore(&wl->wl_lock, flags);
- mutex_lock(&wl->mutex);
-
/* test the recovery flag before calling any SDIO functions */
pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS,
&wl->flags);
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d316b35f404b..2ed673649c48 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1646,7 +1646,7 @@ static int xennet_xdp_set(struct net_device *dev, struct bpf_prog *prog,
/* avoid the race with XDP headroom adjustment */
wait_event(module_wq,
- xenbus_read_driver_state(np->xbdev->otherend) ==
+ xenbus_read_driver_state(np->xbdev, np->xbdev->otherend) ==
XenbusStateReconfigured);
np->netfront_xdp_enabled = true;
@@ -1764,9 +1764,9 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
do {
xenbus_switch_state(dev, XenbusStateInitialising);
err = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) !=
+ xenbus_read_driver_state(dev, dev->otherend) !=
XenbusStateClosed &&
- xenbus_read_driver_state(dev->otherend) !=
+ xenbus_read_driver_state(dev, dev->otherend) !=
XenbusStateUnknown, XENNET_TIMEOUT);
} while (!err);
@@ -2626,31 +2626,31 @@ static void xennet_bus_close(struct xenbus_device *dev)
{
int ret;
- if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+ if (xenbus_read_driver_state(dev, dev->otherend) == XenbusStateClosed)
return;
do {
xenbus_switch_state(dev, XenbusStateClosing);
ret = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosing ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosed ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateUnknown,
- XENNET_TIMEOUT);
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosing ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosed ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateUnknown,
+ XENNET_TIMEOUT);
} while (!ret);
- if (xenbus_read_driver_state(dev->otherend) == XenbusStateClosed)
+ if (xenbus_read_driver_state(dev, dev->otherend) == XenbusStateClosed)
return;
do {
xenbus_switch_state(dev, XenbusStateClosed);
ret = wait_event_timeout(module_wq,
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateClosed ||
- xenbus_read_driver_state(dev->otherend) ==
- XenbusStateUnknown,
- XENNET_TIMEOUT);
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateClosed ||
+ xenbus_read_driver_state(dev, dev->otherend) ==
+ XenbusStateUnknown,
+ XENNET_TIMEOUT);
} while (!ret);
}
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index f5ebcaa2f859..58bf432ec5e6 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2046,14 +2046,10 @@ static u32 nvme_configure_atomic_write(struct nvme_ns *ns,
if (id->nabspf)
boundary = (le16_to_cpu(id->nabspf) + 1) * bs;
} else {
- /*
- * Use the controller wide atomic write unit. This sucks
- * because the limit is defined in terms of logical blocks while
- * namespaces can have different formats, and because there is
- * no clear language in the specification prohibiting different
- * values for different controllers in the subsystem.
- */
- atomic_bs = (1 + ns->ctrl->subsys->awupf) * bs;
+ if (ns->ctrl->awupf)
+ dev_info_once(ns->ctrl->device,
+ "AWUPF ignored, only NAWUPF accepted\n");
+ atomic_bs = bs;
}
lim->atomic_write_hw_max = atomic_bs;
@@ -3222,7 +3218,6 @@ static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
memcpy(subsys->model, id->mn, sizeof(subsys->model));
subsys->vendor_id = le16_to_cpu(id->vid);
subsys->cmic = id->cmic;
- subsys->awupf = le16_to_cpu(id->awupf);
/* Versions prior to 1.4 don't necessarily report a valid type */
if (id->cntrltype == NVME_CTRL_DISC ||
@@ -3655,6 +3650,7 @@ static int nvme_init_identify(struct nvme_ctrl *ctrl)
dev_pm_qos_expose_latency_tolerance(ctrl->device);
else if (!ctrl->apst_enabled && prev_apst_enabled)
dev_pm_qos_hide_latency_tolerance(ctrl->device);
+ ctrl->awupf = le16_to_cpu(id->awupf);
out_free:
kfree(id);
return ret;
@@ -4186,13 +4182,6 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, struct nvme_ns_info *info)
nvme_mpath_add_disk(ns, info->anagrpid);
nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name);
- /*
- * Set ns->disk->device->driver_data to ns so we can access
- * ns->head->passthru_err_log_enabled in
- * nvme_io_passthru_err_log_enabled_[store | show]().
- */
- dev_set_drvdata(disk_to_dev(ns->disk), ns);
-
return;
out_cleanup_ns_from_list:
@@ -4865,6 +4854,13 @@ int nvme_alloc_admin_tag_set(struct nvme_ctrl *ctrl, struct blk_mq_tag_set *set,
if (ret)
return ret;
+ /*
+ * If a previous admin queue exists (e.g., from before a reset),
+ * put it now before allocating a new one to avoid orphaning it.
+ */
+ if (ctrl->admin_q)
+ blk_put_queue(ctrl->admin_q);
+
ctrl->admin_q = blk_mq_alloc_queue(set, &lim, NULL);
if (IS_ERR(ctrl->admin_q)) {
ret = PTR_ERR(ctrl->admin_q);
diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c
index 5fe09e327b3d..ac3d4f400601 100644
--- a/drivers/nvme/host/fabrics.c
+++ b/drivers/nvme/host/fabrics.c
@@ -1290,8 +1290,8 @@ void nvmf_free_options(struct nvmf_ctrl_options *opts)
kfree(opts->subsysnqn);
kfree(opts->host_traddr);
kfree(opts->host_iface);
- kfree(opts->dhchap_secret);
- kfree(opts->dhchap_ctrl_secret);
+ kfree_sensitive(opts->dhchap_secret);
+ kfree_sensitive(opts->dhchap_ctrl_secret);
kfree(opts);
}
EXPORT_SYMBOL_GPL(nvmf_free_options);
diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c
index 174027d1cc19..fc6800a9f7f9 100644
--- a/drivers/nvme/host/multipath.c
+++ b/drivers/nvme/host/multipath.c
@@ -1300,7 +1300,7 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
mutex_lock(&head->subsys->lock);
/*
* We are called when all paths have been removed, and at that point
- * head->list is expected to be empty. However, nvme_remove_ns() and
+ * head->list is expected to be empty. However, nvme_ns_remove() and
* nvme_init_ns_head() can run concurrently and so if head->delayed_
* removal_secs is configured, it is possible that by the time we reach
* this point, head->list may no longer be empty. Therefore, we recheck
@@ -1310,13 +1310,11 @@ void nvme_mpath_remove_disk(struct nvme_ns_head *head)
if (!list_empty(&head->list))
goto out;
- if (head->delayed_removal_secs) {
- /*
- * Ensure that no one could remove this module while the head
- * remove work is pending.
- */
- if (!try_module_get(THIS_MODULE))
- goto out;
+ /*
+ * Ensure that no one could remove this module while the head
+ * remove work is pending.
+ */
+ if (head->delayed_removal_secs && try_module_get(THIS_MODULE)) {
mod_delayed_work(nvme_wq, &head->remove_work,
head->delayed_removal_secs * HZ);
} else {
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index 9a5f28c5103c..9971045dbc05 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -180,6 +180,60 @@ enum nvme_quirks {
NVME_QUIRK_DMAPOOL_ALIGN_512 = (1 << 22),
};
+static inline char *nvme_quirk_name(enum nvme_quirks q)
+{
+ switch (q) {
+ case NVME_QUIRK_STRIPE_SIZE:
+ return "stripe_size";
+ case NVME_QUIRK_IDENTIFY_CNS:
+ return "identify_cns";
+ case NVME_QUIRK_DEALLOCATE_ZEROES:
+ return "deallocate_zeroes";
+ case NVME_QUIRK_DELAY_BEFORE_CHK_RDY:
+ return "delay_before_chk_rdy";
+ case NVME_QUIRK_NO_APST:
+ return "no_apst";
+ case NVME_QUIRK_NO_DEEPEST_PS:
+ return "no_deepest_ps";
+ case NVME_QUIRK_QDEPTH_ONE:
+ return "qdepth_one";
+ case NVME_QUIRK_MEDIUM_PRIO_SQ:
+ return "medium_prio_sq";
+ case NVME_QUIRK_IGNORE_DEV_SUBNQN:
+ return "ignore_dev_subnqn";
+ case NVME_QUIRK_DISABLE_WRITE_ZEROES:
+ return "disable_write_zeroes";
+ case NVME_QUIRK_SIMPLE_SUSPEND:
+ return "simple_suspend";
+ case NVME_QUIRK_SINGLE_VECTOR:
+ return "single_vector";
+ case NVME_QUIRK_128_BYTES_SQES:
+ return "128_bytes_sqes";
+ case NVME_QUIRK_SHARED_TAGS:
+ return "shared_tags";
+ case NVME_QUIRK_NO_TEMP_THRESH_CHANGE:
+ return "no_temp_thresh_change";
+ case NVME_QUIRK_NO_NS_DESC_LIST:
+ return "no_ns_desc_list";
+ case NVME_QUIRK_DMA_ADDRESS_BITS_48:
+ return "dma_address_bits_48";
+ case NVME_QUIRK_SKIP_CID_GEN:
+ return "skip_cid_gen";
+ case NVME_QUIRK_BOGUS_NID:
+ return "bogus_nid";
+ case NVME_QUIRK_NO_SECONDARY_TEMP_THRESH:
+ return "no_secondary_temp_thresh";
+ case NVME_QUIRK_FORCE_NO_SIMPLE_SUSPEND:
+ return "force_no_simple_suspend";
+ case NVME_QUIRK_BROKEN_MSI:
+ return "broken_msi";
+ case NVME_QUIRK_DMAPOOL_ALIGN_512:
+ return "dmapool_align_512";
+ }
+
+ return "unknown";
+}
+
/*
* Common request structure for NVMe passthrough. All drivers must have
* this structure as the first member of their request-private data.
@@ -410,6 +464,8 @@ struct nvme_ctrl {
enum nvme_ctrl_type cntrltype;
enum nvme_dctype dctype;
+
+ u16 awupf; /* 0's based value. */
};
static inline enum nvme_ctrl_state nvme_ctrl_state(struct nvme_ctrl *ctrl)
@@ -442,7 +498,6 @@ struct nvme_subsystem {
u8 cmic;
enum nvme_subsys_type subtype;
u16 vendor_id;
- u16 awupf; /* 0's based value. */
struct ida ns_ida;
#ifdef CONFIG_NVME_MULTIPATH
enum nvme_iopolicy iopolicy;
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 2f0c05719316..8d09fa7d7ff9 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -72,6 +72,13 @@
static_assert(MAX_PRP_RANGE / NVME_CTRL_PAGE_SIZE <=
(1 /* prp1 */ + NVME_MAX_NR_DESCRIPTORS * PRPS_PER_PAGE));
+struct quirk_entry {
+ u16 vendor_id;
+ u16 dev_id;
+ u32 enabled_quirks;
+ u32 disabled_quirks;
+};
+
static int use_threaded_interrupts;
module_param(use_threaded_interrupts, int, 0444);
@@ -102,6 +109,143 @@ static unsigned int io_queue_depth = 1024;
module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644);
MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2 and < 4096");
+static struct quirk_entry *nvme_pci_quirk_list;
+static unsigned int nvme_pci_quirk_count;
+
+/* Helper to parse individual quirk names */
+static int nvme_parse_quirk_names(char *quirk_str, struct quirk_entry *entry)
+{
+ int i;
+ size_t field_len;
+ bool disabled, found;
+ char *p = quirk_str, *field;
+
+ while ((field = strsep(&p, ",")) && *field) {
+ disabled = false;
+ found = false;
+
+ if (*field == '^') {
+ /* Skip the '^' character */
+ disabled = true;
+ field++;
+ }
+
+ field_len = strlen(field);
+ for (i = 0; i < 32; i++) {
+ unsigned int bit = 1U << i;
+ char *q_name = nvme_quirk_name(bit);
+ size_t q_len = strlen(q_name);
+
+ if (!strcmp(q_name, "unknown"))
+ break;
+
+ if (!strcmp(q_name, field) &&
+ q_len == field_len) {
+ if (disabled)
+ entry->disabled_quirks |= bit;
+ else
+ entry->enabled_quirks |= bit;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pr_err("nvme: unrecognized quirk %s\n", field);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/* Helper to parse a single VID:DID:quirk_names entry */
+static int nvme_parse_quirk_entry(char *s, struct quirk_entry *entry)
+{
+ char *field;
+
+ field = strsep(&s, ":");
+ if (!field || kstrtou16(field, 16, &entry->vendor_id))
+ return -EINVAL;
+
+ field = strsep(&s, ":");
+ if (!field || kstrtou16(field, 16, &entry->dev_id))
+ return -EINVAL;
+
+ field = strsep(&s, ":");
+ if (!field)
+ return -EINVAL;
+
+ return nvme_parse_quirk_names(field, entry);
+}
+
+static int quirks_param_set(const char *value, const struct kernel_param *kp)
+{
+ int count, err, i;
+ struct quirk_entry *qlist;
+ char *field, *val, *sep_ptr;
+
+ err = param_set_copystring(value, kp);
+ if (err)
+ return err;
+
+ val = kstrdup(value, GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
+
+ if (!*val)
+ goto out_free_val;
+
+ count = 1;
+ for (i = 0; val[i]; i++) {
+ if (val[i] == '-')
+ count++;
+ }
+
+ qlist = kcalloc(count, sizeof(*qlist), GFP_KERNEL);
+ if (!qlist) {
+ err = -ENOMEM;
+ goto out_free_val;
+ }
+
+ i = 0;
+ sep_ptr = val;
+ while ((field = strsep(&sep_ptr, "-"))) {
+ if (nvme_parse_quirk_entry(field, &qlist[i])) {
+ pr_err("nvme: failed to parse quirk string %s\n",
+ value);
+ goto out_free_qlist;
+ }
+
+ i++;
+ }
+
+ kfree(nvme_pci_quirk_list);
+ nvme_pci_quirk_count = count;
+ nvme_pci_quirk_list = qlist;
+ goto out_free_val;
+
+out_free_qlist:
+ kfree(qlist);
+out_free_val:
+ kfree(val);
+ return err;
+}
+
+static char quirks_param[128];
+static const struct kernel_param_ops quirks_param_ops = {
+ .set = quirks_param_set,
+ .get = param_get_string,
+};
+
+static struct kparam_string quirks_param_string = {
+ .maxlen = sizeof(quirks_param),
+ .string = quirks_param,
+};
+
+module_param_cb(quirks, &quirks_param_ops, &quirks_param_string, 0444);
+MODULE_PARM_DESC(quirks, "Enable/disable NVMe quirks by specifying "
+ "quirks=VID:DID:quirk_names");
+
static int io_queue_count_set(const char *val, const struct kernel_param *kp)
{
unsigned int n;
@@ -1496,7 +1640,8 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx, struct io_comp_batch *iob)
struct nvme_queue *nvmeq = hctx->driver_data;
bool found;
- if (!nvme_cqe_pending(nvmeq))
+ if (!test_bit(NVMEQ_POLLED, &nvmeq->flags) ||
+ !nvme_cqe_pending(nvmeq))
return 0;
spin_lock(&nvmeq->cq_poll_lock);
@@ -2774,7 +2919,25 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
dev->nr_write_queues = write_queues;
dev->nr_poll_queues = poll_queues;
- nr_io_queues = dev->nr_allocated_queues - 1;
+ if (dev->ctrl.tagset) {
+ /*
+ * The set's maps are allocated only once at initialization
+ * time. We can't add special queues later if their mq_map
+ * wasn't preallocated.
+ */
+ if (dev->ctrl.tagset->nr_maps < 3)
+ dev->nr_poll_queues = 0;
+ if (dev->ctrl.tagset->nr_maps < 2)
+ dev->nr_write_queues = 0;
+ }
+
+ /*
+ * The initial number of allocated queue slots may be too large if the
+ * user reduced the special queue parameters. Cap the value to the
+ * number we need for this round.
+ */
+ nr_io_queues = min(nvme_max_io_queues(dev),
+ dev->nr_allocated_queues - 1);
result = nvme_set_queue_count(&dev->ctrl, &nr_io_queues);
if (result < 0)
return result;
@@ -3458,12 +3621,25 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev)
return 0;
}
+static struct quirk_entry *detect_dynamic_quirks(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < nvme_pci_quirk_count; i++)
+ if (pdev->vendor == nvme_pci_quirk_list[i].vendor_id &&
+ pdev->device == nvme_pci_quirk_list[i].dev_id)
+ return &nvme_pci_quirk_list[i];
+
+ return NULL;
+}
+
static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
const struct pci_device_id *id)
{
unsigned long quirks = id->driver_data;
int node = dev_to_node(&pdev->dev);
struct nvme_dev *dev;
+ struct quirk_entry *qentry;
int ret = -ENOMEM;
dev = kzalloc_node(struct_size(dev, descriptor_pools, nr_node_ids),
@@ -3495,6 +3671,11 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev,
"platform quirk: setting simple suspend\n");
quirks |= NVME_QUIRK_SIMPLE_SUSPEND;
}
+ qentry = detect_dynamic_quirks(pdev);
+ if (qentry) {
+ quirks |= qentry->enabled_quirks;
+ quirks &= ~qentry->disabled_quirks;
+ }
ret = nvme_init_ctrl(&dev->ctrl, &pdev->dev, &nvme_pci_ctrl_ops,
quirks);
if (ret)
@@ -4095,6 +4276,7 @@ static int __init nvme_init(void)
static void __exit nvme_exit(void)
{
+ kfree(nvme_pci_quirk_list);
pci_unregister_driver(&nvme_driver);
flush_workqueue(nvme_wq);
}
diff --git a/drivers/nvme/host/pr.c b/drivers/nvme/host/pr.c
index ad2ecc2f49a9..fe7dbe264815 100644
--- a/drivers/nvme/host/pr.c
+++ b/drivers/nvme/host/pr.c
@@ -242,7 +242,7 @@ static int nvme_pr_read_keys(struct block_device *bdev,
if (rse_len > U32_MAX)
return -EINVAL;
- rse = kzalloc(rse_len, GFP_KERNEL);
+ rse = kvzalloc(rse_len, GFP_KERNEL);
if (!rse)
return -ENOMEM;
@@ -267,7 +267,7 @@ static int nvme_pr_read_keys(struct block_device *bdev,
}
free_rse:
- kfree(rse);
+ kvfree(rse);
return ret;
}
diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c
index 29430949ce2f..16c6fea4b2db 100644
--- a/drivers/nvme/host/sysfs.c
+++ b/drivers/nvme/host/sysfs.c
@@ -601,6 +601,28 @@ static ssize_t dctype_show(struct device *dev,
}
static DEVICE_ATTR_RO(dctype);
+static ssize_t quirks_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ int count = 0, i;
+ struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
+ unsigned long quirks = ctrl->quirks;
+
+ if (!quirks)
+ return sysfs_emit(buf, "none\n");
+
+ for (i = 0; quirks; ++i) {
+ if (quirks & 1) {
+ count += sysfs_emit_at(buf, count, "%s\n",
+ nvme_quirk_name(BIT(i)));
+ }
+ quirks >>= 1;
+ }
+
+ return count;
+}
+static DEVICE_ATTR_RO(quirks);
+
#ifdef CONFIG_NVME_HOST_AUTH
static ssize_t nvme_ctrl_dhchap_secret_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -742,6 +764,7 @@ static struct attribute *nvme_dev_attrs[] = {
&dev_attr_kato.attr,
&dev_attr_cntrltype.attr,
&dev_attr_dctype.attr,
+ &dev_attr_quirks.attr,
#ifdef CONFIG_NVME_HOST_AUTH
&dev_attr_dhchap_secret.attr,
&dev_attr_dhchap_ctrl_secret.attr,
diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c
index 9ab3f61196a3..243dab830dc8 100644
--- a/drivers/nvme/host/tcp.c
+++ b/drivers/nvme/host/tcp.c
@@ -25,7 +25,8 @@
struct nvme_tcp_queue;
-/* Define the socket priority to use for connections were it is desirable
+/*
+ * Define the socket priority to use for connections where it is desirable
* that the NIC consider performing optimized packet processing or filtering.
* A non-zero value being sufficient to indicate general consideration of any
* possible optimization. Making it a module param allows for alternative
@@ -926,7 +927,7 @@ static int nvme_tcp_recv_data(struct nvme_tcp_queue *queue, struct sk_buff *skb,
req->curr_bio = req->curr_bio->bi_next;
/*
- * If we don`t have any bios it means that controller
+ * If we don't have any bios it means the controller
* sent more data than we requested, hence error
*/
if (!req->curr_bio) {
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 866048f07e61..b63af3b643a6 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -491,6 +491,7 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
struct fcloop_rport *rport = remoteport->private;
struct nvmet_fc_target_port *targetport = rport->targetport;
struct fcloop_tport *tport;
+ int ret = 0;
if (!targetport) {
/*
@@ -500,12 +501,18 @@ fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport,
* We end up here from delete association exchange:
* nvmet_fc_xmt_disconnect_assoc sends an async request.
*
- * Return success because this is what LLDDs do; silently
- * drop the response.
+ * Return success when remoteport is still online because this
+ * is what LLDDs do and silently drop the response. Otherwise,
+ * return with error to signal upper layer to perform the lsrsp
+ * resource cleanup.
*/
- lsrsp->done(lsrsp);
+ if (remoteport->port_state == FC_OBJSTATE_ONLINE)
+ lsrsp->done(lsrsp);
+ else
+ ret = -ENODEV;
+
kmem_cache_free(lsreq_cache, tls_req);
- return 0;
+ return ret;
}
memcpy(lsreq->rspaddr, lsrsp->rspbuf,
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index b8aaa292c3e7..cffc32d66032 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -856,7 +856,7 @@ static void pcifront_try_connect(struct pcifront_device *pdev)
int err;
/* Only connect once */
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitialised)
return;
@@ -876,7 +876,7 @@ static int pcifront_try_disconnect(struct pcifront_device *pdev)
enum xenbus_state prev_state;
- prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
+ prev_state = xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename);
if (prev_state >= XenbusStateClosing)
goto out;
@@ -895,7 +895,7 @@ out:
static void pcifront_attach_devices(struct pcifront_device *pdev)
{
- if (xenbus_read_driver_state(pdev->xdev->nodename) ==
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) ==
XenbusStateReconfiguring)
pcifront_connect(pdev);
}
@@ -909,7 +909,7 @@ static int pcifront_detach_devices(struct pcifront_device *pdev)
struct pci_dev *pci_dev;
char str[64];
- state = xenbus_read_driver_state(pdev->xdev->nodename);
+ state = xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename);
if (state == XenbusStateInitialised) {
dev_dbg(&pdev->xdev->dev, "Handle skipped connect.\n");
/* We missed Connected and need to initialize. */
diff --git a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
index a8f82104a384..227c37c360e1 100644
--- a/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
+++ b/drivers/pinctrl/cirrus/pinctrl-cs42l43.c
@@ -574,10 +574,9 @@ static int cs42l43_pin_probe(struct platform_device *pdev)
if (child) {
ret = devm_add_action_or_reset(&pdev->dev,
cs42l43_fwnode_put, child);
- if (ret) {
- fwnode_handle_put(child);
+ if (ret)
return ret;
- }
+
if (!child->dev)
child->dev = priv->dev;
fwnode = child;
diff --git a/drivers/pinctrl/cix/pinctrl-sky1.c b/drivers/pinctrl/cix/pinctrl-sky1.c
index 5d0d8be815b2..938894058d86 100644
--- a/drivers/pinctrl/cix/pinctrl-sky1.c
+++ b/drivers/pinctrl/cix/pinctrl-sky1.c
@@ -522,11 +522,10 @@ static int __maybe_unused sky1_pinctrl_resume(struct device *dev)
return pinctrl_force_default(spctl->pctl);
}
-const struct dev_pm_ops sky1_pinctrl_pm_ops = {
+static const struct dev_pm_ops sky1_pinctrl_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(sky1_pinctrl_suspend,
sky1_pinctrl_resume)
};
-EXPORT_SYMBOL_GPL(sky1_pinctrl_pm_ops);
static int sky1_pinctrl_probe(struct platform_device *pdev)
{
diff --git a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
index dfa32b11555c..e2293a872dcb 100644
--- a/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
+++ b/drivers/pinctrl/meson/pinctrl-amlogic-a4.c
@@ -679,7 +679,6 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
unsigned int *num_maps)
{
struct device *dev = pctldev->dev;
- struct device_node *pnode;
unsigned long *configs = NULL;
unsigned int num_configs = 0;
struct property *prop;
@@ -693,7 +692,7 @@ static int aml_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev,
return -ENOENT;
}
- pnode = of_get_parent(np);
+ struct device_node *pnode __free(device_node) = of_get_parent(np);
if (!pnode) {
dev_info(dev, "Missing function node\n");
return -EINVAL;
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 94b1d057197c..2b030bd0e6ad 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -351,13 +351,13 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
ret = parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
if (ret)
- return ret;
+ goto out;
if (pctldev && pctldev->desc->num_custom_params &&
pctldev->desc->custom_params) {
ret = parse_dt_cfg(np, pctldev->desc->custom_params,
pctldev->desc->num_custom_params, cfg, &ncfg);
if (ret)
- return ret;
+ goto out;
}
/* no configs found at all */
diff --git a/drivers/pinctrl/pinctrl-amdisp.c b/drivers/pinctrl/pinctrl-amdisp.c
index efbf40c776ea..e0874cc086a7 100644
--- a/drivers/pinctrl/pinctrl-amdisp.c
+++ b/drivers/pinctrl/pinctrl-amdisp.c
@@ -80,7 +80,7 @@ static int amdisp_get_group_pins(struct pinctrl_dev *pctldev,
return 0;
}
-const struct pinctrl_ops amdisp_pinctrl_ops = {
+static const struct pinctrl_ops amdisp_pinctrl_ops = {
.get_groups_count = amdisp_get_groups_count,
.get_group_name = amdisp_get_group_name,
.get_group_pins = amdisp_get_group_pins,
diff --git a/drivers/pinctrl/pinctrl-cy8c95x0.c b/drivers/pinctrl/pinctrl-cy8c95x0.c
index a4b04bf6d081..5c055d344ac9 100644
--- a/drivers/pinctrl/pinctrl-cy8c95x0.c
+++ b/drivers/pinctrl/pinctrl-cy8c95x0.c
@@ -627,7 +627,7 @@ static int cy8c95x0_write_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
bitmap_scatter(tval, val, chip->map, MAX_LINE);
- for_each_set_clump8(offset, bits, tmask, chip->tpin) {
+ for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
unsigned int i = offset / 8;
write_val = bitmap_get_value8(tval, offset);
@@ -655,7 +655,7 @@ static int cy8c95x0_read_regs_mask(struct cy8c95x0_pinctrl *chip, int reg,
bitmap_scatter(tmask, mask, chip->map, MAX_LINE);
bitmap_scatter(tval, val, chip->map, MAX_LINE);
- for_each_set_clump8(offset, bits, tmask, chip->tpin) {
+ for_each_set_clump8(offset, bits, tmask, chip->nport * BANK_SZ) {
unsigned int i = offset / 8;
ret = cy8c95x0_regmap_read_bits(chip, reg, i, bits, &read_val);
diff --git a/drivers/pinctrl/pinctrl-equilibrium.c b/drivers/pinctrl/pinctrl-equilibrium.c
index 48b55c5bf8d4..ba1c867b7b89 100644
--- a/drivers/pinctrl/pinctrl-equilibrium.c
+++ b/drivers/pinctrl/pinctrl-equilibrium.c
@@ -23,7 +23,7 @@
#define PIN_NAME_LEN 10
#define PAD_REG_OFF 0x100
-static void eqbr_gpio_disable_irq(struct irq_data *d)
+static void eqbr_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -36,7 +36,7 @@ static void eqbr_gpio_disable_irq(struct irq_data *d)
gpiochip_disable_irq(gc, offset);
}
-static void eqbr_gpio_enable_irq(struct irq_data *d)
+static void eqbr_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -50,7 +50,7 @@ static void eqbr_gpio_enable_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
-static void eqbr_gpio_ack_irq(struct irq_data *d)
+static void eqbr_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -62,10 +62,17 @@ static void eqbr_gpio_ack_irq(struct irq_data *d)
raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
-static void eqbr_gpio_mask_ack_irq(struct irq_data *d)
+static void eqbr_irq_mask_ack(struct irq_data *d)
{
- eqbr_gpio_disable_irq(d);
- eqbr_gpio_ack_irq(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
+ unsigned int offset = irqd_to_hwirq(d);
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&gctrl->lock, flags);
+ writel(BIT(offset), gctrl->membase + GPIO_IRNENCLR);
+ writel(BIT(offset), gctrl->membase + GPIO_IRNCR);
+ raw_spin_unlock_irqrestore(&gctrl->lock, flags);
}
static inline void eqbr_cfg_bit(void __iomem *addr,
@@ -92,7 +99,7 @@ static int eqbr_irq_type_cfg(struct gpio_irq_type *type,
return 0;
}
-static int eqbr_gpio_set_irq_type(struct irq_data *d, unsigned int type)
+static int eqbr_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct eqbr_gpio_ctrl *gctrl = gpiochip_get_data(gc);
@@ -166,11 +173,11 @@ static void eqbr_irq_handler(struct irq_desc *desc)
static const struct irq_chip eqbr_irq_chip = {
.name = "gpio_irq",
- .irq_mask = eqbr_gpio_disable_irq,
- .irq_unmask = eqbr_gpio_enable_irq,
- .irq_ack = eqbr_gpio_ack_irq,
- .irq_mask_ack = eqbr_gpio_mask_ack_irq,
- .irq_set_type = eqbr_gpio_set_irq_type,
+ .irq_ack = eqbr_irq_ack,
+ .irq_mask = eqbr_irq_mask,
+ .irq_mask_ack = eqbr_irq_mask_ack,
+ .irq_unmask = eqbr_irq_unmask,
+ .irq_set_type = eqbr_irq_set_type,
.flags = IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index d87c0b1de616..f15b18f334ee 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -3640,14 +3640,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
* or the gpio driver hasn't probed yet.
*/
scoped_guard(mutex, &bank->deferred_lock) {
- if (!gpio || !gpio->direction_output) {
- rc = rockchip_pinconf_defer_pin(bank,
- pin - bank->pin_base,
- param, arg);
- if (rc)
- return rc;
- break;
- }
+ if (!gpio || !gpio->direction_output)
+ return rockchip_pinconf_defer_pin(bank,
+ pin - bank->pin_base,
+ param, arg);
}
}
diff --git a/drivers/pinctrl/qcom/pinctrl-qcs615.c b/drivers/pinctrl/qcom/pinctrl-qcs615.c
index 4dfa820d4e77..f1c827ddbfbf 100644
--- a/drivers/pinctrl/qcom/pinctrl-qcs615.c
+++ b/drivers/pinctrl/qcom/pinctrl-qcs615.c
@@ -1067,6 +1067,7 @@ static const struct msm_pinctrl_soc_data qcs615_tlmm = {
.ntiles = ARRAY_SIZE(qcs615_tiles),
.wakeirq_map = qcs615_pdc_map,
.nwakeirq_map = ARRAY_SIZE(qcs615_pdc_map),
+ .wakeirq_dual_edge_errata = true,
};
static const struct of_device_id qcs615_tlmm_of_match[] = {
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
index d93af5f0e8d3..65411abfbfac 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm660-lpass-lpi.c
@@ -76,7 +76,7 @@ static const char * const pdm_clk_groups[] = { "gpio18" };
static const char * const pdm_rx_groups[] = { "gpio21", "gpio23", "gpio25" };
static const char * const pdm_sync_groups[] = { "gpio19" };
-const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
+static const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
LPI_PINGROUP_OFFSET(0, LPI_NO_SLEW, _, _, _, _, 0x0000),
LPI_PINGROUP_OFFSET(1, LPI_NO_SLEW, _, _, _, _, 0x1000),
LPI_PINGROUP_OFFSET(2, LPI_NO_SLEW, _, _, _, _, 0x2000),
@@ -113,7 +113,7 @@ const struct lpi_pingroup sdm660_lpi_pinctrl_groups[] = {
LPI_PINGROUP_OFFSET(31, LPI_NO_SLEW, _, _, _, _, 0xb010),
};
-const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
+static const struct lpi_function sdm660_lpi_pinctrl_functions[] = {
LPI_FUNCTION(comp_rx),
LPI_FUNCTION(dmic1_clk),
LPI_FUNCTION(dmic1_data),
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
index 48434292a39b..c990b6118172 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c
@@ -204,6 +204,32 @@ sunxi_pinctrl_desc_find_function_by_pin(struct sunxi_pinctrl *pctl,
return NULL;
}
+static struct sunxi_desc_function *
+sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl,
+ const u16 pin_num,
+ const u8 muxval)
+{
+ for (unsigned int i = 0; i < pctl->desc->npins; i++) {
+ const struct sunxi_desc_pin *pin = pctl->desc->pins + i;
+ struct sunxi_desc_function *func = pin->functions;
+
+ if (pin->pin.number != pin_num)
+ continue;
+
+ if (pin->variant && !(pctl->variant & pin->variant))
+ continue;
+
+ while (func->name) {
+ if (func->muxval == muxval)
+ return func;
+
+ func++;
+ }
+ }
+
+ return NULL;
+}
+
static int sunxi_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
{
struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
@@ -930,6 +956,30 @@ static const struct pinmux_ops sunxi_pmx_ops = {
.strict = true,
};
+static int sunxi_pinctrl_gpio_get_direction(struct gpio_chip *chip,
+ unsigned int offset)
+{
+ struct sunxi_pinctrl *pctl = gpiochip_get_data(chip);
+ const struct sunxi_desc_function *func;
+ u32 pin = offset + chip->base;
+ u32 reg, shift, mask;
+ u8 muxval;
+
+ sunxi_mux_reg(pctl, offset, &reg, &shift, &mask);
+
+ muxval = (readl(pctl->membase + reg) & mask) >> shift;
+
+ func = sunxi_pinctrl_desc_find_function_by_pin_and_mux(pctl, pin, muxval);
+ if (!func)
+ return -ENODEV;
+
+ if (!strcmp(func->name, "gpio_out"))
+ return GPIO_LINE_DIRECTION_OUT;
+ if (!strcmp(func->name, "gpio_in") || !strcmp(func->name, "irq"))
+ return GPIO_LINE_DIRECTION_IN;
+ return -EINVAL;
+}
+
static int sunxi_pinctrl_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
@@ -1599,6 +1649,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev,
pctl->chip->request = gpiochip_generic_request;
pctl->chip->free = gpiochip_generic_free;
pctl->chip->set_config = gpiochip_generic_config;
+ pctl->chip->get_direction = sunxi_pinctrl_gpio_get_direction;
pctl->chip->direction_input = sunxi_pinctrl_gpio_direction_input;
pctl->chip->direction_output = sunxi_pinctrl_gpio_direction_output;
pctl->chip->get = sunxi_pinctrl_gpio_get;
diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h
index 6e9703bd5017..208f6fe16168 100644
--- a/drivers/platform/x86/asus-armoury.h
+++ b/drivers/platform/x86/asus-armoury.h
@@ -348,6 +348,35 @@ struct power_data {
static const struct dmi_system_id power_limits[] = {
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "FA401UM"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 35,
+ .ppt_pl2_sppt_max = 80,
+ .ppt_pl3_fppt_min = 35,
+ .ppt_pl3_fppt_max = 80,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 15,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 25,
+ .ppt_pl1_spl_max = 35,
+ .ppt_pl2_sppt_min = 31,
+ .ppt_pl2_sppt_max = 44,
+ .ppt_pl3_fppt_min = 45,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 75,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "FA401UV"),
},
.driver_data = &(struct power_data) {
@@ -1459,6 +1488,38 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "GX650RX"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_def = 70,
+ .ppt_pl1_spl_max = 90,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_def = 70,
+ .ppt_pl2_sppt_max = 100,
+ .ppt_pl3_fppt_min = 28,
+ .ppt_pl3_fppt_def = 110,
+ .ppt_pl3_fppt_max = 125,
+ .nv_dynamic_boost_min = 5,
+ .nv_dynamic_boost_max = 25,
+ .nv_temp_target_min = 76,
+ .nv_temp_target_max = 87,
+ },
+ .dc_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 28,
+ .ppt_pl1_spl_max = 50,
+ .ppt_pl2_sppt_min = 28,
+ .ppt_pl2_sppt_max = 50,
+ .ppt_pl3_fppt_min = 28,
+ .ppt_pl3_fppt_max = 65,
+ .nv_temp_target_min = 76,
+ .nv_temp_target_max = 87,
+ },
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G513I"),
},
.driver_data = &(struct power_data) {
@@ -1710,6 +1771,20 @@ static const struct dmi_system_id power_limits[] = {
},
{
.matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "G733QS"),
+ },
+ .driver_data = &(struct power_data) {
+ .ac_data = &(struct power_limits) {
+ .ppt_pl1_spl_min = 15,
+ .ppt_pl1_spl_max = 80,
+ .ppt_pl2_sppt_min = 15,
+ .ppt_pl2_sppt_max = 80,
+ },
+ .requires_fan_curve = false,
+ },
+ },
+ {
+ .matches = {
DMI_MATCH(DMI_BOARD_NAME, "G814J"),
},
.driver_data = &(struct power_data) {
diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c
index e69b50162bb1..d1b4df91401b 100644
--- a/drivers/platform/x86/dell/alienware-wmi-wmax.c
+++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c
@@ -175,7 +175,7 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = {
DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18"),
},
- .driver_data = &generic_quirks,
+ .driver_data = &g_series_quirks,
},
{
.ident = "Alienware x15",
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 4eefbade2f5e..e7a411ae9ca1 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -80,6 +80,12 @@ static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = {
static const struct key_entry dell_wmi_keymap_type_0000[] = {
{ KE_IGNORE, 0x003a, { KEY_CAPSLOCK } },
+ /* Audio mute toggle */
+ { KE_KEY, 0x0109, { KEY_MUTE } },
+
+ /* Mic mute toggle */
+ { KE_KEY, 0x0150, { KEY_MICMUTE } },
+
/* Meta key lock */
{ KE_IGNORE, 0xe000, { KEY_RIGHTMETA } },
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
index 86ec962aace9..e586f7957946 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/passwordattr-interface.c
@@ -93,7 +93,6 @@ int set_new_password(const char *password_type, const char *new)
if (ret < 0)
goto out;
- print_hex_dump_bytes("set new password data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
ret = call_password_interface(wmi_priv.password_attr_wdev, buffer, buffer_size);
/* on success copy the new password to current password */
if (!ret)
diff --git a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
index 470b9f44ed7a..af4d1920d488 100644
--- a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
+++ b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c
@@ -94,8 +94,11 @@ int hp_alloc_enumeration_data(void)
bioscfg_drv.enumeration_instances_count =
hp_get_instance_count(HP_WMI_BIOS_ENUMERATION_GUID);
- bioscfg_drv.enumeration_data = kzalloc_objs(*bioscfg_drv.enumeration_data,
- bioscfg_drv.enumeration_instances_count);
+ if (!bioscfg_drv.enumeration_instances_count)
+ return -EINVAL;
+ bioscfg_drv.enumeration_data = kvcalloc(bioscfg_drv.enumeration_instances_count,
+ sizeof(*bioscfg_drv.enumeration_data), GFP_KERNEL);
+
if (!bioscfg_drv.enumeration_data) {
bioscfg_drv.enumeration_instances_count = 0;
return -ENOMEM;
@@ -444,6 +447,6 @@ void hp_exit_enumeration_attributes(void)
}
bioscfg_drv.enumeration_instances_count = 0;
- kfree(bioscfg_drv.enumeration_data);
+ kvfree(bioscfg_drv.enumeration_data);
bioscfg_drv.enumeration_data = NULL;
}
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 304d9ac63c8a..68ede7e5757a 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -146,6 +146,7 @@ static const char * const omen_thermal_profile_boards[] = {
"8900", "8901", "8902", "8912", "8917", "8918", "8949", "894A", "89EB",
"8A15", "8A42",
"8BAD",
+ "8E41",
};
/* DMI Board names of Omen laptops that are specifically set to be thermal
@@ -166,18 +167,27 @@ static const char * const omen_timed_thermal_profile_boards[] = {
"8BAD",
};
-/* DMI Board names of Victus 16-d1xxx laptops */
+/* DMI Board names of Victus 16-d laptops */
static const char * const victus_thermal_profile_boards[] = {
+ "88F8",
"8A25",
};
/* DMI Board names of Victus 16-r and Victus 16-s laptops */
static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = {
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAB") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BBE") },
.driver_data = (void *)&victus_s_thermal_params,
},
{
+ .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCD") },
+ .driver_data = (void *)&omen_v1_thermal_params,
+ },
+ {
.matches = { DMI_MATCH(DMI_BOARD_NAME, "8BD4") },
.driver_data = (void *)&victus_s_thermal_params,
},
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 0f8684f4464b..95c405c8bac0 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -136,6 +136,13 @@ static const struct dmi_system_id button_array_table[] = {
},
},
{
+ .ident = "Lenovo ThinkPad X1 Fold 16 Gen 1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_FAMILY, "ThinkPad X1 Fold 16 Gen 1"),
+ },
+ },
+ {
.ident = "Microsoft Surface Go 3",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
@@ -189,6 +196,18 @@ static const struct dmi_system_id dmi_vgbs_allow_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Dell Pro Rugged 12 Tablet RA02260"),
},
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell 14 Plus 2-in-1 DB04250"),
+ },
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Dell 16 Plus 2-in-1 DB06250"),
+ },
+ },
{ }
};
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 1455d9a7afca..1c65ce87cde0 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -223,6 +223,10 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
*con_id = "avdd";
*gpio_flags = GPIO_ACTIVE_HIGH;
break;
+ case INT3472_GPIO_TYPE_DOVDD:
+ *con_id = "dovdd";
+ *gpio_flags = GPIO_ACTIVE_HIGH;
+ break;
case INT3472_GPIO_TYPE_HANDSHAKE:
*con_id = "dvdd";
*gpio_flags = GPIO_ACTIVE_HIGH;
@@ -251,6 +255,7 @@ static void int3472_get_con_id_and_polarity(struct int3472_discrete_device *int3
* 0x0b Power enable
* 0x0c Clock enable
* 0x0d Privacy LED
+ * 0x10 DOVDD (digital I/O voltage)
* 0x13 Hotplug detect
*
* There are some known platform specific quirks where that does not quite
@@ -332,6 +337,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
case INT3472_GPIO_TYPE_CLK_ENABLE:
case INT3472_GPIO_TYPE_PRIVACY_LED:
case INT3472_GPIO_TYPE_POWER_ENABLE:
+ case INT3472_GPIO_TYPE_DOVDD:
case INT3472_GPIO_TYPE_HANDSHAKE:
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, con_id, gpio_flags);
if (IS_ERR(gpio)) {
@@ -356,6 +362,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
case INT3472_GPIO_TYPE_POWER_ENABLE:
second_sensor = int3472->quirks.avdd_second_sensor;
fallthrough;
+ case INT3472_GPIO_TYPE_DOVDD:
case INT3472_GPIO_TYPE_HANDSHAKE:
ret = skl_int3472_register_regulator(int3472, gpio, enable_time_us,
con_id, second_sensor);
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
index f9c736777908..8982d92dfd97 100644
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
@@ -9525,14 +9525,16 @@ static int tpacpi_battery_get(int what, int battery, int *ret)
{
switch (what) {
case THRESHOLD_START:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery))
+ if (!battery_info.batteries[battery].start_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_START, ret, battery)))
return -ENODEV;
/* The value is in the low 8 bits of the response */
*ret = *ret & 0xFF;
return 0;
case THRESHOLD_STOP:
- if ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery))
+ if (!battery_info.batteries[battery].stop_support ||
+ ACPI_FAILURE(tpacpi_battery_acpi_eval(GET_STOP, ret, battery)))
return -ENODEV;
/* Value is in lower 8 bits */
*ret = *ret & 0xFF;
diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
index 144a454103b9..6d4a53a2ed60 100644
--- a/drivers/platform/x86/oxpec.c
+++ b/drivers/platform/x86/oxpec.c
@@ -11,7 +11,7 @@
*
* Copyright (C) 2022 Joaquín I. Aramendía <samsagax@gmail.com>
* Copyright (C) 2024 Derek J. Clark <derekjohn.clark@gmail.com>
- * Copyright (C) 2025 Antheas Kapenekakis <lkml@antheas.dev>
+ * Copyright (C) 2025-2026 Antheas Kapenekakis <lkml@antheas.dev>
*/
#include <linux/acpi.h>
@@ -117,6 +117,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A2 Pro"),
+ },
+ .driver_data = (void *)aok_zoe_a1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "AOKZOE"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "AOKZOE A1X"),
},
.driver_data = (void *)oxp_fly,
@@ -145,6 +152,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER APEX"),
+ },
+ .driver_data = (void *)oxp_fly,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER F1"),
},
.driver_data = (void *)oxp_fly,
@@ -215,6 +229,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1z"),
+ },
+ .driver_data = (void *)oxp_x1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 A"),
},
.driver_data = (void *)oxp_x1,
@@ -229,6 +250,13 @@ static const struct dmi_system_id dmi_table[] = {
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
+ DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1Air"),
+ },
+ .driver_data = (void *)oxp_x1,
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ONE-NETBOOK"),
DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONEXPLAYER X1 mini"),
},
.driver_data = (void *)oxp_x1,
diff --git a/drivers/platform/x86/redmi-wmi.c b/drivers/platform/x86/redmi-wmi.c
index 949236b93a32..e5cb348e3a39 100644
--- a/drivers/platform/x86/redmi-wmi.c
+++ b/drivers/platform/x86/redmi-wmi.c
@@ -20,7 +20,10 @@
static const struct key_entry redmi_wmi_keymap[] = {
{KE_KEY, 0x00000201, {KEY_SELECTIVE_SCREENSHOT}},
{KE_KEY, 0x00000301, {KEY_ALL_APPLICATIONS}},
- {KE_KEY, 0x00001b01, {KEY_SETUP}},
+ {KE_KEY, 0x00001b01, {KEY_CONFIG}},
+ {KE_KEY, 0x00011b01, {KEY_CONFIG}},
+ {KE_KEY, 0x00010101, {KEY_SWITCHVIDEOMODE}},
+ {KE_KEY, 0x00001a01, {KEY_REFRESH_RATE_TOGGLE}},
/* AI button has code for each position */
{KE_KEY, 0x00011801, {KEY_ASSISTANT}},
@@ -32,6 +35,26 @@ static const struct key_entry redmi_wmi_keymap[] = {
{KE_IGNORE, 0x00050501, {}},
{KE_IGNORE, 0x000a0501, {}},
+ /* Xiaomi G Command Center */
+ {KE_KEY, 0x00010a01, {KEY_VENDOR}},
+
+ /* OEM preset power mode */
+ {KE_IGNORE, 0x00011601, {}},
+ {KE_IGNORE, 0x00021601, {}},
+ {KE_IGNORE, 0x00031601, {}},
+ {KE_IGNORE, 0x00041601, {}},
+
+ /* Fn Lock state */
+ {KE_IGNORE, 0x00000701, {}},
+ {KE_IGNORE, 0x00010701, {}},
+
+ /* Fn+`/1/2/3/4 */
+ {KE_KEY, 0x00011101, {KEY_F13}},
+ {KE_KEY, 0x00011201, {KEY_F14}},
+ {KE_KEY, 0x00011301, {KEY_F15}},
+ {KE_KEY, 0x00011401, {KEY_F16}},
+ {KE_KEY, 0x00011501, {KEY_F17}},
+
{KE_END}
};
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index bdc19cd8d3ed..d83c387821ea 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -410,6 +410,16 @@ static const struct ts_dmi_data gdix1002_upside_down_data = {
.properties = gdix1001_upside_down_props,
};
+static const struct property_entry gdix1001_y_inverted_props[] = {
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ { }
+};
+
+static const struct ts_dmi_data gdix1001_y_inverted_data = {
+ .acpi_name = "GDIX1001",
+ .properties = gdix1001_y_inverted_props,
+};
+
static const struct property_entry gp_electronic_t701_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 960),
PROPERTY_ENTRY_U32("touchscreen-size-y", 640),
@@ -1659,6 +1669,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* SUPI S10 */
+ .driver_data = (void *)&gdix1001_y_inverted_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SUPI"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "S10"),
+ },
+ },
+ {
/* Techbite Arc 11.6 */
.driver_data = (void *)&techbite_arc_11_6_data,
.matches = {
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index fee93537aa43..6341dca20b76 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -314,8 +314,8 @@
#define LED_CHANNELS 3
#define LED_MAX_BRIGHTNESS 200
-#define UNIWILL_FEATURE_FN_LOCK_TOGGLE BIT(0)
-#define UNIWILL_FEATURE_SUPER_KEY_TOGGLE BIT(1)
+#define UNIWILL_FEATURE_FN_LOCK BIT(0)
+#define UNIWILL_FEATURE_SUPER_KEY BIT(1)
#define UNIWILL_FEATURE_TOUCHPAD_TOGGLE BIT(2)
#define UNIWILL_FEATURE_LIGHTBAR BIT(3)
#define UNIWILL_FEATURE_BATTERY BIT(4)
@@ -330,6 +330,7 @@ struct uniwill_data {
struct acpi_battery_hook hook;
unsigned int last_charge_ctrl;
struct mutex battery_lock; /* Protects the list of currently registered batteries */
+ unsigned int last_status;
unsigned int last_switch_status;
struct mutex super_key_lock; /* Protects the toggling of the super key lock state */
struct list_head batteries;
@@ -377,11 +378,15 @@ static const struct key_entry uniwill_keymap[] = {
{ KE_IGNORE, UNIWILL_OSD_CAPSLOCK, { KEY_CAPSLOCK }},
{ KE_IGNORE, UNIWILL_OSD_NUMLOCK, { KEY_NUMLOCK }},
- /* Reported when the user locks/unlocks the super key */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE, { KEY_UNKNOWN }},
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE, { KEY_UNKNOWN }},
+ /*
+ * Reported when the user enables/disables the super key.
+ * Those events might even be reported when the change was done
+ * using the sysfs attribute!
+ */
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_DISABLE, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_ENABLE, { KEY_UNKNOWN }},
/* Optional, might not be reported by all devices */
- { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED, { KEY_UNKNOWN }},
+ { KE_IGNORE, UNIWILL_OSD_SUPER_KEY_STATE_CHANGED, { KEY_UNKNOWN }},
/* Reported in manual mode when toggling the airplane mode status */
{ KE_KEY, UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
@@ -401,9 +406,6 @@ static const struct key_entry uniwill_keymap[] = {
/* Reported when the user wants to toggle the mute status */
{ KE_IGNORE, UNIWILL_OSD_MUTE, { KEY_MUTE }},
- /* Reported when the user locks/unlocks the Fn key */
- { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
-
/* Reported when the user wants to toggle the brightness of the keyboard */
{ KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
@@ -576,6 +578,7 @@ static bool uniwill_volatile_reg(struct device *dev, unsigned int reg)
case EC_ADDR_SECOND_FAN_RPM_1:
case EC_ADDR_SECOND_FAN_RPM_2:
case EC_ADDR_BAT_ALERT:
+ case EC_ADDR_BIOS_OEM:
case EC_ADDR_PWM_1:
case EC_ADDR_PWM_2:
case EC_ADDR_TRIGGER:
@@ -600,8 +603,8 @@ static const struct regmap_config uniwill_ec_config = {
.use_single_write = true,
};
-static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t fn_lock_store(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -624,8 +627,7 @@ static ssize_t fn_lock_toggle_enable_store(struct device *dev, struct device_att
return count;
}
-static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t fn_lock_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -638,10 +640,10 @@ static ssize_t fn_lock_toggle_enable_show(struct device *dev, struct device_attr
return sysfs_emit(buf, "%d\n", !!(value & FN_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(fn_lock_toggle_enable);
+static DEVICE_ATTR_RW(fn_lock);
-static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t super_key_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -673,8 +675,7 @@ static ssize_t super_key_toggle_enable_store(struct device *dev, struct device_a
return count;
}
-static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_attribute *attr,
- char *buf)
+static ssize_t super_key_enable_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct uniwill_data *data = dev_get_drvdata(dev);
unsigned int value;
@@ -687,7 +688,7 @@ static ssize_t super_key_toggle_enable_show(struct device *dev, struct device_at
return sysfs_emit(buf, "%d\n", !(value & SUPER_KEY_LOCK_STATUS));
}
-static DEVICE_ATTR_RW(super_key_toggle_enable);
+static DEVICE_ATTR_RW(super_key_enable);
static ssize_t touchpad_toggle_enable_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
@@ -881,8 +882,8 @@ static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
static struct attribute *uniwill_attrs[] = {
/* Keyboard-related */
- &dev_attr_fn_lock_toggle_enable.attr,
- &dev_attr_super_key_toggle_enable.attr,
+ &dev_attr_fn_lock.attr,
+ &dev_attr_super_key_enable.attr,
&dev_attr_touchpad_toggle_enable.attr,
/* Lightbar-related */
&dev_attr_rainbow_animation.attr,
@@ -897,13 +898,13 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
struct device *dev = kobj_to_dev(kobj);
struct uniwill_data *data = dev_get_drvdata(dev);
- if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK_TOGGLE))
+ if (attr == &dev_attr_fn_lock.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
return attr->mode;
}
- if (attr == &dev_attr_super_key_toggle_enable.attr) {
- if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (attr == &dev_attr_super_key_enable.attr) {
+ if (uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return attr->mode;
}
@@ -1357,6 +1358,9 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
switch (action) {
case UNIWILL_OSD_BATTERY_ALERT:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_BATTERY))
+ return NOTIFY_DONE;
+
mutex_lock(&data->battery_lock);
list_for_each_entry(entry, &data->batteries, head) {
power_supply_changed(entry->battery);
@@ -1370,6 +1374,13 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
*/
return NOTIFY_OK;
+ case UNIWILL_OSD_FN_LOCK:
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return NOTIFY_DONE;
+
+ sysfs_notify(&data->dev->kobj, NULL, "fn_lock");
+
+ return NOTIFY_OK;
default:
mutex_lock(&data->input_lock);
sparse_keymap_report_event(data->input_device, action, 1, true);
@@ -1503,9 +1514,21 @@ static void uniwill_shutdown(struct platform_device *pdev)
regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
}
-static int uniwill_suspend_keyboard(struct uniwill_data *data)
+static int uniwill_suspend_fn_lock(struct uniwill_data *data)
{
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ /*
+ * The EC_ADDR_BIOS_OEM is marked as volatile, so we have to restore it
+ * ourselves.
+ */
+ return regmap_read(data->regmap, EC_ADDR_BIOS_OEM, &data->last_status);
+}
+
+static int uniwill_suspend_super_key(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
/*
@@ -1542,7 +1565,11 @@ static int uniwill_suspend(struct device *dev)
struct uniwill_data *data = dev_get_drvdata(dev);
int ret;
- ret = uniwill_suspend_keyboard(data);
+ ret = uniwill_suspend_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_suspend_super_key(data);
if (ret < 0)
return ret;
@@ -1560,12 +1587,21 @@ static int uniwill_suspend(struct device *dev)
return 0;
}
-static int uniwill_resume_keyboard(struct uniwill_data *data)
+static int uniwill_resume_fn_lock(struct uniwill_data *data)
+{
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_FN_LOCK))
+ return 0;
+
+ return regmap_update_bits(data->regmap, EC_ADDR_BIOS_OEM, FN_LOCK_STATUS,
+ data->last_status);
+}
+
+static int uniwill_resume_super_key(struct uniwill_data *data)
{
unsigned int value;
int ret;
- if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+ if (!uniwill_device_supports(data, UNIWILL_FEATURE_SUPER_KEY))
return 0;
ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
@@ -1608,7 +1644,11 @@ static int uniwill_resume(struct device *dev)
if (ret < 0)
return ret;
- ret = uniwill_resume_keyboard(data);
+ ret = uniwill_resume_fn_lock(data);
+ if (ret < 0)
+ return ret;
+
+ ret = uniwill_resume_super_key(data);
if (ret < 0)
return ret;
@@ -1643,16 +1683,16 @@ static struct platform_driver uniwill_driver = {
};
static struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_BATTERY |
UNIWILL_FEATURE_HWMON,
};
static struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
- .features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
- UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+ .features = UNIWILL_FEATURE_FN_LOCK |
+ UNIWILL_FEATURE_SUPER_KEY |
UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
UNIWILL_FEATURE_LIGHTBAR |
UNIWILL_FEATURE_BATTERY |
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
index 48783b2e9ffb..fb1910c0f741 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.h
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
@@ -64,8 +64,8 @@
#define UNIWILL_OSD_KB_LED_LEVEL3 0x3E
#define UNIWILL_OSD_KB_LED_LEVEL4 0x3F
-#define UNIWILL_OSD_SUPER_KEY_LOCK_ENABLE 0x40
-#define UNIWILL_OSD_SUPER_KEY_LOCK_DISABLE 0x41
+#define UNIWILL_OSD_SUPER_KEY_DISABLE 0x40
+#define UNIWILL_OSD_SUPER_KEY_ENABLE 0x41
#define UNIWILL_OSD_MENU_JP 0x42
@@ -74,7 +74,7 @@
#define UNIWILL_OSD_RFKILL 0xA4
-#define UNIWILL_OSD_SUPER_KEY_LOCK_CHANGED 0xA5
+#define UNIWILL_OSD_SUPER_KEY_STATE_CHANGED 0xA5
#define UNIWILL_OSD_LIGHTBAR_STATE_CHANGED 0xA6
diff --git a/drivers/pmdomain/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c
index 1d29addfe036..0450202bbee2 100644
--- a/drivers/pmdomain/bcm/bcm2835-power.c
+++ b/drivers/pmdomain/bcm/bcm2835-power.c
@@ -580,11 +580,11 @@ static int bcm2835_reset_status(struct reset_controller_dev *rcdev,
switch (id) {
case BCM2835_RESET_V3D:
- return !PM_READ(PM_GRAFX & PM_V3DRSTN);
+ return !(PM_READ(PM_GRAFX) & PM_V3DRSTN);
case BCM2835_RESET_H264:
- return !PM_READ(PM_IMAGE & PM_H264RSTN);
+ return !(PM_READ(PM_IMAGE) & PM_H264RSTN);
case BCM2835_RESET_ISP:
- return !PM_READ(PM_IMAGE & PM_ISPRSTN);
+ return !(PM_READ(PM_IMAGE) & PM_ISPRSTN);
default:
return -EINVAL;
}
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index 997e93c12951..44d34840ede7 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -1311,7 +1311,7 @@ static const struct rockchip_domain_info rk3576_pm_domains[] = {
static const struct rockchip_domain_info rk3588_pm_domains[] = {
[RK3588_PD_GPU] = DOMAIN_RK3588("gpu", 0x0, BIT(0), 0, 0x0, 0, BIT(1), 0x0, BIT(0), BIT(0), false, true),
[RK3588_PD_NPU] = DOMAIN_RK3588("npu", 0x0, BIT(1), BIT(1), 0x0, 0, 0, 0x0, 0, 0, false, true),
- [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, false),
+ [RK3588_PD_VCODEC] = DOMAIN_RK3588("vcodec", 0x0, BIT(2), BIT(2), 0x0, 0, 0, 0x0, 0, 0, false, true),
[RK3588_PD_NPUTOP] = DOMAIN_RK3588("nputop", 0x0, BIT(3), 0, 0x0, BIT(11), BIT(2), 0x0, BIT(1), BIT(1), false, false),
[RK3588_PD_NPU1] = DOMAIN_RK3588("npu1", 0x0, BIT(4), 0, 0x0, BIT(12), BIT(3), 0x0, BIT(2), BIT(2), false, false),
[RK3588_PD_NPU2] = DOMAIN_RK3588("npu2", 0x0, BIT(5), 0, 0x0, BIT(13), BIT(4), 0x0, BIT(3), BIT(3), false, false),
diff --git a/drivers/regulator/mt6363-regulator.c b/drivers/regulator/mt6363-regulator.c
index 03af5fa53600..0aebcbda0a19 100644
--- a/drivers/regulator/mt6363-regulator.c
+++ b/drivers/regulator/mt6363-regulator.c
@@ -899,10 +899,8 @@ static int mt6363_regulator_probe(struct platform_device *pdev)
"Failed to map IRQ%d\n", info->hwirq);
ret = devm_add_action_or_reset(dev, mt6363_irq_remove, &info->virq);
- if (ret) {
- irq_dispose_mapping(info->hwirq);
+ if (ret)
return ret;
- }
config.driver_data = info;
INIT_DELAYED_WORK(&info->oc_work, mt6363_oc_irq_enable_work);
diff --git a/drivers/regulator/pf9453-regulator.c b/drivers/regulator/pf9453-regulator.c
index 779a6fdb0574..eed3055d1c1c 100644
--- a/drivers/regulator/pf9453-regulator.c
+++ b/drivers/regulator/pf9453-regulator.c
@@ -809,7 +809,7 @@ static int pf9453_i2c_probe(struct i2c_client *i2c)
}
ret = devm_request_threaded_irq(pf9453->dev, pf9453->irq, NULL, pf9453_irq_handler,
- (IRQF_TRIGGER_FALLING | IRQF_ONESHOT),
+ IRQF_ONESHOT,
"pf9453-irq", pf9453);
if (ret)
return dev_err_probe(pf9453->dev, ret, "Failed to request IRQ: %d\n", pf9453->irq);
diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c
index 5875065e2849..c744210cc901 100644
--- a/drivers/scsi/mpi3mr/mpi3mr_fw.c
+++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c
@@ -1618,6 +1618,7 @@ retry_bring_ioc_ready:
ioc_info(mrioc,
"successfully transitioned to %s state\n",
mpi3mr_iocstate_name(ioc_state));
+ mpi3mr_clear_reset_history(mrioc);
return 0;
}
ioc_status = readl(&mrioc->sysif_regs->ioc_status);
@@ -1637,6 +1638,15 @@ retry_bring_ioc_ready:
elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
} while (elapsed_time_sec < mrioc->ready_timeout);
+ ioc_state = mpi3mr_get_iocstate(mrioc);
+ if (ioc_state == MRIOC_STATE_READY) {
+ ioc_info(mrioc,
+ "successfully transitioned to %s state after %llu seconds\n",
+ mpi3mr_iocstate_name(ioc_state), elapsed_time_sec);
+ mpi3mr_clear_reset_history(mrioc);
+ return 0;
+ }
+
out_failed:
elapsed_time_sec = jiffies_to_msecs(jiffies - start_time)/1000;
if ((retry < 2) && (elapsed_time_sec < (mrioc->ready_timeout - 60))) {
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 0dada89d8d99..68a992494b12 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -190,7 +190,7 @@ static struct {
{"IBM", "2076", NULL, BLIST_NO_VPD_SIZE},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
- {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN},
+ {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN | BLIST_SKIP_IO_HINTS},
{"IOMEGA", "Io20S *F", NULL, BLIST_KEY},
{"INSITE", "Floptical F*8I", NULL, BLIST_KEY},
{"INSITE", "I325VM", NULL, BLIST_KEY},
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 60c06fa4ec32..2cfcf1f5d6a4 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -361,6 +361,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
* since we use this queue depth most of times.
*/
if (scsi_realloc_sdev_budget_map(sdev, depth)) {
+ kref_put(&sdev->host->tagset_refcnt, scsi_mq_free_tags);
put_device(&starget->dev);
kfree(sdev);
goto out;
diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c
index 42cde0017f12..989bcaee42ca 100644
--- a/drivers/scsi/xen-scsifront.c
+++ b/drivers/scsi/xen-scsifront.c
@@ -1175,7 +1175,7 @@ static void scsifront_backend_changed(struct xenbus_device *dev,
return;
}
- if (xenbus_read_driver_state(dev->nodename) ==
+ if (xenbus_read_driver_state(dev, dev->nodename) ==
XenbusStateInitialised)
scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
diff --git a/drivers/spi/spi-dw-dma.c b/drivers/spi/spi-dw-dma.c
index 65adec7c7524..fe726b9b1780 100644
--- a/drivers/spi/spi-dw-dma.c
+++ b/drivers/spi/spi-dw-dma.c
@@ -271,7 +271,7 @@ static int dw_spi_dma_wait(struct dw_spi *dws, unsigned int len, u32 speed)
msecs_to_jiffies(ms));
if (ms == 0) {
- dev_err(&dws->ctlr->cur_msg->spi->dev,
+ dev_err(&dws->ctlr->dev,
"DMA transaction timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 17608ea39d5a..a1c91d4515bc 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -108,8 +108,8 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
const char *page, size_t count)
{
ssize_t read_bytes;
- struct file *fp;
ssize_t r = -EINVAL;
+ struct path path = {};
mutex_lock(&target_devices_lock);
if (target_devices) {
@@ -131,17 +131,14 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item,
db_root_stage[read_bytes - 1] = '\0';
/* validate new db root before accepting it */
- fp = filp_open(db_root_stage, O_RDONLY, 0);
- if (IS_ERR(fp)) {
+ r = kern_path(db_root_stage, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
+ if (r) {
pr_err("db_root: cannot open: %s\n", db_root_stage);
+ if (r == -ENOTDIR)
+ pr_err("db_root: not a directory: %s\n", db_root_stage);
goto unlock;
}
- if (!S_ISDIR(file_inode(fp)->i_mode)) {
- filp_close(fp, NULL);
- pr_err("db_root: not a directory: %s\n", db_root_stage);
- goto unlock;
- }
- filp_close(fp, NULL);
+ path_put(&path);
strscpy(db_root, db_root_stage);
pr_debug("Target_Core_ConfigFS: db_root set to %s\n", db_root);
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 31903bfdce9f..897ae2a0b5a0 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -378,11 +378,8 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv)
acpi_psd[acpi_id].domain);
}
- status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- if (!pblk)
- return AE_OK;
- }
+ if (!pblk && !acpi_has_method(handle, "_CST"))
+ return AE_OK;
/* .. and it has a C-state */
__set_bit(acpi_id, acpi_id_cst_present);
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 22ff9cf35fc4..b34785ba72e1 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -149,12 +149,12 @@ static int xen_pcibk_attach(struct xen_pcibk_device *pdev)
mutex_lock(&pdev->dev_lock);
/* Make sure we only do this setup once */
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitialised)
goto out;
/* Wait for frontend to state that it has published the configuration */
- if (xenbus_read_driver_state(pdev->xdev->otherend) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->otherend) !=
XenbusStateInitialised)
goto out;
@@ -374,7 +374,7 @@ static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev,
dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
mutex_lock(&pdev->dev_lock);
- if (xenbus_read_driver_state(pdev->xdev->nodename) != state)
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) != state)
goto out;
err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
@@ -572,7 +572,7 @@ static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev)
/* It's possible we could get the call to setup twice, so make sure
* we're not already connected.
*/
- if (xenbus_read_driver_state(pdev->xdev->nodename) !=
+ if (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename) !=
XenbusStateInitWait)
goto out;
@@ -662,7 +662,7 @@ static void xen_pcibk_be_watch(struct xenbus_watch *watch,
struct xen_pcibk_device *pdev =
container_of(watch, struct xen_pcibk_device, be_watch);
- switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
+ switch (xenbus_read_driver_state(pdev->xdev, pdev->xdev->nodename)) {
case XenbusStateInitWait:
xen_pcibk_setup_backend(pdev);
break;
diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c
index 0ab1329e79de..27682cb5e58a 100644
--- a/drivers/xen/xenbus/xenbus_client.c
+++ b/drivers/xen/xenbus/xenbus_client.c
@@ -226,8 +226,9 @@ __xenbus_switch_state(struct xenbus_device *dev,
struct xenbus_transaction xbt;
int current_state;
int err, abort;
+ bool vanished = false;
- if (state == dev->state)
+ if (state == dev->state || dev->vanished)
return 0;
again:
@@ -242,6 +243,10 @@ again:
err = xenbus_scanf(xbt, dev->nodename, "state", "%d", &current_state);
if (err != 1)
goto abort;
+ if (current_state != dev->state && current_state == XenbusStateInitialising) {
+ vanished = true;
+ goto abort;
+ }
err = xenbus_printf(xbt, dev->nodename, "state", "%d", state);
if (err) {
@@ -256,7 +261,7 @@ abort:
if (err == -EAGAIN && !abort)
goto again;
xenbus_switch_fatal(dev, depth, err, "ending transaction");
- } else
+ } else if (!vanished)
dev->state = state;
return 0;
@@ -931,14 +936,20 @@ static int xenbus_unmap_ring_hvm(struct xenbus_device *dev, void *vaddr)
/**
* xenbus_read_driver_state - read state from a store path
+ * @dev: xenbus device pointer
* @path: path for driver
*
* Returns: the state of the driver rooted at the given store path, or
* XenbusStateUnknown if no state can be read.
*/
-enum xenbus_state xenbus_read_driver_state(const char *path)
+enum xenbus_state xenbus_read_driver_state(const struct xenbus_device *dev,
+ const char *path)
{
enum xenbus_state result;
+
+ if (dev && dev->vanished)
+ return XenbusStateUnknown;
+
int err = xenbus_gather(XBT_NIL, path, "state", "%d", &result, NULL);
if (err)
result = XenbusStateUnknown;
diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c
index 9f9011cd7447..eb260eceb4d2 100644
--- a/drivers/xen/xenbus/xenbus_probe.c
+++ b/drivers/xen/xenbus/xenbus_probe.c
@@ -191,7 +191,7 @@ void xenbus_otherend_changed(struct xenbus_watch *watch,
return;
}
- state = xenbus_read_driver_state(dev->otherend);
+ state = xenbus_read_driver_state(dev, dev->otherend);
dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n",
state, xenbus_strstate(state), dev->otherend_watch.node, path);
@@ -364,7 +364,7 @@ void xenbus_dev_remove(struct device *_dev)
* closed.
*/
if (!drv->allow_rebind ||
- xenbus_read_driver_state(dev->nodename) == XenbusStateClosing)
+ xenbus_read_driver_state(dev, dev->nodename) == XenbusStateClosing)
xenbus_switch_state(dev, XenbusStateClosed);
}
EXPORT_SYMBOL_GPL(xenbus_dev_remove);
@@ -444,6 +444,9 @@ static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
info.dev = NULL;
bus_for_each_dev(bus, NULL, &info, cleanup_dev);
if (info.dev) {
+ dev_warn(&info.dev->dev,
+ "device forcefully removed from xenstore\n");
+ info.dev->vanished = true;
device_unregister(&info.dev->dev);
put_device(&info.dev->dev);
}
@@ -514,7 +517,7 @@ int xenbus_probe_node(struct xen_bus_type *bus,
size_t stringlen;
char *tmpstring;
- enum xenbus_state state = xenbus_read_driver_state(nodename);
+ enum xenbus_state state = xenbus_read_driver_state(NULL, nodename);
if (state != XenbusStateInitialising) {
/* Device is not new, so ignore it. This can happen if a
@@ -659,6 +662,39 @@ void xenbus_dev_changed(const char *node, struct xen_bus_type *bus)
return;
dev = xenbus_device_find(root, &bus->bus);
+ /*
+ * Backend domain crash results in not coordinated frontend removal,
+ * without going through XenbusStateClosing. If this is a new instance
+ * of the same device Xen tools will have reset the state to
+ * XenbusStateInitializing.
+ * It might be that the backend crashed early during the init phase of
+ * device setup, in which case the known state would have been
+ * XenbusStateInitializing. So test the backend domid to match the
+ * saved one. In case the new backend happens to have the same domid as
+ * the old one, we can just carry on, as there is no inconsistency
+ * resulting in this case.
+ */
+ if (dev && !strcmp(bus->root, "device")) {
+ enum xenbus_state state = xenbus_read_driver_state(dev, dev->nodename);
+ unsigned int backend = xenbus_read_unsigned(root, "backend-id",
+ dev->otherend_id);
+
+ if (state == XenbusStateInitialising &&
+ (state != dev->state || backend != dev->otherend_id)) {
+ /*
+ * State has been reset, assume the old one vanished
+ * and new one needs to be probed.
+ */
+ dev_warn(&dev->dev,
+ "state reset occurred, reconnecting\n");
+ dev->vanished = true;
+ }
+ if (dev->vanished) {
+ device_unregister(&dev->dev);
+ put_device(&dev->dev);
+ dev = NULL;
+ }
+ }
if (!dev)
xenbus_probe_node(bus, type, root);
else
diff --git a/drivers/xen/xenbus/xenbus_probe_frontend.c b/drivers/xen/xenbus/xenbus_probe_frontend.c
index f04707d1f667..ca04609730df 100644
--- a/drivers/xen/xenbus/xenbus_probe_frontend.c
+++ b/drivers/xen/xenbus/xenbus_probe_frontend.c
@@ -253,7 +253,7 @@ static int print_device_status(struct device *dev, void *data)
} else if (xendev->state < XenbusStateConnected) {
enum xenbus_state rstate = XenbusStateUnknown;
if (xendev->otherend)
- rstate = xenbus_read_driver_state(xendev->otherend);
+ rstate = xenbus_read_driver_state(xendev, xendev->otherend);
pr_warn("Timeout connecting to device: %s (local state %d, remote state %d)\n",
xendev->nodename, xendev->state, rstate);
}
diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index c284f48cfae4..2a886bece810 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -3340,7 +3340,6 @@ again:
btrfs_abort_transaction(trans, ret);
goto out_put;
}
- WARN_ON(ret);
/* We've already setup this transaction, go ahead and exit */
if (block_group->cache_generation == trans->transid &&
diff --git a/fs/btrfs/delayed-inode.c b/fs/btrfs/delayed-inode.c
index d97bbbd045e0..56ff8afe9a22 100644
--- a/fs/btrfs/delayed-inode.c
+++ b/fs/btrfs/delayed-inode.c
@@ -1657,7 +1657,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
if (unlikely(ret)) {
btrfs_err(trans->fs_info,
"failed to add delayed dir index item, root: %llu, inode: %llu, index: %llu, error: %d",
- index, btrfs_root_id(node->root), node->inode_id, ret);
+ btrfs_root_id(node->root), node->inode_id, index, ret);
btrfs_delayed_item_release_metadata(dir->root, item);
btrfs_release_delayed_item(item);
}
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index f6fa15a1193f..e4fad777b034 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1994,7 +1994,7 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
int level = btrfs_super_log_root_level(disk_super);
if (unlikely(fs_devices->rw_devices == 0)) {
- btrfs_warn(fs_info, "log replay required on RO media");
+ btrfs_err(fs_info, "log replay required on RO media");
return -EIO;
}
@@ -2008,9 +2008,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
check.owner_root = BTRFS_TREE_LOG_OBJECTID;
log_tree_root->node = read_tree_block(fs_info, bytenr, &check);
if (IS_ERR(log_tree_root->node)) {
- btrfs_warn(fs_info, "failed to read log tree");
ret = PTR_ERR(log_tree_root->node);
log_tree_root->node = NULL;
+ btrfs_err(fs_info, "failed to read log tree with error: %d", ret);
btrfs_put_root(log_tree_root);
return ret;
}
@@ -2023,9 +2023,9 @@ static int btrfs_replay_log(struct btrfs_fs_info *fs_info,
/* returns with log_tree_root freed on success */
ret = btrfs_recover_log_trees(log_tree_root);
btrfs_put_root(log_tree_root);
- if (ret) {
- btrfs_handle_fs_error(fs_info, ret,
- "Failed to recover log tree");
+ if (unlikely(ret)) {
+ ASSERT(BTRFS_FS_ERROR(fs_info) != 0);
+ btrfs_err(fs_info, "failed to recover log trees with error: %d", ret);
return ret;
}
@@ -2972,7 +2972,6 @@ static int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid");
if (IS_ERR(task)) {
/* fs_info->update_uuid_tree_gen remains 0 in all error case */
- btrfs_warn(fs_info, "failed to start uuid_rescan task");
up(&fs_info->uuid_tree_rescan_sem);
return PTR_ERR(task);
}
@@ -3188,7 +3187,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
if (incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP) {
btrfs_err(fs_info,
"cannot mount because of unknown incompat features (0x%llx)",
- incompat);
+ incompat & ~BTRFS_FEATURE_INCOMPAT_SUPP);
return -EINVAL;
}
@@ -3220,7 +3219,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
if (compat_ro_unsupp && is_rw_mount) {
btrfs_err(fs_info,
"cannot mount read-write because of unknown compat_ro features (0x%llx)",
- compat_ro);
+ compat_ro_unsupp);
return -EINVAL;
}
@@ -3233,7 +3232,7 @@ int btrfs_check_features(struct btrfs_fs_info *fs_info, bool is_rw_mount)
!btrfs_test_opt(fs_info, NOLOGREPLAY)) {
btrfs_err(fs_info,
"cannot replay dirty log with unsupported compat_ro features (0x%llx), try rescue=nologreplay",
- compat_ro);
+ compat_ro_unsupp);
return -EINVAL;
}
@@ -3642,7 +3641,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
fs_info->fs_root = btrfs_get_fs_root(fs_info, BTRFS_FS_TREE_OBJECTID, true);
if (IS_ERR(fs_info->fs_root)) {
ret = PTR_ERR(fs_info->fs_root);
- btrfs_warn(fs_info, "failed to read fs tree: %d", ret);
+ btrfs_err(fs_info, "failed to read fs tree: %d", ret);
fs_info->fs_root = NULL;
goto fail_qgroup;
}
@@ -3663,8 +3662,7 @@ int __cold open_ctree(struct super_block *sb, struct btrfs_fs_devices *fs_device
btrfs_info(fs_info, "checking UUID tree");
ret = btrfs_check_uuid_tree(fs_info);
if (ret) {
- btrfs_warn(fs_info,
- "failed to check the UUID tree: %d", ret);
+ btrfs_err(fs_info, "failed to check the UUID tree: %d", ret);
close_ctree(fs_info);
return ret;
}
@@ -4399,9 +4397,17 @@ void __cold close_ctree(struct btrfs_fs_info *fs_info)
*/
btrfs_flush_workqueue(fs_info->delayed_workers);
- ret = btrfs_commit_super(fs_info);
- if (ret)
- btrfs_err(fs_info, "commit super ret %d", ret);
+ /*
+ * If the filesystem is shutdown, then an attempt to commit the
+ * super block (or any write) will just fail. Since we freeze
+ * the filesystem before shutting it down, the filesystem is in
+ * a consistent state and we don't need to commit super blocks.
+ */
+ if (!btrfs_is_shutdown(fs_info)) {
+ ret = btrfs_commit_super(fs_info);
+ if (ret)
+ btrfs_err(fs_info, "commit super block returned %d", ret);
+ }
}
kthread_stop(fs_info->transaction_kthread);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 03cf9f242c70..b0d9baf5b412 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2933,9 +2933,15 @@ int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans)
while (!TRANS_ABORTED(trans) && cached_state) {
struct extent_state *next_state;
- if (btrfs_test_opt(fs_info, DISCARD_SYNC))
+ if (btrfs_test_opt(fs_info, DISCARD_SYNC)) {
ret = btrfs_discard_extent(fs_info, start,
end + 1 - start, NULL, true);
+ if (ret) {
+ btrfs_warn(fs_info,
+ "discard failed for extent [%llu, %llu]: errno=%d %s",
+ start, end, ret, btrfs_decode_error(ret));
+ }
+ }
next_state = btrfs_next_extent_state(unpin, cached_state);
btrfs_clear_extent_dirty(unpin, start, end, &cached_state);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 6efb543f1c24..a11fcc9e9f50 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1392,10 +1392,25 @@ static int cow_one_range(struct btrfs_inode *inode, struct folio *locked_folio,
return ret;
free_reserved:
+ /*
+ * If we have reserved an extent for the current range and failed to
+ * create the respective extent map or ordered extent, it means that
+ * when we reserved the extent we decremented the extent's size from
+ * the data space_info's bytes_may_use counter and
+ * incremented the space_info's bytes_reserved counter by the same
+ * amount.
+ *
+ * We must make sure extent_clear_unlock_delalloc() does not try
+ * to decrement again the data space_info's bytes_may_use counter, which
+ * will be handled by btrfs_free_reserved_extent().
+ *
+ * Therefore we do not pass it the flag EXTENT_CLEAR_DATA_RESV, but only
+ * EXTENT_CLEAR_META_RESV.
+ */
extent_clear_unlock_delalloc(inode, file_offset, cur_end, locked_folio, cached,
EXTENT_LOCKED | EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW |
- EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
+ EXTENT_DEFRAG | EXTENT_CLEAR_META_RESV,
PAGE_UNLOCK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK);
btrfs_qgroup_free_data(inode, NULL, file_offset, cur_len, NULL);
@@ -4764,7 +4779,7 @@ int btrfs_delete_subvolume(struct btrfs_inode *dir, struct dentry *dentry)
spin_unlock(&dest->root_item_lock);
btrfs_warn(fs_info,
"attempt to delete subvolume %llu with active swapfile",
- btrfs_root_id(root));
+ btrfs_root_id(dest));
ret = -EPERM;
goto out_up_write;
}
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index ae2173235c4d..a1fd44c44ecf 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -4581,7 +4581,7 @@ static int btrfs_uring_read_extent(struct kiocb *iocb, struct iov_iter *iter,
{
struct btrfs_inode *inode = BTRFS_I(file_inode(iocb->ki_filp));
struct extent_io_tree *io_tree = &inode->io_tree;
- struct page **pages;
+ struct page **pages = NULL;
struct btrfs_uring_priv *priv = NULL;
unsigned long nr_pages;
int ret;
@@ -4639,6 +4639,11 @@ out_fail:
btrfs_unlock_extent(io_tree, start, lockend, &cached_state);
btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
kfree(priv);
+ for (int i = 0; i < nr_pages; i++) {
+ if (pages[i])
+ __free_page(pages[i]);
+ }
+ kfree(pages);
return ret;
}
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 3cdd9755dc52..3b2a6517d0b5 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -370,7 +370,7 @@ static bool squota_check_parent_usage(struct btrfs_fs_info *fs_info, struct btrf
nr_members++;
}
mismatch = (parent->excl != excl_sum || parent->rfer != rfer_sum ||
- parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != excl_cmpr_sum);
+ parent->excl_cmpr != excl_cmpr_sum || parent->rfer_cmpr != rfer_cmpr_sum);
WARN(mismatch,
"parent squota qgroup %hu/%llu has mismatched usage from its %d members. "
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 95db7c48fbad..a330d8624b83 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4723,6 +4723,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
ret = btrfs_remove_dev_extents(trans, chunk_map);
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
@@ -4732,6 +4733,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
if (unlikely(ret)) {
mutex_unlock(&trans->fs_info->chunk_mutex);
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
}
@@ -4750,6 +4752,7 @@ int btrfs_last_identity_remap_gone(struct btrfs_chunk_map *chunk_map,
ret = remove_chunk_stripes(trans, chunk_map, path);
if (unlikely(ret)) {
btrfs_abort_transaction(trans, ret);
+ btrfs_end_transaction(trans);
return ret;
}
@@ -5982,6 +5985,9 @@ static int remove_range_from_remap_tree(struct btrfs_trans_handle *trans,
struct btrfs_block_group *dest_bg;
dest_bg = btrfs_lookup_block_group(fs_info, new_addr);
+ if (unlikely(!dest_bg))
+ return -EUCLEAN;
+
adjust_block_group_remap_bytes(trans, dest_bg, -overlap_length);
btrfs_put_block_group(dest_bg);
ret = btrfs_add_to_free_space_tree(trans,
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 81022d912abb..bc94bbc00772 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -743,7 +743,7 @@ static void scrub_verify_one_metadata(struct scrub_stripe *stripe, int sector_nr
btrfs_warn_rl(fs_info,
"scrub: tree block %llu mirror %u has bad fsid, has %pU want %pU",
logical, stripe->mirror_num,
- header->fsid, fs_info->fs_devices->fsid);
+ header->fsid, fs_info->fs_devices->metadata_uuid);
return;
}
if (memcmp(header->chunk_tree_uuid, fs_info->chunk_tree_uuid,
diff --git a/fs/btrfs/tree-checker.c b/fs/btrfs/tree-checker.c
index 452394b34d01..ac4c4573ee39 100644
--- a/fs/btrfs/tree-checker.c
+++ b/fs/btrfs/tree-checker.c
@@ -1740,7 +1740,7 @@ static int check_extent_data_ref(struct extent_buffer *leaf,
objectid > BTRFS_LAST_FREE_OBJECTID)) {
extent_err(leaf, slot,
"invalid extent data backref objectid value %llu",
- root);
+ objectid);
return -EUCLEAN;
}
if (unlikely(!IS_ALIGNED(offset, leaf->fs_info->sectorsize))) {
@@ -1921,7 +1921,7 @@ static int check_dev_extent_item(const struct extent_buffer *leaf,
if (unlikely(prev_key->offset + prev_len > key->offset)) {
generic_err(leaf, slot,
"dev extent overlap, prev offset %llu len %llu current offset %llu",
- prev_key->objectid, prev_len, key->offset);
+ prev_key->offset, prev_len, key->offset);
return -EUCLEAN;
}
}
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 6fb0c4cd50ff..648bb09fc416 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6907,7 +6907,7 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
ret = btrfs_translate_remap(fs_info, &new_logical, length);
if (ret)
- return ret;
+ goto out;
if (new_logical != logical) {
btrfs_free_chunk_map(map);
@@ -6921,8 +6921,10 @@ int btrfs_map_block(struct btrfs_fs_info *fs_info, enum btrfs_map_op op,
}
num_copies = btrfs_chunk_map_num_copies(map);
- if (io_geom.mirror_num > num_copies)
- return -EINVAL;
+ if (io_geom.mirror_num > num_copies) {
+ ret = -EINVAL;
+ goto out;
+ }
map_offset = logical - map->start;
io_geom.raid56_full_stripe_start = (u64)-1;
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c
index bc82083e420a..00f0efaf12b2 100644
--- a/fs/iomap/buffered-io.c
+++ b/fs/iomap/buffered-io.c
@@ -80,18 +80,27 @@ static void iomap_set_range_uptodate(struct folio *folio, size_t off,
{
struct iomap_folio_state *ifs = folio->private;
unsigned long flags;
- bool uptodate = true;
+ bool mark_uptodate = true;
if (folio_test_uptodate(folio))
return;
if (ifs) {
spin_lock_irqsave(&ifs->state_lock, flags);
- uptodate = ifs_set_range_uptodate(folio, ifs, off, len);
+ /*
+ * If a read with bytes pending is in progress, we must not call
+ * folio_mark_uptodate(). The read completion path
+ * (iomap_read_end()) will call folio_end_read(), which uses XOR
+ * semantics to set the uptodate bit. If we set it here, the XOR
+ * in folio_end_read() will clear it, leaving the folio not
+ * uptodate.
+ */
+ mark_uptodate = ifs_set_range_uptodate(folio, ifs, off, len) &&
+ !ifs->read_bytes_pending;
spin_unlock_irqrestore(&ifs->state_lock, flags);
}
- if (uptodate)
+ if (mark_uptodate)
folio_mark_uptodate(folio);
}
diff --git a/fs/iomap/direct-io.c b/fs/iomap/direct-io.c
index 95254aa1b654..e911daedff65 100644
--- a/fs/iomap/direct-io.c
+++ b/fs/iomap/direct-io.c
@@ -87,6 +87,19 @@ static inline enum fserror_type iomap_dio_err_type(const struct iomap_dio *dio)
return FSERR_DIRECTIO_READ;
}
+static inline bool should_report_dio_fserror(const struct iomap_dio *dio)
+{
+ switch (dio->error) {
+ case 0:
+ case -EAGAIN:
+ case -ENOTBLK:
+ /* don't send fsnotify for success or magic retry codes */
+ return false;
+ default:
+ return true;
+ }
+}
+
ssize_t iomap_dio_complete(struct iomap_dio *dio)
{
const struct iomap_dio_ops *dops = dio->dops;
@@ -96,7 +109,7 @@ ssize_t iomap_dio_complete(struct iomap_dio *dio)
if (dops && dops->end_io)
ret = dops->end_io(iocb, dio->size, ret, dio->flags);
- if (dio->error)
+ if (should_report_dio_fserror(dio))
fserror_report_io(file_inode(iocb->ki_filp),
iomap_dio_err_type(dio), offset, dio->size,
dio->error, GFP_NOFS);
diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
index 4d1ef8a2cee9..60546fa14dfe 100644
--- a/fs/iomap/ioend.c
+++ b/fs/iomap/ioend.c
@@ -215,17 +215,18 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
WARN_ON_ONCE(!folio->private && map_len < dirty_len);
switch (wpc->iomap.type) {
- case IOMAP_INLINE:
- WARN_ON_ONCE(1);
- return -EIO;
+ case IOMAP_UNWRITTEN:
+ ioend_flags |= IOMAP_IOEND_UNWRITTEN;
+ break;
+ case IOMAP_MAPPED:
+ break;
case IOMAP_HOLE:
return map_len;
default:
- break;
+ WARN_ON_ONCE(1);
+ return -EIO;
}
- if (wpc->iomap.type == IOMAP_UNWRITTEN)
- ioend_flags |= IOMAP_IOEND_UNWRITTEN;
if (wpc->iomap.flags & IOMAP_F_SHARED)
ioend_flags |= IOMAP_IOEND_SHARED;
if (folio_test_dropbehind(folio))
diff --git a/fs/netfs/direct_write.c b/fs/netfs/direct_write.c
index a9d1c3b2c084..dd1451bf7543 100644
--- a/fs/netfs/direct_write.c
+++ b/fs/netfs/direct_write.c
@@ -10,6 +10,202 @@
#include "internal.h"
/*
+ * Perform the cleanup rituals after an unbuffered write is complete.
+ */
+static void netfs_unbuffered_write_done(struct netfs_io_request *wreq)
+{
+ struct netfs_inode *ictx = netfs_inode(wreq->inode);
+
+ _enter("R=%x", wreq->debug_id);
+
+ /* Okay, declare that all I/O is complete. */
+ trace_netfs_rreq(wreq, netfs_rreq_trace_write_done);
+
+ if (!wreq->error)
+ netfs_update_i_size(ictx, &ictx->inode, wreq->start, wreq->transferred);
+
+ if (wreq->origin == NETFS_DIO_WRITE &&
+ wreq->mapping->nrpages) {
+ /* mmap may have got underfoot and we may now have folios
+ * locally covering the region we just wrote. Attempt to
+ * discard the folios, but leave in place any modified locally.
+ * ->write_iter() is prevented from interfering by the DIO
+ * counter.
+ */
+ pgoff_t first = wreq->start >> PAGE_SHIFT;
+ pgoff_t last = (wreq->start + wreq->transferred - 1) >> PAGE_SHIFT;
+
+ invalidate_inode_pages2_range(wreq->mapping, first, last);
+ }
+
+ if (wreq->origin == NETFS_DIO_WRITE)
+ inode_dio_end(wreq->inode);
+
+ _debug("finished");
+ netfs_wake_rreq_flag(wreq, NETFS_RREQ_IN_PROGRESS, netfs_rreq_trace_wake_ip);
+ /* As we cleared NETFS_RREQ_IN_PROGRESS, we acquired its ref. */
+
+ if (wreq->iocb) {
+ size_t written = umin(wreq->transferred, wreq->len);
+
+ wreq->iocb->ki_pos += written;
+ if (wreq->iocb->ki_complete) {
+ trace_netfs_rreq(wreq, netfs_rreq_trace_ki_complete);
+ wreq->iocb->ki_complete(wreq->iocb, wreq->error ?: written);
+ }
+ wreq->iocb = VFS_PTR_POISON;
+ }
+
+ netfs_clear_subrequests(wreq);
+}
+
+/*
+ * Collect the subrequest results of unbuffered write subrequests.
+ */
+static void netfs_unbuffered_write_collect(struct netfs_io_request *wreq,
+ struct netfs_io_stream *stream,
+ struct netfs_io_subrequest *subreq)
+{
+ trace_netfs_collect_sreq(wreq, subreq);
+
+ spin_lock(&wreq->lock);
+ list_del_init(&subreq->rreq_link);
+ spin_unlock(&wreq->lock);
+
+ wreq->transferred += subreq->transferred;
+ iov_iter_advance(&wreq->buffer.iter, subreq->transferred);
+
+ stream->collected_to = subreq->start + subreq->transferred;
+ wreq->collected_to = stream->collected_to;
+ netfs_put_subrequest(subreq, netfs_sreq_trace_put_done);
+
+ trace_netfs_collect_stream(wreq, stream);
+ trace_netfs_collect_state(wreq, wreq->collected_to, 0);
+}
+
+/*
+ * Write data to the server without going through the pagecache and without
+ * writing it to the local cache. We dispatch the subrequests serially and
+ * wait for each to complete before dispatching the next, lest we leave a gap
+ * in the data written due to a failure such as ENOSPC. We could, however
+ * attempt to do preparation such as content encryption for the next subreq
+ * whilst the current is in progress.
+ */
+static int netfs_unbuffered_write(struct netfs_io_request *wreq)
+{
+ struct netfs_io_subrequest *subreq = NULL;
+ struct netfs_io_stream *stream = &wreq->io_streams[0];
+ int ret;
+
+ _enter("%llx", wreq->len);
+
+ if (wreq->origin == NETFS_DIO_WRITE)
+ inode_dio_begin(wreq->inode);
+
+ stream->collected_to = wreq->start;
+
+ for (;;) {
+ bool retry = false;
+
+ if (!subreq) {
+ netfs_prepare_write(wreq, stream, wreq->start + wreq->transferred);
+ subreq = stream->construct;
+ stream->construct = NULL;
+ stream->front = NULL;
+ }
+
+ /* Check if (re-)preparation failed. */
+ if (unlikely(test_bit(NETFS_SREQ_FAILED, &subreq->flags))) {
+ netfs_write_subrequest_terminated(subreq, subreq->error);
+ wreq->error = subreq->error;
+ break;
+ }
+
+ iov_iter_truncate(&subreq->io_iter, wreq->len - wreq->transferred);
+ if (!iov_iter_count(&subreq->io_iter))
+ break;
+
+ subreq->len = netfs_limit_iter(&subreq->io_iter, 0,
+ stream->sreq_max_len,
+ stream->sreq_max_segs);
+ iov_iter_truncate(&subreq->io_iter, subreq->len);
+ stream->submit_extendable_to = subreq->len;
+
+ trace_netfs_sreq(subreq, netfs_sreq_trace_submit);
+ stream->issue_write(subreq);
+
+ /* Async, need to wait. */
+ netfs_wait_for_in_progress_stream(wreq, stream);
+
+ if (test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) {
+ retry = true;
+ } else if (test_bit(NETFS_SREQ_FAILED, &subreq->flags)) {
+ ret = subreq->error;
+ wreq->error = ret;
+ netfs_see_subrequest(subreq, netfs_sreq_trace_see_failed);
+ subreq = NULL;
+ break;
+ }
+ ret = 0;
+
+ if (!retry) {
+ netfs_unbuffered_write_collect(wreq, stream, subreq);
+ subreq = NULL;
+ if (wreq->transferred >= wreq->len)
+ break;
+ if (!wreq->iocb && signal_pending(current)) {
+ ret = wreq->transferred ? -EINTR : -ERESTARTSYS;
+ trace_netfs_rreq(wreq, netfs_rreq_trace_intr);
+ break;
+ }
+ continue;
+ }
+
+ /* We need to retry the last subrequest, so first reset the
+ * iterator, taking into account what, if anything, we managed
+ * to transfer.
+ */
+ subreq->error = -EAGAIN;
+ trace_netfs_sreq(subreq, netfs_sreq_trace_retry);
+ if (subreq->transferred > 0)
+ iov_iter_advance(&wreq->buffer.iter, subreq->transferred);
+
+ if (stream->source == NETFS_UPLOAD_TO_SERVER &&
+ wreq->netfs_ops->retry_request)
+ wreq->netfs_ops->retry_request(wreq, stream);
+
+ __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags);
+ __clear_bit(NETFS_SREQ_BOUNDARY, &subreq->flags);
+ __clear_bit(NETFS_SREQ_FAILED, &subreq->flags);
+ subreq->io_iter = wreq->buffer.iter;
+ subreq->start = wreq->start + wreq->transferred;
+ subreq->len = wreq->len - wreq->transferred;
+ subreq->transferred = 0;
+ subreq->retry_count += 1;
+ stream->sreq_max_len = UINT_MAX;
+ stream->sreq_max_segs = INT_MAX;
+
+ netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit);
+ stream->prepare_write(subreq);
+
+ __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags);
+ netfs_stat(&netfs_n_wh_retry_write_subreq);
+ }
+
+ netfs_unbuffered_write_done(wreq);
+ _leave(" = %d", ret);
+ return ret;
+}
+
+static void netfs_unbuffered_write_async(struct work_struct *work)
+{
+ struct netfs_io_request *wreq = container_of(work, struct netfs_io_request, work);
+
+ netfs_unbuffered_write(wreq);
+ netfs_put_request(wreq, netfs_rreq_trace_put_complete);
+}
+
+/*
* Perform an unbuffered write where we may have to do an RMW operation on an
* encrypted file. This can also be used for direct I/O writes.
*/
@@ -70,35 +266,35 @@ ssize_t netfs_unbuffered_write_iter_locked(struct kiocb *iocb, struct iov_iter *
*/
wreq->buffer.iter = *iter;
}
+
+ wreq->len = iov_iter_count(&wreq->buffer.iter);
}
__set_bit(NETFS_RREQ_USE_IO_ITER, &wreq->flags);
- if (async)
- __set_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &wreq->flags);
/* Copy the data into the bounce buffer and encrypt it. */
// TODO
/* Dispatch the write. */
__set_bit(NETFS_RREQ_UPLOAD_TO_SERVER, &wreq->flags);
- if (async)
- wreq->iocb = iocb;
- wreq->len = iov_iter_count(&wreq->buffer.iter);
- ret = netfs_unbuffered_write(wreq, is_sync_kiocb(iocb), wreq->len);
- if (ret < 0) {
- _debug("begin = %zd", ret);
- goto out;
- }
- if (!async) {
- ret = netfs_wait_for_write(wreq);
- if (ret > 0)
- iocb->ki_pos += ret;
- } else {
+ if (async) {
+ INIT_WORK(&wreq->work, netfs_unbuffered_write_async);
+ wreq->iocb = iocb;
+ queue_work(system_dfl_wq, &wreq->work);
ret = -EIOCBQUEUED;
+ } else {
+ ret = netfs_unbuffered_write(wreq);
+ if (ret < 0) {
+ _debug("begin = %zd", ret);
+ } else {
+ iocb->ki_pos += wreq->transferred;
+ ret = wreq->transferred ?: wreq->error;
+ }
+
+ netfs_put_request(wreq, netfs_rreq_trace_put_complete);
}
-out:
netfs_put_request(wreq, netfs_rreq_trace_put_return);
return ret;
diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h
index 4319611f5354..d436e20d3418 100644
--- a/fs/netfs/internal.h
+++ b/fs/netfs/internal.h
@@ -198,6 +198,9 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping,
struct file *file,
loff_t start,
enum netfs_io_origin origin);
+void netfs_prepare_write(struct netfs_io_request *wreq,
+ struct netfs_io_stream *stream,
+ loff_t start);
void netfs_reissue_write(struct netfs_io_stream *stream,
struct netfs_io_subrequest *subreq,
struct iov_iter *source);
@@ -212,7 +215,6 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c
struct folio **writethrough_cache);
ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_control *wbc,
struct folio *writethrough_cache);
-int netfs_unbuffered_write(struct netfs_io_request *wreq, bool may_wait, size_t len);
/*
* write_retry.c
diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c
index 61eab34ea67e..83eb3dc1adf8 100644
--- a/fs/netfs/write_collect.c
+++ b/fs/netfs/write_collect.c
@@ -399,27 +399,6 @@ bool netfs_write_collection(struct netfs_io_request *wreq)
ictx->ops->invalidate_cache(wreq);
}
- if ((wreq->origin == NETFS_UNBUFFERED_WRITE ||
- wreq->origin == NETFS_DIO_WRITE) &&
- !wreq->error)
- netfs_update_i_size(ictx, &ictx->inode, wreq->start, wreq->transferred);
-
- if (wreq->origin == NETFS_DIO_WRITE &&
- wreq->mapping->nrpages) {
- /* mmap may have got underfoot and we may now have folios
- * locally covering the region we just wrote. Attempt to
- * discard the folios, but leave in place any modified locally.
- * ->write_iter() is prevented from interfering by the DIO
- * counter.
- */
- pgoff_t first = wreq->start >> PAGE_SHIFT;
- pgoff_t last = (wreq->start + wreq->transferred - 1) >> PAGE_SHIFT;
- invalidate_inode_pages2_range(wreq->mapping, first, last);
- }
-
- if (wreq->origin == NETFS_DIO_WRITE)
- inode_dio_end(wreq->inode);
-
_debug("finished");
netfs_wake_rreq_flag(wreq, NETFS_RREQ_IN_PROGRESS, netfs_rreq_trace_wake_ip);
/* As we cleared NETFS_RREQ_IN_PROGRESS, we acquired its ref. */
diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c
index 34894da5a23e..437268f65640 100644
--- a/fs/netfs/write_issue.c
+++ b/fs/netfs/write_issue.c
@@ -154,9 +154,9 @@ EXPORT_SYMBOL(netfs_prepare_write_failed);
* Prepare a write subrequest. We need to allocate a new subrequest
* if we don't have one.
*/
-static void netfs_prepare_write(struct netfs_io_request *wreq,
- struct netfs_io_stream *stream,
- loff_t start)
+void netfs_prepare_write(struct netfs_io_request *wreq,
+ struct netfs_io_stream *stream,
+ loff_t start)
{
struct netfs_io_subrequest *subreq;
struct iov_iter *wreq_iter = &wreq->buffer.iter;
@@ -699,41 +699,6 @@ ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_c
}
/*
- * Write data to the server without going through the pagecache and without
- * writing it to the local cache.
- */
-int netfs_unbuffered_write(struct netfs_io_request *wreq, bool may_wait, size_t len)
-{
- struct netfs_io_stream *upload = &wreq->io_streams[0];
- ssize_t part;
- loff_t start = wreq->start;
- int error = 0;
-
- _enter("%zx", len);
-
- if (wreq->origin == NETFS_DIO_WRITE)
- inode_dio_begin(wreq->inode);
-
- while (len) {
- // TODO: Prepare content encryption
-
- _debug("unbuffered %zx", len);
- part = netfs_advance_write(wreq, upload, start, len, false);
- start += part;
- len -= part;
- rolling_buffer_advance(&wreq->buffer, part);
- if (test_bit(NETFS_RREQ_PAUSE, &wreq->flags))
- netfs_wait_for_paused_write(wreq);
- if (test_bit(NETFS_RREQ_FAILED, &wreq->flags))
- break;
- }
-
- netfs_end_issue_write(wreq);
- _leave(" = %d", error);
- return error;
-}
-
-/*
* Write some of a pending folio data back to the server and/or the cache.
*/
static int netfs_write_folio_single(struct netfs_io_request *wreq,
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index e9acd2cd602c..4cc8a58fa56a 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -377,15 +377,15 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
}
/*
- * write_threads - Start NFSD, or report the current number of running threads
+ * write_threads - Start NFSD, or report the configured number of threads
*
* Input:
* buf: ignored
* size: zero
* Output:
* On success: passed-in buffer filled with '\n'-terminated C
- * string numeric value representing the number of
- * running NFSD threads;
+ * string numeric value representing the configured
+ * number of NFSD threads;
* return code is the size in bytes of the string
* On error: return code is zero
*
@@ -399,8 +399,8 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
* Output:
* On success: NFS service is started;
* passed-in buffer filled with '\n'-terminated C
- * string numeric value representing the number of
- * running NFSD threads;
+ * string numeric value representing the configured
+ * number of NFSD threads;
* return code is the size in bytes of the string
* On error: return code is zero or a negative errno value
*/
@@ -430,7 +430,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
}
/*
- * write_pool_threads - Set or report the current number of threads per pool
+ * write_pool_threads - Set or report the configured number of threads per pool
*
* Input:
* buf: ignored
@@ -447,7 +447,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
* Output:
* On success: passed-in buffer filled with '\n'-terminated C
* string containing integer values representing the
- * number of NFSD threads in each pool;
+ * configured number of NFSD threads in each pool;
* return code is the size in bytes of the string
* On error: return code is zero or a negative errno value
*/
@@ -1647,7 +1647,7 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
if (attr)
nn->min_threads = nla_get_u32(attr);
- ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
+ ret = nfsd_svc(nrpools, nthreads, net, current_cred(), scope);
if (ret > 0)
ret = 0;
out_unlock:
@@ -1657,7 +1657,7 @@ out_unlock:
}
/**
- * nfsd_nl_threads_get_doit - get the number of running threads
+ * nfsd_nl_threads_get_doit - get the maximum number of running threads
* @skb: reply buffer
* @info: netlink metadata and command arguments
*
@@ -1700,7 +1700,7 @@ int nfsd_nl_threads_get_doit(struct sk_buff *skb, struct genl_info *info)
struct svc_pool *sp = &nn->nfsd_serv->sv_pools[i];
err = nla_put_u32(skb, NFSD_A_SERVER_THREADS,
- sp->sp_nrthreads);
+ sp->sp_nrthrmax);
if (err)
goto err_unlock;
}
@@ -2000,7 +2000,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
}
ret = svc_xprt_create_from_sa(serv, xcl_name, net, sa, 0,
- get_current_cred());
+ current_cred());
/* always save the latest error */
if (ret < 0)
err = ret;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 0887ee601d3c..4a04208393b8 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -239,12 +239,13 @@ static void nfsd_net_free(struct percpu_ref *ref)
int nfsd_nrthreads(struct net *net)
{
- int rv = 0;
+ int i, rv = 0;
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
mutex_lock(&nfsd_mutex);
if (nn->nfsd_serv)
- rv = nn->nfsd_serv->sv_nrthreads;
+ for (i = 0; i < nn->nfsd_serv->sv_nrpools; ++i)
+ rv += nn->nfsd_serv->sv_pools[i].sp_nrthrmax;
mutex_unlock(&nfsd_mutex);
return rv;
}
@@ -659,7 +660,7 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
if (serv)
for (i = 0; i < serv->sv_nrpools && i < n; i++)
- nthreads[i] = serv->sv_pools[i].sp_nrthreads;
+ nthreads[i] = serv->sv_pools[i].sp_nrthrmax;
return 0;
}
diff --git a/fs/nsfs.c b/fs/nsfs.c
index db91de208645..c215878d55e8 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -199,6 +199,17 @@ static bool nsfs_ioctl_valid(unsigned int cmd)
return false;
}
+static bool may_use_nsfs_ioctl(unsigned int cmd)
+{
+ switch (_IOC_NR(cmd)) {
+ case _IOC_NR(NS_MNT_GET_NEXT):
+ fallthrough;
+ case _IOC_NR(NS_MNT_GET_PREV):
+ return may_see_all_namespaces();
+ }
+ return true;
+}
+
static long ns_ioctl(struct file *filp, unsigned int ioctl,
unsigned long arg)
{
@@ -214,6 +225,8 @@ static long ns_ioctl(struct file *filp, unsigned int ioctl,
if (!nsfs_ioctl_valid(ioctl))
return -ENOIOCTLCMD;
+ if (!may_use_nsfs_ioctl(ioctl))
+ return -EPERM;
ns = get_proc_ns(file_inode(filp));
switch (ioctl) {
@@ -614,7 +627,7 @@ static struct dentry *nsfs_fh_to_dentry(struct super_block *sb, struct fid *fh,
return ERR_PTR(-EOPNOTSUPP);
}
- if (owning_ns && !ns_capable(owning_ns, CAP_SYS_ADMIN)) {
+ if (owning_ns && !may_see_all_namespaces()) {
ns->ops->put(ns);
return ERR_PTR(-EPERM);
}
diff --git a/fs/smb/client/Makefile b/fs/smb/client/Makefile
index 3abd357d6df6..26b6105f04d1 100644
--- a/fs/smb/client/Makefile
+++ b/fs/smb/client/Makefile
@@ -56,4 +56,6 @@ $(obj)/smb2maperror.o: $(obj)/smb2_mapping_table.c
quiet_cmd_gen_smb2_mapping = GEN $@
cmd_gen_smb2_mapping = perl $(src)/gen_smb2_mapping $< $@
+obj-$(CONFIG_SMB_KUNIT_TESTS) += smb2maperror_test.o
+
clean-files += smb2_mapping_table.c
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index 427558404aa5..b6e3db993cc6 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -332,10 +332,14 @@ static void cifs_kill_sb(struct super_block *sb)
/*
* We need to release all dentries for the cached directories
- * before we kill the sb.
+ * and close all deferred file handles before we kill the sb.
*/
if (cifs_sb->root) {
close_all_cached_dirs(cifs_sb);
+ cifs_close_all_deferred_files_sb(cifs_sb);
+
+ /* Wait for all pending oplock breaks to complete */
+ flush_workqueue(cifsoplockd_wq);
/* finally release root dentry */
dput(cifs_sb->root);
@@ -868,7 +872,6 @@ static void cifs_umount_begin(struct super_block *sb)
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
- cifs_close_all_deferred_files(tcon);
/* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */
/* cancel_notify_requests(tcon); */
if (tcon->ses && tcon->ses->server) {
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 96d6b5325aa3..800a7e418c32 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -261,6 +261,7 @@ void cifs_close_deferred_file(struct cifsInodeInfo *cifs_inode);
void cifs_close_all_deferred_files(struct cifs_tcon *tcon);
+void cifs_close_all_deferred_files_sb(struct cifs_sb_info *cifs_sb);
void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
struct dentry *dentry);
diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c
index f3ddcdf406c8..cffcf82c1b69 100644
--- a/fs/smb/client/file.c
+++ b/fs/smb/client/file.c
@@ -711,8 +711,6 @@ struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
mutex_init(&cfile->fh_mutex);
spin_lock_init(&cfile->file_info_lock);
- cifs_sb_active(inode->i_sb);
-
/*
* If the server returned a read oplock and we have mandatory brlocks,
* set oplock level to None.
@@ -767,7 +765,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
struct inode *inode = d_inode(cifs_file->dentry);
struct cifsInodeInfo *cifsi = CIFS_I(inode);
struct cifsLockInfo *li, *tmp;
- struct super_block *sb = inode->i_sb;
/*
* Delete any outstanding lock records. We'll lose them when the file
@@ -785,7 +782,6 @@ static void cifsFileInfo_put_final(struct cifsFileInfo *cifs_file)
cifs_put_tlink(cifs_file->tlink);
dput(cifs_file->dentry);
- cifs_sb_deactive(sb);
kfree(cifs_file->symlink_target);
kfree(cifs_file);
}
@@ -3163,12 +3159,6 @@ void cifs_oplock_break(struct work_struct *work)
__u64 persistent_fid, volatile_fid;
__u16 net_fid;
- /*
- * Hold a reference to the superblock to prevent it and its inodes from
- * being freed while we are accessing cinode. Otherwise, _cifsFileInfo_put()
- * may release the last reference to the sb and trigger inode eviction.
- */
- cifs_sb_active(sb);
wait_on_bit(&cinode->flags, CIFS_INODE_PENDING_WRITERS,
TASK_UNINTERRUPTIBLE);
@@ -3253,7 +3243,6 @@ oplock_break_ack:
cifs_put_tlink(tlink);
out:
cifs_done_oplock_break(cinode);
- cifs_sb_deactive(sb);
}
static int cifs_swap_activate(struct swap_info_struct *sis,
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index bc24c92b8b95..2aff1cab6c31 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -28,6 +28,11 @@
#include "fs_context.h"
#include "cached_dir.h"
+struct tcon_list {
+ struct list_head entry;
+ struct cifs_tcon *tcon;
+};
+
/* The xid serves as a useful identifier for each incoming vfs request,
in a similar way to the mid which is useful to track each sent smb,
and CurrentXid can also provide a running counter (although it
@@ -554,6 +559,43 @@ cifs_close_all_deferred_files(struct cifs_tcon *tcon)
}
}
+void cifs_close_all_deferred_files_sb(struct cifs_sb_info *cifs_sb)
+{
+ struct rb_root *root = &cifs_sb->tlink_tree;
+ struct rb_node *node;
+ struct cifs_tcon *tcon;
+ struct tcon_link *tlink;
+ struct tcon_list *tmp_list, *q;
+ LIST_HEAD(tcon_head);
+
+ spin_lock(&cifs_sb->tlink_tree_lock);
+ for (node = rb_first(root); node; node = rb_next(node)) {
+ tlink = rb_entry(node, struct tcon_link, tl_rbnode);
+ tcon = tlink_tcon(tlink);
+ if (IS_ERR(tcon))
+ continue;
+ tmp_list = kmalloc_obj(struct tcon_list, GFP_ATOMIC);
+ if (tmp_list == NULL)
+ break;
+ tmp_list->tcon = tcon;
+ /* Take a reference on tcon to prevent it from being freed */
+ spin_lock(&tcon->tc_lock);
+ ++tcon->tc_count;
+ trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
+ netfs_trace_tcon_ref_get_close_defer_files);
+ spin_unlock(&tcon->tc_lock);
+ list_add_tail(&tmp_list->entry, &tcon_head);
+ }
+ spin_unlock(&cifs_sb->tlink_tree_lock);
+
+ list_for_each_entry_safe(tmp_list, q, &tcon_head, entry) {
+ cifs_close_all_deferred_files(tmp_list->tcon);
+ list_del(&tmp_list->entry);
+ cifs_put_tcon(tmp_list->tcon, netfs_trace_tcon_ref_put_close_defer_files);
+ kfree(tmp_list);
+ }
+}
+
void cifs_close_deferred_file_under_dentry(struct cifs_tcon *tcon,
struct dentry *dentry)
{
diff --git a/fs/smb/client/smb1encrypt.c b/fs/smb/client/smb1encrypt.c
index 0dbbce2431ff..bf10fdeeedca 100644
--- a/fs/smb/client/smb1encrypt.c
+++ b/fs/smb/client/smb1encrypt.c
@@ -11,6 +11,7 @@
#include <linux/fips.h>
#include <crypto/md5.h>
+#include <crypto/utils.h>
#include "cifsproto.h"
#include "smb1proto.h"
#include "cifs_debug.h"
@@ -131,7 +132,7 @@ int cifs_verify_signature(struct smb_rqst *rqst,
/* cifs_dump_mem("what we think it should be: ",
what_we_think_sig_should_be, 16); */
- if (memcmp(server_response_sig, what_we_think_sig_should_be, 8))
+ if (crypto_memneq(server_response_sig, what_we_think_sig_should_be, 8))
return -EACCES;
else
return 0;
diff --git a/fs/smb/client/smb2glob.h b/fs/smb/client/smb2glob.h
index e56e4d402f13..19da74b1edab 100644
--- a/fs/smb/client/smb2glob.h
+++ b/fs/smb/client/smb2glob.h
@@ -46,4 +46,16 @@ enum smb2_compound_ops {
#define END_OF_CHAIN 4
#define RELATED_REQUEST 8
+/*
+ *****************************************************************
+ * Struct definitions go here
+ *****************************************************************
+ */
+
+struct status_to_posix_error {
+ __u32 smb2_status;
+ int posix_error;
+ char *status_string;
+};
+
#endif /* _SMB2_GLOB_H */
diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c
index 195a38fd61e8..5280c5c869ad 100644
--- a/fs/smb/client/smb2inode.c
+++ b/fs/smb/client/smb2inode.c
@@ -325,7 +325,7 @@ replay_again:
cfile->fid.volatile_fid,
SMB_FIND_FILE_POSIX_INFO,
SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo *) +
+ sizeof(struct smb311_posix_qinfo) +
(PATH_MAX * 2) +
(sizeof(struct smb_sid) * 2), 0, NULL);
} else {
@@ -335,7 +335,7 @@ replay_again:
COMPOUND_FID,
SMB_FIND_FILE_POSIX_INFO,
SMB2_O_INFO_FILE, 0,
- sizeof(struct smb311_posix_qinfo *) +
+ sizeof(struct smb311_posix_qinfo) +
(PATH_MAX * 2) +
(sizeof(struct smb_sid) * 2), 0, NULL);
}
@@ -1216,6 +1216,7 @@ again:
memset(resp_buftype, 0, sizeof(resp_buftype));
memset(rsp_iov, 0, sizeof(rsp_iov));
+ memset(open_iov, 0, sizeof(open_iov));
rqst[0].rq_iov = open_iov;
rqst[0].rq_nvec = ARRAY_SIZE(open_iov);
@@ -1240,14 +1241,15 @@ again:
creq = rqst[0].rq_iov[0].iov_base;
creq->ShareAccess = FILE_SHARE_DELETE_LE;
+ memset(&close_iov, 0, sizeof(close_iov));
rqst[1].rq_iov = &close_iov;
rqst[1].rq_nvec = 1;
rc = SMB2_close_init(tcon, server, &rqst[1],
COMPOUND_FID, COMPOUND_FID, false);
- smb2_set_related(&rqst[1]);
if (rc)
goto err_free;
+ smb2_set_related(&rqst[1]);
if (retries) {
/* Back-off before retry */
diff --git a/fs/smb/client/smb2maperror.c b/fs/smb/client/smb2maperror.c
index cd036365201f..f4cff44e2796 100644
--- a/fs/smb/client/smb2maperror.c
+++ b/fs/smb/client/smb2maperror.c
@@ -8,7 +8,6 @@
*
*/
#include <linux/errno.h>
-#include "cifsglob.h"
#include "cifsproto.h"
#include "cifs_debug.h"
#include "smb2proto.h"
@@ -16,12 +15,6 @@
#include "../common/smb2status.h"
#include "trace.h"
-struct status_to_posix_error {
- __u32 smb2_status;
- int posix_error;
- char *status_string;
-};
-
static const struct status_to_posix_error smb2_error_map_table[] = {
/*
* Automatically generated by the `gen_smb2_mapping` script,
@@ -115,10 +108,19 @@ int __init smb2_init_maperror(void)
return 0;
}
-#define SMB_CLIENT_KUNIT_AVAILABLE \
- ((IS_MODULE(CONFIG_CIFS) && IS_ENABLED(CONFIG_KUNIT)) || \
- (IS_BUILTIN(CONFIG_CIFS) && IS_BUILTIN(CONFIG_KUNIT)))
+#if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
+/* Previous prototype for eliminating the build warning. */
+const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status);
+
+const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status)
+{
+ return smb2_get_err_map(smb2_status);
+}
+EXPORT_SYMBOL_GPL(smb2_get_err_map_test);
+
+const struct status_to_posix_error *smb2_error_map_table_test = smb2_error_map_table;
+EXPORT_SYMBOL_GPL(smb2_error_map_table_test);
-#if SMB_CLIENT_KUNIT_AVAILABLE && IS_ENABLED(CONFIG_SMB_KUNIT_TESTS)
-#include "smb2maperror_test.c"
-#endif /* CONFIG_SMB_KUNIT_TESTS */
+unsigned int smb2_error_map_num = ARRAY_SIZE(smb2_error_map_table);
+EXPORT_SYMBOL_GPL(smb2_error_map_num);
+#endif
diff --git a/fs/smb/client/smb2maperror_test.c b/fs/smb/client/smb2maperror_test.c
index 38ea6b846a99..8c47dea7a2c1 100644
--- a/fs/smb/client/smb2maperror_test.c
+++ b/fs/smb/client/smb2maperror_test.c
@@ -9,13 +9,18 @@
*/
#include <kunit/test.h>
+#include "smb2glob.h"
+
+const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_status);
+extern const struct status_to_posix_error *smb2_error_map_table_test;
+extern unsigned int smb2_error_map_num;
static void
test_cmp_map(struct kunit *test, const struct status_to_posix_error *expect)
{
const struct status_to_posix_error *result;
- result = smb2_get_err_map(expect->smb2_status);
+ result = smb2_get_err_map_test(expect->smb2_status);
KUNIT_EXPECT_PTR_NE(test, NULL, result);
KUNIT_EXPECT_EQ(test, expect->smb2_status, result->smb2_status);
KUNIT_EXPECT_EQ(test, expect->posix_error, result->posix_error);
@@ -26,8 +31,8 @@ static void maperror_test_check_search(struct kunit *test)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(smb2_error_map_table); i++)
- test_cmp_map(test, &smb2_error_map_table[i]);
+ for (i = 0; i < smb2_error_map_num; i++)
+ test_cmp_map(test, &smb2_error_map_table_test[i]);
}
static struct kunit_case maperror_test_cases[] = {
@@ -43,3 +48,4 @@ static struct kunit_suite maperror_suite = {
kunit_test_suite(maperror_suite);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests of SMB2 maperror");
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 04e361ed2356..c43ca74e8704 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -3989,24 +3989,6 @@ int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
NULL);
}
-#if 0
-/* currently unused, as now we are doing compounding instead (see smb311_posix_query_path_info) */
-int
-SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb311_posix_qinfo *data, u32 *plen)
-{
- size_t output_len = sizeof(struct smb311_posix_qinfo *) +
- (sizeof(struct smb_sid) * 2) + (PATH_MAX * 2);
- *plen = 0;
-
- return query_info(xid, tcon, persistent_fid, volatile_fid,
- SMB_FIND_FILE_POSIX_INFO, SMB2_O_INFO_FILE, 0,
- output_len, sizeof(struct smb311_posix_qinfo), (void **)&data, plen);
- /* Note caller must free "data" (passed in above). It may be allocated in query_info call */
-}
-#endif
-
int
SMB2_query_acl(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
diff --git a/fs/smb/client/smb2pdu.h b/fs/smb/client/smb2pdu.h
index 78bb99f29d38..30d70097fe2f 100644
--- a/fs/smb/client/smb2pdu.h
+++ b/fs/smb/client/smb2pdu.h
@@ -224,7 +224,7 @@ struct smb2_file_reparse_point_info {
__le32 Tag;
} __packed;
-/* See MS-FSCC 2.4.21 */
+/* See MS-FSCC 2.4.26 */
struct smb2_file_id_information {
__le64 VolumeSerialNumber;
__u64 PersistentFileId; /* opaque endianness */
@@ -251,7 +251,10 @@ struct smb2_file_id_extd_directory_info {
extern char smb2_padding[7];
-/* equivalent of the contents of SMB3.1.1 POSIX open context response */
+/*
+ * See POSIX-SMB2 2.2.14.2.16
+ * Link: https://gitlab.com/samba-team/smb3-posix-spec/-/blob/master/smb3_posix_extensions.md
+ */
struct create_posix_rsp {
u32 nlink;
u32 reparse_tag;
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 881e42cf66ce..230bb1e9f4e1 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -167,9 +167,6 @@ int SMB2_flush_init(const unsigned int xid, struct smb_rqst *rqst,
struct cifs_tcon *tcon, struct TCP_Server_Info *server,
u64 persistent_fid, u64 volatile_fid);
void SMB2_flush_free(struct smb_rqst *rqst);
-int SMB311_posix_query_info(const unsigned int xid, struct cifs_tcon *tcon,
- u64 persistent_fid, u64 volatile_fid,
- struct smb311_posix_qinfo *data, u32 *plen);
int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
u64 persistent_fid, u64 volatile_fid,
struct smb2_file_all_info *data);
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 8b9000a83181..81be2b226e26 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -20,6 +20,7 @@
#include <linux/highmem.h>
#include <crypto/aead.h>
#include <crypto/sha2.h>
+#include <crypto/utils.h>
#include "cifsglob.h"
#include "cifsproto.h"
#include "smb2proto.h"
@@ -617,7 +618,8 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
if (rc)
return rc;
- if (memcmp(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE)) {
+ if (crypto_memneq(server_response_sig, shdr->Signature,
+ SMB2_SIGNATURE_SIZE)) {
cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n",
shdr->Command, shdr->MessageId);
return -EACCES;
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 9228f95cae2b..acfbb63086ea 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -176,6 +176,7 @@
EM(netfs_trace_tcon_ref_get_cached_laundromat, "GET Ch-Lau") \
EM(netfs_trace_tcon_ref_get_cached_lease_break, "GET Ch-Lea") \
EM(netfs_trace_tcon_ref_get_cancelled_close, "GET Cn-Cls") \
+ EM(netfs_trace_tcon_ref_get_close_defer_files, "GET Cl-Def") \
EM(netfs_trace_tcon_ref_get_dfs_refer, "GET DfsRef") \
EM(netfs_trace_tcon_ref_get_find, "GET Find ") \
EM(netfs_trace_tcon_ref_get_find_sess_tcon, "GET FndSes") \
@@ -187,6 +188,7 @@
EM(netfs_trace_tcon_ref_put_cancelled_close, "PUT Cn-Cls") \
EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \
EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \
+ EM(netfs_trace_tcon_ref_put_close_defer_files, "PUT Cl-Def") \
EM(netfs_trace_tcon_ref_put_mnt_ctx, "PUT MntCtx") \
EM(netfs_trace_tcon_ref_put_dfs_refer, "PUT DfsRfr") \
EM(netfs_trace_tcon_ref_put_reconnect_server, "PUT Reconn") \
diff --git a/fs/smb/server/smb2pdu.h b/fs/smb/server/smb2pdu.h
index 257c6d26df26..8b6eafb70dca 100644
--- a/fs/smb/server/smb2pdu.h
+++ b/fs/smb/server/smb2pdu.h
@@ -83,7 +83,10 @@ struct create_durable_rsp {
} Data;
} __packed;
-/* equivalent of the contents of SMB3.1.1 POSIX open context response */
+/*
+ * See POSIX-SMB2 2.2.14.2.16
+ * Link: https://gitlab.com/samba-team/smb3-posix-spec/-/blob/master/smb3_posix_extensions.md
+ */
struct create_posix_rsp {
struct create_context_hdr ccontext;
__u8 Name[16];
diff --git a/fs/verity/Kconfig b/fs/verity/Kconfig
index 76d1c5971b82..b20882963ffb 100644
--- a/fs/verity/Kconfig
+++ b/fs/verity/Kconfig
@@ -2,6 +2,9 @@
config FS_VERITY
bool "FS Verity (read-only file-based authenticity protection)"
+ # Filesystems cache the Merkle tree at a 64K aligned offset in the
+ # pagecache. That approach assumes the page size is at most 64K.
+ depends on PAGE_SHIFT <= 16
select CRYPTO_HASH_INFO
select CRYPTO_LIB_SHA256
select CRYPTO_LIB_SHA512
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index eeb070f330bd..1e1580febe4b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -848,12 +848,14 @@
/* Required sections not related to debugging. */
#define ELF_DETAILS \
- .modinfo : { *(.modinfo) . = ALIGN(8); } \
.comment 0 : { *(.comment) } \
.symtab 0 : { *(.symtab) } \
.strtab 0 : { *(.strtab) } \
.shstrtab 0 : { *(.shstrtab) }
+#define MODINFO \
+ .modinfo : { *(.modinfo) . = ALIGN(8); }
+
#ifdef CONFIG_GENERIC_BUG
#define BUG_TABLE \
. = ALIGN(8); \
diff --git a/include/drm/display/drm_dp.h b/include/drm/display/drm_dp.h
index e4eebabab975..8b15d3eeb716 100644
--- a/include/drm/display/drm_dp.h
+++ b/include/drm/display/drm_dp.h
@@ -571,6 +571,8 @@
# define DP_PANEL_REPLAY_LINK_OFF_SUPPORTED_IN_PR_AFTER_ADAPTIVE_SYNC_SDP (1 << 7)
#define DP_PANEL_REPLAY_CAP_X_GRANULARITY 0xb2
+# define DP_PANEL_REPLAY_FULL_LINE_GRANULARITY 0xffff
+
#define DP_PANEL_REPLAY_CAP_Y_GRANULARITY 0xb4
/* Link Configuration */
diff --git a/include/kunit/run-in-irq-context.h b/include/kunit/run-in-irq-context.h
index c89b1b1b12dd..bfe60d6cf28d 100644
--- a/include/kunit/run-in-irq-context.h
+++ b/include/kunit/run-in-irq-context.h
@@ -12,16 +12,16 @@
#include <linux/hrtimer.h>
#include <linux/workqueue.h>
-#define KUNIT_IRQ_TEST_HRTIMER_INTERVAL us_to_ktime(5)
-
struct kunit_irq_test_state {
bool (*func)(void *test_specific_state);
void *test_specific_state;
bool task_func_reported_failure;
bool hardirq_func_reported_failure;
bool softirq_func_reported_failure;
+ atomic_t task_func_calls;
atomic_t hardirq_func_calls;
atomic_t softirq_func_calls;
+ ktime_t interval;
struct hrtimer timer;
struct work_struct bh_work;
};
@@ -30,14 +30,25 @@ static enum hrtimer_restart kunit_irq_test_timer_func(struct hrtimer *timer)
{
struct kunit_irq_test_state *state =
container_of(timer, typeof(*state), timer);
+ int task_calls, hardirq_calls, softirq_calls;
WARN_ON_ONCE(!in_hardirq());
- atomic_inc(&state->hardirq_func_calls);
+ task_calls = atomic_read(&state->task_func_calls);
+ hardirq_calls = atomic_inc_return(&state->hardirq_func_calls);
+ softirq_calls = atomic_read(&state->softirq_func_calls);
+
+ /*
+ * If the timer is firing too often for the softirq or task to ever have
+ * a chance to run, increase the timer interval. This is needed on very
+ * slow systems.
+ */
+ if (hardirq_calls >= 20 && (softirq_calls == 0 || task_calls == 0))
+ state->interval = ktime_add_ns(state->interval, 250);
if (!state->func(state->test_specific_state))
state->hardirq_func_reported_failure = true;
- hrtimer_forward_now(&state->timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL);
+ hrtimer_forward_now(&state->timer, state->interval);
queue_work(system_bh_wq, &state->bh_work);
return HRTIMER_RESTART;
}
@@ -86,10 +97,14 @@ static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *),
struct kunit_irq_test_state state = {
.func = func,
.test_specific_state = test_specific_state,
+ /*
+ * Start with a 5us timer interval. If the system can't keep
+ * up, kunit_irq_test_timer_func() will increase it.
+ */
+ .interval = us_to_ktime(5),
};
unsigned long end_jiffies;
- int hardirq_calls, softirq_calls;
- bool allctx = false;
+ int task_calls, hardirq_calls, softirq_calls;
/*
* Set up a hrtimer (the way we access hardirq context) and a work
@@ -104,21 +119,18 @@ static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *),
* and hardirq), or 1 second, whichever comes first.
*/
end_jiffies = jiffies + HZ;
- hrtimer_start(&state.timer, KUNIT_IRQ_TEST_HRTIMER_INTERVAL,
- HRTIMER_MODE_REL_HARD);
- for (int task_calls = 0, calls = 0;
- ((calls < max_iterations) || !allctx) &&
- !time_after(jiffies, end_jiffies);
- task_calls++) {
+ hrtimer_start(&state.timer, state.interval, HRTIMER_MODE_REL_HARD);
+ do {
if (!func(test_specific_state))
state.task_func_reported_failure = true;
+ task_calls = atomic_inc_return(&state.task_func_calls);
hardirq_calls = atomic_read(&state.hardirq_func_calls);
softirq_calls = atomic_read(&state.softirq_func_calls);
- calls = task_calls + hardirq_calls + softirq_calls;
- allctx = (task_calls > 0) && (hardirq_calls > 0) &&
- (softirq_calls > 0);
- }
+ } while ((task_calls + hardirq_calls + softirq_calls < max_iterations ||
+ (task_calls == 0 || hardirq_calls == 0 ||
+ softirq_calls == 0)) &&
+ !time_after(jiffies, end_jiffies));
/* Cancel the timer and work. */
hrtimer_cancel(&state.timer);
diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h
index 99c3c83ea520..63de5f053c33 100644
--- a/include/linux/device/bus.h
+++ b/include/linux/device/bus.h
@@ -35,6 +35,8 @@ struct fwnode_handle;
* otherwise. It may also return error code if determining that
* the driver supports the device is not possible. In case of
* -EPROBE_DEFER it will queue the device for deferred probing.
+ * Note: This callback may be invoked with or without the device
+ * lock held.
* @uevent: Called when a device is added, removed, or a few other things
* that generate uevents to add the environment variables.
* @probe: Called when a new device or driver add to this bus, and callback
diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h
index ccb478eb174b..ea9ca0e4172a 100644
--- a/include/linux/eventpoll.h
+++ b/include/linux/eventpoll.h
@@ -82,11 +82,14 @@ static inline struct epoll_event __user *
epoll_put_uevent(__poll_t revents, __u64 data,
struct epoll_event __user *uevent)
{
- if (__put_user(revents, &uevent->events) ||
- __put_user(data, &uevent->data))
- return NULL;
-
+ scoped_user_write_access_size(uevent, sizeof(*uevent), efault) {
+ unsafe_put_user(revents, &uevent->events, efault);
+ unsafe_put_user(data, &uevent->data, efault);
+ }
return uevent+1;
+
+efault:
+ return NULL;
}
#endif
diff --git a/include/linux/hid.h b/include/linux/hid.h
index dce862cafbbd..2990b9f94cb5 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -836,6 +836,12 @@ struct hid_usage_id {
* raw_event and event should return negative on error, any other value will
* pass the event on to .event() typically return 0 for success.
*
+ * report_fixup must return a report descriptor pointer whose lifetime is at
+ * least that of the input rdesc. This is usually done by mutating the input
+ * rdesc and returning it or a sub-portion of it. In case a new buffer is
+ * allocated and returned, the implementation of report_fixup is responsible for
+ * freeing it later.
+ *
* input_mapping shall return a negative value to completely ignore this usage
* (e.g. doubled or invalid usage), zero to continue with parsing of this
* usage by generic code (no special handling needed) or positive to skip
diff --git a/include/linux/indirect_call_wrapper.h b/include/linux/indirect_call_wrapper.h
index 35227d47cfc9..dc272b514a01 100644
--- a/include/linux/indirect_call_wrapper.h
+++ b/include/linux/indirect_call_wrapper.h
@@ -16,22 +16,26 @@
*/
#define INDIRECT_CALL_1(f, f1, ...) \
({ \
- likely(f == f1) ? f1(__VA_ARGS__) : f(__VA_ARGS__); \
+ typeof(f) __f1 = (f); \
+ likely(__f1 == f1) ? f1(__VA_ARGS__) : __f1(__VA_ARGS__); \
})
#define INDIRECT_CALL_2(f, f2, f1, ...) \
({ \
- likely(f == f2) ? f2(__VA_ARGS__) : \
- INDIRECT_CALL_1(f, f1, __VA_ARGS__); \
+ typeof(f) __f2 = (f); \
+ likely(__f2 == f2) ? f2(__VA_ARGS__) : \
+ INDIRECT_CALL_1(__f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALL_3(f, f3, f2, f1, ...) \
({ \
- likely(f == f3) ? f3(__VA_ARGS__) : \
- INDIRECT_CALL_2(f, f2, f1, __VA_ARGS__); \
+ typeof(f) __f3 = (f); \
+ likely(__f3 == f3) ? f3(__VA_ARGS__) : \
+ INDIRECT_CALL_2(__f3, f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALL_4(f, f4, f3, f2, f1, ...) \
({ \
- likely(f == f4) ? f4(__VA_ARGS__) : \
- INDIRECT_CALL_3(f, f3, f2, f1, __VA_ARGS__); \
+ typeof(f) __f4 = (f); \
+ likely(__f4 == f4) ? f4(__VA_ARGS__) : \
+ INDIRECT_CALL_3(__f4, f3, f2, f1, __VA_ARGS__); \
})
#define INDIRECT_CALLABLE_DECLARE(f) f
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index c92c1149ee6e..a01a474719a7 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -7,6 +7,24 @@
struct mm_struct;
+/* opaque kthread data */
+struct kthread;
+
+/*
+ * When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will
+ * always remain a kthread. For kthreads p->worker_private always
+ * points to a struct kthread. For tasks that are not kthreads
+ * p->worker_private is used to point to other things.
+ *
+ * Return NULL for any task that is not a kthread.
+ */
+static inline struct kthread *tsk_is_kthread(struct task_struct *p)
+{
+ if (p->flags & PF_KTHREAD)
+ return p->worker_private;
+ return NULL;
+}
+
__printf(4, 5)
struct task_struct *kthread_create_on_node(int (*threadfn)(void *data),
void *data,
@@ -98,9 +116,10 @@ void *kthread_probe_data(struct task_struct *k);
int kthread_park(struct task_struct *k);
void kthread_unpark(struct task_struct *k);
void kthread_parkme(void);
-void kthread_exit(long result) __noreturn;
+#define kthread_exit(result) do_exit(result)
void kthread_complete_and_exit(struct completion *, long) __noreturn;
int kthreads_update_housekeeping(void);
+void kthread_do_exit(struct kthread *, long);
int kthreadd(void *unused);
extern struct task_struct *kthreadd_task;
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index 26ca00c325d9..d5af2b7f577b 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -65,7 +65,7 @@ bool isolate_folio_to_list(struct folio *folio, struct list_head *list);
int migrate_huge_page_move_mapping(struct address_space *mapping,
struct folio *dst, struct folio *src);
-void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
+void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
__releases(ptl);
void folio_migrate_flags(struct folio *newfolio, struct folio *folio);
int folio_migrate_mapping(struct address_space *mapping,
@@ -97,6 +97,14 @@ static inline int set_movable_ops(const struct movable_operations *ops, enum pag
return -ENOSYS;
}
+static inline void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
+ __releases(ptl)
+{
+ WARN_ON_ONCE(1);
+
+ spin_unlock(ptl);
+}
+
#endif /* CONFIG_MIGRATION */
#ifdef CONFIG_NUMA_BALANCING
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d4e6e00bb90a..67e25f6d15a4 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -4711,7 +4711,7 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits)
static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu)
{
spin_lock(&txq->_xmit_lock);
- /* Pairs with READ_ONCE() in __dev_queue_xmit() */
+ /* Pairs with READ_ONCE() in netif_tx_owned() */
WRITE_ONCE(txq->xmit_lock_owner, cpu);
}
@@ -4729,7 +4729,7 @@ static inline void __netif_tx_release(struct netdev_queue *txq)
static inline void __netif_tx_lock_bh(struct netdev_queue *txq)
{
spin_lock_bh(&txq->_xmit_lock);
- /* Pairs with READ_ONCE() in __dev_queue_xmit() */
+ /* Pairs with READ_ONCE() in netif_tx_owned() */
WRITE_ONCE(txq->xmit_lock_owner, smp_processor_id());
}
@@ -4738,7 +4738,7 @@ static inline bool __netif_tx_trylock(struct netdev_queue *txq)
bool ok = spin_trylock(&txq->_xmit_lock);
if (likely(ok)) {
- /* Pairs with READ_ONCE() in __dev_queue_xmit() */
+ /* Pairs with READ_ONCE() in netif_tx_owned() */
WRITE_ONCE(txq->xmit_lock_owner, smp_processor_id());
}
return ok;
@@ -4746,14 +4746,14 @@ static inline bool __netif_tx_trylock(struct netdev_queue *txq)
static inline void __netif_tx_unlock(struct netdev_queue *txq)
{
- /* Pairs with READ_ONCE() in __dev_queue_xmit() */
+ /* Pairs with READ_ONCE() in netif_tx_owned() */
WRITE_ONCE(txq->xmit_lock_owner, -1);
spin_unlock(&txq->_xmit_lock);
}
static inline void __netif_tx_unlock_bh(struct netdev_queue *txq)
{
- /* Pairs with READ_ONCE() in __dev_queue_xmit() */
+ /* Pairs with READ_ONCE() in netif_tx_owned() */
WRITE_ONCE(txq->xmit_lock_owner, -1);
spin_unlock_bh(&txq->_xmit_lock);
}
@@ -4846,6 +4846,23 @@ static inline void netif_tx_disable(struct net_device *dev)
local_bh_enable();
}
+#ifndef CONFIG_PREEMPT_RT
+static inline bool netif_tx_owned(struct netdev_queue *txq, unsigned int cpu)
+{
+ /* Other cpus might concurrently change txq->xmit_lock_owner
+ * to -1 or to their cpu id, but not to our id.
+ */
+ return READ_ONCE(txq->xmit_lock_owner) == cpu;
+}
+
+#else
+static inline bool netif_tx_owned(struct netdev_queue *txq, unsigned int cpu)
+{
+ return rt_mutex_owner(&txq->_xmit_lock.lock) == current;
+}
+
+#endif
+
static inline void netif_addr_lock(struct net_device *dev)
{
unsigned char nest_level = 0;
diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h
index 825f5865bfc5..c8e227a3f9e2 100644
--- a/include/linux/ns_common.h
+++ b/include/linux/ns_common.h
@@ -55,6 +55,8 @@ static __always_inline bool is_ns_init_id(const struct ns_common *ns)
#define ns_common_free(__ns) __ns_common_free(to_ns_common((__ns)))
+bool may_see_all_namespaces(void);
+
static __always_inline __must_check int __ns_ref_active_read(const struct ns_common *ns)
{
return atomic_read(&ns->__ns_ref_active);
diff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h
index f6cca7a035c7..50b6be57da66 100644
--- a/include/linux/platform_data/mlxreg.h
+++ b/include/linux/platform_data/mlxreg.h
@@ -13,10 +13,10 @@
/**
* enum mlxreg_wdt_type - type of HW watchdog
*
- * TYPE1 HW watchdog implementation exist in old systems.
- * All new systems have TYPE2 HW watchdog.
- * TYPE3 HW watchdog can exist on all systems with new CPLD.
- * TYPE3 is selected by WD capability bit.
+ * @MLX_WDT_TYPE1: HW watchdog implementation in old systems.
+ * @MLX_WDT_TYPE2: All new systems have TYPE2 HW watchdog.
+ * @MLX_WDT_TYPE3: HW watchdog that can exist on all systems with new CPLD.
+ * TYPE3 is selected by WD capability bit.
*/
enum mlxreg_wdt_type {
MLX_WDT_TYPE1,
@@ -35,7 +35,7 @@ enum mlxreg_wdt_type {
* @MLXREG_HOTPLUG_LC_SYNCED: entry for line card synchronization events, coming
* after hardware-firmware synchronization handshake;
* @MLXREG_HOTPLUG_LC_READY: entry for line card ready events, indicating line card
- PHYs ready / unready state;
+ * PHYs ready / unready state;
* @MLXREG_HOTPLUG_LC_ACTIVE: entry for line card active events, indicating firmware
* availability / unavailability for the ports on line card;
* @MLXREG_HOTPLUG_LC_THERMAL: entry for line card thermal shutdown events, positive
@@ -123,8 +123,8 @@ struct mlxreg_hotplug_device {
* @reg_pwr: attribute power register;
* @reg_ena: attribute enable register;
* @mode: access mode;
- * @np - pointer to node platform associated with attribute;
- * @hpdev - hotplug device data;
+ * @np: pointer to node platform associated with attribute;
+ * @hpdev: hotplug device data;
* @notifier: pointer to event notifier block;
* @health_cntr: dynamic device health indication counter;
* @attached: true if device has been attached after good health indication;
diff --git a/include/linux/platform_data/x86/int3472.h b/include/linux/platform_data/x86/int3472.h
index b1b837583d54..dbe745dc88d5 100644
--- a/include/linux/platform_data/x86/int3472.h
+++ b/include/linux/platform_data/x86/int3472.h
@@ -26,6 +26,7 @@
#define INT3472_GPIO_TYPE_POWER_ENABLE 0x0b
#define INT3472_GPIO_TYPE_CLK_ENABLE 0x0c
#define INT3472_GPIO_TYPE_PRIVACY_LED 0x0d
+#define INT3472_GPIO_TYPE_DOVDD 0x10
#define INT3472_GPIO_TYPE_HANDSHAKE 0x12
#define INT3472_GPIO_TYPE_HOTPLUG_DETECT 0x13
@@ -33,8 +34,8 @@
#define INT3472_MAX_SENSOR_GPIOS 3
#define INT3472_MAX_REGULATORS 3
-/* E.g. "avdd\0" */
-#define GPIO_SUPPLY_NAME_LENGTH 5
+/* E.g. "dovdd\0" */
+#define GPIO_SUPPLY_NAME_LENGTH 6
/* 12 chars for acpi_dev_name() + "-", e.g. "ABCD1234:00-" */
#define GPIO_REGULATOR_NAME_LENGTH (12 + GPIO_SUPPLY_NAME_LENGTH)
/* lower- and upper-case mapping */
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h
index 876358cfe1b1..d862fa610270 100644
--- a/include/linux/ring_buffer.h
+++ b/include/linux/ring_buffer.h
@@ -248,6 +248,7 @@ int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node);
int ring_buffer_map(struct trace_buffer *buffer, int cpu,
struct vm_area_struct *vma);
+void ring_buffer_map_dup(struct trace_buffer *buffer, int cpu);
int ring_buffer_unmap(struct trace_buffer *buffer, int cpu);
int ring_buffer_map_get_reader(struct trace_buffer *buffer, int cpu);
#endif /* _LINUX_RING_BUFFER_H */
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 1f3804245c06..809e4f7dfdbd 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -647,36 +647,22 @@ static inline void user_access_restore(unsigned long flags) { }
/* Define RW variant so the below _mode macro expansion works */
#define masked_user_rw_access_begin(u) masked_user_access_begin(u)
#define user_rw_access_begin(u, s) user_access_begin(u, s)
-#define user_rw_access_end() user_access_end()
/* Scoped user access */
-#define USER_ACCESS_GUARD(_mode) \
-static __always_inline void __user * \
-class_user_##_mode##_begin(void __user *ptr) \
-{ \
- return ptr; \
-} \
- \
-static __always_inline void \
-class_user_##_mode##_end(void __user *ptr) \
-{ \
- user_##_mode##_access_end(); \
-} \
- \
-DEFINE_CLASS(user_ ##_mode## _access, void __user *, \
- class_user_##_mode##_end(_T), \
- class_user_##_mode##_begin(ptr), void __user *ptr) \
- \
-static __always_inline class_user_##_mode##_access_t \
-class_user_##_mode##_access_ptr(void __user *scope) \
-{ \
- return scope; \
-}
-USER_ACCESS_GUARD(read)
-USER_ACCESS_GUARD(write)
-USER_ACCESS_GUARD(rw)
-#undef USER_ACCESS_GUARD
+/* Cleanup wrapper functions */
+static __always_inline void __scoped_user_read_access_end(const void *p)
+{
+ user_read_access_end();
+};
+static __always_inline void __scoped_user_write_access_end(const void *p)
+{
+ user_write_access_end();
+};
+static __always_inline void __scoped_user_rw_access_end(const void *p)
+{
+ user_access_end();
+};
/**
* __scoped_user_access_begin - Start a scoped user access
@@ -750,13 +736,13 @@ USER_ACCESS_GUARD(rw)
*
* Don't use directly. Use scoped_masked_user_$MODE_access() instead.
*/
-#define __scoped_user_access(mode, uptr, size, elbl) \
-for (bool done = false; !done; done = true) \
- for (void __user *_tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \
- !done; done = true) \
- for (CLASS(user_##mode##_access, scope)(_tmpptr); !done; done = true) \
- /* Force modified pointer usage within the scope */ \
- for (const typeof(uptr) uptr = _tmpptr; !done; done = true)
+#define __scoped_user_access(mode, uptr, size, elbl) \
+for (bool done = false; !done; done = true) \
+ for (auto _tmpptr = __scoped_user_access_begin(mode, uptr, size, elbl); \
+ !done; done = true) \
+ /* Force modified pointer usage within the scope */ \
+ for (const auto uptr __cleanup(__scoped_user_##mode##_access_end) = \
+ _tmpptr; !done; done = true)
/**
* scoped_user_read_access_size - Start a scoped user read access with given size
diff --git a/include/linux/usb/r8152.h b/include/linux/usb/r8152.h
index 2ca60828f28b..1502b2a355f9 100644
--- a/include/linux/usb/r8152.h
+++ b/include/linux/usb/r8152.h
@@ -32,6 +32,7 @@
#define VENDOR_ID_DLINK 0x2001
#define VENDOR_ID_DELL 0x413c
#define VENDOR_ID_ASUS 0x0b05
+#define VENDOR_ID_TRENDNET 0x20f4
#if IS_REACHABLE(CONFIG_USB_RTL8152)
extern u8 rtl8152_get_version(struct usb_interface *intf);
diff --git a/include/net/act_api.h b/include/net/act_api.h
index e1e8f0f7dacb..d11b79107930 100644
--- a/include/net/act_api.h
+++ b/include/net/act_api.h
@@ -70,6 +70,7 @@ struct tc_action {
#define TCA_ACT_FLAGS_REPLACE (1U << (TCA_ACT_FLAGS_USER_BITS + 2))
#define TCA_ACT_FLAGS_NO_RTNL (1U << (TCA_ACT_FLAGS_USER_BITS + 3))
#define TCA_ACT_FLAGS_AT_INGRESS (1U << (TCA_ACT_FLAGS_USER_BITS + 4))
+#define TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT (1U << (TCA_ACT_FLAGS_USER_BITS + 5))
/* Update lastuse only if needed, to avoid dirtying a cache line.
* We use a temp variable to avoid fetching jiffies twice.
diff --git a/include/net/bonding.h b/include/net/bonding.h
index 4ad5521e7731..395c6e281c5f 100644
--- a/include/net/bonding.h
+++ b/include/net/bonding.h
@@ -699,6 +699,7 @@ void bond_debug_register(struct bonding *bond);
void bond_debug_unregister(struct bonding *bond);
void bond_debug_reregister(struct bonding *bond);
const char *bond_mode_name(int mode);
+bool __bond_xdp_check(int mode, int xmit_policy);
bool bond_xdp_check(struct bonding *bond, int mode);
void bond_setup(struct net_device *bond_dev);
unsigned int bond_get_num_tx_queues(void);
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index 282e29237d93..c16de5b7963f 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -175,7 +175,7 @@ static inline bool inet6_match(const struct net *net, const struct sock *sk,
{
if (!net_eq(sock_net(sk), net) ||
sk->sk_family != AF_INET6 ||
- sk->sk_portpair != ports ||
+ READ_ONCE(sk->sk_portpair) != ports ||
!ipv6_addr_equal(&sk->sk_v6_daddr, saddr) ||
!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
return false;
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index ac05a52d9e13..5a979dcab538 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -345,7 +345,7 @@ static inline bool inet_match(const struct net *net, const struct sock *sk,
int dif, int sdif)
{
if (!net_eq(sock_net(sk), net) ||
- sk->sk_portpair != ports ||
+ READ_ONCE(sk->sk_portpair) != ports ||
sk->sk_addrpair != cookie)
return false;
diff --git a/include/net/ip.h b/include/net/ip.h
index 69d5cef46004..7f9abd457e01 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -101,7 +101,7 @@ static inline void ipcm_init_sk(struct ipcm_cookie *ipcm,
ipcm->oif = READ_ONCE(inet->sk.sk_bound_dev_if);
ipcm->addr = inet->inet_saddr;
- ipcm->protocol = inet->inet_num;
+ ipcm->protocol = READ_ONCE(inet->inet_num);
}
#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb))
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index b4495c38e0a0..318593743b6e 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -559,7 +559,7 @@ static inline u32 fib_multipath_hash_from_keys(const struct net *net,
siphash_aligned_key_t hash_key;
u32 mp_seed;
- mp_seed = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed).mp_seed;
+ mp_seed = READ_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed.mp_seed);
fib_multipath_hash_construct_key(&hash_key, mp_seed);
return flow_hash_from_keys_seed(keys, &hash_key);
diff --git a/include/net/libeth/xsk.h b/include/net/libeth/xsk.h
index 481a7b28e6f2..82b5d21aae87 100644
--- a/include/net/libeth/xsk.h
+++ b/include/net/libeth/xsk.h
@@ -597,6 +597,7 @@ __libeth_xsk_run_pass(struct libeth_xdp_buff *xdp,
* @pending: current number of XSkFQEs to refill
* @thresh: threshold below which the queue is refilled
* @buf_len: HW-writeable length per each buffer
+ * @truesize: step between consecutive buffers, 0 if none exists
* @nid: ID of the closest NUMA node with memory
*/
struct libeth_xskfq {
@@ -614,6 +615,8 @@ struct libeth_xskfq {
u32 thresh;
u32 buf_len;
+ u32 truesize;
+
int nid;
};
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 426534a711b0..e2d2bfc1f989 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -320,11 +320,13 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
* @NFT_ITER_UNSPEC: unspecified, to catch errors
* @NFT_ITER_READ: read-only iteration over set elements
* @NFT_ITER_UPDATE: iteration under mutex to update set element state
+ * @NFT_ITER_UPDATE_CLONE: clone set before iteration under mutex to update element
*/
enum nft_iter_type {
NFT_ITER_UNSPEC,
NFT_ITER_READ,
NFT_ITER_UPDATE,
+ NFT_ITER_UPDATE_CLONE,
};
struct nft_set;
@@ -1861,6 +1863,11 @@ struct nft_trans_gc {
struct rcu_head rcu;
};
+static inline int nft_trans_gc_space(const struct nft_trans_gc *trans)
+{
+ return NFT_TRANS_GC_BATCHCOUNT - trans->count;
+}
+
static inline void nft_ctx_update(struct nft_ctx *ctx,
const struct nft_trans *trans)
{
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index c3a7268b567e..d5d55cb21686 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -778,13 +778,23 @@ static inline bool skb_skip_tc_classify(struct sk_buff *skb)
static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i)
{
struct Qdisc *qdisc;
+ bool nolock;
for (; i < dev->num_tx_queues; i++) {
qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc);
if (qdisc) {
+ nolock = qdisc->flags & TCQ_F_NOLOCK;
+
+ if (nolock)
+ spin_lock_bh(&qdisc->seqlock);
spin_lock_bh(qdisc_lock(qdisc));
qdisc_reset(qdisc);
spin_unlock_bh(qdisc_lock(qdisc));
+ if (nolock) {
+ clear_bit(__QDISC_STATE_MISSED, &qdisc->state);
+ clear_bit(__QDISC_STATE_DRAINING, &qdisc->state);
+ spin_unlock_bh(&qdisc->seqlock);
+ }
}
}
}
diff --git a/include/net/secure_seq.h b/include/net/secure_seq.h
index cddebafb9f77..6f996229167b 100644
--- a/include/net/secure_seq.h
+++ b/include/net/secure_seq.h
@@ -5,16 +5,47 @@
#include <linux/types.h>
struct net;
+extern struct net init_net;
+
+union tcp_seq_and_ts_off {
+ struct {
+ u32 seq;
+ u32 ts_off;
+ };
+ u64 hash64;
+};
u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
__be16 dport);
-u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport);
-u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr);
-u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
- __be16 sport, __be16 dport);
-u32 secure_tcpv6_ts_off(const struct net *net,
- const __be32 *saddr, const __be32 *daddr);
+union tcp_seq_and_ts_off
+secure_tcp_seq_and_ts_off(const struct net *net, __be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport);
+
+static inline u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport)
+{
+ union tcp_seq_and_ts_off ts;
+
+ ts = secure_tcp_seq_and_ts_off(&init_net, saddr, daddr,
+ sport, dport);
+
+ return ts.seq;
+}
+
+union tcp_seq_and_ts_off
+secure_tcpv6_seq_and_ts_off(const struct net *net, const __be32 *saddr,
+ const __be32 *daddr,
+ __be16 sport, __be16 dport);
+
+static inline u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
+ __be16 sport, __be16 dport)
+{
+ union tcp_seq_and_ts_off ts;
+
+ ts = secure_tcpv6_seq_and_ts_off(&init_net, saddr, daddr,
+ sport, dport);
+ return ts.seq;
+}
#endif /* _NET_SECURE_SEQ */
diff --git a/include/net/tc_act/tc_gate.h b/include/net/tc_act/tc_gate.h
index b147a3bb1a46..e0fded18e18c 100644
--- a/include/net/tc_act/tc_gate.h
+++ b/include/net/tc_act/tc_gate.h
@@ -32,6 +32,7 @@ struct tcf_gate_params {
s32 tcfg_clockid;
size_t num_entries;
struct list_head entries;
+ struct rcu_head rcu;
};
#define GATE_ACT_GATE_OPEN BIT(0)
@@ -39,7 +40,7 @@ struct tcf_gate_params {
struct tcf_gate {
struct tc_action common;
- struct tcf_gate_params param;
+ struct tcf_gate_params __rcu *param;
u8 current_gate_status;
ktime_t current_close_time;
u32 current_entry_octets;
@@ -51,47 +52,65 @@ struct tcf_gate {
#define to_gate(a) ((struct tcf_gate *)a)
+static inline struct tcf_gate_params *tcf_gate_params_locked(const struct tc_action *a)
+{
+ struct tcf_gate *gact = to_gate(a);
+
+ return rcu_dereference_protected(gact->param,
+ lockdep_is_held(&gact->tcf_lock));
+}
+
static inline s32 tcf_gate_prio(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
s32 tcfg_prio;
- tcfg_prio = to_gate(a)->param.tcfg_priority;
+ p = tcf_gate_params_locked(a);
+ tcfg_prio = p->tcfg_priority;
return tcfg_prio;
}
static inline u64 tcf_gate_basetime(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_basetime;
- tcfg_basetime = to_gate(a)->param.tcfg_basetime;
+ p = tcf_gate_params_locked(a);
+ tcfg_basetime = p->tcfg_basetime;
return tcfg_basetime;
}
static inline u64 tcf_gate_cycletime(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_cycletime;
- tcfg_cycletime = to_gate(a)->param.tcfg_cycletime;
+ p = tcf_gate_params_locked(a);
+ tcfg_cycletime = p->tcfg_cycletime;
return tcfg_cycletime;
}
static inline u64 tcf_gate_cycletimeext(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u64 tcfg_cycletimeext;
- tcfg_cycletimeext = to_gate(a)->param.tcfg_cycletime_ext;
+ p = tcf_gate_params_locked(a);
+ tcfg_cycletimeext = p->tcfg_cycletime_ext;
return tcfg_cycletimeext;
}
static inline u32 tcf_gate_num_entries(const struct tc_action *a)
{
+ struct tcf_gate_params *p;
u32 num_entries;
- num_entries = to_gate(a)->param.num_entries;
+ p = tcf_gate_params_locked(a);
+ num_entries = p->num_entries;
return num_entries;
}
@@ -105,7 +124,7 @@ static inline struct action_gate_entry
u32 num_entries;
int i = 0;
- p = &to_gate(a)->param;
+ p = tcf_gate_params_locked(a);
num_entries = p->num_entries;
list_for_each_entry(entry, &p->entries, list)
diff --git a/include/net/tc_act/tc_ife.h b/include/net/tc_act/tc_ife.h
index c7f24a2da1ca..24d4d5a62b3c 100644
--- a/include/net/tc_act/tc_ife.h
+++ b/include/net/tc_act/tc_ife.h
@@ -13,15 +13,13 @@ struct tcf_ife_params {
u8 eth_src[ETH_ALEN];
u16 eth_type;
u16 flags;
-
+ struct list_head metalist;
struct rcu_head rcu;
};
struct tcf_ife_info {
struct tc_action common;
struct tcf_ife_params __rcu *params;
- /* list of metaids allowed */
- struct list_head metalist;
};
#define to_ife(a) ((struct tcf_ife_info *)a)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index eb8bf63fdafc..978eea2d5df0 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -43,6 +43,7 @@
#include <net/dst.h>
#include <net/mptcp.h>
#include <net/xfrm.h>
+#include <net/secure_seq.h>
#include <linux/seq_file.h>
#include <linux/memcontrol.h>
@@ -2464,8 +2465,9 @@ struct tcp_request_sock_ops {
struct flowi *fl,
struct request_sock *req,
u32 tw_isn);
- u32 (*init_seq)(const struct sk_buff *skb);
- u32 (*init_ts_off)(const struct net *net, const struct sk_buff *skb);
+ union tcp_seq_and_ts_off (*init_seq_and_ts_off)(
+ const struct net *net,
+ const struct sk_buff *skb);
int (*send_synack)(const struct sock *sk, struct dst_entry *dst,
struct flowi *fl, struct request_sock *req,
struct tcp_fastopen_cookie *foc,
diff --git a/include/net/xdp_sock_drv.h b/include/net/xdp_sock_drv.h
index 242e34f771cc..6b9ebae2dc95 100644
--- a/include/net/xdp_sock_drv.h
+++ b/include/net/xdp_sock_drv.h
@@ -51,6 +51,11 @@ static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
return xsk_pool_get_chunk_size(pool) - xsk_pool_get_headroom(pool);
}
+static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool)
+{
+ return pool->unaligned ? 0 : xsk_pool_get_chunk_size(pool);
+}
+
static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool,
struct xdp_rxq_info *rxq)
{
@@ -122,7 +127,7 @@ static inline void xsk_buff_free(struct xdp_buff *xdp)
goto out;
list_for_each_entry_safe(pos, tmp, xskb_list, list_node) {
- list_del(&pos->list_node);
+ list_del_init(&pos->list_node);
xp_free(pos);
}
@@ -157,7 +162,7 @@ static inline struct xdp_buff *xsk_buff_get_frag(const struct xdp_buff *first)
frag = list_first_entry_or_null(&xskb->pool->xskb_list,
struct xdp_buff_xsk, list_node);
if (frag) {
- list_del(&frag->list_node);
+ list_del_init(&frag->list_node);
ret = &frag->xdp;
}
@@ -168,7 +173,7 @@ static inline void xsk_buff_del_frag(struct xdp_buff *xdp)
{
struct xdp_buff_xsk *xskb = container_of(xdp, struct xdp_buff_xsk, xdp);
- list_del(&xskb->list_node);
+ list_del_init(&xskb->list_node);
}
static inline struct xdp_buff *xsk_buff_get_head(struct xdp_buff *first)
@@ -337,6 +342,11 @@ static inline u32 xsk_pool_get_rx_frame_size(struct xsk_buff_pool *pool)
return 0;
}
+static inline u32 xsk_pool_get_rx_frag_step(struct xsk_buff_pool *pool)
+{
+ return 0;
+}
+
static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool,
struct xdp_rxq_info *rxq)
{
diff --git a/include/sound/cs35l56.h b/include/sound/cs35l56.h
index ae1e1489b671..28f9f5940ab6 100644
--- a/include/sound/cs35l56.h
+++ b/include/sound/cs35l56.h
@@ -406,6 +406,7 @@ extern const char * const cs35l56_cal_set_status_text[3];
extern const char * const cs35l56_tx_input_texts[CS35L56_NUM_INPUT_SRC];
extern const unsigned int cs35l56_tx_input_values[CS35L56_NUM_INPUT_SRC];
+int cs35l56_set_asp_patch(struct cs35l56_base *cs35l56_base);
int cs35l56_set_patch(struct cs35l56_base *cs35l56_base);
int cs35l56_mbox_send(struct cs35l56_base *cs35l56_base, unsigned int command);
int cs35l56_firmware_shutdown(struct cs35l56_base *cs35l56_base);
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index 7c03bdc951bb..e847cf51878c 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -151,6 +151,7 @@ struct tasdevice {
struct bulk_reg_val *cali_data_backup;
struct bulk_reg_val alp_cali_bckp;
struct tasdevice_fw *cali_data_fmw;
+ void *cali_specific;
unsigned int dev_addr;
unsigned int err_code;
unsigned char cur_book;
diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h
index 64a382fbc31a..2d366be46a1c 100644
--- a/include/trace/events/netfs.h
+++ b/include/trace/events/netfs.h
@@ -57,6 +57,7 @@
EM(netfs_rreq_trace_done, "DONE ") \
EM(netfs_rreq_trace_end_copy_to_cache, "END-C2C") \
EM(netfs_rreq_trace_free, "FREE ") \
+ EM(netfs_rreq_trace_intr, "INTR ") \
EM(netfs_rreq_trace_ki_complete, "KI-CMPL") \
EM(netfs_rreq_trace_recollect, "RECLLCT") \
EM(netfs_rreq_trace_redirty, "REDIRTY") \
@@ -169,7 +170,8 @@
EM(netfs_sreq_trace_put_oom, "PUT OOM ") \
EM(netfs_sreq_trace_put_wip, "PUT WIP ") \
EM(netfs_sreq_trace_put_work, "PUT WORK ") \
- E_(netfs_sreq_trace_put_terminated, "PUT TERM ")
+ EM(netfs_sreq_trace_put_terminated, "PUT TERM ") \
+ E_(netfs_sreq_trace_see_failed, "SEE FAILED ")
#define netfs_folio_traces \
EM(netfs_folio_is_uptodate, "mod-uptodate") \
diff --git a/include/uapi/linux/dma-buf.h b/include/uapi/linux/dma-buf.h
index 5a6fda66d9ad..e827c9d20c5d 100644
--- a/include/uapi/linux/dma-buf.h
+++ b/include/uapi/linux/dma-buf.h
@@ -20,6 +20,7 @@
#ifndef _DMA_BUF_UAPI_H_
#define _DMA_BUF_UAPI_H_
+#include <linux/ioctl.h>
#include <linux/types.h>
/**
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 6750c383a2ab..1ff16141c8a5 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -188,7 +188,8 @@ enum io_uring_sqe_flags_bit {
/*
* If COOP_TASKRUN is set, get notified if task work is available for
* running and a kernel transition would be needed to run it. This sets
- * IORING_SQ_TASKRUN in the sq ring flags. Not valid with COOP_TASKRUN.
+ * IORING_SQ_TASKRUN in the sq ring flags. Not valid without COOP_TASKRUN
+ * or DEFER_TASKRUN.
*/
#define IORING_SETUP_TASKRUN_FLAG (1U << 9)
#define IORING_SETUP_SQE128 (1U << 10) /* SQEs are 128 byte */
diff --git a/include/xen/xenbus.h b/include/xen/xenbus.h
index c94caf852aea..8ca15743af7f 100644
--- a/include/xen/xenbus.h
+++ b/include/xen/xenbus.h
@@ -80,6 +80,7 @@ struct xenbus_device {
const char *devicetype;
const char *nodename;
const char *otherend;
+ bool vanished;
int otherend_id;
struct xenbus_watch otherend_watch;
struct device dev;
@@ -228,7 +229,8 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr);
int xenbus_alloc_evtchn(struct xenbus_device *dev, evtchn_port_t *port);
int xenbus_free_evtchn(struct xenbus_device *dev, evtchn_port_t port);
-enum xenbus_state xenbus_read_driver_state(const char *path);
+enum xenbus_state xenbus_read_driver_state(const struct xenbus_device *dev,
+ const char *path);
__printf(3, 4)
void xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt, ...);
diff --git a/init/Kconfig b/init/Kconfig
index b55deae9256c..444ce811ea67 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1902,7 +1902,7 @@ config IO_URING_MOCK_FILE
default n
depends on IO_URING
help
- Enable mock files for io_uring subststem testing. The ABI might
+ Enable mock files for io_uring subsystem testing. The ABI might
still change, so it's still experimental and should only be enabled
for specific test purposes.
diff --git a/io_uring/net.c b/io_uring/net.c
index 8576c6cb2236..d27adbe3f20b 100644
--- a/io_uring/net.c
+++ b/io_uring/net.c
@@ -375,6 +375,8 @@ static int io_send_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe)
kmsg->msg.msg_namelen = addr_len;
}
if (sr->flags & IORING_RECVSEND_FIXED_BUF) {
+ if (sr->flags & IORING_SEND_VECTORIZED)
+ return -EINVAL;
req->flags |= REQ_F_IMPORT_BUFFER;
return 0;
}
diff --git a/io_uring/zcrx.c b/io_uring/zcrx.c
index cf5bec065aaf..62d693287457 100644
--- a/io_uring/zcrx.c
+++ b/io_uring/zcrx.c
@@ -837,7 +837,8 @@ int io_register_zcrx_ifq(struct io_ring_ctx *ctx,
if (ret)
goto netdev_put_unlock;
- mp_param.rx_page_size = 1U << ifq->niov_shift;
+ if (reg.rx_buf_len)
+ mp_param.rx_page_size = 1U << ifq->niov_shift;
mp_param.mp_ops = &io_uring_pp_zc_ops;
mp_param.mp_priv = ifq;
ret = __net_mp_open_rxq(ifq->netdev, reg.if_rxq, &mp_param, NULL);
@@ -926,11 +927,12 @@ static inline bool io_parse_rqe(struct io_uring_zcrx_rqe *rqe,
struct io_zcrx_ifq *ifq,
struct net_iov **ret_niov)
{
+ __u64 off = READ_ONCE(rqe->off);
unsigned niov_idx, area_idx;
struct io_zcrx_area *area;
- area_idx = rqe->off >> IORING_ZCRX_AREA_SHIFT;
- niov_idx = (rqe->off & ~IORING_ZCRX_AREA_MASK) >> ifq->niov_shift;
+ area_idx = off >> IORING_ZCRX_AREA_SHIFT;
+ niov_idx = (off & ~IORING_ZCRX_AREA_MASK) >> ifq->niov_shift;
if (unlikely(rqe->__pad || area_idx))
return false;
diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index 84db9e658e52..f02254a21585 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -1002,10 +1002,8 @@ int bpf_trampoline_link_cgroup_shim(struct bpf_prog *prog,
mutex_lock(&tr->mutex);
shim_link = cgroup_shim_find(tr, bpf_func);
- if (shim_link) {
+ if (shim_link && !IS_ERR(bpf_link_inc_not_zero(&shim_link->link.link))) {
/* Reusing existing shim attached by the other program. */
- bpf_link_inc(&shim_link->link.link);
-
mutex_unlock(&tr->mutex);
bpf_trampoline_put(tr); /* bpf_trampoline_get above */
return 0;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 401d6c4960ec..159b25f8269d 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2511,6 +2511,30 @@ static void __reg32_deduce_bounds(struct bpf_reg_state *reg)
if ((u32)reg->s32_min_value <= (u32)reg->s32_max_value) {
reg->u32_min_value = max_t(u32, reg->s32_min_value, reg->u32_min_value);
reg->u32_max_value = min_t(u32, reg->s32_max_value, reg->u32_max_value);
+ } else {
+ if (reg->u32_max_value < (u32)reg->s32_min_value) {
+ /* See __reg64_deduce_bounds() for detailed explanation.
+ * Refine ranges in the following situation:
+ *
+ * 0 U32_MAX
+ * | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] |
+ * |----------------------------|----------------------------|
+ * |xxxxx s32 range xxxxxxxxx] [xxxxxxx|
+ * 0 S32_MAX S32_MIN -1
+ */
+ reg->s32_min_value = (s32)reg->u32_min_value;
+ reg->u32_max_value = min_t(u32, reg->u32_max_value, reg->s32_max_value);
+ } else if ((u32)reg->s32_max_value < reg->u32_min_value) {
+ /*
+ * 0 U32_MAX
+ * | [xxxxxxxxxxxxxx u32 range xxxxxxxxxxxxxx] |
+ * |----------------------------|----------------------------|
+ * |xxxxxxxxx] [xxxxxxxxxxxx s32 range |
+ * 0 S32_MAX S32_MIN -1
+ */
+ reg->s32_max_value = (s32)reg->u32_max_value;
+ reg->u32_min_value = max_t(u32, reg->u32_min_value, reg->s32_min_value);
+ }
}
}
@@ -17335,17 +17359,24 @@ static void __collect_linked_regs(struct linked_regs *reg_set, struct bpf_reg_st
* in verifier state, save R in linked_regs if R->id == id.
* If there are too many Rs sharing same id, reset id for leftover Rs.
*/
-static void collect_linked_regs(struct bpf_verifier_state *vstate, u32 id,
+static void collect_linked_regs(struct bpf_verifier_env *env,
+ struct bpf_verifier_state *vstate,
+ u32 id,
struct linked_regs *linked_regs)
{
+ struct bpf_insn_aux_data *aux = env->insn_aux_data;
struct bpf_func_state *func;
struct bpf_reg_state *reg;
+ u16 live_regs;
int i, j;
id = id & ~BPF_ADD_CONST;
for (i = vstate->curframe; i >= 0; i--) {
+ live_regs = aux[frame_insn_idx(vstate, i)].live_regs_before;
func = vstate->frame[i];
for (j = 0; j < BPF_REG_FP; j++) {
+ if (!(live_regs & BIT(j)))
+ continue;
reg = &func->regs[j];
__collect_linked_regs(linked_regs, reg, id, i, j, true);
}
@@ -17560,9 +17591,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
* if parent state is created.
*/
if (BPF_SRC(insn->code) == BPF_X && src_reg->type == SCALAR_VALUE && src_reg->id)
- collect_linked_regs(this_branch, src_reg->id, &linked_regs);
+ collect_linked_regs(env, this_branch, src_reg->id, &linked_regs);
if (dst_reg->type == SCALAR_VALUE && dst_reg->id)
- collect_linked_regs(this_branch, dst_reg->id, &linked_regs);
+ collect_linked_regs(env, this_branch, dst_reg->id, &linked_regs);
if (linked_regs.cnt > 1) {
err = push_jmp_history(env, this_branch, 0, linked_regs_pack(&linked_regs));
if (err)
@@ -25261,7 +25292,6 @@ BTF_ID(func, __x64_sys_exit_group)
BTF_ID(func, do_exit)
BTF_ID(func, do_group_exit)
BTF_ID(func, kthread_complete_and_exit)
-BTF_ID(func, kthread_exit)
BTF_ID(func, make_task_dead)
BTF_SET_END(noreturn_deny)
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index c22cda7766d8..be1d71dda317 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -2608,6 +2608,7 @@ static void cgroup_migrate_add_task(struct task_struct *task,
mgctx->tset.nr_tasks++;
+ css_set_skip_task_iters(cset, task);
list_move_tail(&task->cg_list, &cset->mg_tasks);
if (list_empty(&cset->mg_node))
list_add_tail(&cset->mg_node,
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 9faf34377a88..e200de7c60b6 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -62,6 +62,75 @@ static const char * const perr_strings[] = {
};
/*
+ * CPUSET Locking Convention
+ * -------------------------
+ *
+ * Below are the four global/local locks guarding cpuset structures in lock
+ * acquisition order:
+ * - cpuset_top_mutex
+ * - cpu_hotplug_lock (cpus_read_lock/cpus_write_lock)
+ * - cpuset_mutex
+ * - callback_lock (raw spinlock)
+ *
+ * As cpuset will now indirectly flush a number of different workqueues in
+ * housekeeping_update() to update housekeeping cpumasks when the set of
+ * isolated CPUs is going to be changed, it may be vulnerable to deadlock
+ * if we hold cpus_read_lock while calling into housekeeping_update().
+ *
+ * The first cpuset_top_mutex will be held except when calling into
+ * cpuset_handle_hotplug() from the CPU hotplug code where cpus_write_lock
+ * and cpuset_mutex will be held instead. The main purpose of this mutex
+ * is to prevent regular cpuset control file write actions from interfering
+ * with the call to housekeeping_update(), though CPU hotplug operation can
+ * still happen in parallel. This mutex also provides protection for some
+ * internal variables.
+ *
+ * A task must hold all the remaining three locks to modify externally visible
+ * or used fields of cpusets, though some of the internally used cpuset fields
+ * and internal variables can be modified without holding callback_lock. If only
+ * reliable read access of the externally used fields are needed, a task can
+ * hold either cpuset_mutex or callback_lock which are exposed to other
+ * external subsystems.
+ *
+ * If a task holds cpu_hotplug_lock and cpuset_mutex, it blocks others,
+ * ensuring that it is the only task able to also acquire callback_lock and
+ * be able to modify cpusets. It can perform various checks on the cpuset
+ * structure first, knowing nothing will change. It can also allocate memory
+ * without holding callback_lock. While it is performing these checks, various
+ * callback routines can briefly acquire callback_lock to query cpusets. Once
+ * it is ready to make the changes, it takes callback_lock, blocking everyone
+ * else.
+ *
+ * Calls to the kernel memory allocator cannot be made while holding
+ * callback_lock which is a spinlock, as the memory allocator may sleep or
+ * call back into cpuset code and acquire callback_lock.
+ *
+ * Now, the task_struct fields mems_allowed and mempolicy may be changed
+ * by other task, we use alloc_lock in the task_struct fields to protect
+ * them.
+ *
+ * The cpuset_common_seq_show() handlers only hold callback_lock across
+ * small pieces of code, such as when reading out possibly multi-word
+ * cpumasks and nodemasks.
+ */
+
+static DEFINE_MUTEX(cpuset_top_mutex);
+static DEFINE_MUTEX(cpuset_mutex);
+
+/*
+ * File level internal variables below follow one of the following exclusion
+ * rules.
+ *
+ * RWCS: Read/write-able by holding either cpus_write_lock (and optionally
+ * cpuset_mutex) or both cpus_read_lock and cpuset_mutex.
+ *
+ * CSCB: Readable by holding either cpuset_mutex or callback_lock. Writable
+ * by holding both cpuset_mutex and callback_lock.
+ *
+ * T: Read/write-able by holding the cpuset_top_mutex.
+ */
+
+/*
* For local partitions, update to subpartitions_cpus & isolated_cpus is done
* in update_parent_effective_cpumask(). For remote partitions, it is done in
* the remote_partition_*() and remote_cpus_update() helpers.
@@ -70,19 +139,22 @@ static const char * const perr_strings[] = {
* Exclusive CPUs distributed out to local or remote sub-partitions of
* top_cpuset
*/
-static cpumask_var_t subpartitions_cpus;
+static cpumask_var_t subpartitions_cpus; /* RWCS */
+
+/*
+ * Exclusive CPUs in isolated partitions (shown in cpuset.cpus.isolated)
+ */
+static cpumask_var_t isolated_cpus; /* CSCB */
/*
- * Exclusive CPUs in isolated partitions
+ * Set if housekeeping cpumasks are to be updated.
*/
-static cpumask_var_t isolated_cpus;
+static bool update_housekeeping; /* RWCS */
/*
- * isolated_cpus updating flag (protected by cpuset_mutex)
- * Set if isolated_cpus is going to be updated in the current
- * cpuset_mutex crtical section.
+ * Copy of isolated_cpus to be passed to housekeeping_update()
*/
-static bool isolated_cpus_updating;
+static cpumask_var_t isolated_hk_cpus; /* T */
/*
* A flag to force sched domain rebuild at the end of an operation.
@@ -98,7 +170,7 @@ static bool isolated_cpus_updating;
* Note that update_relax_domain_level() in cpuset-v1.c can still call
* rebuild_sched_domains_locked() directly without using this flag.
*/
-static bool force_sd_rebuild;
+static bool force_sd_rebuild; /* RWCS */
/*
* Partition root states:
@@ -218,42 +290,6 @@ struct cpuset top_cpuset = {
.partition_root_state = PRS_ROOT,
};
-/*
- * There are two global locks guarding cpuset structures - cpuset_mutex and
- * callback_lock. The cpuset code uses only cpuset_mutex. Other kernel
- * subsystems can use cpuset_lock()/cpuset_unlock() to prevent change to cpuset
- * structures. Note that cpuset_mutex needs to be a mutex as it is used in
- * paths that rely on priority inheritance (e.g. scheduler - on RT) for
- * correctness.
- *
- * A task must hold both locks to modify cpusets. If a task holds
- * cpuset_mutex, it blocks others, ensuring that it is the only task able to
- * also acquire callback_lock and be able to modify cpusets. It can perform
- * various checks on the cpuset structure first, knowing nothing will change.
- * It can also allocate memory while just holding cpuset_mutex. While it is
- * performing these checks, various callback routines can briefly acquire
- * callback_lock to query cpusets. Once it is ready to make the changes, it
- * takes callback_lock, blocking everyone else.
- *
- * Calls to the kernel memory allocator can not be made while holding
- * callback_lock, as that would risk double tripping on callback_lock
- * from one of the callbacks into the cpuset code from within
- * __alloc_pages().
- *
- * If a task is only holding callback_lock, then it has read-only
- * access to cpusets.
- *
- * Now, the task_struct fields mems_allowed and mempolicy may be changed
- * by other task, we use alloc_lock in the task_struct fields to protect
- * them.
- *
- * The cpuset_common_seq_show() handlers only hold callback_lock across
- * small pieces of code, such as when reading out possibly multi-word
- * cpumasks and nodemasks.
- */
-
-static DEFINE_MUTEX(cpuset_mutex);
-
/**
* cpuset_lock - Acquire the global cpuset mutex
*
@@ -283,6 +319,7 @@ void lockdep_assert_cpuset_lock_held(void)
*/
void cpuset_full_lock(void)
{
+ mutex_lock(&cpuset_top_mutex);
cpus_read_lock();
mutex_lock(&cpuset_mutex);
}
@@ -291,12 +328,14 @@ void cpuset_full_unlock(void)
{
mutex_unlock(&cpuset_mutex);
cpus_read_unlock();
+ mutex_unlock(&cpuset_top_mutex);
}
#ifdef CONFIG_LOCKDEP
bool lockdep_is_cpuset_held(void)
{
- return lockdep_is_held(&cpuset_mutex);
+ return lockdep_is_held(&cpuset_mutex) ||
+ lockdep_is_held(&cpuset_top_mutex);
}
#endif
@@ -961,7 +1000,7 @@ void rebuild_sched_domains_locked(void)
* offline CPUs, a warning is emitted and we return directly to
* prevent the panic.
*/
- for (i = 0; i < ndoms; ++i) {
+ for (i = 0; doms && i < ndoms; i++) {
if (WARN_ON_ONCE(!cpumask_subset(doms[i], cpu_active_mask)))
return;
}
@@ -1161,12 +1200,18 @@ static void reset_partition_data(struct cpuset *cs)
static void isolated_cpus_update(int old_prs, int new_prs, struct cpumask *xcpus)
{
WARN_ON_ONCE(old_prs == new_prs);
- if (new_prs == PRS_ISOLATED)
+ lockdep_assert_held(&callback_lock);
+ lockdep_assert_held(&cpuset_mutex);
+ if (new_prs == PRS_ISOLATED) {
+ if (cpumask_subset(xcpus, isolated_cpus))
+ return;
cpumask_or(isolated_cpus, isolated_cpus, xcpus);
- else
+ } else {
+ if (!cpumask_intersects(xcpus, isolated_cpus))
+ return;
cpumask_andnot(isolated_cpus, isolated_cpus, xcpus);
-
- isolated_cpus_updating = true;
+ }
+ update_housekeeping = true;
}
/*
@@ -1219,8 +1264,8 @@ static void partition_xcpus_del(int old_prs, struct cpuset *parent,
isolated_cpus_update(old_prs, parent->partition_root_state,
xcpus);
- cpumask_and(xcpus, xcpus, cpu_active_mask);
cpumask_or(parent->effective_cpus, parent->effective_cpus, xcpus);
+ cpumask_and(parent->effective_cpus, parent->effective_cpus, cpu_active_mask);
}
/*
@@ -1284,22 +1329,43 @@ static bool prstate_housekeeping_conflict(int prstate, struct cpumask *new_cpus)
}
/*
- * update_isolation_cpumasks - Update external isolation related CPU masks
+ * update_hk_sched_domains - Update HK cpumasks & rebuild sched domains
*
- * The following external CPU masks will be updated if necessary:
- * - workqueue unbound cpumask
+ * Update housekeeping cpumasks and rebuild sched domains if necessary.
+ * This should be called at the end of cpuset or hotplug actions.
*/
-static void update_isolation_cpumasks(void)
+static void update_hk_sched_domains(void)
{
- int ret;
-
- if (!isolated_cpus_updating)
- return;
+ if (update_housekeeping) {
+ /* Updating HK cpumasks implies rebuild sched domains */
+ update_housekeeping = false;
+ force_sd_rebuild = true;
+ cpumask_copy(isolated_hk_cpus, isolated_cpus);
- ret = housekeeping_update(isolated_cpus);
- WARN_ON_ONCE(ret < 0);
+ /*
+ * housekeeping_update() is now called without holding
+ * cpus_read_lock and cpuset_mutex. Only cpuset_top_mutex
+ * is still being held for mutual exclusion.
+ */
+ mutex_unlock(&cpuset_mutex);
+ cpus_read_unlock();
+ WARN_ON_ONCE(housekeeping_update(isolated_hk_cpus));
+ cpus_read_lock();
+ mutex_lock(&cpuset_mutex);
+ }
+ /* force_sd_rebuild will be cleared in rebuild_sched_domains_locked() */
+ if (force_sd_rebuild)
+ rebuild_sched_domains_locked();
+}
- isolated_cpus_updating = false;
+/*
+ * Work function to invoke update_hk_sched_domains()
+ */
+static void hk_sd_workfn(struct work_struct *work)
+{
+ cpuset_full_lock();
+ update_hk_sched_domains();
+ cpuset_full_unlock();
}
/**
@@ -1450,7 +1516,6 @@ static int remote_partition_enable(struct cpuset *cs, int new_prs,
cs->remote_partition = true;
cpumask_copy(cs->effective_xcpus, tmp->new_cpus);
spin_unlock_irq(&callback_lock);
- update_isolation_cpumasks();
cpuset_force_rebuild();
cs->prs_err = 0;
@@ -1495,7 +1560,6 @@ static void remote_partition_disable(struct cpuset *cs, struct tmpmasks *tmp)
compute_excpus(cs, cs->effective_xcpus);
reset_partition_data(cs);
spin_unlock_irq(&callback_lock);
- update_isolation_cpumasks();
cpuset_force_rebuild();
/*
@@ -1566,7 +1630,6 @@ static void remote_cpus_update(struct cpuset *cs, struct cpumask *xcpus,
if (xcpus)
cpumask_copy(cs->exclusive_cpus, xcpus);
spin_unlock_irq(&callback_lock);
- update_isolation_cpumasks();
if (adding || deleting)
cpuset_force_rebuild();
@@ -1910,7 +1973,6 @@ write_error:
partition_xcpus_add(new_prs, parent, tmp->delmask);
spin_unlock_irq(&callback_lock);
- update_isolation_cpumasks();
if ((old_prs != new_prs) && (cmd == partcmd_update))
update_partition_exclusive_flag(cs, new_prs);
@@ -2155,7 +2217,7 @@ get_css:
WARN_ON(!is_in_v2_mode() &&
!cpumask_equal(cp->cpus_allowed, cp->effective_cpus));
- cpuset_update_tasks_cpumask(cp, cp->effective_cpus);
+ cpuset_update_tasks_cpumask(cp, tmp->new_cpus);
/*
* On default hierarchy, inherit the CS_SCHED_LOAD_BALANCE
@@ -2878,7 +2940,6 @@ out:
else if (isolcpus_updated)
isolated_cpus_update(old_prs, new_prs, cs->effective_xcpus);
spin_unlock_irq(&callback_lock);
- update_isolation_cpumasks();
/* Force update if switching back to member & update effective_xcpus */
update_cpumasks_hier(cs, &tmpmask, !new_prs);
@@ -3168,9 +3229,8 @@ ssize_t cpuset_write_resmask(struct kernfs_open_file *of,
}
free_cpuset(trialcs);
- if (force_sd_rebuild)
- rebuild_sched_domains_locked();
out_unlock:
+ update_hk_sched_domains();
cpuset_full_unlock();
if (of_cft(of)->private == FILE_MEMLIST)
schedule_flush_migrate_mm();
@@ -3278,6 +3338,7 @@ static ssize_t cpuset_partition_write(struct kernfs_open_file *of, char *buf,
cpuset_full_lock();
if (is_cpuset_online(cs))
retval = update_prstate(cs, val);
+ update_hk_sched_domains();
cpuset_full_unlock();
return retval ?: nbytes;
}
@@ -3452,6 +3513,7 @@ static void cpuset_css_killed(struct cgroup_subsys_state *css)
/* Reset valid partition back to member */
if (is_partition_valid(cs))
update_prstate(cs, PRS_MEMBER);
+ update_hk_sched_domains();
cpuset_full_unlock();
}
@@ -3607,6 +3669,7 @@ int __init cpuset_init(void)
BUG_ON(!alloc_cpumask_var(&top_cpuset.exclusive_cpus, GFP_KERNEL));
BUG_ON(!zalloc_cpumask_var(&subpartitions_cpus, GFP_KERNEL));
BUG_ON(!zalloc_cpumask_var(&isolated_cpus, GFP_KERNEL));
+ BUG_ON(!zalloc_cpumask_var(&isolated_hk_cpus, GFP_KERNEL));
cpumask_setall(top_cpuset.cpus_allowed);
nodes_setall(top_cpuset.mems_allowed);
@@ -3778,6 +3841,7 @@ unlock:
*/
static void cpuset_handle_hotplug(void)
{
+ static DECLARE_WORK(hk_sd_work, hk_sd_workfn);
static cpumask_t new_cpus;
static nodemask_t new_mems;
bool cpus_updated, mems_updated;
@@ -3859,9 +3923,21 @@ static void cpuset_handle_hotplug(void)
rcu_read_unlock();
}
- /* rebuild sched domains if necessary */
- if (force_sd_rebuild)
- rebuild_sched_domains_cpuslocked();
+
+ /*
+ * Queue a work to call housekeeping_update() & rebuild_sched_domains()
+ * There will be a slight delay before the HK_TYPE_DOMAIN housekeeping
+ * cpumask can correctly reflect what is in isolated_cpus.
+ *
+ * We rely on WORK_STRUCT_PENDING_BIT to not requeue a work item that
+ * is still pending. Before the pending bit is cleared, the work data
+ * is copied out and work item dequeued. So it is possible to queue
+ * the work again before the hk_sd_workfn() is invoked to process the
+ * previously queued work. Since hk_sd_workfn() doesn't use the work
+ * item at all, this is not a problem.
+ */
+ if (update_housekeeping || force_sd_rebuild)
+ queue_work(system_unbound_wq, &hk_sd_work);
free_tmpmasks(ptmp);
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 8a87021211ae..ede3117fa7d4 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -896,11 +896,16 @@ static void synchronize_group_exit(struct task_struct *tsk, long code)
void __noreturn do_exit(long code)
{
struct task_struct *tsk = current;
+ struct kthread *kthread;
int group_dead;
WARN_ON(irqs_disabled());
WARN_ON(tsk->plug);
+ kthread = tsk_is_kthread(tsk);
+ if (unlikely(kthread))
+ kthread_do_exit(kthread, code);
+
kcov_task_exit(tsk);
kmsan_task_exit(tsk);
@@ -1013,6 +1018,7 @@ void __noreturn do_exit(long code)
lockdep_free_task(tsk);
do_task_dead();
}
+EXPORT_SYMBOL(do_exit);
void __noreturn make_task_dead(int signr)
{
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 20451b624b67..791210daf8b4 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -85,24 +85,6 @@ static inline struct kthread *to_kthread(struct task_struct *k)
return k->worker_private;
}
-/*
- * Variant of to_kthread() that doesn't assume @p is a kthread.
- *
- * When "(p->flags & PF_KTHREAD)" is set the task is a kthread and will
- * always remain a kthread. For kthreads p->worker_private always
- * points to a struct kthread. For tasks that are not kthreads
- * p->worker_private is used to point to other things.
- *
- * Return NULL for any task that is not a kthread.
- */
-static inline struct kthread *__to_kthread(struct task_struct *p)
-{
- void *kthread = p->worker_private;
- if (kthread && !(p->flags & PF_KTHREAD))
- kthread = NULL;
- return kthread;
-}
-
void get_kthread_comm(char *buf, size_t buf_size, struct task_struct *tsk)
{
struct kthread *kthread = to_kthread(tsk);
@@ -193,7 +175,7 @@ EXPORT_SYMBOL_GPL(kthread_should_park);
bool kthread_should_stop_or_park(void)
{
- struct kthread *kthread = __to_kthread(current);
+ struct kthread *kthread = tsk_is_kthread(current);
if (!kthread)
return false;
@@ -234,7 +216,7 @@ EXPORT_SYMBOL_GPL(kthread_freezable_should_stop);
*/
void *kthread_func(struct task_struct *task)
{
- struct kthread *kthread = __to_kthread(task);
+ struct kthread *kthread = tsk_is_kthread(task);
if (kthread)
return kthread->threadfn;
return NULL;
@@ -266,7 +248,7 @@ EXPORT_SYMBOL_GPL(kthread_data);
*/
void *kthread_probe_data(struct task_struct *task)
{
- struct kthread *kthread = __to_kthread(task);
+ struct kthread *kthread = tsk_is_kthread(task);
void *data = NULL;
if (kthread)
@@ -309,19 +291,8 @@ void kthread_parkme(void)
}
EXPORT_SYMBOL_GPL(kthread_parkme);
-/**
- * kthread_exit - Cause the current kthread return @result to kthread_stop().
- * @result: The integer value to return to kthread_stop().
- *
- * While kthread_exit can be called directly, it exists so that
- * functions which do some additional work in non-modular code such as
- * module_put_and_kthread_exit can be implemented.
- *
- * Does not return.
- */
-void __noreturn kthread_exit(long result)
+void kthread_do_exit(struct kthread *kthread, long result)
{
- struct kthread *kthread = to_kthread(current);
kthread->result = result;
if (!list_empty(&kthread->affinity_node)) {
mutex_lock(&kthread_affinity_lock);
@@ -333,9 +304,7 @@ void __noreturn kthread_exit(long result)
kthread->preferred_affinity = NULL;
}
}
- do_exit(0);
}
-EXPORT_SYMBOL(kthread_exit);
/**
* kthread_complete_and_exit - Exit the current kthread.
@@ -683,7 +652,7 @@ void kthread_set_per_cpu(struct task_struct *k, int cpu)
bool kthread_is_per_cpu(struct task_struct *p)
{
- struct kthread *kthread = __to_kthread(p);
+ struct kthread *kthread = tsk_is_kthread(p);
if (!kthread)
return false;
diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig
index be74917802ad..43b1bb01fd27 100644
--- a/kernel/module/Kconfig
+++ b/kernel/module/Kconfig
@@ -169,9 +169,10 @@ config MODVERSIONS
make them incompatible with the kernel you are running. If
unsure, say N.
+if MODVERSIONS
+
choice
prompt "Module versioning implementation"
- depends on MODVERSIONS
help
Select the tool used to calculate symbol versions for modules.
@@ -206,7 +207,7 @@ endchoice
config ASM_MODVERSIONS
bool
- default HAVE_ASM_MODVERSIONS && MODVERSIONS
+ default HAVE_ASM_MODVERSIONS
help
This enables module versioning for exported symbols also from
assembly. This can be enabled only when the target architecture
@@ -214,7 +215,6 @@ config ASM_MODVERSIONS
config EXTENDED_MODVERSIONS
bool "Extended Module Versioning Support"
- depends on MODVERSIONS
help
This enables extended MODVERSIONs support, allowing long symbol
names to be versioned.
@@ -224,7 +224,6 @@ config EXTENDED_MODVERSIONS
config BASIC_MODVERSIONS
bool "Basic Module Versioning Support"
- depends on MODVERSIONS
default y
help
This enables basic MODVERSIONS support, allowing older tools or
@@ -237,6 +236,8 @@ config BASIC_MODVERSIONS
This is enabled by default when MODVERSIONS are enabled.
If unsure, say Y.
+endif # MODVERSIONS
+
config MODULE_SRCVERSION_ALL
bool "Source checksum for all modules"
help
@@ -277,10 +278,11 @@ config MODULE_SIG_FORCE
Reject unsigned modules or signed modules for which we don't have a
key. Without this, such modules will simply taint the kernel.
+if MODULE_SIG || IMA_APPRAISE_MODSIG
+
config MODULE_SIG_ALL
bool "Automatically sign all modules"
default y
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
help
Sign all modules during make modules_install. Without this option,
modules must be signed manually, using the scripts/sign-file tool.
@@ -290,7 +292,6 @@ comment "Do not forget to sign required modules with scripts/sign-file"
choice
prompt "Hash algorithm to sign modules"
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
default MODULE_SIG_SHA512
help
This determines which sort of hashing algorithm will be used during
@@ -327,7 +328,6 @@ endchoice
config MODULE_SIG_HASH
string
- depends on MODULE_SIG || IMA_APPRAISE_MODSIG
default "sha256" if MODULE_SIG_SHA256
default "sha384" if MODULE_SIG_SHA384
default "sha512" if MODULE_SIG_SHA512
@@ -335,6 +335,8 @@ config MODULE_SIG_HASH
default "sha3-384" if MODULE_SIG_SHA3_384
default "sha3-512" if MODULE_SIG_SHA3_512
+endif # MODULE_SIG || IMA_APPRAISE_MODSIG
+
config MODULE_COMPRESS
bool "Module compression"
help
@@ -350,9 +352,10 @@ config MODULE_COMPRESS
If unsure, say N.
+if MODULE_COMPRESS
+
choice
prompt "Module compression type"
- depends on MODULE_COMPRESS
help
Choose the supported algorithm for module compression.
@@ -379,7 +382,6 @@ endchoice
config MODULE_COMPRESS_ALL
bool "Automatically compress all modules"
default y
- depends on MODULE_COMPRESS
help
Compress all modules during 'make modules_install'.
@@ -389,7 +391,6 @@ config MODULE_COMPRESS_ALL
config MODULE_DECOMPRESS
bool "Support in-kernel module decompression"
- depends on MODULE_COMPRESS
select ZLIB_INFLATE if MODULE_COMPRESS_GZIP
select XZ_DEC if MODULE_COMPRESS_XZ
select ZSTD_DECOMPRESS if MODULE_COMPRESS_ZSTD
@@ -400,6 +401,8 @@ config MODULE_DECOMPRESS
If unsure, say N.
+endif # MODULE_COMPRESS
+
config MODULE_ALLOW_MISSING_NAMESPACE_IMPORTS
bool "Allow loading of modules with missing namespace imports"
help
diff --git a/kernel/module/main.c b/kernel/module/main.c
index 2bac4c7cd019..c3ce106c70af 100644
--- a/kernel/module/main.c
+++ b/kernel/module/main.c
@@ -1568,6 +1568,13 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
break;
default:
+ if (sym[i].st_shndx >= info->hdr->e_shnum) {
+ pr_err("%s: Symbol %s has an invalid section index %u (max %u)\n",
+ mod->name, name, sym[i].st_shndx, info->hdr->e_shnum - 1);
+ ret = -ENOEXEC;
+ break;
+ }
+
/* Divert to percpu allocation if a percpu var. */
if (sym[i].st_shndx == info->index.pcpu)
secbase = (unsigned long)mod_percpu(mod);
@@ -3544,12 +3551,6 @@ static int load_module(struct load_info *info, const char __user *uargs,
mutex_unlock(&module_mutex);
free_module:
mod_stat_bump_invalid(info, flags);
- /* Free lock-classes; relies on the preceding sync_rcu() */
- for_class_mod_mem_type(type, core_data) {
- lockdep_free_key_range(mod->mem[type].base,
- mod->mem[type].size);
- }
-
module_memory_restore_rox(mod);
module_deallocate(mod, info);
free_copy:
diff --git a/kernel/nscommon.c b/kernel/nscommon.c
index bdc3c86231d3..3166c1fd844a 100644
--- a/kernel/nscommon.c
+++ b/kernel/nscommon.c
@@ -309,3 +309,9 @@ void __ns_ref_active_get(struct ns_common *ns)
return;
}
}
+
+bool may_see_all_namespaces(void)
+{
+ return (task_active_pid_ns(current) == &init_pid_ns) &&
+ ns_capable_noaudit(init_pid_ns.user_ns, CAP_SYS_ADMIN);
+}
diff --git a/kernel/nstree.c b/kernel/nstree.c
index f36c59e6951d..6d12e5900ac0 100644
--- a/kernel/nstree.c
+++ b/kernel/nstree.c
@@ -515,32 +515,11 @@ static inline bool __must_check ns_requested(const struct klistns *kls,
static inline bool __must_check may_list_ns(const struct klistns *kls,
struct ns_common *ns)
{
- if (kls->user_ns) {
- if (kls->userns_capable)
- return true;
- } else {
- struct ns_common *owner;
- struct user_namespace *user_ns;
-
- owner = ns_owner(ns);
- if (owner)
- user_ns = to_user_ns(owner);
- else
- user_ns = &init_user_ns;
- if (ns_capable_noaudit(user_ns, CAP_SYS_ADMIN))
- return true;
- }
-
- if (is_current_namespace(ns))
+ if (kls->user_ns && kls->userns_capable)
return true;
-
- if (ns->ns_type != CLONE_NEWUSER)
- return false;
-
- if (ns_capable_noaudit(to_user_ns(ns), CAP_SYS_ADMIN))
+ if (is_current_namespace(ns))
return true;
-
- return false;
+ return may_see_all_namespaces();
}
static inline void ns_put(struct ns_common *ns)
@@ -600,7 +579,7 @@ static ssize_t do_listns_userns(struct klistns *kls)
ret = 0;
head = &to_ns_common(kls->user_ns)->ns_owner_root.ns_list_head;
- kls->userns_capable = ns_capable_noaudit(kls->user_ns, CAP_SYS_ADMIN);
+ kls->userns_capable = may_see_all_namespaces();
rcu_read_lock();
diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c
index 06cc0a4aec66..1594987d637b 100644
--- a/kernel/sched/ext.c
+++ b/kernel/sched/ext.c
@@ -976,8 +976,12 @@ static bool scx_dsq_priq_less(struct rb_node *node_a,
static void dsq_mod_nr(struct scx_dispatch_q *dsq, s32 delta)
{
- /* scx_bpf_dsq_nr_queued() reads ->nr without locking, use WRITE_ONCE() */
- WRITE_ONCE(dsq->nr, dsq->nr + delta);
+ /*
+ * scx_bpf_dsq_nr_queued() reads ->nr without locking. Use READ_ONCE()
+ * on the read side and WRITE_ONCE() on the write side to properly
+ * annotate the concurrent lockless access and avoid KCSAN warnings.
+ */
+ WRITE_ONCE(dsq->nr, READ_ONCE(dsq->nr) + delta);
}
static void refill_task_slice_dfl(struct scx_sched *sch, struct task_struct *p)
@@ -2735,7 +2739,7 @@ static bool check_rq_for_timeouts(struct rq *rq)
unsigned long last_runnable = p->scx.runnable_at;
if (unlikely(time_after(jiffies,
- last_runnable + scx_watchdog_timeout))) {
+ last_runnable + READ_ONCE(scx_watchdog_timeout)))) {
u32 dur_ms = jiffies_to_msecs(jiffies - last_runnable);
scx_exit(sch, SCX_EXIT_ERROR_STALL, 0,
@@ -2763,7 +2767,7 @@ static void scx_watchdog_workfn(struct work_struct *work)
cond_resched();
}
queue_delayed_work(system_unbound_wq, to_delayed_work(work),
- scx_watchdog_timeout / 2);
+ READ_ONCE(scx_watchdog_timeout) / 2);
}
void scx_tick(struct rq *rq)
@@ -3585,7 +3589,6 @@ static int scx_cgroup_init(struct scx_sched *sch)
ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, cgroup_init, NULL,
css->cgroup, &args);
if (ret) {
- css_put(css);
scx_error(sch, "ops.cgroup_init() failed (%d)", ret);
return ret;
}
@@ -3708,7 +3711,9 @@ static void scx_kobj_release(struct kobject *kobj)
static ssize_t scx_attr_ops_show(struct kobject *kobj,
struct kobj_attribute *ka, char *buf)
{
- return sysfs_emit(buf, "%s\n", scx_root->ops.name);
+ struct scx_sched *sch = container_of(kobj, struct scx_sched, kobj);
+
+ return sysfs_emit(buf, "%s\n", sch->ops.name);
}
SCX_ATTR(ops);
@@ -3752,7 +3757,9 @@ static const struct kobj_type scx_ktype = {
static int scx_uevent(const struct kobject *kobj, struct kobj_uevent_env *env)
{
- return add_uevent_var(env, "SCXOPS=%s", scx_root->ops.name);
+ const struct scx_sched *sch = container_of(kobj, struct scx_sched, kobj);
+
+ return add_uevent_var(env, "SCXOPS=%s", sch->ops.name);
}
static const struct kset_uevent_ops scx_uevent_ops = {
@@ -4423,10 +4430,19 @@ done:
scx_bypass(false);
}
+/*
+ * Claim the exit on @sch. The caller must ensure that the helper kthread work
+ * is kicked before the current task can be preempted. Once exit_kind is
+ * claimed, scx_error() can no longer trigger, so if the current task gets
+ * preempted and the BPF scheduler fails to schedule it back, the helper work
+ * will never be kicked and the whole system can wedge.
+ */
static bool scx_claim_exit(struct scx_sched *sch, enum scx_exit_kind kind)
{
int none = SCX_EXIT_NONE;
+ lockdep_assert_preemption_disabled();
+
if (!atomic_try_cmpxchg(&sch->exit_kind, &none, kind))
return false;
@@ -4449,6 +4465,7 @@ static void scx_disable(enum scx_exit_kind kind)
rcu_read_lock();
sch = rcu_dereference(scx_root);
if (sch) {
+ guard(preempt)();
scx_claim_exit(sch, kind);
kthread_queue_work(sch->helper, &sch->disable_work);
}
@@ -4771,6 +4788,8 @@ static bool scx_vexit(struct scx_sched *sch,
{
struct scx_exit_info *ei = sch->exit_info;
+ guard(preempt)();
+
if (!scx_claim_exit(sch, kind))
return false;
@@ -4955,20 +4974,30 @@ static int validate_ops(struct scx_sched *sch, const struct sched_ext_ops *ops)
return 0;
}
-static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
+/*
+ * scx_enable() is offloaded to a dedicated system-wide RT kthread to avoid
+ * starvation. During the READY -> ENABLED task switching loop, the calling
+ * thread's sched_class gets switched from fair to ext. As fair has higher
+ * priority than ext, the calling thread can be indefinitely starved under
+ * fair-class saturation, leading to a system hang.
+ */
+struct scx_enable_cmd {
+ struct kthread_work work;
+ struct sched_ext_ops *ops;
+ int ret;
+};
+
+static void scx_enable_workfn(struct kthread_work *work)
{
+ struct scx_enable_cmd *cmd =
+ container_of(work, struct scx_enable_cmd, work);
+ struct sched_ext_ops *ops = cmd->ops;
struct scx_sched *sch;
struct scx_task_iter sti;
struct task_struct *p;
unsigned long timeout;
int i, cpu, ret;
- if (!cpumask_equal(housekeeping_cpumask(HK_TYPE_DOMAIN),
- cpu_possible_mask)) {
- pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n");
- return -EINVAL;
- }
-
mutex_lock(&scx_enable_mutex);
if (scx_enable_state() != SCX_DISABLED) {
@@ -5060,7 +5089,7 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
WRITE_ONCE(scx_watchdog_timeout, timeout);
WRITE_ONCE(scx_watchdog_timestamp, jiffies);
queue_delayed_work(system_unbound_wq, &scx_watchdog_work,
- scx_watchdog_timeout / 2);
+ READ_ONCE(scx_watchdog_timeout) / 2);
/*
* Once __scx_enabled is set, %current can be switched to SCX anytime.
@@ -5185,13 +5214,15 @@ static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
atomic_long_inc(&scx_enable_seq);
- return 0;
+ cmd->ret = 0;
+ return;
err_free_ksyncs:
free_kick_syncs();
err_unlock:
mutex_unlock(&scx_enable_mutex);
- return ret;
+ cmd->ret = ret;
+ return;
err_disable_unlock_all:
scx_cgroup_unlock();
@@ -5210,7 +5241,41 @@ err_disable:
*/
scx_error(sch, "scx_enable() failed (%d)", ret);
kthread_flush_work(&sch->disable_work);
- return 0;
+ cmd->ret = 0;
+}
+
+static int scx_enable(struct sched_ext_ops *ops, struct bpf_link *link)
+{
+ static struct kthread_worker *helper;
+ static DEFINE_MUTEX(helper_mutex);
+ struct scx_enable_cmd cmd;
+
+ if (!cpumask_equal(housekeeping_cpumask(HK_TYPE_DOMAIN),
+ cpu_possible_mask)) {
+ pr_err("sched_ext: Not compatible with \"isolcpus=\" domain isolation\n");
+ return -EINVAL;
+ }
+
+ if (!READ_ONCE(helper)) {
+ mutex_lock(&helper_mutex);
+ if (!helper) {
+ helper = kthread_run_worker(0, "scx_enable_helper");
+ if (IS_ERR_OR_NULL(helper)) {
+ helper = NULL;
+ mutex_unlock(&helper_mutex);
+ return -ENOMEM;
+ }
+ sched_set_fifo(helper->task);
+ }
+ mutex_unlock(&helper_mutex);
+ }
+
+ kthread_init_work(&cmd.work, scx_enable_workfn);
+ cmd.ops = ops;
+
+ kthread_queue_work(READ_ONCE(helper), &cmd.work);
+ kthread_flush_work(&cmd.work);
+ return cmd.ret;
}
diff --git a/kernel/sched/ext_idle.c b/kernel/sched/ext_idle.c
index c5a3b0bac7c3..ba298ac3ce6c 100644
--- a/kernel/sched/ext_idle.c
+++ b/kernel/sched/ext_idle.c
@@ -663,9 +663,8 @@ void scx_idle_init_masks(void)
BUG_ON(!alloc_cpumask_var(&scx_idle_global_masks.cpu, GFP_KERNEL));
BUG_ON(!alloc_cpumask_var(&scx_idle_global_masks.smt, GFP_KERNEL));
- /* Allocate per-node idle cpumasks */
- scx_idle_node_masks = kzalloc_objs(*scx_idle_node_masks,
- num_possible_nodes());
+ /* Allocate per-node idle cpumasks (use nr_node_ids for non-contiguous NUMA nodes) */
+ scx_idle_node_masks = kzalloc_objs(*scx_idle_node_masks, nr_node_ids);
BUG_ON(!scx_idle_node_masks);
for_each_node(i) {
diff --git a/kernel/sched/ext_internal.h b/kernel/sched/ext_internal.h
index 386c677e4c9a..11ebb744d893 100644
--- a/kernel/sched/ext_internal.h
+++ b/kernel/sched/ext_internal.h
@@ -74,7 +74,7 @@ enum scx_exit_flags {
* info communication. The following flag indicates whether ops.init()
* finished successfully.
*/
- SCX_EFLAG_INITIALIZED,
+ SCX_EFLAG_INITIALIZED = 1LLU << 0,
};
/*
diff --git a/kernel/sched/isolation.c b/kernel/sched/isolation.c
index 3b725d39c06e..ef152d401fe2 100644
--- a/kernel/sched/isolation.c
+++ b/kernel/sched/isolation.c
@@ -123,8 +123,6 @@ int housekeeping_update(struct cpumask *isol_mask)
struct cpumask *trial, *old = NULL;
int err;
- lockdep_assert_cpus_held();
-
trial = kmalloc(cpumask_size(), GFP_KERNEL);
if (!trial)
return -ENOMEM;
@@ -136,7 +134,7 @@ int housekeeping_update(struct cpumask *isol_mask)
}
if (!housekeeping.flags)
- static_branch_enable_cpuslocked(&housekeeping_overridden);
+ static_branch_enable(&housekeeping_overridden);
if (housekeeping.flags & HK_FLAG_DOMAIN)
old = housekeeping_cpumask_dereference(HK_TYPE_DOMAIN);
diff --git a/kernel/sched/syscalls.c b/kernel/sched/syscalls.c
index 6f10db3646e7..cadb0e9fe19b 100644
--- a/kernel/sched/syscalls.c
+++ b/kernel/sched/syscalls.c
@@ -284,6 +284,35 @@ static bool check_same_owner(struct task_struct *p)
uid_eq(cred->euid, pcred->uid));
}
+#ifdef CONFIG_RT_MUTEXES
+static inline void __setscheduler_dl_pi(int newprio, int policy,
+ struct task_struct *p,
+ struct sched_change_ctx *scope)
+{
+ /*
+ * In case a DEADLINE task (either proper or boosted) gets
+ * setscheduled to a lower priority class, check if it neeeds to
+ * inherit parameters from a potential pi_task. In that case make
+ * sure replenishment happens with the next enqueue.
+ */
+
+ if (dl_prio(newprio) && !dl_policy(policy)) {
+ struct task_struct *pi_task = rt_mutex_get_top_task(p);
+
+ if (pi_task) {
+ p->dl.pi_se = pi_task->dl.pi_se;
+ scope->flags |= ENQUEUE_REPLENISH;
+ }
+ }
+}
+#else /* !CONFIG_RT_MUTEXES */
+static inline void __setscheduler_dl_pi(int newprio, int policy,
+ struct task_struct *p,
+ struct sched_change_ctx *scope)
+{
+}
+#endif /* !CONFIG_RT_MUTEXES */
+
#ifdef CONFIG_UCLAMP_TASK
static int uclamp_validate(struct task_struct *p,
@@ -655,6 +684,7 @@ change:
__setscheduler_params(p, attr);
p->sched_class = next_class;
p->prio = newprio;
+ __setscheduler_dl_pi(newprio, policy, p, scope);
}
__setscheduler_uclamp(p, attr);
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index a5c7d15fce72..9daf8c5d9687 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -256,8 +256,6 @@ EXPORT_SYMBOL(proc_dointvec_jiffies);
int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- if (SYSCTL_USER_TO_KERN(dir) && USER_HZ < HZ)
- return -EINVAL;
return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
do_proc_int_conv_userhz_jiffies);
}
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 91fa2003351c..c07e562ee4c1 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -2653,7 +2653,8 @@ static int timekeeping_validate_timex(const struct __kernel_timex *txc, bool aux
if (aux_clock) {
/* Auxiliary clocks are similar to TAI and do not have leap seconds */
- if (txc->status & (STA_INS | STA_DEL))
+ if (txc->modes & ADJ_STATUS &&
+ txc->status & (STA_INS | STA_DEL))
return -EINVAL;
/* No TAI offset setting */
@@ -2661,7 +2662,8 @@ static int timekeeping_validate_timex(const struct __kernel_timex *txc, bool aux
return -EINVAL;
/* No PPS support either */
- if (txc->status & (STA_PPSFREQ | STA_PPSTIME))
+ if (txc->modes & ADJ_STATUS &&
+ txc->status & (STA_PPSFREQ | STA_PPSTIME))
return -EINVAL;
}
diff --git a/kernel/time/timer_migration.c b/kernel/time/timer_migration.c
index c1ed0d5e8de6..155eeaea4113 100644
--- a/kernel/time/timer_migration.c
+++ b/kernel/time/timer_migration.c
@@ -1559,8 +1559,6 @@ int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask)
cpumask_var_t cpumask __free(free_cpumask_var) = CPUMASK_VAR_NULL;
int cpu;
- lockdep_assert_cpus_held();
-
if (!works)
return -ENOMEM;
if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
@@ -1570,6 +1568,7 @@ int tmigr_isolated_exclude_cpumask(struct cpumask *exclude_cpumask)
* First set previously isolated CPUs as available (unisolate).
* This cpumask contains only CPUs that switched to available now.
*/
+ guard(cpus_read_lock)();
cpumask_andnot(cpumask, cpu_online_mask, exclude_cpumask);
cpumask_andnot(cpumask, cpumask, tmigr_available_cpumask);
@@ -1626,7 +1625,6 @@ static int __init tmigr_init_isolation(void)
cpumask_andnot(cpumask, cpu_possible_mask, housekeeping_cpumask(HK_TYPE_DOMAIN));
/* Protect against RCU torture hotplug testing */
- guard(cpus_read_lock)();
return tmigr_isolated_exclude_cpumask(cpumask);
}
late_initcall(tmigr_init_isolation);
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 30259dcaa838..8cd2520b4c99 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -383,8 +383,6 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
cpu = raw_smp_processor_id();
if (blk_tracer) {
- tracing_record_cmdline(current);
-
buffer = blk_tr->array_buffer.buffer;
trace_ctx = tracing_gen_ctx_flags(0);
switch (bt->version) {
@@ -419,6 +417,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
if (!event)
return;
+ tracing_record_cmdline(current);
switch (bt->version) {
case 1:
record_blktrace_event(ring_buffer_event_data(event),
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 827fb9a0bf0d..8df69e702706 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -6404,6 +6404,7 @@ int update_ftrace_direct_add(struct ftrace_ops *ops, struct ftrace_hash *hash)
new_filter_hash = old_filter_hash;
}
} else {
+ guard(mutex)(&ftrace_lock);
err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
/*
* new_filter_hash is dup-ed, so we need to release it anyway,
@@ -6530,6 +6531,7 @@ int update_ftrace_direct_del(struct ftrace_ops *ops, struct ftrace_hash *hash)
ops->func_hash->filter_hash = NULL;
}
} else {
+ guard(mutex)(&ftrace_lock);
err = ftrace_update_ops(ops, new_filter_hash, EMPTY_HASH);
/*
* new_filter_hash is dup-ed, so we need to release it anyway,
@@ -8611,6 +8613,7 @@ ftrace_pid_follow_sched_process_fork(void *data,
struct trace_pid_list *pid_list;
struct trace_array *tr = data;
+ guard(preempt)();
pid_list = rcu_dereference_sched(tr->function_pids);
trace_filter_add_remove_task(pid_list, self, task);
@@ -8624,6 +8627,7 @@ ftrace_pid_follow_sched_process_exit(void *data, struct task_struct *task)
struct trace_pid_list *pid_list;
struct trace_array *tr = data;
+ guard(preempt)();
pid_list = rcu_dereference_sched(tr->function_pids);
trace_filter_add_remove_task(pid_list, NULL, task);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f16f053ef77d..17d0ea0cc3e6 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -7310,6 +7310,27 @@ int ring_buffer_map(struct trace_buffer *buffer, int cpu,
return err;
}
+/*
+ * This is called when a VMA is duplicated (e.g., on fork()) to increment
+ * the user_mapped counter without remapping pages.
+ */
+void ring_buffer_map_dup(struct trace_buffer *buffer, int cpu)
+{
+ struct ring_buffer_per_cpu *cpu_buffer;
+
+ if (WARN_ON(!cpumask_test_cpu(cpu, buffer->cpumask)))
+ return;
+
+ cpu_buffer = buffer->buffers[cpu];
+
+ guard(mutex)(&cpu_buffer->mapping_lock);
+
+ if (cpu_buffer->user_mapped)
+ __rb_inc_dec_mapped(cpu_buffer, true);
+ else
+ WARN(1, "Unexpected buffer stat, it should be mapped");
+}
+
int ring_buffer_unmap(struct trace_buffer *buffer, int cpu)
{
struct ring_buffer_per_cpu *cpu_buffer;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 23de3719f495..ebd996f8710e 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -8213,6 +8213,18 @@ static inline int get_snapshot_map(struct trace_array *tr) { return 0; }
static inline void put_snapshot_map(struct trace_array *tr) { }
#endif
+/*
+ * This is called when a VMA is duplicated (e.g., on fork()) to increment
+ * the user_mapped counter without remapping pages.
+ */
+static void tracing_buffers_mmap_open(struct vm_area_struct *vma)
+{
+ struct ftrace_buffer_info *info = vma->vm_file->private_data;
+ struct trace_iterator *iter = &info->iter;
+
+ ring_buffer_map_dup(iter->array_buffer->buffer, iter->cpu_file);
+}
+
static void tracing_buffers_mmap_close(struct vm_area_struct *vma)
{
struct ftrace_buffer_info *info = vma->vm_file->private_data;
@@ -8232,6 +8244,7 @@ static int tracing_buffers_may_split(struct vm_area_struct *vma, unsigned long a
}
static const struct vm_operations_struct tracing_buffers_vmops = {
+ .open = tracing_buffers_mmap_open,
.close = tracing_buffers_mmap_close,
.may_split = tracing_buffers_may_split,
};
@@ -9337,7 +9350,7 @@ static void setup_trace_scratch(struct trace_array *tr,
}
static int
-allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, int size)
+allocate_trace_buffer(struct trace_array *tr, struct array_buffer *buf, unsigned long size)
{
enum ring_buffer_flags rb_flags;
struct trace_scratch *tscratch;
@@ -9392,7 +9405,7 @@ static void free_trace_buffer(struct array_buffer *buf)
}
}
-static int allocate_trace_buffers(struct trace_array *tr, int size)
+static int allocate_trace_buffers(struct trace_array *tr, unsigned long size)
{
int ret;
@@ -10756,7 +10769,7 @@ __init static void enable_instances(void)
__init static int tracer_alloc_buffers(void)
{
- int ring_buf_size;
+ unsigned long ring_buf_size;
int ret = -ENOMEM;
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 9928da636c9d..249d1cba72c0 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1039,6 +1039,7 @@ event_filter_pid_sched_process_exit(void *data, struct task_struct *task)
struct trace_pid_list *pid_list;
struct trace_array *tr = data;
+ guard(preempt)();
pid_list = rcu_dereference_raw(tr->filtered_pids);
trace_filter_add_remove_task(pid_list, NULL, task);
@@ -1054,6 +1055,7 @@ event_filter_pid_sched_process_fork(void *data,
struct trace_pid_list *pid_list;
struct trace_array *tr = data;
+ guard(preempt)();
pid_list = rcu_dereference_sched(tr->filtered_pids);
trace_filter_add_remove_task(pid_list, self, task);
@@ -4491,7 +4493,11 @@ static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata;
static __init int setup_trace_event(char *str)
{
- strscpy(bootup_event_buf, str, COMMAND_LINE_SIZE);
+ if (bootup_event_buf[0] != '\0')
+ strlcat(bootup_event_buf, ",", COMMAND_LINE_SIZE);
+
+ strlcat(bootup_event_buf, str, COMMAND_LINE_SIZE);
+
trace_set_ring_buffer_expanded(NULL);
disable_tracing_selftest("running event tracing");
@@ -4668,26 +4674,22 @@ static __init int event_trace_memsetup(void)
return 0;
}
-__init void
-early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
+/*
+ * Helper function to enable or disable a comma-separated list of events
+ * from the bootup buffer.
+ */
+static __init void __early_set_events(struct trace_array *tr, char *buf, bool enable)
{
char *token;
- int ret;
-
- while (true) {
- token = strsep(&buf, ",");
-
- if (!token)
- break;
+ while ((token = strsep(&buf, ","))) {
if (*token) {
- /* Restarting syscalls requires that we stop them first */
- if (disable_first)
+ if (enable) {
+ if (ftrace_set_clr_event(tr, token, 1))
+ pr_warn("Failed to enable trace event: %s\n", token);
+ } else {
ftrace_set_clr_event(tr, token, 0);
-
- ret = ftrace_set_clr_event(tr, token, 1);
- if (ret)
- pr_warn("Failed to enable trace event: %s\n", token);
+ }
}
/* Put back the comma to allow this to be called again */
@@ -4696,6 +4698,32 @@ early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
}
}
+/**
+ * early_enable_events - enable events from the bootup buffer
+ * @tr: The trace array to enable the events in
+ * @buf: The buffer containing the comma separated list of events
+ * @disable_first: If true, disable all events in @buf before enabling them
+ *
+ * This function enables events from the bootup buffer. If @disable_first
+ * is true, it will first disable all events in the buffer before enabling
+ * them.
+ *
+ * For syscall events, which rely on a global refcount to register the
+ * SYSCALL_WORK_SYSCALL_TRACEPOINT flag (especially for pid 1), we must
+ * ensure the refcount hits zero before re-enabling them. A simple
+ * "disable then enable" per-event is not enough if multiple syscalls are
+ * used, as the refcount will stay above zero. Thus, we need a two-phase
+ * approach: disable all, then enable all.
+ */
+__init void
+early_enable_events(struct trace_array *tr, char *buf, bool disable_first)
+{
+ if (disable_first)
+ __early_set_events(tr, buf, false);
+
+ __early_set_events(tr, buf, true);
+}
+
static __init int event_trace_enable(void)
{
struct trace_array *tr = top_trace_array();
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index fecbd679d432..d5230b759a2d 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -50,6 +50,9 @@ static int trigger_kthread_fn(void *ignore)
void trigger_data_free(struct event_trigger_data *data)
{
+ if (!data)
+ return;
+
if (data->cmd_ops->set_filter)
data->cmd_ops->set_filter(NULL, data, NULL);
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 3d8239fee004..0d2d3a2ea7dd 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -400,14 +400,19 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
struct fgraph_ops *gops,
struct ftrace_regs *fregs)
{
+ unsigned long *task_var = fgraph_get_task_var(gops);
struct fgraph_times *ftimes;
struct trace_array *tr;
+ unsigned int trace_ctx;
+ u64 calltime, rettime;
int size;
+ rettime = trace_clock_local();
+
ftrace_graph_addr_finish(gops, trace);
- if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) {
- trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT);
+ if (*task_var & TRACE_GRAPH_NOTRACE) {
+ *task_var &= ~TRACE_GRAPH_NOTRACE;
return;
}
@@ -418,11 +423,13 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace,
tr = gops->private;
handle_nosleeptime(tr, trace, ftimes, size);
- if (tracing_thresh &&
- (trace_clock_local() - ftimes->calltime < tracing_thresh))
+ calltime = ftimes->calltime;
+
+ if (tracing_thresh && (rettime - calltime < tracing_thresh))
return;
- else
- trace_graph_return(trace, gops, fregs);
+
+ trace_ctx = tracing_gen_ctx();
+ __trace_graph_return(tr, trace, trace_ctx, calltime, rettime);
}
static struct fgraph_ops funcgraph_ops = {
diff --git a/lib/crypto/.kunitconfig b/lib/crypto/.kunitconfig
new file mode 100644
index 000000000000..6b2ce28ae509
--- /dev/null
+++ b/lib/crypto/.kunitconfig
@@ -0,0 +1,34 @@
+CONFIG_KUNIT=y
+
+# These kconfig options select all the CONFIG_CRYPTO_LIB_* symbols that have a
+# corresponding KUnit test. Those symbols cannot be directly enabled here,
+# since they are hidden symbols.
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ADIANTUM=y
+CONFIG_CRYPTO_BLAKE2B=y
+CONFIG_CRYPTO_CHACHA20POLY1305=y
+CONFIG_CRYPTO_HCTR2=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MLDSA=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_SHA3=y
+CONFIG_INET=y
+CONFIG_IPV6=y
+CONFIG_NET=y
+CONFIG_NETDEVICES=y
+CONFIG_WIREGUARD=y
+
+CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_NH_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_POLY1305_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_POLYVAL_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_SHA1_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_SHA256_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_SHA512_KUNIT_TEST=y
+CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST=y
diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 4970463ea0aa..0de289b429a9 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -2,10 +2,9 @@
config CRYPTO_LIB_BLAKE2B_KUNIT_TEST
tristate "KUnit tests for BLAKE2b" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_BLAKE2B
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_BLAKE2B
help
KUnit tests for the BLAKE2b cryptographic hash function.
@@ -14,71 +13,64 @@ config CRYPTO_LIB_BLAKE2S_KUNIT_TEST
depends on KUNIT
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- # No need to select CRYPTO_LIB_BLAKE2S here, as that option doesn't
+ # No need to depend on CRYPTO_LIB_BLAKE2S here, as that option doesn't
# exist; the BLAKE2s code is always built-in for the /dev/random driver.
help
KUnit tests for the BLAKE2s cryptographic hash function.
config CRYPTO_LIB_CURVE25519_KUNIT_TEST
tristate "KUnit tests for Curve25519" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_CURVE25519
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_CURVE25519
help
KUnit tests for the Curve25519 Diffie-Hellman function.
config CRYPTO_LIB_MD5_KUNIT_TEST
tristate "KUnit tests for MD5" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_MD5
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_MD5
help
KUnit tests for the MD5 cryptographic hash function and its
corresponding HMAC.
config CRYPTO_LIB_MLDSA_KUNIT_TEST
tristate "KUnit tests for ML-DSA" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_MLDSA
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_MLDSA
help
KUnit tests for the ML-DSA digital signature algorithm.
config CRYPTO_LIB_NH_KUNIT_TEST
tristate "KUnit tests for NH" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_NH
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
- select CRYPTO_LIB_NH
help
KUnit tests for the NH almost-universal hash function.
config CRYPTO_LIB_POLY1305_KUNIT_TEST
tristate "KUnit tests for Poly1305" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_POLY1305
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_POLY1305
help
KUnit tests for the Poly1305 library functions.
config CRYPTO_LIB_POLYVAL_KUNIT_TEST
tristate "KUnit tests for POLYVAL" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_POLYVAL
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_POLYVAL
help
KUnit tests for the POLYVAL library functions.
config CRYPTO_LIB_SHA1_KUNIT_TEST
tristate "KUnit tests for SHA-1" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_SHA1
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_SHA1
help
KUnit tests for the SHA-1 cryptographic hash function and its
corresponding HMAC.
@@ -87,10 +79,9 @@ config CRYPTO_LIB_SHA1_KUNIT_TEST
# included, for consistency with the naming used elsewhere (e.g. CRYPTO_SHA256).
config CRYPTO_LIB_SHA256_KUNIT_TEST
tristate "KUnit tests for SHA-224 and SHA-256" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_SHA256
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_SHA256
help
KUnit tests for the SHA-224 and SHA-256 cryptographic hash functions
and their corresponding HMACs.
@@ -99,20 +90,18 @@ config CRYPTO_LIB_SHA256_KUNIT_TEST
# included, for consistency with the naming used elsewhere (e.g. CRYPTO_SHA512).
config CRYPTO_LIB_SHA512_KUNIT_TEST
tristate "KUnit tests for SHA-384 and SHA-512" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_SHA512
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_SHA512
help
KUnit tests for the SHA-384 and SHA-512 cryptographic hash functions
and their corresponding HMACs.
config CRYPTO_LIB_SHA3_KUNIT_TEST
tristate "KUnit tests for SHA-3" if !KUNIT_ALL_TESTS
- depends on KUNIT
+ depends on KUNIT && CRYPTO_LIB_SHA3
default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
select CRYPTO_LIB_BENCHMARK_VISIBLE
- select CRYPTO_LIB_SHA3
help
KUnit tests for the SHA3 cryptographic hash and XOF functions,
including SHA3-224, SHA3-256, SHA3-384, SHA3-512, SHAKE128 and
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 62eb529824c6..41e1c89799b6 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -94,7 +94,7 @@ struct kunit_result_stats {
unsigned long total;
};
-static bool kunit_should_print_stats(struct kunit_result_stats stats)
+static bool kunit_should_print_stats(struct kunit_result_stats *stats)
{
if (kunit_stats_enabled == 0)
return false;
@@ -102,11 +102,11 @@ static bool kunit_should_print_stats(struct kunit_result_stats stats)
if (kunit_stats_enabled == 2)
return true;
- return (stats.total > 1);
+ return (stats->total > 1);
}
static void kunit_print_test_stats(struct kunit *test,
- struct kunit_result_stats stats)
+ struct kunit_result_stats *stats)
{
if (!kunit_should_print_stats(stats))
return;
@@ -115,10 +115,10 @@ static void kunit_print_test_stats(struct kunit *test,
KUNIT_SUBTEST_INDENT
"# %s: pass:%lu fail:%lu skip:%lu total:%lu",
test->name,
- stats.passed,
- stats.failed,
- stats.skipped,
- stats.total);
+ stats->passed,
+ stats->failed,
+ stats->skipped,
+ stats->total);
}
/* Append formatted message to log. */
@@ -600,26 +600,26 @@ static void kunit_run_case_catch_errors(struct kunit_suite *suite,
}
static void kunit_print_suite_stats(struct kunit_suite *suite,
- struct kunit_result_stats suite_stats,
- struct kunit_result_stats param_stats)
+ struct kunit_result_stats *suite_stats,
+ struct kunit_result_stats *param_stats)
{
if (kunit_should_print_stats(suite_stats)) {
kunit_log(KERN_INFO, suite,
"# %s: pass:%lu fail:%lu skip:%lu total:%lu",
suite->name,
- suite_stats.passed,
- suite_stats.failed,
- suite_stats.skipped,
- suite_stats.total);
+ suite_stats->passed,
+ suite_stats->failed,
+ suite_stats->skipped,
+ suite_stats->total);
}
if (kunit_should_print_stats(param_stats)) {
kunit_log(KERN_INFO, suite,
"# Totals: pass:%lu fail:%lu skip:%lu total:%lu",
- param_stats.passed,
- param_stats.failed,
- param_stats.skipped,
- param_stats.total);
+ param_stats->passed,
+ param_stats->failed,
+ param_stats->skipped,
+ param_stats->total);
}
}
@@ -681,13 +681,116 @@ static void kunit_init_parent_param_test(struct kunit_case *test_case, struct ku
}
}
-int kunit_run_tests(struct kunit_suite *suite)
+static noinline_for_stack void
+kunit_run_param_test(struct kunit_suite *suite, struct kunit_case *test_case,
+ struct kunit *test,
+ struct kunit_result_stats *suite_stats,
+ struct kunit_result_stats *total_stats,
+ struct kunit_result_stats *param_stats)
{
char param_desc[KUNIT_PARAM_DESC_SIZE];
+ const void *curr_param;
+
+ kunit_init_parent_param_test(test_case, test);
+ if (test_case->status == KUNIT_FAILURE) {
+ kunit_update_stats(param_stats, test->status);
+ return;
+ }
+ /* Get initial param. */
+ param_desc[0] = '\0';
+ /* TODO: Make generate_params try-catch */
+ curr_param = test_case->generate_params(test, NULL, param_desc);
+ test_case->status = KUNIT_SKIPPED;
+ kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
+ "KTAP version 1\n");
+ kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
+ "# Subtest: %s", test_case->name);
+ if (test->params_array.params &&
+ test_case->generate_params == kunit_array_gen_params) {
+ kunit_log(KERN_INFO, test, KUNIT_SUBTEST_INDENT
+ KUNIT_SUBTEST_INDENT "1..%zd\n",
+ test->params_array.num_params);
+ }
+
+ while (curr_param) {
+ struct kunit param_test = {
+ .param_value = curr_param,
+ .param_index = ++test->param_index,
+ .parent = test,
+ };
+ kunit_init_test(&param_test, test_case->name, NULL);
+ param_test.log = test_case->log;
+ kunit_run_case_catch_errors(suite, test_case, &param_test);
+
+ if (param_desc[0] == '\0') {
+ snprintf(param_desc, sizeof(param_desc),
+ "param-%d", param_test.param_index);
+ }
+
+ kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
+ param_test.status,
+ param_test.param_index,
+ param_desc,
+ param_test.status_comment);
+
+ kunit_update_stats(param_stats, param_test.status);
+
+ /* Get next param. */
+ param_desc[0] = '\0';
+ curr_param = test_case->generate_params(test, curr_param,
+ param_desc);
+ }
+ /*
+ * TODO: Put into a try catch. Since we don't need suite->exit
+ * for it we can't reuse kunit_try_run_cleanup for this yet.
+ */
+ if (test_case->param_exit)
+ test_case->param_exit(test);
+ /* TODO: Put this kunit_cleanup into a try-catch. */
+ kunit_cleanup(test);
+}
+
+static noinline_for_stack void
+kunit_run_one_test(struct kunit_suite *suite, struct kunit_case *test_case,
+ struct kunit_result_stats *suite_stats,
+ struct kunit_result_stats *total_stats)
+{
+ struct kunit test = { .param_value = NULL, .param_index = 0 };
+ struct kunit_result_stats param_stats = { 0 };
+
+ kunit_init_test(&test, test_case->name, test_case->log);
+ if (test_case->status == KUNIT_SKIPPED) {
+ /* Test marked as skip */
+ test.status = KUNIT_SKIPPED;
+ kunit_update_stats(&param_stats, test.status);
+ } else if (!test_case->generate_params) {
+ /* Non-parameterised test. */
+ test_case->status = KUNIT_SKIPPED;
+ kunit_run_case_catch_errors(suite, test_case, &test);
+ kunit_update_stats(&param_stats, test.status);
+ } else {
+ kunit_run_param_test(suite, test_case, &test, suite_stats,
+ total_stats, &param_stats);
+ }
+ kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
+
+ kunit_print_test_stats(&test, &param_stats);
+
+ kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status,
+ kunit_test_case_num(suite, test_case),
+ test_case->name,
+ test.status_comment);
+
+ kunit_update_stats(suite_stats, test_case->status);
+ kunit_accumulate_stats(total_stats, param_stats);
+}
+
+
+int kunit_run_tests(struct kunit_suite *suite)
+{
struct kunit_case *test_case;
struct kunit_result_stats suite_stats = { 0 };
struct kunit_result_stats total_stats = { 0 };
- const void *curr_param;
/* Taint the kernel so we know we've run tests. */
add_taint(TAINT_TEST, LOCKDEP_STILL_OK);
@@ -703,97 +806,13 @@ int kunit_run_tests(struct kunit_suite *suite)
kunit_print_suite_start(suite);
- kunit_suite_for_each_test_case(suite, test_case) {
- struct kunit test = { .param_value = NULL, .param_index = 0 };
- struct kunit_result_stats param_stats = { 0 };
-
- kunit_init_test(&test, test_case->name, test_case->log);
- if (test_case->status == KUNIT_SKIPPED) {
- /* Test marked as skip */
- test.status = KUNIT_SKIPPED;
- kunit_update_stats(&param_stats, test.status);
- } else if (!test_case->generate_params) {
- /* Non-parameterised test. */
- test_case->status = KUNIT_SKIPPED;
- kunit_run_case_catch_errors(suite, test_case, &test);
- kunit_update_stats(&param_stats, test.status);
- } else {
- kunit_init_parent_param_test(test_case, &test);
- if (test_case->status == KUNIT_FAILURE) {
- kunit_update_stats(&param_stats, test.status);
- goto test_case_end;
- }
- /* Get initial param. */
- param_desc[0] = '\0';
- /* TODO: Make generate_params try-catch */
- curr_param = test_case->generate_params(&test, NULL, param_desc);
- test_case->status = KUNIT_SKIPPED;
- kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
- "KTAP version 1\n");
- kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
- "# Subtest: %s", test_case->name);
- if (test.params_array.params &&
- test_case->generate_params == kunit_array_gen_params) {
- kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT
- KUNIT_SUBTEST_INDENT "1..%zd\n",
- test.params_array.num_params);
- }
-
- while (curr_param) {
- struct kunit param_test = {
- .param_value = curr_param,
- .param_index = ++test.param_index,
- .parent = &test,
- };
- kunit_init_test(&param_test, test_case->name, NULL);
- param_test.log = test_case->log;
- kunit_run_case_catch_errors(suite, test_case, &param_test);
-
- if (param_desc[0] == '\0') {
- snprintf(param_desc, sizeof(param_desc),
- "param-%d", param_test.param_index);
- }
-
- kunit_print_ok_not_ok(&param_test, KUNIT_LEVEL_CASE_PARAM,
- param_test.status,
- param_test.param_index,
- param_desc,
- param_test.status_comment);
-
- kunit_update_stats(&param_stats, param_test.status);
-
- /* Get next param. */
- param_desc[0] = '\0';
- curr_param = test_case->generate_params(&test, curr_param,
- param_desc);
- }
- /*
- * TODO: Put into a try catch. Since we don't need suite->exit
- * for it we can't reuse kunit_try_run_cleanup for this yet.
- */
- if (test_case->param_exit)
- test_case->param_exit(&test);
- /* TODO: Put this kunit_cleanup into a try-catch. */
- kunit_cleanup(&test);
- }
-test_case_end:
- kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE);
-
- kunit_print_test_stats(&test, param_stats);
-
- kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE, test_case->status,
- kunit_test_case_num(suite, test_case),
- test_case->name,
- test.status_comment);
-
- kunit_update_stats(&suite_stats, test_case->status);
- kunit_accumulate_stats(&total_stats, param_stats);
- }
+ kunit_suite_for_each_test_case(suite, test_case)
+ kunit_run_one_test(suite, test_case, &suite_stats, &total_stats);
if (suite->suite_exit)
suite->suite_exit(suite);
- kunit_print_suite_stats(suite, suite_stats, total_stats);
+ kunit_print_suite_stats(suite, &suite_stats, &total_stats);
suite_end:
kunit_print_suite_end(suite);
diff --git a/mm/filemap.c b/mm/filemap.c
index 6cd7974d4ada..406cef06b684 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1379,14 +1379,16 @@ repeat:
#ifdef CONFIG_MIGRATION
/**
- * migration_entry_wait_on_locked - Wait for a migration entry to be removed
- * @entry: migration swap entry.
+ * softleaf_entry_wait_on_locked - Wait for a migration entry or
+ * device_private entry to be removed.
+ * @entry: migration or device_private swap entry.
* @ptl: already locked ptl. This function will drop the lock.
*
- * Wait for a migration entry referencing the given page to be removed. This is
+ * Wait for a migration entry referencing the given page, or device_private
+ * entry referencing a dvice_private page to be unlocked. This is
* equivalent to folio_put_wait_locked(folio, TASK_UNINTERRUPTIBLE) except
* this can be called without taking a reference on the page. Instead this
- * should be called while holding the ptl for the migration entry referencing
+ * should be called while holding the ptl for @entry referencing
* the page.
*
* Returns after unlocking the ptl.
@@ -1394,7 +1396,7 @@ repeat:
* This follows the same logic as folio_wait_bit_common() so see the comments
* there.
*/
-void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
+void softleaf_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
__releases(ptl)
{
struct wait_page_queue wait_page;
@@ -1428,6 +1430,9 @@ void migration_entry_wait_on_locked(softleaf_t entry, spinlock_t *ptl)
* If a migration entry exists for the page the migration path must hold
* a valid reference to the page, and it must take the ptl to remove the
* migration entry. So the page is valid until the ptl is dropped.
+ * Similarly any path attempting to drop the last reference to a
+ * device-private page needs to grab the ptl to remove the device-private
+ * entry.
*/
spin_unlock(ptl);
diff --git a/mm/madvise.c b/mm/madvise.c
index c0370d9b4e23..dbb69400786d 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1389,7 +1389,7 @@ static int madvise_vma_behavior(struct madvise_behavior *madv_behavior)
new_flags |= VM_DONTCOPY;
break;
case MADV_DOFORK:
- if (new_flags & VM_IO)
+ if (new_flags & VM_SPECIAL)
return -EINVAL;
new_flags &= ~VM_DONTCOPY;
break;
diff --git a/mm/memory.c b/mm/memory.c
index 07778814b4a8..2f815a34d924 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -4763,7 +4763,8 @@ vm_fault_t do_swap_page(struct vm_fault *vmf)
unlock_page(vmf->page);
put_page(vmf->page);
} else {
- pte_unmap_unlock(vmf->pte, vmf->ptl);
+ pte_unmap(vmf->pte);
+ softleaf_entry_wait_on_locked(entry, vmf->ptl);
}
} else if (softleaf_is_hwpoison(entry)) {
ret = VM_FAULT_HWPOISON;
diff --git a/mm/migrate.c b/mm/migrate.c
index 1bf2cf8c44dd..2c3d489ecf51 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -500,7 +500,7 @@ void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd,
if (!softleaf_is_migration(entry))
goto out;
- migration_entry_wait_on_locked(entry, ptl);
+ softleaf_entry_wait_on_locked(entry, ptl);
return;
out:
spin_unlock(ptl);
@@ -532,10 +532,10 @@ void migration_entry_wait_huge(struct vm_area_struct *vma, unsigned long addr, p
* If migration entry existed, safe to release vma lock
* here because the pgtable page won't be freed without the
* pgtable lock released. See comment right above pgtable
- * lock release in migration_entry_wait_on_locked().
+ * lock release in softleaf_entry_wait_on_locked().
*/
hugetlb_vma_unlock_read(vma);
- migration_entry_wait_on_locked(entry, ptl);
+ softleaf_entry_wait_on_locked(entry, ptl);
return;
}
@@ -553,7 +553,7 @@ void pmd_migration_entry_wait(struct mm_struct *mm, pmd_t *pmd)
ptl = pmd_lock(mm, pmd);
if (!pmd_is_migration_entry(*pmd))
goto unlock;
- migration_entry_wait_on_locked(softleaf_from_pmd(*pmd), ptl);
+ softleaf_entry_wait_on_locked(softleaf_from_pmd(*pmd), ptl);
return;
unlock:
spin_unlock(ptl);
diff --git a/mm/migrate_device.c b/mm/migrate_device.c
index 0a8b31939640..8079676c8f1f 100644
--- a/mm/migrate_device.c
+++ b/mm/migrate_device.c
@@ -176,7 +176,7 @@ static int migrate_vma_collect_huge_pmd(pmd_t *pmdp, unsigned long start,
}
if (softleaf_is_migration(entry)) {
- migration_entry_wait_on_locked(entry, ptl);
+ softleaf_entry_wait_on_locked(entry, ptl);
spin_unlock(ptl);
return -EAGAIN;
}
diff --git a/mm/slab.h b/mm/slab.h
index f6ef862b60ef..e9ab292acd22 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -59,7 +59,7 @@ struct freelist_counters {
* to save memory. In case ->stride field is not available,
* such optimizations are disabled.
*/
- unsigned short stride;
+ unsigned int stride;
#endif
};
};
@@ -559,20 +559,20 @@ static inline void put_slab_obj_exts(unsigned long obj_exts)
}
#ifdef CONFIG_64BIT
-static inline void slab_set_stride(struct slab *slab, unsigned short stride)
+static inline void slab_set_stride(struct slab *slab, unsigned int stride)
{
slab->stride = stride;
}
-static inline unsigned short slab_get_stride(struct slab *slab)
+static inline unsigned int slab_get_stride(struct slab *slab)
{
return slab->stride;
}
#else
-static inline void slab_set_stride(struct slab *slab, unsigned short stride)
+static inline void slab_set_stride(struct slab *slab, unsigned int stride)
{
VM_WARN_ON_ONCE(stride != sizeof(struct slabobj_ext));
}
-static inline unsigned short slab_get_stride(struct slab *slab)
+static inline unsigned int slab_get_stride(struct slab *slab)
{
return sizeof(struct slabobj_ext);
}
diff --git a/mm/slub.c b/mm/slub.c
index 0c906fefc31b..20cb4f3b636d 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2858,19 +2858,19 @@ static void __kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p);
* object pointers are moved to a on-stack array under the lock. To bound the
* stack usage, limit each batch to PCS_BATCH_MAX.
*
- * returns true if at least partially flushed
+ * Must be called with s->cpu_sheaves->lock locked, returns with the lock
+ * unlocked.
+ *
+ * Returns how many objects are remaining to be flushed
*/
-static bool sheaf_flush_main(struct kmem_cache *s)
+static unsigned int __sheaf_flush_main_batch(struct kmem_cache *s)
{
struct slub_percpu_sheaves *pcs;
unsigned int batch, remaining;
void *objects[PCS_BATCH_MAX];
struct slab_sheaf *sheaf;
- bool ret = false;
-next_batch:
- if (!local_trylock(&s->cpu_sheaves->lock))
- return ret;
+ lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
pcs = this_cpu_ptr(s->cpu_sheaves);
sheaf = pcs->main;
@@ -2888,10 +2888,37 @@ next_batch:
stat_add(s, SHEAF_FLUSH, batch);
- ret = true;
+ return remaining;
+}
- if (remaining)
- goto next_batch;
+static void sheaf_flush_main(struct kmem_cache *s)
+{
+ unsigned int remaining;
+
+ do {
+ local_lock(&s->cpu_sheaves->lock);
+
+ remaining = __sheaf_flush_main_batch(s);
+
+ } while (remaining);
+}
+
+/*
+ * Returns true if the main sheaf was at least partially flushed.
+ */
+static bool sheaf_try_flush_main(struct kmem_cache *s)
+{
+ unsigned int remaining;
+ bool ret = false;
+
+ do {
+ if (!local_trylock(&s->cpu_sheaves->lock))
+ return ret;
+
+ ret = true;
+ remaining = __sheaf_flush_main_batch(s);
+
+ } while (remaining);
return ret;
}
@@ -4540,7 +4567,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
struct slab_sheaf *empty = NULL;
struct slab_sheaf *full;
struct node_barn *barn;
- bool can_alloc;
+ bool allow_spin;
lockdep_assert_held(this_cpu_ptr(&s->cpu_sheaves->lock));
@@ -4561,8 +4588,9 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
return NULL;
}
- full = barn_replace_empty_sheaf(barn, pcs->main,
- gfpflags_allow_spinning(gfp));
+ allow_spin = gfpflags_allow_spinning(gfp);
+
+ full = barn_replace_empty_sheaf(barn, pcs->main, allow_spin);
if (full) {
stat(s, BARN_GET);
@@ -4572,9 +4600,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
stat(s, BARN_GET_FAIL);
- can_alloc = gfpflags_allow_blocking(gfp);
-
- if (can_alloc) {
+ if (allow_spin) {
if (pcs->spare) {
empty = pcs->spare;
pcs->spare = NULL;
@@ -4584,8 +4610,9 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
}
local_unlock(&s->cpu_sheaves->lock);
+ pcs = NULL;
- if (!can_alloc)
+ if (!allow_spin)
return NULL;
if (empty) {
@@ -4605,11 +4632,8 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
if (!full)
return NULL;
- /*
- * we can reach here only when gfpflags_allow_blocking
- * so this must not be an irq
- */
- local_lock(&s->cpu_sheaves->lock);
+ if (!local_trylock(&s->cpu_sheaves->lock))
+ goto barn_put;
pcs = this_cpu_ptr(s->cpu_sheaves);
/*
@@ -4640,6 +4664,7 @@ __pcs_replace_empty_main(struct kmem_cache *s, struct slub_percpu_sheaves *pcs,
return pcs;
}
+barn_put:
barn_put_full_sheaf(barn, full);
stat(s, BARN_PUT);
@@ -5704,7 +5729,7 @@ alloc_empty:
if (put_fail)
stat(s, BARN_PUT_FAIL);
- if (!sheaf_flush_main(s))
+ if (!sheaf_try_flush_main(s))
return NULL;
if (!local_trylock(&s->cpu_sheaves->lock))
diff --git a/net/atm/lec.c b/net/atm/lec.c
index a107375c0629..fb93c6e1c329 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1260,24 +1260,28 @@ static void lec_arp_clear_vccs(struct lec_arp_table *entry)
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = (struct net_device *)vcc->proto_data;
- vcc->pop = vpriv->old_pop;
- if (vpriv->xoff)
- netif_wake_queue(dev);
- kfree(vpriv);
- vcc->user_back = NULL;
- vcc->push = entry->old_push;
- vcc_release_async(vcc, -EPIPE);
+ if (vpriv) {
+ vcc->pop = vpriv->old_pop;
+ if (vpriv->xoff)
+ netif_wake_queue(dev);
+ kfree(vpriv);
+ vcc->user_back = NULL;
+ vcc->push = entry->old_push;
+ vcc_release_async(vcc, -EPIPE);
+ }
entry->vcc = NULL;
}
if (entry->recv_vcc) {
struct atm_vcc *vcc = entry->recv_vcc;
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
- kfree(vpriv);
- vcc->user_back = NULL;
+ if (vpriv) {
+ kfree(vpriv);
+ vcc->user_back = NULL;
- entry->recv_vcc->push = entry->old_recv_push;
- vcc_release_async(entry->recv_vcc, -EPIPE);
+ entry->recv_vcc->push = entry->old_recv_push;
+ vcc_release_async(entry->recv_vcc, -EPIPE);
+ }
entry->recv_vcc = NULL;
}
}
diff --git a/net/batman-adv/bat_v_elp.c b/net/batman-adv/bat_v_elp.c
index 2ce4e5bf9292..fdc2abe96d77 100644
--- a/net/batman-adv/bat_v_elp.c
+++ b/net/batman-adv/bat_v_elp.c
@@ -111,7 +111,15 @@ static bool batadv_v_elp_get_throughput(struct batadv_hardif_neigh_node *neigh,
/* unsupported WiFi driver version */
goto default_throughput;
- real_netdev = batadv_get_real_netdev(hard_iface->net_dev);
+ /* only use rtnl_trylock because the elp worker will be cancelled while
+ * the rntl_lock is held. the cancel_delayed_work_sync() would otherwise
+ * wait forever when the elp work_item was started and it is then also
+ * trying to rtnl_lock
+ */
+ if (!rtnl_trylock())
+ return false;
+ real_netdev = __batadv_get_real_netdev(hard_iface->net_dev);
+ rtnl_unlock();
if (!real_netdev)
goto default_throughput;
diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c
index 7b7640f3ffe2..d6732c34aeaf 100644
--- a/net/batman-adv/hard-interface.c
+++ b/net/batman-adv/hard-interface.c
@@ -204,7 +204,7 @@ static bool batadv_is_valid_iface(const struct net_device *net_dev)
}
/**
- * batadv_get_real_netdevice() - check if the given netdev struct is a virtual
+ * __batadv_get_real_netdev() - check if the given netdev struct is a virtual
* interface on top of another 'real' interface
* @netdev: the device to check
*
@@ -214,7 +214,7 @@ static bool batadv_is_valid_iface(const struct net_device *net_dev)
* Return: the 'real' net device or the original net device and NULL in case
* of an error.
*/
-static struct net_device *batadv_get_real_netdevice(struct net_device *netdev)
+struct net_device *__batadv_get_real_netdev(struct net_device *netdev)
{
struct batadv_hard_iface *hard_iface = NULL;
struct net_device *real_netdev = NULL;
@@ -267,7 +267,7 @@ struct net_device *batadv_get_real_netdev(struct net_device *net_device)
struct net_device *real_netdev;
rtnl_lock();
- real_netdev = batadv_get_real_netdevice(net_device);
+ real_netdev = __batadv_get_real_netdev(net_device);
rtnl_unlock();
return real_netdev;
@@ -336,7 +336,7 @@ static u32 batadv_wifi_flags_evaluate(struct net_device *net_device)
if (batadv_is_cfg80211_netdev(net_device))
wifi_flags |= BATADV_HARDIF_WIFI_CFG80211_DIRECT;
- real_netdev = batadv_get_real_netdevice(net_device);
+ real_netdev = __batadv_get_real_netdev(net_device);
if (!real_netdev)
return wifi_flags;
diff --git a/net/batman-adv/hard-interface.h b/net/batman-adv/hard-interface.h
index 9db8a310961e..9ba8fb2bdceb 100644
--- a/net/batman-adv/hard-interface.h
+++ b/net/batman-adv/hard-interface.h
@@ -67,6 +67,7 @@ enum batadv_hard_if_bcast {
extern struct notifier_block batadv_hard_if_notifier;
+struct net_device *__batadv_get_real_netdev(struct net_device *net_device);
struct net_device *batadv_get_real_netdev(struct net_device *net_device);
bool batadv_is_cfg80211_hardif(struct batadv_hard_iface *hard_iface);
bool batadv_is_wifi_hardif(struct batadv_hard_iface *hard_iface);
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index ee01122f466f..f7502e62dd35 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -74,7 +74,7 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
br_do_proxy_suppress_arp(skb, br, vid, NULL);
- } else if (IS_ENABLED(CONFIG_IPV6) &&
+ } else if (ipv6_mod_enabled() &&
skb->protocol == htons(ETH_P_IPV6) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index 1405f1061a54..2cbae0f9ae1f 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -170,7 +170,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
(skb->protocol == htons(ETH_P_ARP) ||
skb->protocol == htons(ETH_P_RARP))) {
br_do_proxy_suppress_arp(skb, br, vid, p);
- } else if (IS_ENABLED(CONFIG_IPV6) &&
+ } else if (ipv6_mod_enabled() &&
skb->protocol == htons(ETH_P_IPV6) &&
br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED) &&
pskb_may_pull(skb, sizeof(struct ipv6hdr) +
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index b9b2981c4841..9b55d38ea9ed 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -1345,6 +1345,16 @@ br_multicast_ctx_options_equal(const struct net_bridge_mcast *brmctx1,
}
static inline bool
+br_multicast_port_ctx_options_equal(const struct net_bridge_mcast_port *pmctx1,
+ const struct net_bridge_mcast_port *pmctx2)
+{
+ return br_multicast_ngroups_get(pmctx1) ==
+ br_multicast_ngroups_get(pmctx2) &&
+ br_multicast_ngroups_get_max(pmctx1) ==
+ br_multicast_ngroups_get_max(pmctx2);
+}
+
+static inline bool
br_multicast_ctx_matches_vlan_snooping(const struct net_bridge_mcast *brmctx)
{
bool vlan_snooping_enabled;
diff --git a/net/bridge/br_vlan_options.c b/net/bridge/br_vlan_options.c
index 8fa89b04ee94..5514e1fc8d1f 100644
--- a/net/bridge/br_vlan_options.c
+++ b/net/bridge/br_vlan_options.c
@@ -43,9 +43,29 @@ bool br_vlan_opts_eq_range(const struct net_bridge_vlan *v_curr,
u8 range_mc_rtr = br_vlan_multicast_router(range_end);
u8 curr_mc_rtr = br_vlan_multicast_router(v_curr);
- return v_curr->state == range_end->state &&
- __vlan_tun_can_enter_range(v_curr, range_end) &&
- curr_mc_rtr == range_mc_rtr;
+ if (v_curr->state != range_end->state)
+ return false;
+
+ if (!__vlan_tun_can_enter_range(v_curr, range_end))
+ return false;
+
+ if (curr_mc_rtr != range_mc_rtr)
+ return false;
+
+ /* Check user-visible priv_flags that affect output */
+ if ((v_curr->priv_flags ^ range_end->priv_flags) &
+ (BR_VLFLAG_NEIGH_SUPPRESS_ENABLED | BR_VLFLAG_MCAST_ENABLED))
+ return false;
+
+#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
+ if (!br_vlan_is_master(v_curr) &&
+ !br_multicast_port_ctx_vlan_disabled(&v_curr->port_mcast_ctx) &&
+ !br_multicast_port_ctx_options_equal(&v_curr->port_mcast_ctx,
+ &range_end->port_mcast_ctx))
+ return false;
+#endif
+
+ return true;
}
bool br_vlan_opts_fill(struct sk_buff *skb, const struct net_bridge_vlan *v,
diff --git a/net/can/bcm.c b/net/can/bcm.c
index b7324e9c955b..fd9fa072881e 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1176,6 +1176,7 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg,
if (!op)
return -ENOMEM;
+ spin_lock_init(&op->bcm_tx_lock);
op->can_id = msg_head->can_id;
op->nframes = msg_head->nframes;
op->cfsiz = CFSIZ(msg_head->flags);
diff --git a/net/core/dev.c b/net/core/dev.c
index c1a9f7fdcffa..14a83f2035b9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3987,7 +3987,7 @@ static struct sk_buff *validate_xmit_unreadable_skb(struct sk_buff *skb,
if (shinfo->nr_frags > 0) {
niov = netmem_to_net_iov(skb_frag_netmem(&shinfo->frags[0]));
if (net_is_devmem_iov(niov) &&
- net_devmem_iov_binding(niov)->dev != dev)
+ READ_ONCE(net_devmem_iov_binding(niov)->dev) != dev)
goto out_free;
}
@@ -4818,10 +4818,7 @@ int __dev_queue_xmit(struct sk_buff *skb, struct net_device *sb_dev)
if (dev->flags & IFF_UP) {
int cpu = smp_processor_id(); /* ok because BHs are off */
- /* Other cpus might concurrently change txq->xmit_lock_owner
- * to -1 or to their cpu id, but not to our id.
- */
- if (READ_ONCE(txq->xmit_lock_owner) != cpu) {
+ if (!netif_tx_owned(txq, cpu)) {
bool is_list = false;
if (dev_xmit_recursion())
@@ -7794,11 +7791,12 @@ static int napi_thread_wait(struct napi_struct *napi)
return -1;
}
-static void napi_threaded_poll_loop(struct napi_struct *napi, bool busy_poll)
+static void napi_threaded_poll_loop(struct napi_struct *napi,
+ unsigned long *busy_poll_last_qs)
{
+ unsigned long last_qs = busy_poll_last_qs ? *busy_poll_last_qs : jiffies;
struct bpf_net_context __bpf_net_ctx, *bpf_net_ctx;
struct softnet_data *sd;
- unsigned long last_qs = jiffies;
for (;;) {
bool repoll = false;
@@ -7827,12 +7825,12 @@ static void napi_threaded_poll_loop(struct napi_struct *napi, bool busy_poll)
/* When busy poll is enabled, the old packets are not flushed in
* napi_complete_done. So flush them here.
*/
- if (busy_poll)
+ if (busy_poll_last_qs)
gro_flush_normal(&napi->gro, HZ >= 1000);
local_bh_enable();
/* Call cond_resched here to avoid watchdog warnings. */
- if (repoll || busy_poll) {
+ if (repoll || busy_poll_last_qs) {
rcu_softirq_qs_periodic(last_qs);
cond_resched();
}
@@ -7840,11 +7838,15 @@ static void napi_threaded_poll_loop(struct napi_struct *napi, bool busy_poll)
if (!repoll)
break;
}
+
+ if (busy_poll_last_qs)
+ *busy_poll_last_qs = last_qs;
}
static int napi_threaded_poll(void *data)
{
struct napi_struct *napi = data;
+ unsigned long last_qs = jiffies;
bool want_busy_poll;
bool in_busy_poll;
unsigned long val;
@@ -7862,7 +7864,7 @@ static int napi_threaded_poll(void *data)
assign_bit(NAPI_STATE_IN_BUSY_POLL, &napi->state,
want_busy_poll);
- napi_threaded_poll_loop(napi, want_busy_poll);
+ napi_threaded_poll_loop(napi, want_busy_poll ? &last_qs : NULL);
}
return 0;
@@ -13175,7 +13177,7 @@ static void run_backlog_napi(unsigned int cpu)
{
struct softnet_data *sd = per_cpu_ptr(&softnet_data, cpu);
- napi_threaded_poll_loop(&sd->backlog, false);
+ napi_threaded_poll_loop(&sd->backlog, NULL);
}
static void backlog_napi_setup(unsigned int cpu)
diff --git a/net/core/devmem.c b/net/core/devmem.c
index 8c9aad776bf4..69d79aee07ef 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c
@@ -396,7 +396,8 @@ struct net_devmem_dmabuf_binding *net_devmem_get_binding(struct sock *sk,
* net_device.
*/
dst_dev = dst_dev_rcu(dst);
- if (unlikely(!dst_dev) || unlikely(dst_dev != binding->dev)) {
+ if (unlikely(!dst_dev) ||
+ unlikely(dst_dev != READ_ONCE(binding->dev))) {
err = -ENODEV;
goto out_unlock;
}
@@ -513,7 +514,8 @@ static void mp_dmabuf_devmem_uninstall(void *mp_priv,
xa_erase(&binding->bound_rxqs, xa_idx);
if (xa_empty(&binding->bound_rxqs)) {
mutex_lock(&binding->lock);
- binding->dev = NULL;
+ ASSERT_EXCLUSIVE_WRITER(binding->dev);
+ WRITE_ONCE(binding->dev, NULL);
mutex_unlock(&binding->lock);
}
break;
diff --git a/net/core/filter.c b/net/core/filter.c
index 0d5d5a17acb2..a77d23fe2359 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -4150,12 +4150,14 @@ static int bpf_xdp_frags_increase_tail(struct xdp_buff *xdp, int offset)
struct skb_shared_info *sinfo = xdp_get_shared_info_from_buff(xdp);
skb_frag_t *frag = &sinfo->frags[sinfo->nr_frags - 1];
struct xdp_rxq_info *rxq = xdp->rxq;
- unsigned int tailroom;
+ int tailroom;
if (!rxq->frag_size || rxq->frag_size > xdp->frame_sz)
return -EOPNOTSUPP;
- tailroom = rxq->frag_size - skb_frag_size(frag) - skb_frag_off(frag);
+ tailroom = rxq->frag_size - skb_frag_size(frag) -
+ skb_frag_off(frag) % rxq->frag_size;
+ WARN_ON_ONCE(tailroom < 0);
if (unlikely(offset > tailroom))
return -EINVAL;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index a8558a52884f..cd74beffd209 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -132,7 +132,7 @@ static int netif_local_xmit_active(struct net_device *dev)
for (i = 0; i < dev->num_tx_queues; i++) {
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
- if (READ_ONCE(txq->xmit_lock_owner) == smp_processor_id())
+ if (netif_tx_owned(txq, smp_processor_id()))
return 1;
}
diff --git a/net/core/secure_seq.c b/net/core/secure_seq.c
index 9a3965680451..6a6f2cda5aae 100644
--- a/net/core/secure_seq.c
+++ b/net/core/secure_seq.c
@@ -20,7 +20,6 @@
#include <net/tcp.h>
static siphash_aligned_key_t net_secret;
-static siphash_aligned_key_t ts_secret;
#define EPHEMERAL_PORT_SHUFFLE_PERIOD (10 * HZ)
@@ -28,11 +27,6 @@ static __always_inline void net_secret_init(void)
{
net_get_random_once(&net_secret, sizeof(net_secret));
}
-
-static __always_inline void ts_secret_init(void)
-{
- net_get_random_once(&ts_secret, sizeof(ts_secret));
-}
#endif
#ifdef CONFIG_INET
@@ -53,28 +47,9 @@ static u32 seq_scale(u32 seq)
#endif
#if IS_ENABLED(CONFIG_IPV6)
-u32 secure_tcpv6_ts_off(const struct net *net,
- const __be32 *saddr, const __be32 *daddr)
-{
- const struct {
- struct in6_addr saddr;
- struct in6_addr daddr;
- } __aligned(SIPHASH_ALIGNMENT) combined = {
- .saddr = *(struct in6_addr *)saddr,
- .daddr = *(struct in6_addr *)daddr,
- };
-
- if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
- return 0;
-
- ts_secret_init();
- return siphash(&combined, offsetofend(typeof(combined), daddr),
- &ts_secret);
-}
-EXPORT_IPV6_MOD(secure_tcpv6_ts_off);
-
-u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
- __be16 sport, __be16 dport)
+union tcp_seq_and_ts_off
+secure_tcpv6_seq_and_ts_off(const struct net *net, const __be32 *saddr,
+ const __be32 *daddr, __be16 sport, __be16 dport)
{
const struct {
struct in6_addr saddr;
@@ -87,14 +62,20 @@ u32 secure_tcpv6_seq(const __be32 *saddr, const __be32 *daddr,
.sport = sport,
.dport = dport
};
- u32 hash;
+ union tcp_seq_and_ts_off st;
net_secret_init();
- hash = siphash(&combined, offsetofend(typeof(combined), dport),
- &net_secret);
- return seq_scale(hash);
+
+ st.hash64 = siphash(&combined, offsetofend(typeof(combined), dport),
+ &net_secret);
+
+ if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
+ st.ts_off = 0;
+
+ st.seq = seq_scale(st.seq);
+ return st;
}
-EXPORT_SYMBOL(secure_tcpv6_seq);
+EXPORT_SYMBOL(secure_tcpv6_seq_and_ts_off);
u64 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
__be16 dport)
@@ -118,33 +99,30 @@ EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
#endif
#ifdef CONFIG_INET
-u32 secure_tcp_ts_off(const struct net *net, __be32 saddr, __be32 daddr)
-{
- if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
- return 0;
-
- ts_secret_init();
- return siphash_2u32((__force u32)saddr, (__force u32)daddr,
- &ts_secret);
-}
-
/* secure_tcp_seq_and_tsoff(a, b, 0, d) == secure_ipv4_port_ephemeral(a, b, d),
* but fortunately, `sport' cannot be 0 in any circumstances. If this changes,
* it would be easy enough to have the former function use siphash_4u32, passing
* the arguments as separate u32.
*/
-u32 secure_tcp_seq(__be32 saddr, __be32 daddr,
- __be16 sport, __be16 dport)
+union tcp_seq_and_ts_off
+secure_tcp_seq_and_ts_off(const struct net *net, __be32 saddr, __be32 daddr,
+ __be16 sport, __be16 dport)
{
- u32 hash;
+ u32 ports = (__force u32)sport << 16 | (__force u32)dport;
+ union tcp_seq_and_ts_off st;
net_secret_init();
- hash = siphash_3u32((__force u32)saddr, (__force u32)daddr,
- (__force u32)sport << 16 | (__force u32)dport,
- &net_secret);
- return seq_scale(hash);
+
+ st.hash64 = siphash_3u32((__force u32)saddr, (__force u32)daddr,
+ ports, &net_secret);
+
+ if (READ_ONCE(net->ipv4.sysctl_tcp_timestamps) != 1)
+ st.ts_off = 0;
+
+ st.seq = seq_scale(st.seq);
+ return st;
}
-EXPORT_SYMBOL_GPL(secure_tcp_seq);
+EXPORT_SYMBOL_GPL(secure_tcp_seq_and_ts_off);
u64 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
{
diff --git a/net/core/skmsg.c b/net/core/skmsg.c
index 2e26174c9919..3261793abe83 100644
--- a/net/core/skmsg.c
+++ b/net/core/skmsg.c
@@ -1205,8 +1205,8 @@ void sk_psock_start_strp(struct sock *sk, struct sk_psock *psock)
return;
psock->saved_data_ready = sk->sk_data_ready;
- sk->sk_data_ready = sk_psock_strp_data_ready;
- sk->sk_write_space = sk_psock_write_space;
+ WRITE_ONCE(sk->sk_data_ready, sk_psock_strp_data_ready);
+ WRITE_ONCE(sk->sk_write_space, sk_psock_write_space);
}
void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
@@ -1216,8 +1216,8 @@ void sk_psock_stop_strp(struct sock *sk, struct sk_psock *psock)
if (!psock->saved_data_ready)
return;
- sk->sk_data_ready = psock->saved_data_ready;
- psock->saved_data_ready = NULL;
+ WRITE_ONCE(sk->sk_data_ready, psock->saved_data_ready);
+ WRITE_ONCE(psock->saved_data_ready, NULL);
strp_stop(&psock->strp);
}
@@ -1296,8 +1296,8 @@ void sk_psock_start_verdict(struct sock *sk, struct sk_psock *psock)
return;
psock->saved_data_ready = sk->sk_data_ready;
- sk->sk_data_ready = sk_psock_verdict_data_ready;
- sk->sk_write_space = sk_psock_write_space;
+ WRITE_ONCE(sk->sk_data_ready, sk_psock_verdict_data_ready);
+ WRITE_ONCE(sk->sk_write_space, sk_psock_write_space);
}
void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
@@ -1308,6 +1308,6 @@ void sk_psock_stop_verdict(struct sock *sk, struct sk_psock *psock)
if (!psock->saved_data_ready)
return;
- sk->sk_data_ready = psock->saved_data_ready;
+ WRITE_ONCE(sk->sk_data_ready, psock->saved_data_ready);
psock->saved_data_ready = NULL;
}
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index b71c22475c51..df922f9f5289 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -748,6 +748,7 @@ config TCP_SIGPOOL
config TCP_AO
bool "TCP: Authentication Option (RFC5925)"
select CRYPTO
+ select CRYPTO_LIB_UTILS
select TCP_SIGPOOL
depends on 64BIT && IPV6 != m # seq-number extension needs WRITE_ONCE(u64)
help
@@ -761,6 +762,7 @@ config TCP_AO
config TCP_MD5SIG
bool "TCP: MD5 Signature Option support (RFC2385)"
select CRYPTO_LIB_MD5
+ select CRYPTO_LIB_UTILS
help
RFC2385 specifies a method of giving MD5 protection to TCP sessions.
Its main (only?) use is to protect BGP sessions between core routers
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fca980772c81..9bfccc283fa6 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -200,7 +200,7 @@ static bool inet_bind2_bucket_addr_match(const struct inet_bind2_bucket *tb2,
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
struct inet_bind2_bucket *tb2, unsigned short port)
{
- inet_sk(sk)->inet_num = port;
+ WRITE_ONCE(inet_sk(sk)->inet_num, port);
inet_csk(sk)->icsk_bind_hash = tb;
inet_csk(sk)->icsk_bind2_hash = tb2;
sk_add_bind_node(sk, &tb2->owners);
@@ -224,7 +224,7 @@ static void __inet_put_port(struct sock *sk)
spin_lock(&head->lock);
tb = inet_csk(sk)->icsk_bind_hash;
inet_csk(sk)->icsk_bind_hash = NULL;
- inet_sk(sk)->inet_num = 0;
+ WRITE_ONCE(inet_sk(sk)->inet_num, 0);
sk->sk_userlocks &= ~SOCK_CONNECT_BIND;
spin_lock(&head2->lock);
@@ -352,7 +352,7 @@ static inline int compute_score(struct sock *sk, const struct net *net,
{
int score = -1;
- if (net_eq(sock_net(sk), net) && sk->sk_num == hnum &&
+ if (net_eq(sock_net(sk), net) && READ_ONCE(sk->sk_num) == hnum &&
!ipv6_only_sock(sk)) {
if (sk->sk_rcv_saddr != daddr)
return -1;
@@ -1206,7 +1206,7 @@ error:
sk->sk_hash = 0;
inet_sk(sk)->inet_sport = 0;
- inet_sk(sk)->inet_num = 0;
+ WRITE_ONCE(inet_sk(sk)->inet_num, 0);
if (tw)
inet_twsk_bind_unhash(tw, hinfo);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 061751aabc8e..fc3affd9c801 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -378,9 +378,14 @@ static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk,
tcp_parse_options(net, skb, &tcp_opt, 0, NULL);
if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) {
- tsoff = secure_tcp_ts_off(net,
- ip_hdr(skb)->daddr,
- ip_hdr(skb)->saddr);
+ union tcp_seq_and_ts_off st;
+
+ st = secure_tcp_seq_and_ts_off(net,
+ ip_hdr(skb)->daddr,
+ ip_hdr(skb)->saddr,
+ tcp_hdr(skb)->dest,
+ tcp_hdr(skb)->source);
+ tsoff = st.ts_off;
tcp_opt.rcv_tsecr -= tsoff;
}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 643763bc2142..5654cc9c8a0b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -486,7 +486,8 @@ static void proc_fib_multipath_hash_set_seed(struct net *net, u32 user_seed)
proc_fib_multipath_hash_rand_seed),
};
- WRITE_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed, new);
+ WRITE_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed.user_seed, new.user_seed);
+ WRITE_ONCE(net->ipv4.sysctl_fib_multipath_hash_seed.mp_seed, new.mp_seed);
}
static int proc_fib_multipath_hash_seed(const struct ctl_table *table, int write,
@@ -500,7 +501,7 @@ static int proc_fib_multipath_hash_seed(const struct ctl_table *table, int write
int ret;
mphs = &net->ipv4.sysctl_fib_multipath_hash_seed;
- user_seed = mphs->user_seed;
+ user_seed = READ_ONCE(mphs->user_seed);
tmp = *table;
tmp.data = &user_seed;
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f84d9a45cc9d..202a4e57a218 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -244,6 +244,7 @@
#define pr_fmt(fmt) "TCP: " fmt
#include <crypto/md5.h>
+#include <crypto/utils.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -1446,7 +1447,7 @@ out_err:
err = sk_stream_error(sk, flags, err);
/* make sure we wake any epoll edge trigger waiter */
if (unlikely(tcp_rtx_and_write_queues_empty(sk) && err == -EAGAIN)) {
- sk->sk_write_space(sk);
+ READ_ONCE(sk->sk_write_space)(sk);
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
}
if (binding)
@@ -4181,7 +4182,7 @@ ao_parse:
break;
case TCP_NOTSENT_LOWAT:
WRITE_ONCE(tp->notsent_lowat, val);
- sk->sk_write_space(sk);
+ READ_ONCE(sk->sk_write_space)(sk);
break;
case TCP_INQ:
if (val > 1 || val < 0)
@@ -4970,7 +4971,7 @@ tcp_inbound_md5_hash(const struct sock *sk, const struct sk_buff *skb,
tcp_v4_md5_hash_skb(newhash, key, NULL, skb);
else
tp->af_specific->calc_md5_hash(newhash, key, NULL, skb);
- if (memcmp(hash_location, newhash, 16) != 0) {
+ if (crypto_memneq(hash_location, newhash, 16)) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE);
trace_tcp_hash_md5_mismatch(sk, skb);
return SKB_DROP_REASON_TCP_MD5FAILURE;
diff --git a/net/ipv4/tcp_ao.c b/net/ipv4/tcp_ao.c
index 4980caddb0fc..a97cdf3e6af4 100644
--- a/net/ipv4/tcp_ao.c
+++ b/net/ipv4/tcp_ao.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) "TCP: " fmt
#include <crypto/hash.h>
+#include <crypto/utils.h>
#include <linux/inetdevice.h>
#include <linux/tcp.h>
@@ -922,7 +923,7 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
/* XXX: make it per-AF callback? */
tcp_ao_hash_skb(family, hash_buf, key, sk, skb, traffic_key,
(phash - (u8 *)th), sne);
- if (memcmp(phash, hash_buf, maclen)) {
+ if (crypto_memneq(phash, hash_buf, maclen)) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
atomic64_inc(&info->counters.pkt_bad);
atomic64_inc(&key->pkt_bad);
diff --git a/net/ipv4/tcp_bpf.c b/net/ipv4/tcp_bpf.c
index c449a044895e..813d2e498c93 100644
--- a/net/ipv4/tcp_bpf.c
+++ b/net/ipv4/tcp_bpf.c
@@ -725,7 +725,7 @@ int tcp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
WRITE_ONCE(sk->sk_prot->unhash, psock->saved_unhash);
tcp_update_ulp(sk, psock->sk_proto, psock->saved_write_space);
} else {
- sk->sk_write_space = psock->saved_write_space;
+ WRITE_ONCE(sk->sk_write_space, psock->saved_write_space);
/* Pairs with lockless read in sk_clone_lock() */
sock_replace_proto(sk, psock->sk_proto);
}
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index d83efd91f461..7935702e394b 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -509,7 +509,7 @@ next_chunk:
if (r->sdiag_family != AF_UNSPEC &&
sk->sk_family != r->sdiag_family)
goto next_normal;
- if (r->id.idiag_sport != htons(sk->sk_num) &&
+ if (r->id.idiag_sport != htons(READ_ONCE(sk->sk_num)) &&
r->id.idiag_sport)
goto next_normal;
if (r->id.idiag_dport != sk->sk_dport &&
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 41c57efd125c..cba89733d121 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5374,25 +5374,11 @@ static void tcp_ofo_queue(struct sock *sk)
static bool tcp_prune_ofo_queue(struct sock *sk, const struct sk_buff *in_skb);
static int tcp_prune_queue(struct sock *sk, const struct sk_buff *in_skb);
-/* Check if this incoming skb can be added to socket receive queues
- * while satisfying sk->sk_rcvbuf limit.
- *
- * In theory we should use skb->truesize, but this can cause problems
- * when applications use too small SO_RCVBUF values.
- * When LRO / hw gro is used, the socket might have a high tp->scaling_ratio,
- * allowing RWIN to be close to available space.
- * Whenever the receive queue gets full, we can receive a small packet
- * filling RWIN, but with a high skb->truesize, because most NIC use 4K page
- * plus sk_buff metadata even when receiving less than 1500 bytes of payload.
- *
- * Note that we use skb->len to decide to accept or drop this packet,
- * but sk->sk_rmem_alloc is the sum of all skb->truesize.
- */
static bool tcp_can_ingest(const struct sock *sk, const struct sk_buff *skb)
{
unsigned int rmem = atomic_read(&sk->sk_rmem_alloc);
- return rmem + skb->len <= sk->sk_rcvbuf;
+ return rmem <= sk->sk_rcvbuf;
}
static int tcp_try_rmem_schedule(struct sock *sk, const struct sk_buff *skb,
@@ -5425,7 +5411,7 @@ static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb)
if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFODROP);
- sk->sk_data_ready(sk);
+ READ_ONCE(sk->sk_data_ready)(sk);
tcp_drop_reason(sk, skb, SKB_DROP_REASON_PROTO_MEM);
return;
}
@@ -5635,7 +5621,7 @@ err:
void tcp_data_ready(struct sock *sk)
{
if (tcp_epollin_ready(sk, sk->sk_rcvlowat) || sock_flag(sk, SOCK_DONE))
- sk->sk_data_ready(sk);
+ READ_ONCE(sk->sk_data_ready)(sk);
}
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
@@ -5691,7 +5677,7 @@ queue_and_out:
inet_csk(sk)->icsk_ack.pending |=
(ICSK_ACK_NOMEM | ICSK_ACK_NOW);
inet_csk_schedule_ack(sk);
- sk->sk_data_ready(sk);
+ READ_ONCE(sk->sk_data_ready)(sk);
if (skb_queue_len(&sk->sk_receive_queue) && skb->len) {
reason = SKB_DROP_REASON_PROTO_MEM;
@@ -6114,7 +6100,9 @@ static void tcp_new_space(struct sock *sk)
tp->snd_cwnd_stamp = tcp_jiffies32;
}
- INDIRECT_CALL_1(sk->sk_write_space, sk_stream_write_space, sk);
+ INDIRECT_CALL_1(READ_ONCE(sk->sk_write_space),
+ sk_stream_write_space,
+ sk);
}
/* Caller made space either from:
@@ -6325,7 +6313,7 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *t
BUG();
WRITE_ONCE(tp->urg_data, TCP_URG_VALID | tmp);
if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk);
+ READ_ONCE(sk->sk_data_ready)(sk);
}
}
}
@@ -7658,6 +7646,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
const struct tcp_sock *tp = tcp_sk(sk);
struct net *net = sock_net(sk);
struct sock *fastopen_sk = NULL;
+ union tcp_seq_and_ts_off st;
struct request_sock *req;
bool want_cookie = false;
struct dst_entry *dst;
@@ -7727,9 +7716,12 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
if (!dst)
goto drop_and_free;
+ if (tmp_opt.tstamp_ok || (!want_cookie && !isn))
+ st = af_ops->init_seq_and_ts_off(net, skb);
+
if (tmp_opt.tstamp_ok) {
tcp_rsk(req)->req_usec_ts = dst_tcp_usec_ts(dst);
- tcp_rsk(req)->ts_off = af_ops->init_ts_off(net, skb);
+ tcp_rsk(req)->ts_off = st.ts_off;
}
if (!want_cookie && !isn) {
int max_syn_backlog = READ_ONCE(net->ipv4.sysctl_max_syn_backlog);
@@ -7751,7 +7743,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
goto drop_and_release;
}
- isn = af_ops->init_seq(skb);
+ isn = st.seq;
}
tcp_ecn_create_request(req, skb, sk, dst);
@@ -7792,7 +7784,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
sock_put(fastopen_sk);
goto drop_and_free;
}
- sk->sk_data_ready(sk);
+ READ_ONCE(sk->sk_data_ready)(sk);
bh_unlock_sock(fastopen_sk);
sock_put(fastopen_sk);
} else {
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d53d39be291a..c7b2463c2e25 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -88,6 +88,7 @@
#include <linux/skbuff_ref.h>
#include <crypto/md5.h>
+#include <crypto/utils.h>
#include <trace/events/tcp.h>
@@ -104,17 +105,14 @@ static DEFINE_PER_CPU(struct sock_bh_locked, ipv4_tcp_sk) = {
static DEFINE_MUTEX(tcp_exit_batch_mutex);
-static u32 tcp_v4_init_seq(const struct sk_buff *skb)
+static union tcp_seq_and_ts_off
+tcp_v4_init_seq_and_ts_off(const struct net *net, const struct sk_buff *skb)
{
- return secure_tcp_seq(ip_hdr(skb)->daddr,
- ip_hdr(skb)->saddr,
- tcp_hdr(skb)->dest,
- tcp_hdr(skb)->source);
-}
-
-static u32 tcp_v4_init_ts_off(const struct net *net, const struct sk_buff *skb)
-{
- return secure_tcp_ts_off(net, ip_hdr(skb)->daddr, ip_hdr(skb)->saddr);
+ return secure_tcp_seq_and_ts_off(net,
+ ip_hdr(skb)->daddr,
+ ip_hdr(skb)->saddr,
+ tcp_hdr(skb)->dest,
+ tcp_hdr(skb)->source);
}
int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
@@ -326,15 +324,16 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr_unsized *uaddr, int addr_len
rt = NULL;
if (likely(!tp->repair)) {
+ union tcp_seq_and_ts_off st;
+
+ st = secure_tcp_seq_and_ts_off(net,
+ inet->inet_saddr,
+ inet->inet_daddr,
+ inet->inet_sport,
+ usin->sin_port);
if (!tp->write_seq)
- WRITE_ONCE(tp->write_seq,
- secure_tcp_seq(inet->inet_saddr,
- inet->inet_daddr,
- inet->inet_sport,
- usin->sin_port));
- WRITE_ONCE(tp->tsoffset,
- secure_tcp_ts_off(net, inet->inet_saddr,
- inet->inet_daddr));
+ WRITE_ONCE(tp->write_seq, st.seq);
+ WRITE_ONCE(tp->tsoffset, st.ts_off);
}
atomic_set(&inet->inet_id, get_random_u16());
@@ -839,7 +838,7 @@ static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb,
goto out;
tcp_v4_md5_hash_skb(newhash, key, NULL, skb);
- if (memcmp(md5_hash_location, newhash, 16) != 0)
+ if (crypto_memneq(md5_hash_location, newhash, 16))
goto out;
}
@@ -1676,8 +1675,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
.cookie_init_seq = cookie_v4_init_sequence,
#endif
.route_req = tcp_v4_route_req,
- .init_seq = tcp_v4_init_seq,
- .init_ts_off = tcp_v4_init_ts_off,
+ .init_seq_and_ts_off = tcp_v4_init_seq_and_ts_off,
.send_synack = tcp_v4_send_synack,
};
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index d9c5a43bd281..dafb63b923d0 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -1004,7 +1004,7 @@ enum skb_drop_reason tcp_child_process(struct sock *parent, struct sock *child,
reason = tcp_rcv_state_process(child, skb);
/* Wakeup parent, send SIGIO */
if (state == TCP_SYN_RECV && child->sk_state != state)
- parent->sk_data_ready(parent);
+ READ_ONCE(parent->sk_data_ready)(parent);
} else {
/* Alas, it is possible again, because we do lookup
* in main socket hash table and lock on listening
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6c6b68a66dcd..b60fad393e18 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1787,7 +1787,7 @@ int __udp_enqueue_schedule_skb(struct sock *sk, struct sk_buff *skb)
* using prepare_to_wait_exclusive().
*/
while (nb) {
- INDIRECT_CALL_1(sk->sk_data_ready,
+ INDIRECT_CALL_1(READ_ONCE(sk->sk_data_ready),
sock_def_readable, sk);
nb--;
}
@@ -2287,7 +2287,6 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
udp_sk(sk)->udp_port_hash);
hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash);
nhslot2 = udp_hashslot2(udptable, newhash);
- udp_sk(sk)->udp_portaddr_hash = newhash;
if (hslot2 != nhslot2 ||
rcu_access_pointer(sk->sk_reuseport_cb)) {
@@ -2321,19 +2320,25 @@ void udp_lib_rehash(struct sock *sk, u16 newhash, u16 newhash4)
if (udp_hashed4(sk)) {
spin_lock_bh(&hslot->lock);
- udp_rehash4(udptable, sk, newhash4);
- if (hslot2 != nhslot2) {
- spin_lock(&hslot2->lock);
- udp_hash4_dec(hslot2);
- spin_unlock(&hslot2->lock);
-
- spin_lock(&nhslot2->lock);
- udp_hash4_inc(nhslot2);
- spin_unlock(&nhslot2->lock);
+ if (inet_rcv_saddr_any(sk)) {
+ udp_unhash4(udptable, sk);
+ } else {
+ udp_rehash4(udptable, sk, newhash4);
+ if (hslot2 != nhslot2) {
+ spin_lock(&hslot2->lock);
+ udp_hash4_dec(hslot2);
+ spin_unlock(&hslot2->lock);
+
+ spin_lock(&nhslot2->lock);
+ udp_hash4_inc(nhslot2);
+ spin_unlock(&nhslot2->lock);
+ }
}
spin_unlock_bh(&hslot->lock);
}
+
+ udp_sk(sk)->udp_portaddr_hash = newhash;
}
}
EXPORT_IPV6_MOD(udp_lib_rehash);
diff --git a/net/ipv4/udp_bpf.c b/net/ipv4/udp_bpf.c
index 91233e37cd97..779a3a03762f 100644
--- a/net/ipv4/udp_bpf.c
+++ b/net/ipv4/udp_bpf.c
@@ -158,7 +158,7 @@ int udp_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool restore)
int family = sk->sk_family == AF_INET ? UDP_BPF_IPV4 : UDP_BPF_IPV6;
if (restore) {
- sk->sk_write_space = psock->saved_write_space;
+ WRITE_ONCE(sk->sk_write_space, psock->saved_write_space);
sock_replace_proto(sk, psock->sk_proto);
return 0;
}
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 5e1da088d8e1..182d38e6d6d8 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -95,7 +95,8 @@ static inline int compute_score(struct sock *sk, const struct net *net,
{
int score = -1;
- if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum &&
+ if (net_eq(sock_net(sk), net) &&
+ READ_ONCE(inet_sk(sk)->inet_num) == hnum &&
sk->sk_family == PF_INET6) {
if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
return -1;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 85df25c36409..08cd86f49bf9 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1063,7 +1063,8 @@ static struct net_device *ip6_rt_get_dev_rcu(const struct fib6_result *res)
*/
if (netif_is_l3_slave(dev) &&
!rt6_need_strict(&res->f6i->fib6_dst.addr))
- dev = l3mdev_master_dev_rcu(dev);
+ dev = l3mdev_master_dev_rcu(dev) ? :
+ dev_net(dev)->loopback_dev;
else if (!netif_is_l3_master(dev))
dev = dev_net(dev)->loopback_dev;
/* last case is netif_is_l3_master(dev) is true in which
@@ -3582,7 +3583,6 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
netdevice_tracker *dev_tracker = &fib6_nh->fib_nh_dev_tracker;
struct net_device *dev = NULL;
struct inet6_dev *idev = NULL;
- int addr_type;
int err;
fib6_nh->fib_nh_family = AF_INET6;
@@ -3624,11 +3624,10 @@ int fib6_nh_init(struct net *net, struct fib6_nh *fib6_nh,
fib6_nh->fib_nh_weight = 1;
- /* We cannot add true routes via loopback here,
- * they would result in kernel looping; promote them to reject routes
+ /* Reset the nexthop device to the loopback device in case of reject
+ * routes.
*/
- addr_type = ipv6_addr_type(&cfg->fc_dst);
- if (fib6_is_reject(cfg->fc_flags, dev, addr_type)) {
+ if (cfg->fc_flags & RTF_REJECT) {
/* hold loopback dev/idev if we haven't done so. */
if (dev != net->loopback_dev) {
if (dev) {
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 7e007f013ec8..4f6f0d751d6c 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -151,9 +151,14 @@ static struct request_sock *cookie_tcp_check(struct net *net, struct sock *sk,
tcp_parse_options(net, skb, &tcp_opt, 0, NULL);
if (tcp_opt.saw_tstamp && tcp_opt.rcv_tsecr) {
- tsoff = secure_tcpv6_ts_off(net,
- ipv6_hdr(skb)->daddr.s6_addr32,
- ipv6_hdr(skb)->saddr.s6_addr32);
+ union tcp_seq_and_ts_off st;
+
+ st = secure_tcpv6_seq_and_ts_off(net,
+ ipv6_hdr(skb)->daddr.s6_addr32,
+ ipv6_hdr(skb)->saddr.s6_addr32,
+ tcp_hdr(skb)->dest,
+ tcp_hdr(skb)->source);
+ tsoff = st.ts_off;
tcp_opt.rcv_tsecr -= tsoff;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index e46a0efae012..bb09d5ccf599 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -68,6 +68,7 @@
#include <linux/seq_file.h>
#include <crypto/md5.h>
+#include <crypto/utils.h>
#include <trace/events/tcp.h>
@@ -104,18 +105,14 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
}
}
-static u32 tcp_v6_init_seq(const struct sk_buff *skb)
+static union tcp_seq_and_ts_off
+tcp_v6_init_seq_and_ts_off(const struct net *net, const struct sk_buff *skb)
{
- return secure_tcpv6_seq(ipv6_hdr(skb)->daddr.s6_addr32,
- ipv6_hdr(skb)->saddr.s6_addr32,
- tcp_hdr(skb)->dest,
- tcp_hdr(skb)->source);
-}
-
-static u32 tcp_v6_init_ts_off(const struct net *net, const struct sk_buff *skb)
-{
- return secure_tcpv6_ts_off(net, ipv6_hdr(skb)->daddr.s6_addr32,
- ipv6_hdr(skb)->saddr.s6_addr32);
+ return secure_tcpv6_seq_and_ts_off(net,
+ ipv6_hdr(skb)->daddr.s6_addr32,
+ ipv6_hdr(skb)->saddr.s6_addr32,
+ tcp_hdr(skb)->dest,
+ tcp_hdr(skb)->source);
}
static int tcp_v6_pre_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
@@ -319,14 +316,16 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr_unsized *uaddr,
sk_set_txhash(sk);
if (likely(!tp->repair)) {
+ union tcp_seq_and_ts_off st;
+
+ st = secure_tcpv6_seq_and_ts_off(net,
+ np->saddr.s6_addr32,
+ sk->sk_v6_daddr.s6_addr32,
+ inet->inet_sport,
+ inet->inet_dport);
if (!tp->write_seq)
- WRITE_ONCE(tp->write_seq,
- secure_tcpv6_seq(np->saddr.s6_addr32,
- sk->sk_v6_daddr.s6_addr32,
- inet->inet_sport,
- inet->inet_dport));
- tp->tsoffset = secure_tcpv6_ts_off(net, np->saddr.s6_addr32,
- sk->sk_v6_daddr.s6_addr32);
+ WRITE_ONCE(tp->write_seq, st.seq);
+ tp->tsoffset = st.ts_off;
}
if (tcp_fastopen_defer_connect(sk, &err))
@@ -816,8 +815,7 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
.cookie_init_seq = cookie_v6_init_sequence,
#endif
.route_req = tcp_v6_route_req,
- .init_seq = tcp_v6_init_seq,
- .init_ts_off = tcp_v6_init_ts_off,
+ .init_seq_and_ts_off = tcp_v6_init_seq_and_ts_off,
.send_synack = tcp_v6_send_synack,
};
@@ -1048,7 +1046,7 @@ static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb,
key.type = TCP_KEY_MD5;
tcp_v6_md5_hash_skb(newhash, key.md5_key, NULL, skb);
- if (memcmp(md5_hash_location, newhash, 16) != 0)
+ if (crypto_memneq(md5_hash_location, newhash, 16))
goto out;
}
#endif
diff --git a/net/mac80211/eht.c b/net/mac80211/eht.c
index 75096b2195d2..078e1e23d8d1 100644
--- a/net/mac80211/eht.c
+++ b/net/mac80211/eht.c
@@ -154,6 +154,7 @@ void ieee80211_rx_eml_op_mode_notif(struct ieee80211_sub_if_data *sdata,
u8 *ptr = mgmt->u.action.u.eml_omn.variable;
struct ieee80211_eml_params eml_params = {
.link_id = status->link_id,
+ .control = control,
};
struct sta_info *sta;
int opt_len = 0;
diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c
index 7298836469b3..57a456690406 100644
--- a/net/mptcp/pm.c
+++ b/net/mptcp/pm.c
@@ -212,9 +212,24 @@ void mptcp_pm_send_ack(struct mptcp_sock *msk,
spin_lock_bh(&msk->pm.lock);
}
-void mptcp_pm_addr_send_ack(struct mptcp_sock *msk)
+static bool subflow_in_rm_list(const struct mptcp_subflow_context *subflow,
+ const struct mptcp_rm_list *rm_list)
+{
+ u8 i, id = subflow_get_local_id(subflow);
+
+ for (i = 0; i < rm_list->nr; i++) {
+ if (rm_list->ids[i] == id)
+ return true;
+ }
+
+ return false;
+}
+
+static void
+mptcp_pm_addr_send_ack_avoid_list(struct mptcp_sock *msk,
+ const struct mptcp_rm_list *rm_list)
{
- struct mptcp_subflow_context *subflow, *alt = NULL;
+ struct mptcp_subflow_context *subflow, *stale = NULL, *same_id = NULL;
msk_owned_by_me(msk);
lockdep_assert_held(&msk->pm.lock);
@@ -224,19 +239,35 @@ void mptcp_pm_addr_send_ack(struct mptcp_sock *msk)
return;
mptcp_for_each_subflow(msk, subflow) {
- if (__mptcp_subflow_active(subflow)) {
- if (!subflow->stale) {
- mptcp_pm_send_ack(msk, subflow, false, false);
- return;
- }
+ if (!__mptcp_subflow_active(subflow))
+ continue;
- if (!alt)
- alt = subflow;
+ if (unlikely(subflow->stale)) {
+ if (!stale)
+ stale = subflow;
+ } else if (unlikely(rm_list &&
+ subflow_in_rm_list(subflow, rm_list))) {
+ if (!same_id)
+ same_id = subflow;
+ } else {
+ goto send_ack;
}
}
- if (alt)
- mptcp_pm_send_ack(msk, alt, false, false);
+ if (same_id)
+ subflow = same_id;
+ else if (stale)
+ subflow = stale;
+ else
+ return;
+
+send_ack:
+ mptcp_pm_send_ack(msk, subflow, false, false);
+}
+
+void mptcp_pm_addr_send_ack(struct mptcp_sock *msk)
+{
+ mptcp_pm_addr_send_ack_avoid_list(msk, NULL);
}
int mptcp_pm_mp_prio_send_ack(struct mptcp_sock *msk,
@@ -470,7 +501,7 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_
msk->pm.rm_list_tx = *rm_list;
rm_addr |= BIT(MPTCP_RM_ADDR_SIGNAL);
WRITE_ONCE(msk->pm.addr_signal, rm_addr);
- mptcp_pm_addr_send_ack(msk);
+ mptcp_pm_addr_send_ack_avoid_list(msk, rm_list);
return 0;
}
diff --git a/net/mptcp/pm_kernel.c b/net/mptcp/pm_kernel.c
index b5316a6c7d1b..b2b9df43960e 100644
--- a/net/mptcp/pm_kernel.c
+++ b/net/mptcp/pm_kernel.c
@@ -418,6 +418,15 @@ subflow:
}
exit:
+ /* If an endpoint has both the signal and subflow flags, but it is not
+ * possible to create subflows -- the 'while' loop body above never
+ * executed -- then still mark the endp as used, which is somehow the
+ * case. This avoids issues later when removing the endpoint and calling
+ * __mark_subflow_endp_available(), which expects the increment here.
+ */
+ if (signal_and_subflow && local.addr.id != msk->mpc_endpoint_id)
+ msk->pm.local_addr_used++;
+
mptcp_pm_nl_check_work_pending(msk);
}
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index fd7f7e4e2a43..1862bd7fe804 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -833,6 +833,11 @@ static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
}
}
+/* Use NFT_ITER_UPDATE iterator even if this may be called from the preparation
+ * phase, the set clone might already exist from a previous command, or it might
+ * be a set that is going away and does not require a clone. The netns and
+ * netlink release paths also need to work on the live set.
+ */
static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
@@ -7170,6 +7175,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
struct nft_data_desc desc;
enum nft_registers dreg;
struct nft_trans *trans;
+ bool set_full = false;
u64 expiration;
u64 timeout;
int err, i;
@@ -7461,10 +7467,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0)
goto err_elem_free;
+ if (!(flags & NFT_SET_ELEM_CATCHALL)) {
+ unsigned int max = nft_set_maxsize(set), nelems;
+
+ nelems = atomic_inc_return(&set->nelems);
+ if (nelems > max)
+ set_full = true;
+ }
+
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
if (trans == NULL) {
err = -ENOMEM;
- goto err_elem_free;
+ goto err_set_size;
}
ext->genmask = nft_genmask_cur(ctx->net);
@@ -7516,7 +7530,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
ue->priv = elem_priv;
nft_trans_commit_list_add_elem(ctx->net, trans);
- goto err_elem_free;
+ goto err_set_size;
}
}
}
@@ -7534,23 +7548,16 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
goto err_element_clash;
}
- if (!(flags & NFT_SET_ELEM_CATCHALL)) {
- unsigned int max = nft_set_maxsize(set);
-
- if (!atomic_add_unless(&set->nelems, 1, max)) {
- err = -ENFILE;
- goto err_set_full;
- }
- }
-
nft_trans_container_elem(trans)->elems[0].priv = elem.priv;
nft_trans_commit_list_add_elem(ctx->net, trans);
- return 0;
-err_set_full:
- nft_setelem_remove(ctx->net, set, elem.priv);
+ return set_full ? -ENFILE : 0;
+
err_element_clash:
kfree(trans);
+err_set_size:
+ if (!(flags & NFT_SET_ELEM_CATCHALL))
+ atomic_dec(&set->nelems);
err_elem_free:
nf_tables_set_elem_destroy(ctx, set, elem.priv);
err_parse_data:
@@ -7901,9 +7908,12 @@ static int nft_set_catchall_flush(const struct nft_ctx *ctx,
static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
{
+ /* The set backend might need to clone the set, do it now from the
+ * preparation phase, use NFT_ITER_UPDATE_CLONE iterator type.
+ */
struct nft_set_iter iter = {
.genmask = genmask,
- .type = NFT_ITER_UPDATE,
+ .type = NFT_ITER_UPDATE_CLONE,
.fn = nft_setelem_flush,
};
@@ -10483,11 +10493,6 @@ static void nft_trans_gc_queue_work(struct nft_trans_gc *trans)
schedule_work(&trans_gc_work);
}
-static int nft_trans_gc_space(struct nft_trans_gc *trans)
-{
- return NFT_TRANS_GC_BATCHCOUNT - trans->count;
-}
-
struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
unsigned int gc_seq, gfp_t gfp)
{
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index 739b992bde59..b0e571c8e3f3 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -374,6 +374,7 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
{
switch (iter->type) {
case NFT_ITER_UPDATE:
+ case NFT_ITER_UPDATE_CLONE:
/* only relevant for netlink dumps which use READ type */
WARN_ON_ONCE(iter->skip != 0);
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index 7ef4b44471d3..a34632ae6048 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -1680,11 +1680,11 @@ 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
+ * pipapo_gc_scan() - Drop expired entries from set and link them to gc list
* @set: nftables API set representation
* @m: Matching data
*/
-static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
+static void pipapo_gc_scan(struct nft_set *set, struct nft_pipapo_match *m)
{
struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
@@ -1697,6 +1697,8 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
if (!gc)
return;
+ list_add(&gc->list, &priv->gc_head);
+
while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) {
union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS];
const struct nft_pipapo_field *f;
@@ -1724,9 +1726,13 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
* NFT_SET_ELEM_DEAD_BIT.
*/
if (__nft_set_elem_expired(&e->ext, tstamp)) {
- gc = nft_trans_gc_queue_sync(gc, GFP_KERNEL);
- if (!gc)
- return;
+ if (!nft_trans_gc_space(gc)) {
+ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL);
+ if (!gc)
+ return;
+
+ list_add(&gc->list, &priv->gc_head);
+ }
nft_pipapo_gc_deactivate(net, set, e);
pipapo_drop(m, rulemap);
@@ -1740,10 +1746,30 @@ static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m)
}
}
- gc = nft_trans_gc_catchall_sync(gc);
+ priv->last_gc = jiffies;
+}
+
+/**
+ * pipapo_gc_queue() - Free expired elements
+ * @set: nftables API set representation
+ */
+static void pipapo_gc_queue(struct nft_set *set)
+{
+ struct nft_pipapo *priv = nft_set_priv(set);
+ struct nft_trans_gc *gc, *next;
+
+ /* always do a catchall cycle: */
+ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL);
if (gc) {
+ gc = nft_trans_gc_catchall_sync(gc);
+ if (gc)
+ nft_trans_gc_queue_sync_done(gc);
+ }
+
+ /* always purge queued gc elements. */
+ list_for_each_entry_safe(gc, next, &priv->gc_head, list) {
+ list_del(&gc->list);
nft_trans_gc_queue_sync_done(gc);
- priv->last_gc = jiffies;
}
}
@@ -1797,6 +1823,10 @@ static void pipapo_reclaim_match(struct rcu_head *rcu)
*
* We also need to create a new working copy for subsequent insertions and
* deletions.
+ *
+ * After the live copy has been replaced by the clone, we can safely queue
+ * expired elements that have been collected by pipapo_gc_scan() for
+ * memory reclaim.
*/
static void nft_pipapo_commit(struct nft_set *set)
{
@@ -1807,7 +1837,7 @@ static void nft_pipapo_commit(struct nft_set *set)
return;
if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set)))
- pipapo_gc(set, priv->clone);
+ pipapo_gc_scan(set, priv->clone);
old = rcu_replace_pointer(priv->match, priv->clone,
nft_pipapo_transaction_mutex_held(set));
@@ -1815,6 +1845,8 @@ static void nft_pipapo_commit(struct nft_set *set)
if (old)
call_rcu(&old->rcu, pipapo_reclaim_match);
+
+ pipapo_gc_queue(set);
}
static void nft_pipapo_abort(const struct nft_set *set)
@@ -2144,13 +2176,20 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
const struct nft_pipapo_match *m;
switch (iter->type) {
- case NFT_ITER_UPDATE:
+ case NFT_ITER_UPDATE_CLONE:
m = pipapo_maybe_clone(set);
if (!m) {
iter->err = -ENOMEM;
return;
}
-
+ nft_pipapo_do_walk(ctx, set, m, iter);
+ break;
+ case NFT_ITER_UPDATE:
+ if (priv->clone)
+ m = priv->clone;
+ else
+ m = rcu_dereference_protected(priv->match,
+ nft_pipapo_transaction_mutex_held(set));
nft_pipapo_do_walk(ctx, set, m, iter);
break;
case NFT_ITER_READ:
@@ -2272,6 +2311,7 @@ static int nft_pipapo_init(const struct nft_set *set,
f->mt = NULL;
}
+ INIT_LIST_HEAD(&priv->gc_head);
rcu_assign_pointer(priv->match, m);
return 0;
@@ -2321,6 +2361,8 @@ static void nft_pipapo_destroy(const struct nft_ctx *ctx,
struct nft_pipapo *priv = nft_set_priv(set);
struct nft_pipapo_match *m;
+ WARN_ON_ONCE(!list_empty(&priv->gc_head));
+
m = rcu_dereference_protected(priv->match, true);
if (priv->clone) {
diff --git a/net/netfilter/nft_set_pipapo.h b/net/netfilter/nft_set_pipapo.h
index eaab422aa56a..9aee9a9eaeb7 100644
--- a/net/netfilter/nft_set_pipapo.h
+++ b/net/netfilter/nft_set_pipapo.h
@@ -156,12 +156,14 @@ struct nft_pipapo_match {
* @clone: Copy where pending insertions and deletions are kept
* @width: Total bytes to be matched for one packet, including padding
* @last_gc: Timestamp of last garbage collection run, jiffies
+ * @gc_head: list of nft_trans_gc to queue up for mem reclaim
*/
struct nft_pipapo {
struct nft_pipapo_match __rcu *match;
struct nft_pipapo_match *clone;
int width;
unsigned long last_gc;
+ struct list_head gc_head;
};
struct nft_pipapo_elem;
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
index 3f02e4478216..ee3d4f5b9ff7 100644
--- a/net/netfilter/nft_set_rbtree.c
+++ b/net/netfilter/nft_set_rbtree.c
@@ -861,13 +861,15 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
struct nft_rbtree *priv = nft_set_priv(set);
switch (iter->type) {
- case NFT_ITER_UPDATE:
- lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex);
-
+ case NFT_ITER_UPDATE_CLONE:
if (nft_array_may_resize(set) < 0) {
iter->err = -ENOMEM;
break;
}
+ fallthrough;
+ case NFT_ITER_UPDATE:
+ lockdep_assert_held(&nft_pernet(ctx->net)->commit_mutex);
+
nft_rbtree_do_walk(ctx, set, iter);
break;
case NFT_ITER_READ:
diff --git a/net/nfc/digital_core.c b/net/nfc/digital_core.c
index 3670bb33732e..7cb1e6aaae90 100644
--- a/net/nfc/digital_core.c
+++ b/net/nfc/digital_core.c
@@ -707,8 +707,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
int rc;
data_exch = kzalloc_obj(*data_exch);
- if (!data_exch)
+ if (!data_exch) {
+ kfree_skb(skb);
return -ENOMEM;
+ }
data_exch->cb = cb;
data_exch->cb_context = cb_context;
@@ -731,8 +733,10 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
data_exch);
exit:
- if (rc)
+ if (rc) {
+ kfree_skb(skb);
kfree(data_exch);
+ }
return rc;
}
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
index 6e9b76e2cc56..43d871525dbc 100644
--- a/net/nfc/nci/core.c
+++ b/net/nfc/nci/core.c
@@ -567,6 +567,10 @@ static int nci_close_device(struct nci_dev *ndev)
flush_workqueue(ndev->cmd_wq);
timer_delete_sync(&ndev->cmd_timer);
timer_delete_sync(&ndev->data_timer);
+ if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ nci_data_exchange_complete(ndev, NULL,
+ ndev->cur_conn_id,
+ -ENODEV);
mutex_unlock(&ndev->req_lock);
return 0;
}
@@ -598,6 +602,11 @@ static int nci_close_device(struct nci_dev *ndev)
flush_workqueue(ndev->cmd_wq);
timer_delete_sync(&ndev->cmd_timer);
+ timer_delete_sync(&ndev->data_timer);
+
+ if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ nci_data_exchange_complete(ndev, NULL, ndev->cur_conn_id,
+ -ENODEV);
/* Clear flags except NCI_UNREG */
ndev->flags &= BIT(NCI_UNREG);
@@ -1035,18 +1044,23 @@ static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
struct nci_conn_info *conn_info;
conn_info = ndev->rf_conn_info;
- if (!conn_info)
+ if (!conn_info) {
+ kfree_skb(skb);
return -EPROTO;
+ }
pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
if (!ndev->target_active_prot) {
pr_err("unable to exchange data, no active target\n");
+ kfree_skb(skb);
return -EINVAL;
}
- if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+ if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags)) {
+ kfree_skb(skb);
return -EBUSY;
+ }
/* store cb and context to be used on receiving data */
conn_info->data_exchange_cb = cb;
@@ -1482,10 +1496,20 @@ static bool nci_valid_size(struct sk_buff *skb)
unsigned int hdr_size = NCI_CTRL_HDR_SIZE;
if (skb->len < hdr_size ||
- !nci_plen(skb->data) ||
skb->len < hdr_size + nci_plen(skb->data)) {
return false;
}
+
+ if (!nci_plen(skb->data)) {
+ /* Allow zero length in proprietary notifications (0x20 - 0x3F). */
+ if (nci_opcode_oid(nci_opcode(skb->data)) >= 0x20 &&
+ nci_mt(skb->data) == NCI_MT_NTF_PKT)
+ return true;
+
+ /* Disallow zero length otherwise. */
+ return false;
+ }
+
return true;
}
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
index 78f4131af3cf..5f98c73db5af 100644
--- a/net/nfc/nci/data.c
+++ b/net/nfc/nci/data.c
@@ -33,7 +33,8 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
if (!conn_info) {
kfree_skb(skb);
- goto exit;
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+ return;
}
cb = conn_info->data_exchange_cb;
@@ -45,6 +46,12 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
timer_delete_sync(&ndev->data_timer);
clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
+ /* Mark the exchange as done before calling the callback.
+ * The callback (e.g. rawsock_data_exchange_complete) may
+ * want to immediately queue another data exchange.
+ */
+ clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+
if (cb) {
/* forward skb to nfc core */
cb(cb_context, skb, err);
@@ -54,9 +61,6 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
/* no waiting callback, free skb */
kfree_skb(skb);
}
-
-exit:
- clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
}
/* ----------------- NCI TX Data ----------------- */
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
index b049022399ae..f7d7a599fade 100644
--- a/net/nfc/rawsock.c
+++ b/net/nfc/rawsock.c
@@ -67,6 +67,17 @@ static int rawsock_release(struct socket *sock)
if (sock->type == SOCK_RAW)
nfc_sock_unlink(&raw_sk_list, sk);
+ if (sk->sk_state == TCP_ESTABLISHED) {
+ /* Prevent rawsock_tx_work from starting new transmits and
+ * wait for any in-progress work to finish. This must happen
+ * before the socket is orphaned to avoid a race where
+ * rawsock_tx_work runs after the NCI device has been freed.
+ */
+ sk->sk_shutdown |= SEND_SHUTDOWN;
+ cancel_work_sync(&nfc_rawsock(sk)->tx_work);
+ rawsock_write_queue_purge(sk);
+ }
+
sock_orphan(sk);
sock_put(sk);
diff --git a/net/rds/tcp.c b/net/rds/tcp.c
index 04f310255692..654e23d13e3d 100644
--- a/net/rds/tcp.c
+++ b/net/rds/tcp.c
@@ -490,18 +490,24 @@ bool rds_tcp_tune(struct socket *sock)
struct rds_tcp_net *rtn;
tcp_sock_set_nodelay(sock->sk);
- lock_sock(sk);
/* TCP timer functions might access net namespace even after
* a process which created this net namespace terminated.
*/
if (!sk->sk_net_refcnt) {
- if (!maybe_get_net(net)) {
- release_sock(sk);
+ if (!maybe_get_net(net))
return false;
- }
+ /*
+ * sk_net_refcnt_upgrade() must be called before lock_sock()
+ * because it does a GFP_KERNEL allocation, which can trigger
+ * fs_reclaim and create a circular lock dependency with the
+ * socket lock. The fields it modifies (sk_net_refcnt,
+ * ns_tracker) are not accessed by any concurrent code path
+ * at this point.
+ */
sk_net_refcnt_upgrade(sk);
put_net(net);
}
+ lock_sock(sk);
rtn = net_generic(net, rds_tcp_netid);
if (rtn->sndbuf_size > 0) {
sk->sk_sndbuf = rtn->sndbuf_size;
diff --git a/net/sched/act_ct.c b/net/sched/act_ct.c
index bd51522c7953..7d5e50c921a0 100644
--- a/net/sched/act_ct.c
+++ b/net/sched/act_ct.c
@@ -1360,6 +1360,12 @@ static int tcf_ct_init(struct net *net, struct nlattr *nla,
return -EINVAL;
}
+ if (bind && !(flags & TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT)) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Attaching ct to a non ingress/clsact qdisc is unsupported");
+ return -EOPNOTSUPP;
+ }
+
err = nla_parse_nested(tb, TCA_CT_MAX, nla, ct_policy, extack);
if (err < 0)
return err;
diff --git a/net/sched/act_gate.c b/net/sched/act_gate.c
index 686eaed81b81..fdbfcaa3e2ab 100644
--- a/net/sched/act_gate.c
+++ b/net/sched/act_gate.c
@@ -32,9 +32,12 @@ static ktime_t gate_get_time(struct tcf_gate *gact)
return KTIME_MAX;
}
-static void gate_get_start_time(struct tcf_gate *gact, ktime_t *start)
+static void tcf_gate_params_free_rcu(struct rcu_head *head);
+
+static void gate_get_start_time(struct tcf_gate *gact,
+ const struct tcf_gate_params *param,
+ ktime_t *start)
{
- struct tcf_gate_params *param = &gact->param;
ktime_t now, base, cycle;
u64 n;
@@ -69,12 +72,14 @@ static enum hrtimer_restart gate_timer_func(struct hrtimer *timer)
{
struct tcf_gate *gact = container_of(timer, struct tcf_gate,
hitimer);
- struct tcf_gate_params *p = &gact->param;
struct tcfg_gate_entry *next;
+ struct tcf_gate_params *p;
ktime_t close_time, now;
spin_lock(&gact->tcf_lock);
+ p = rcu_dereference_protected(gact->param,
+ lockdep_is_held(&gact->tcf_lock));
next = gact->next_entry;
/* cycle start, clear pending bit, clear total octets */
@@ -225,6 +230,35 @@ static void release_entry_list(struct list_head *entries)
}
}
+static int tcf_gate_copy_entries(struct tcf_gate_params *dst,
+ const struct tcf_gate_params *src,
+ struct netlink_ext_ack *extack)
+{
+ struct tcfg_gate_entry *entry;
+ int i = 0;
+
+ list_for_each_entry(entry, &src->entries, list) {
+ struct tcfg_gate_entry *new;
+
+ new = kzalloc(sizeof(*new), GFP_ATOMIC);
+ if (!new) {
+ NL_SET_ERR_MSG(extack, "Not enough memory for entry");
+ return -ENOMEM;
+ }
+
+ new->index = entry->index;
+ new->gate_state = entry->gate_state;
+ new->interval = entry->interval;
+ new->ipv = entry->ipv;
+ new->maxoctets = entry->maxoctets;
+ list_add_tail(&new->list, &dst->entries);
+ i++;
+ }
+
+ dst->num_entries = i;
+ return 0;
+}
+
static int parse_gate_list(struct nlattr *list_attr,
struct tcf_gate_params *sched,
struct netlink_ext_ack *extack)
@@ -270,24 +304,44 @@ release_list:
return err;
}
-static void gate_setup_timer(struct tcf_gate *gact, u64 basetime,
- enum tk_offsets tko, s32 clockid,
- bool do_init)
+static bool gate_timer_needs_cancel(u64 basetime, u64 old_basetime,
+ enum tk_offsets tko,
+ enum tk_offsets old_tko,
+ s32 clockid, s32 old_clockid)
{
- if (!do_init) {
- if (basetime == gact->param.tcfg_basetime &&
- tko == gact->tk_offset &&
- clockid == gact->param.tcfg_clockid)
- return;
+ return basetime != old_basetime ||
+ clockid != old_clockid ||
+ tko != old_tko;
+}
- spin_unlock_bh(&gact->tcf_lock);
- hrtimer_cancel(&gact->hitimer);
- spin_lock_bh(&gact->tcf_lock);
+static int gate_clock_resolve(s32 clockid, enum tk_offsets *tko,
+ struct netlink_ext_ack *extack)
+{
+ switch (clockid) {
+ case CLOCK_REALTIME:
+ *tko = TK_OFFS_REAL;
+ return 0;
+ case CLOCK_MONOTONIC:
+ *tko = TK_OFFS_MAX;
+ return 0;
+ case CLOCK_BOOTTIME:
+ *tko = TK_OFFS_BOOT;
+ return 0;
+ case CLOCK_TAI:
+ *tko = TK_OFFS_TAI;
+ return 0;
+ default:
+ NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
+ return -EINVAL;
}
- gact->param.tcfg_basetime = basetime;
- gact->param.tcfg_clockid = clockid;
- gact->tk_offset = tko;
- hrtimer_setup(&gact->hitimer, gate_timer_func, clockid, HRTIMER_MODE_ABS_SOFT);
+}
+
+static void gate_setup_timer(struct tcf_gate *gact, s32 clockid,
+ enum tk_offsets tko)
+{
+ WRITE_ONCE(gact->tk_offset, tko);
+ hrtimer_setup(&gact->hitimer, gate_timer_func, clockid,
+ HRTIMER_MODE_ABS_SOFT);
}
static int tcf_gate_init(struct net *net, struct nlattr *nla,
@@ -296,15 +350,22 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
struct netlink_ext_ack *extack)
{
struct tc_action_net *tn = net_generic(net, act_gate_ops.net_id);
- enum tk_offsets tk_offset = TK_OFFS_TAI;
+ u64 cycletime = 0, basetime = 0, cycletime_ext = 0;
+ struct tcf_gate_params *p = NULL, *old_p = NULL;
+ enum tk_offsets old_tk_offset = TK_OFFS_TAI;
+ const struct tcf_gate_params *cur_p = NULL;
bool bind = flags & TCA_ACT_FLAGS_BIND;
struct nlattr *tb[TCA_GATE_MAX + 1];
+ enum tk_offsets tko = TK_OFFS_TAI;
struct tcf_chain *goto_ch = NULL;
- u64 cycletime = 0, basetime = 0;
- struct tcf_gate_params *p;
+ s32 timer_clockid = CLOCK_TAI;
+ bool use_old_entries = false;
+ s32 old_clockid = CLOCK_TAI;
+ bool need_cancel = false;
s32 clockid = CLOCK_TAI;
struct tcf_gate *gact;
struct tc_gate *parm;
+ u64 old_basetime = 0;
int ret = 0, err;
u32 gflags = 0;
s32 prio = -1;
@@ -321,26 +382,8 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (!tb[TCA_GATE_PARMS])
return -EINVAL;
- if (tb[TCA_GATE_CLOCKID]) {
+ if (tb[TCA_GATE_CLOCKID])
clockid = nla_get_s32(tb[TCA_GATE_CLOCKID]);
- switch (clockid) {
- case CLOCK_REALTIME:
- tk_offset = TK_OFFS_REAL;
- break;
- case CLOCK_MONOTONIC:
- tk_offset = TK_OFFS_MAX;
- break;
- case CLOCK_BOOTTIME:
- tk_offset = TK_OFFS_BOOT;
- break;
- case CLOCK_TAI:
- tk_offset = TK_OFFS_TAI;
- break;
- default:
- NL_SET_ERR_MSG(extack, "Invalid 'clockid'");
- return -EINVAL;
- }
- }
parm = nla_data(tb[TCA_GATE_PARMS]);
index = parm->index;
@@ -366,6 +409,60 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
return -EEXIST;
}
+ gact = to_gate(*a);
+
+ err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
+ if (err < 0)
+ goto release_idr;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ err = -ENOMEM;
+ goto chain_put;
+ }
+ INIT_LIST_HEAD(&p->entries);
+
+ use_old_entries = !tb[TCA_GATE_ENTRY_LIST];
+ if (!use_old_entries) {
+ err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
+ if (err < 0)
+ goto err_free;
+ use_old_entries = !err;
+ }
+
+ if (ret == ACT_P_CREATED && use_old_entries) {
+ NL_SET_ERR_MSG(extack, "The entry list is empty");
+ err = -EINVAL;
+ goto err_free;
+ }
+
+ if (ret != ACT_P_CREATED) {
+ rcu_read_lock();
+ cur_p = rcu_dereference(gact->param);
+
+ old_basetime = cur_p->tcfg_basetime;
+ old_clockid = cur_p->tcfg_clockid;
+ old_tk_offset = READ_ONCE(gact->tk_offset);
+
+ basetime = old_basetime;
+ cycletime_ext = cur_p->tcfg_cycletime_ext;
+ prio = cur_p->tcfg_priority;
+ gflags = cur_p->tcfg_flags;
+
+ if (!tb[TCA_GATE_CLOCKID])
+ clockid = old_clockid;
+
+ err = 0;
+ if (use_old_entries) {
+ err = tcf_gate_copy_entries(p, cur_p, extack);
+ if (!err && !tb[TCA_GATE_CYCLE_TIME])
+ cycletime = cur_p->tcfg_cycletime;
+ }
+ rcu_read_unlock();
+ if (err)
+ goto err_free;
+ }
+
if (tb[TCA_GATE_PRIORITY])
prio = nla_get_s32(tb[TCA_GATE_PRIORITY]);
@@ -375,25 +472,26 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (tb[TCA_GATE_FLAGS])
gflags = nla_get_u32(tb[TCA_GATE_FLAGS]);
- gact = to_gate(*a);
- if (ret == ACT_P_CREATED)
- INIT_LIST_HEAD(&gact->param.entries);
+ if (tb[TCA_GATE_CYCLE_TIME])
+ cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
- err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
- if (err < 0)
- goto release_idr;
+ if (tb[TCA_GATE_CYCLE_TIME_EXT])
+ cycletime_ext = nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
- spin_lock_bh(&gact->tcf_lock);
- p = &gact->param;
+ err = gate_clock_resolve(clockid, &tko, extack);
+ if (err)
+ goto err_free;
+ timer_clockid = clockid;
- if (tb[TCA_GATE_CYCLE_TIME])
- cycletime = nla_get_u64(tb[TCA_GATE_CYCLE_TIME]);
+ need_cancel = ret != ACT_P_CREATED &&
+ gate_timer_needs_cancel(basetime, old_basetime,
+ tko, old_tk_offset,
+ timer_clockid, old_clockid);
- if (tb[TCA_GATE_ENTRY_LIST]) {
- err = parse_gate_list(tb[TCA_GATE_ENTRY_LIST], p, extack);
- if (err < 0)
- goto chain_put;
- }
+ if (need_cancel)
+ hrtimer_cancel(&gact->hitimer);
+
+ spin_lock_bh(&gact->tcf_lock);
if (!cycletime) {
struct tcfg_gate_entry *entry;
@@ -402,22 +500,20 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
list_for_each_entry(entry, &p->entries, list)
cycle = ktime_add_ns(cycle, entry->interval);
cycletime = cycle;
- if (!cycletime) {
- err = -EINVAL;
- goto chain_put;
- }
}
p->tcfg_cycletime = cycletime;
+ p->tcfg_cycletime_ext = cycletime_ext;
- if (tb[TCA_GATE_CYCLE_TIME_EXT])
- p->tcfg_cycletime_ext =
- nla_get_u64(tb[TCA_GATE_CYCLE_TIME_EXT]);
-
- gate_setup_timer(gact, basetime, tk_offset, clockid,
- ret == ACT_P_CREATED);
+ if (need_cancel || ret == ACT_P_CREATED)
+ gate_setup_timer(gact, timer_clockid, tko);
p->tcfg_priority = prio;
p->tcfg_flags = gflags;
- gate_get_start_time(gact, &start);
+ p->tcfg_basetime = basetime;
+ p->tcfg_clockid = timer_clockid;
+ gate_get_start_time(gact, p, &start);
+
+ old_p = rcu_replace_pointer(gact->param, p,
+ lockdep_is_held(&gact->tcf_lock));
gact->current_close_time = start;
gact->current_gate_status = GATE_ACT_GATE_OPEN | GATE_ACT_PENDING;
@@ -434,11 +530,15 @@ static int tcf_gate_init(struct net *net, struct nlattr *nla,
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
+ if (old_p)
+ call_rcu(&old_p->rcu, tcf_gate_params_free_rcu);
+
return ret;
+err_free:
+ release_entry_list(&p->entries);
+ kfree(p);
chain_put:
- spin_unlock_bh(&gact->tcf_lock);
-
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
release_idr:
@@ -446,21 +546,29 @@ release_idr:
* without taking tcf_lock.
*/
if (ret == ACT_P_CREATED)
- gate_setup_timer(gact, gact->param.tcfg_basetime,
- gact->tk_offset, gact->param.tcfg_clockid,
- true);
+ gate_setup_timer(gact, timer_clockid, tko);
+
tcf_idr_release(*a, bind);
return err;
}
+static void tcf_gate_params_free_rcu(struct rcu_head *head)
+{
+ struct tcf_gate_params *p = container_of(head, struct tcf_gate_params, rcu);
+
+ release_entry_list(&p->entries);
+ kfree(p);
+}
+
static void tcf_gate_cleanup(struct tc_action *a)
{
struct tcf_gate *gact = to_gate(a);
struct tcf_gate_params *p;
- p = &gact->param;
hrtimer_cancel(&gact->hitimer);
- release_entry_list(&p->entries);
+ p = rcu_dereference_protected(gact->param, 1);
+ if (p)
+ call_rcu(&p->rcu, tcf_gate_params_free_rcu);
}
static int dumping_entry(struct sk_buff *skb,
@@ -509,10 +617,9 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc_action *a,
struct nlattr *entry_list;
struct tcf_t t;
- spin_lock_bh(&gact->tcf_lock);
- opt.action = gact->tcf_action;
-
- p = &gact->param;
+ rcu_read_lock();
+ opt.action = READ_ONCE(gact->tcf_action);
+ p = rcu_dereference(gact->param);
if (nla_put(skb, TCA_GATE_PARMS, sizeof(opt), &opt))
goto nla_put_failure;
@@ -552,12 +659,12 @@ static int tcf_gate_dump(struct sk_buff *skb, struct tc_action *a,
tcf_tm_dump(&t, &gact->tcf_tm);
if (nla_put_64bit(skb, TCA_GATE_TM, sizeof(t), &t, TCA_GATE_PAD))
goto nla_put_failure;
- spin_unlock_bh(&gact->tcf_lock);
+ rcu_read_unlock();
return skb->len;
nla_put_failure:
- spin_unlock_bh(&gact->tcf_lock);
+ rcu_read_unlock();
nlmsg_trim(skb, b);
return -1;
}
diff --git a/net/sched/act_ife.c b/net/sched/act_ife.c
index 79df81d12894..d5e8a91bb4eb 100644
--- a/net/sched/act_ife.c
+++ b/net/sched/act_ife.c
@@ -293,8 +293,8 @@ static int load_metaops_and_vet(u32 metaid, void *val, int len, bool rtnl_held)
/* called when adding new meta information
*/
static int __add_metainfo(const struct tcf_meta_ops *ops,
- struct tcf_ife_info *ife, u32 metaid, void *metaval,
- int len, bool atomic, bool exists)
+ struct tcf_ife_params *p, u32 metaid, void *metaval,
+ int len, bool atomic)
{
struct tcf_meta_info *mi = NULL;
int ret = 0;
@@ -313,45 +313,40 @@ static int __add_metainfo(const struct tcf_meta_ops *ops,
}
}
- if (exists)
- spin_lock_bh(&ife->tcf_lock);
- list_add_tail(&mi->metalist, &ife->metalist);
- if (exists)
- spin_unlock_bh(&ife->tcf_lock);
+ list_add_tail(&mi->metalist, &p->metalist);
return ret;
}
static int add_metainfo_and_get_ops(const struct tcf_meta_ops *ops,
- struct tcf_ife_info *ife, u32 metaid,
- bool exists)
+ struct tcf_ife_params *p, u32 metaid)
{
int ret;
if (!try_module_get(ops->owner))
return -ENOENT;
- ret = __add_metainfo(ops, ife, metaid, NULL, 0, true, exists);
+ ret = __add_metainfo(ops, p, metaid, NULL, 0, true);
if (ret)
module_put(ops->owner);
return ret;
}
-static int add_metainfo(struct tcf_ife_info *ife, u32 metaid, void *metaval,
- int len, bool exists)
+static int add_metainfo(struct tcf_ife_params *p, u32 metaid, void *metaval,
+ int len)
{
const struct tcf_meta_ops *ops = find_ife_oplist(metaid);
int ret;
if (!ops)
return -ENOENT;
- ret = __add_metainfo(ops, ife, metaid, metaval, len, false, exists);
+ ret = __add_metainfo(ops, p, metaid, metaval, len, false);
if (ret)
/*put back what find_ife_oplist took */
module_put(ops->owner);
return ret;
}
-static int use_all_metadata(struct tcf_ife_info *ife, bool exists)
+static int use_all_metadata(struct tcf_ife_params *p)
{
struct tcf_meta_ops *o;
int rc = 0;
@@ -359,7 +354,7 @@ static int use_all_metadata(struct tcf_ife_info *ife, bool exists)
read_lock(&ife_mod_lock);
list_for_each_entry(o, &ifeoplist, list) {
- rc = add_metainfo_and_get_ops(o, ife, o->metaid, exists);
+ rc = add_metainfo_and_get_ops(o, p, o->metaid);
if (rc == 0)
installed += 1;
}
@@ -371,7 +366,7 @@ static int use_all_metadata(struct tcf_ife_info *ife, bool exists)
return -EINVAL;
}
-static int dump_metalist(struct sk_buff *skb, struct tcf_ife_info *ife)
+static int dump_metalist(struct sk_buff *skb, struct tcf_ife_params *p)
{
struct tcf_meta_info *e;
struct nlattr *nest;
@@ -379,14 +374,14 @@ static int dump_metalist(struct sk_buff *skb, struct tcf_ife_info *ife)
int total_encoded = 0;
/*can only happen on decode */
- if (list_empty(&ife->metalist))
+ if (list_empty(&p->metalist))
return 0;
nest = nla_nest_start_noflag(skb, TCA_IFE_METALST);
if (!nest)
goto out_nlmsg_trim;
- list_for_each_entry(e, &ife->metalist, metalist) {
+ list_for_each_entry(e, &p->metalist, metalist) {
if (!e->ops->get(skb, e))
total_encoded += 1;
}
@@ -403,13 +398,11 @@ out_nlmsg_trim:
return -1;
}
-/* under ife->tcf_lock */
-static void _tcf_ife_cleanup(struct tc_action *a)
+static void __tcf_ife_cleanup(struct tcf_ife_params *p)
{
- struct tcf_ife_info *ife = to_ife(a);
struct tcf_meta_info *e, *n;
- list_for_each_entry_safe(e, n, &ife->metalist, metalist) {
+ list_for_each_entry_safe(e, n, &p->metalist, metalist) {
list_del(&e->metalist);
if (e->metaval) {
if (e->ops->release)
@@ -422,18 +415,23 @@ static void _tcf_ife_cleanup(struct tc_action *a)
}
}
+static void tcf_ife_cleanup_params(struct rcu_head *head)
+{
+ struct tcf_ife_params *p = container_of(head, struct tcf_ife_params,
+ rcu);
+
+ __tcf_ife_cleanup(p);
+ kfree(p);
+}
+
static void tcf_ife_cleanup(struct tc_action *a)
{
struct tcf_ife_info *ife = to_ife(a);
struct tcf_ife_params *p;
- spin_lock_bh(&ife->tcf_lock);
- _tcf_ife_cleanup(a);
- spin_unlock_bh(&ife->tcf_lock);
-
p = rcu_dereference_protected(ife->params, 1);
if (p)
- kfree_rcu(p, rcu);
+ call_rcu(&p->rcu, tcf_ife_cleanup_params);
}
static int load_metalist(struct nlattr **tb, bool rtnl_held)
@@ -455,8 +453,7 @@ static int load_metalist(struct nlattr **tb, bool rtnl_held)
return 0;
}
-static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
- bool exists, bool rtnl_held)
+static int populate_metalist(struct tcf_ife_params *p, struct nlattr **tb)
{
int len = 0;
int rc = 0;
@@ -468,7 +465,7 @@ static int populate_metalist(struct tcf_ife_info *ife, struct nlattr **tb,
val = nla_data(tb[i]);
len = nla_len(tb[i]);
- rc = add_metainfo(ife, i, val, len, exists);
+ rc = add_metainfo(p, i, val, len);
if (rc)
return rc;
}
@@ -523,6 +520,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
p = kzalloc_obj(*p);
if (!p)
return -ENOMEM;
+ INIT_LIST_HEAD(&p->metalist);
if (tb[TCA_IFE_METALST]) {
err = nla_parse_nested_deprecated(tb2, IFE_META_MAX,
@@ -567,8 +565,6 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
}
ife = to_ife(*a);
- if (ret == ACT_P_CREATED)
- INIT_LIST_HEAD(&ife->metalist);
err = tcf_action_check_ctrlact(parm->action, tp, &goto_ch, extack);
if (err < 0)
@@ -600,8 +596,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
}
if (tb[TCA_IFE_METALST]) {
- err = populate_metalist(ife, tb2, exists,
- !(flags & TCA_ACT_FLAGS_NO_RTNL));
+ err = populate_metalist(p, tb2);
if (err)
goto metadata_parse_err;
} else {
@@ -610,7 +605,7 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
* as we can. You better have at least one else we are
* going to bail out
*/
- err = use_all_metadata(ife, exists);
+ err = use_all_metadata(p);
if (err)
goto metadata_parse_err;
}
@@ -626,13 +621,14 @@ static int tcf_ife_init(struct net *net, struct nlattr *nla,
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
if (p)
- kfree_rcu(p, rcu);
+ call_rcu(&p->rcu, tcf_ife_cleanup_params);
return ret;
metadata_parse_err:
if (goto_ch)
tcf_chain_put_by_act(goto_ch);
release_idr:
+ __tcf_ife_cleanup(p);
kfree(p);
tcf_idr_release(*a, bind);
return err;
@@ -679,7 +675,7 @@ static int tcf_ife_dump(struct sk_buff *skb, struct tc_action *a, int bind,
if (nla_put(skb, TCA_IFE_TYPE, 2, &p->eth_type))
goto nla_put_failure;
- if (dump_metalist(skb, ife)) {
+ if (dump_metalist(skb, p)) {
/*ignore failure to dump metalist */
pr_info("Failed to dump metalist\n");
}
@@ -693,13 +689,13 @@ nla_put_failure:
return -1;
}
-static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_info *ife,
+static int find_decode_metaid(struct sk_buff *skb, struct tcf_ife_params *p,
u16 metaid, u16 mlen, void *mdata)
{
struct tcf_meta_info *e;
/* XXX: use hash to speed up */
- list_for_each_entry(e, &ife->metalist, metalist) {
+ list_for_each_entry_rcu(e, &p->metalist, metalist) {
if (metaid == e->metaid) {
if (e->ops) {
/* We check for decode presence already */
@@ -716,10 +712,13 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
{
struct tcf_ife_info *ife = to_ife(a);
int action = ife->tcf_action;
+ struct tcf_ife_params *p;
u8 *ifehdr_end;
u8 *tlv_data;
u16 metalen;
+ p = rcu_dereference_bh(ife->params);
+
bstats_update(this_cpu_ptr(ife->common.cpu_bstats), skb);
tcf_lastuse_update(&ife->tcf_tm);
@@ -745,7 +744,7 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
return TC_ACT_SHOT;
}
- if (find_decode_metaid(skb, ife, mtype, dlen, curr_data)) {
+ if (find_decode_metaid(skb, p, mtype, dlen, curr_data)) {
/* abuse overlimits to count when we receive metadata
* but dont have an ops for it
*/
@@ -769,12 +768,12 @@ static int tcf_ife_decode(struct sk_buff *skb, const struct tc_action *a,
/*XXX: check if we can do this at install time instead of current
* send data path
**/
-static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_info *ife)
+static int ife_get_sz(struct sk_buff *skb, struct tcf_ife_params *p)
{
- struct tcf_meta_info *e, *n;
+ struct tcf_meta_info *e;
int tot_run_sz = 0, run_sz = 0;
- list_for_each_entry_safe(e, n, &ife->metalist, metalist) {
+ list_for_each_entry_rcu(e, &p->metalist, metalist) {
if (e->ops->check_presence) {
run_sz = e->ops->check_presence(skb, e);
tot_run_sz += run_sz;
@@ -795,7 +794,7 @@ static int tcf_ife_encode(struct sk_buff *skb, const struct tc_action *a,
OUTERHDR:TOTMETALEN:{TLVHDR:Metadatum:TLVHDR..}:ORIGDATA
where ORIGDATA = original ethernet header ...
*/
- u16 metalen = ife_get_sz(skb, ife);
+ u16 metalen = ife_get_sz(skb, p);
int hdrm = metalen + skb->dev->hard_header_len + IFE_METAHDRLEN;
unsigned int skboff = 0;
int new_len = skb->len + hdrm;
@@ -833,25 +832,21 @@ drop:
if (!ife_meta)
goto drop;
- spin_lock(&ife->tcf_lock);
-
/* XXX: we dont have a clever way of telling encode to
* not repeat some of the computations that are done by
* ops->presence_check...
*/
- list_for_each_entry(e, &ife->metalist, metalist) {
+ list_for_each_entry_rcu(e, &p->metalist, metalist) {
if (e->ops->encode) {
err = e->ops->encode(skb, (void *)(ife_meta + skboff),
e);
}
if (err < 0) {
/* too corrupt to keep around if overwritten */
- spin_unlock(&ife->tcf_lock);
goto drop;
}
skboff += err;
}
- spin_unlock(&ife->tcf_lock);
oethh = (struct ethhdr *)skb->data;
if (!is_zero_ether_addr(p->eth_src))
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 343309e9009b..4829c27446e3 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -2228,6 +2228,11 @@ static bool is_qdisc_ingress(__u32 classid)
return (TC_H_MIN(classid) == TC_H_MIN(TC_H_MIN_INGRESS));
}
+static bool is_ingress_or_clsact(struct tcf_block *block, struct Qdisc *q)
+{
+ return tcf_block_shared(block) || (q && !!(q->flags & TCQ_F_INGRESS));
+}
+
static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n,
struct netlink_ext_ack *extack)
{
@@ -2420,6 +2425,8 @@ replay:
flags |= TCA_ACT_FLAGS_NO_RTNL;
if (is_qdisc_ingress(parent))
flags |= TCA_ACT_FLAGS_AT_INGRESS;
+ if (is_ingress_or_clsact(block, q))
+ flags |= TCA_ACT_FLAGS_AT_INGRESS_OR_CLSACT;
err = tp->ops->change(net, skb, tp, cl, t->tcm_handle, tca, &fh,
flags, extack);
if (err == 0) {
diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index a01f14b1c216..9efe23f8371b 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -391,8 +391,8 @@ static const u32 inv_sqrt_cache[REC_INV_SQRT_CACHE] = {
1239850263, 1191209601, 1147878294, 1108955788
};
-static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
- u64 target_ns, u64 rtt_est_ns);
+static void cake_configure_rates(struct Qdisc *sch, u64 rate, bool rate_adjust);
+
/* http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
* new_invsqrt = (invsqrt / 2) * (3 - count * invsqrt^2)
*
@@ -2013,7 +2013,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
u64 delay;
u32 len;
- if (q->config->is_shared && now - q->last_checked_active >= q->config->sync_time) {
+ if (q->config->is_shared && q->rate_ns &&
+ now - q->last_checked_active >= q->config->sync_time) {
struct net_device *dev = qdisc_dev(sch);
struct cake_sched_data *other_priv;
u64 new_rate = q->config->rate_bps;
@@ -2039,12 +2040,9 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
if (num_active_qs > 1)
new_rate = div64_u64(q->config->rate_bps, num_active_qs);
- /* mtu = 0 is used to only update the rate and not mess with cobalt params */
- cake_set_rate(b, new_rate, 0, 0, 0);
+ cake_configure_rates(sch, new_rate, true);
q->last_checked_active = now;
q->active_queues = num_active_qs;
- q->rate_ns = b->tin_rate_ns;
- q->rate_shft = b->tin_rate_shft;
}
begin:
@@ -2361,12 +2359,10 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu,
b->cparams.p_dec = 1 << 20; /* 1/4096 */
}
-static int cake_config_besteffort(struct Qdisc *sch)
+static int cake_config_besteffort(struct Qdisc *sch, u64 rate, u32 mtu)
{
struct cake_sched_data *q = qdisc_priv(sch);
struct cake_tin_data *b = &q->tins[0];
- u32 mtu = psched_mtu(qdisc_dev(sch));
- u64 rate = q->config->rate_bps;
q->tin_cnt = 1;
@@ -2380,12 +2376,10 @@ static int cake_config_besteffort(struct Qdisc *sch)
return 0;
}
-static int cake_config_precedence(struct Qdisc *sch)
+static int cake_config_precedence(struct Qdisc *sch, u64 rate, u32 mtu)
{
/* convert high-level (user visible) parameters into internal format */
struct cake_sched_data *q = qdisc_priv(sch);
- u32 mtu = psched_mtu(qdisc_dev(sch));
- u64 rate = q->config->rate_bps;
u32 quantum = 256;
u32 i;
@@ -2456,7 +2450,7 @@ static int cake_config_precedence(struct Qdisc *sch)
* Total 12 traffic classes.
*/
-static int cake_config_diffserv8(struct Qdisc *sch)
+static int cake_config_diffserv8(struct Qdisc *sch, u64 rate, u32 mtu)
{
/* Pruned list of traffic classes for typical applications:
*
@@ -2473,8 +2467,6 @@ static int cake_config_diffserv8(struct Qdisc *sch)
*/
struct cake_sched_data *q = qdisc_priv(sch);
- u32 mtu = psched_mtu(qdisc_dev(sch));
- u64 rate = q->config->rate_bps;
u32 quantum = 256;
u32 i;
@@ -2504,7 +2496,7 @@ static int cake_config_diffserv8(struct Qdisc *sch)
return 0;
}
-static int cake_config_diffserv4(struct Qdisc *sch)
+static int cake_config_diffserv4(struct Qdisc *sch, u64 rate, u32 mtu)
{
/* Further pruned list of traffic classes for four-class system:
*
@@ -2517,8 +2509,6 @@ static int cake_config_diffserv4(struct Qdisc *sch)
*/
struct cake_sched_data *q = qdisc_priv(sch);
- u32 mtu = psched_mtu(qdisc_dev(sch));
- u64 rate = q->config->rate_bps;
u32 quantum = 1024;
q->tin_cnt = 4;
@@ -2546,7 +2536,7 @@ static int cake_config_diffserv4(struct Qdisc *sch)
return 0;
}
-static int cake_config_diffserv3(struct Qdisc *sch)
+static int cake_config_diffserv3(struct Qdisc *sch, u64 rate, u32 mtu)
{
/* Simplified Diffserv structure with 3 tins.
* Latency Sensitive (CS7, CS6, EF, VA, TOS4)
@@ -2554,8 +2544,6 @@ static int cake_config_diffserv3(struct Qdisc *sch)
* Low Priority (LE, CS1)
*/
struct cake_sched_data *q = qdisc_priv(sch);
- u32 mtu = psched_mtu(qdisc_dev(sch));
- u64 rate = q->config->rate_bps;
u32 quantum = 1024;
q->tin_cnt = 3;
@@ -2580,32 +2568,33 @@ static int cake_config_diffserv3(struct Qdisc *sch)
return 0;
}
-static void cake_reconfigure(struct Qdisc *sch)
+static void cake_configure_rates(struct Qdisc *sch, u64 rate, bool rate_adjust)
{
+ u32 mtu = likely(rate_adjust) ? 0 : psched_mtu(qdisc_dev(sch));
struct cake_sched_data *qd = qdisc_priv(sch);
struct cake_sched_config *q = qd->config;
int c, ft;
switch (q->tin_mode) {
case CAKE_DIFFSERV_BESTEFFORT:
- ft = cake_config_besteffort(sch);
+ ft = cake_config_besteffort(sch, rate, mtu);
break;
case CAKE_DIFFSERV_PRECEDENCE:
- ft = cake_config_precedence(sch);
+ ft = cake_config_precedence(sch, rate, mtu);
break;
case CAKE_DIFFSERV_DIFFSERV8:
- ft = cake_config_diffserv8(sch);
+ ft = cake_config_diffserv8(sch, rate, mtu);
break;
case CAKE_DIFFSERV_DIFFSERV4:
- ft = cake_config_diffserv4(sch);
+ ft = cake_config_diffserv4(sch, rate, mtu);
break;
case CAKE_DIFFSERV_DIFFSERV3:
default:
- ft = cake_config_diffserv3(sch);
+ ft = cake_config_diffserv3(sch, rate, mtu);
break;
}
@@ -2616,6 +2605,14 @@ static void cake_reconfigure(struct Qdisc *sch)
qd->rate_ns = qd->tins[ft].tin_rate_ns;
qd->rate_shft = qd->tins[ft].tin_rate_shft;
+}
+
+static void cake_reconfigure(struct Qdisc *sch)
+{
+ struct cake_sched_data *qd = qdisc_priv(sch);
+ struct cake_sched_config *q = qd->config;
+
+ cake_configure_rates(sch, qd->config->rate_bps, false);
if (q->buffer_config_limit) {
qd->buffer_limit = q->buffer_config_limit;
diff --git a/net/sched/sch_ets.c b/net/sched/sch_ets.c
index 306e046276d4..a4b07b661b77 100644
--- a/net/sched/sch_ets.c
+++ b/net/sched/sch_ets.c
@@ -115,12 +115,12 @@ static void ets_offload_change(struct Qdisc *sch)
struct ets_sched *q = qdisc_priv(sch);
struct tc_ets_qopt_offload qopt;
unsigned int w_psum_prev = 0;
- unsigned int q_psum = 0;
- unsigned int q_sum = 0;
unsigned int quantum;
unsigned int w_psum;
unsigned int weight;
unsigned int i;
+ u64 q_psum = 0;
+ u64 q_sum = 0;
if (!tc_can_offload(dev) || !dev->netdev_ops->ndo_setup_tc)
return;
@@ -138,8 +138,12 @@ static void ets_offload_change(struct Qdisc *sch)
for (i = 0; i < q->nbands; i++) {
quantum = q->classes[i].quantum;
- q_psum += quantum;
- w_psum = quantum ? q_psum * 100 / q_sum : 0;
+ if (quantum) {
+ q_psum += quantum;
+ w_psum = div64_u64(q_psum * 100, q_sum);
+ } else {
+ w_psum = 0;
+ }
weight = w_psum - w_psum_prev;
w_psum_prev = w_psum;
diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c
index 80235e85f844..05084c9af48e 100644
--- a/net/sched/sch_fq.c
+++ b/net/sched/sch_fq.c
@@ -827,6 +827,7 @@ static void fq_reset(struct Qdisc *sch)
for (idx = 0; idx < FQ_BANDS; idx++) {
q->band_flows[idx].new_flows.first = NULL;
q->band_flows[idx].old_flows.first = NULL;
+ q->band_pkt_count[idx] = 0;
}
q->delayed = RB_ROOT;
q->flows = 0;
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 3756a93dc63a..7eaa5b187fef 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1785,7 +1785,7 @@ restart:
__skb_queue_tail(&other->sk_receive_queue, skb);
spin_unlock(&other->sk_receive_queue.lock);
unix_state_unlock(other);
- other->sk_data_ready(other);
+ READ_ONCE(other->sk_data_ready)(other);
sock_put(other);
return 0;
@@ -2278,7 +2278,7 @@ restart_locked:
scm_stat_add(other, skb);
skb_queue_tail(&other->sk_receive_queue, skb);
unix_state_unlock(other);
- other->sk_data_ready(other);
+ READ_ONCE(other->sk_data_ready)(other);
sock_put(other);
scm_destroy(&scm);
return len;
@@ -2351,7 +2351,7 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
sk_send_sigurg(other);
unix_state_unlock(other);
- other->sk_data_ready(other);
+ READ_ONCE(other->sk_data_ready)(other);
return 0;
out_unlock:
@@ -2477,7 +2477,7 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
spin_unlock(&other->sk_receive_queue.lock);
unix_state_unlock(other);
- other->sk_data_ready(other);
+ READ_ONCE(other->sk_data_ready)(other);
sent += size;
}
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 3b46bc635c43..6149f6a79897 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -167,26 +167,32 @@ static int xsk_rcv_zc(struct xdp_sock *xs, struct xdp_buff *xdp, u32 len)
struct xdp_buff_xsk *pos, *tmp;
struct list_head *xskb_list;
u32 contd = 0;
+ u32 num_desc;
int err;
- if (frags)
- contd = XDP_PKT_CONTD;
+ if (likely(!frags)) {
+ err = __xsk_rcv_zc(xs, xskb, len, contd);
+ if (err)
+ goto err;
+ return 0;
+ }
- err = __xsk_rcv_zc(xs, xskb, len, contd);
- if (err)
+ contd = XDP_PKT_CONTD;
+ num_desc = xdp_get_shared_info_from_buff(xdp)->nr_frags + 1;
+ if (xskq_prod_nb_free(xs->rx, num_desc) < num_desc) {
+ xs->rx_queue_full++;
+ err = -ENOBUFS;
goto err;
- if (likely(!frags))
- return 0;
+ }
+ __xsk_rcv_zc(xs, xskb, len, contd);
xskb_list = &xskb->pool->xskb_list;
list_for_each_entry_safe(pos, tmp, xskb_list, list_node) {
if (list_is_singular(xskb_list))
contd = 0;
len = pos->xdp.data_end - pos->xdp.data;
- err = __xsk_rcv_zc(xs, pos, len, contd);
- if (err)
- goto err;
- list_del(&pos->list_node);
+ __xsk_rcv_zc(xs, pos, len, contd);
+ list_del_init(&pos->list_node);
}
return 0;
diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs
index f93f24a60bdd..a1edf7491579 100644
--- a/rust/kernel/kunit.rs
+++ b/rust/kernel/kunit.rs
@@ -14,6 +14,10 @@ use crate::prelude::*;
/// Public but hidden since it should only be used from KUnit generated code.
#[doc(hidden)]
pub fn err(args: fmt::Arguments<'_>) {
+ // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
+ #[cfg(not(CONFIG_PRINTK))]
+ let _ = args;
+
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
// are passing.
#[cfg(CONFIG_PRINTK)]
@@ -30,6 +34,10 @@ pub fn err(args: fmt::Arguments<'_>) {
/// Public but hidden since it should only be used from KUnit generated code.
#[doc(hidden)]
pub fn info(args: fmt::Arguments<'_>) {
+ // `args` is unused if `CONFIG_PRINTK` is not set - this avoids a build-time warning.
+ #[cfg(not(CONFIG_PRINTK))]
+ let _ = args;
+
// SAFETY: The format string is null-terminated and the `%pA` specifier matches the argument we
// are passing.
#[cfg(CONFIG_PRINTK)]
diff --git a/scripts/genksyms/parse.y b/scripts/genksyms/parse.y
index efdcf07c4eb6..cabcd146f3aa 100644
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -325,8 +325,8 @@ direct_declarator:
{ $$ = $4; }
| direct_declarator BRACKET_PHRASE
{ $$ = $2; }
- | '(' declarator ')'
- { $$ = $3; }
+ | '(' attribute_opt declarator ')'
+ { $$ = $4; }
;
/* Nested declarators differ from regular declarators in that they do
diff --git a/scripts/package/install-extmod-build b/scripts/package/install-extmod-build
index 2576cf7902db..f12e1ffe409e 100755
--- a/scripts/package/install-extmod-build
+++ b/scripts/package/install-extmod-build
@@ -32,6 +32,10 @@ mkdir -p "${destdir}"
echo tools/objtool/objtool
fi
+ if is_enabled CONFIG_DEBUG_INFO_BTF_MODULES; then
+ echo tools/bpf/resolve_btfids/resolve_btfids
+ fi
+
echo Module.symvers
echo "arch/${SRCARCH}/include/generated"
echo include/config/auto.conf
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 85d265c7d544..f7a50bae4b55 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -122,7 +122,7 @@ static void dice_card_strings(struct snd_dice *dice)
fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
strscpy(model, "?");
fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
- snprintf(card->longname, sizeof(card->longname),
+ scnprintf(card->longname, sizeof(card->longname),
"%s %s (serial %u) at %s, S%d",
vendor, model, dev->config_rom[4] & 0x3fffff,
dev_name(&dice->unit->device), 100 << dev->max_speed);
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
index bf342a76807c..a0677d7da8e2 100644
--- a/sound/hda/codecs/ca0132.c
+++ b/sound/hda/codecs/ca0132.c
@@ -9816,6 +9816,15 @@ static void ca0132_config(struct hda_codec *codec)
spec->dig_in = 0x09;
break;
}
+
+ /* Default HP/Speaker auto-detect from headphone pin verb: enable if the
+ * pin config indicates presence detect (not AC_DEFCFG_MISC_NO_PRESENCE).
+ */
+ if (spec->unsol_tag_hp &&
+ (snd_hda_query_pin_caps(codec, spec->unsol_tag_hp) & AC_PINCAP_PRES_DETECT) &&
+ !(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, spec->unsol_tag_hp)) &
+ AC_DEFCFG_MISC_NO_PRESENCE))
+ spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID] = 1;
}
static int ca0132_prepare_verbs(struct hda_codec *codec)
diff --git a/sound/hda/codecs/hdmi/tegrahdmi.c b/sound/hda/codecs/hdmi/tegrahdmi.c
index 5f6fe31aa202..ebb6410a4831 100644
--- a/sound/hda/codecs/hdmi/tegrahdmi.c
+++ b/sound/hda/codecs/hdmi/tegrahdmi.c
@@ -299,6 +299,7 @@ static const struct hda_device_id snd_hda_id_tegrahdmi[] = {
HDA_CODEC_ID_MODEL(0x10de002f, "Tegra194 HDMI/DP2", MODEL_TEGRA),
HDA_CODEC_ID_MODEL(0x10de0030, "Tegra194 HDMI/DP3", MODEL_TEGRA),
HDA_CODEC_ID_MODEL(0x10de0031, "Tegra234 HDMI/DP", MODEL_TEGRA234),
+ HDA_CODEC_ID_MODEL(0x10de0032, "Tegra238 HDMI/DP", MODEL_TEGRA234),
HDA_CODEC_ID_MODEL(0x10de0033, "SoC 33 HDMI/DP", MODEL_TEGRA234),
HDA_CODEC_ID_MODEL(0x10de0034, "Tegra264 HDMI/DP", MODEL_TEGRA234),
HDA_CODEC_ID_MODEL(0x10de0035, "SoC 35 HDMI/DP", MODEL_TEGRA234),
diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 86bb22d19629..4c49f1195e1b 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -6904,6 +6904,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x103c, 0x88b3, "HP ENVY x360 Convertible 15-es0xxx", ALC245_FIXUP_HP_ENVY_X360_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x88d1, "HP Pavilion 15-eh1xxx (mainboard 88D1)", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED),
SND_PCI_QUIRK(0x103c, 0x88eb, "HP Victus 16-e0xxx", ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT),
SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c
index 3a50d4b3a064..6239a25bb8f3 100644
--- a/sound/hda/codecs/senarytech.c
+++ b/sound/hda/codecs/senarytech.c
@@ -19,15 +19,13 @@
#include "hda_jack.h"
#include "generic.h"
-/* GPIO node ID */
-#define SENARY_GPIO_NODE 0x01
-
struct senary_spec {
struct hda_gen_spec gen;
/* extra EAPD pins */
unsigned int num_eapds;
hda_nid_t eapds[4];
+ bool dynamic_eapd;
hda_nid_t mute_led_eapd;
unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
@@ -123,19 +121,23 @@ static void senary_init_gpio_led(struct hda_codec *codec)
unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
if (mask) {
- snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_MASK,
+ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_MASK,
mask);
- snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DIRECTION,
+ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DIRECTION,
mask);
- snd_hda_codec_write(codec, SENARY_GPIO_NODE, 0, AC_VERB_SET_GPIO_DATA,
+ snd_hda_codec_write(codec, codec->core.afg, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
}
}
static int senary_init(struct hda_codec *codec)
{
+ struct senary_spec *spec = codec->spec;
+
snd_hda_gen_init(codec);
senary_init_gpio_led(codec);
+ if (!spec->dynamic_eapd)
+ senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
return 0;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index 74c3cf1e45e1..67240ce184e1 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -60,7 +60,6 @@ struct tas2781_hda_i2c_priv {
int (*save_calibration)(struct tas2781_hda *h);
int hda_chip_id;
- bool skip_calibration;
};
static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
@@ -479,8 +478,7 @@ static void tasdevice_dspfw_init(void *context)
/* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
*/
- if (!hda_priv->skip_calibration)
- hda_priv->save_calibration(tas_hda);
+ hda_priv->save_calibration(tas_hda);
}
static void tasdev_fw_ready(const struct firmware *fmw, void *context)
@@ -535,7 +533,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
void *master_data)
{
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
- struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
struct hda_component_parent *parent = master_data;
struct hda_component *comp;
struct hda_codec *codec;
@@ -564,14 +561,6 @@ static int tas2781_hda_bind(struct device *dev, struct device *master,
break;
}
- /*
- * Using ASUS ROG Xbox Ally X (RC73XA) UEFI calibration data
- * causes audio dropouts during playback, use fallback data
- * from DSP firmware as a workaround.
- */
- if (codec->core.subsystem_id == 0x10431384)
- hda_priv->skip_calibration = true;
-
guard(pm_runtime_active_auto)(dev);
comp->dev = dev;
@@ -643,6 +632,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
*/
device_name = "TIAS2781";
hda_priv->hda_chip_id = HDA_TAS2781;
+ tas_hda->priv->chip_id = TAS2781;
hda_priv->save_calibration = tas2781_save_calibration;
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
} else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) {
@@ -656,6 +646,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
"i2c-TXNW2781:00-tas2781-hda.0")) {
device_name = "TXNW2781";
hda_priv->hda_chip_id = HDA_TAS2781;
+ tas_hda->priv->chip_id = TAS2781;
hda_priv->save_calibration = tas2781_save_calibration;
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
} else if (strstr(dev_name(&clt->dev), "INT8866")) {
diff --git a/sound/soc/amd/acp/amd-acp63-acpi-match.c b/sound/soc/amd/acp/amd-acp63-acpi-match.c
index 9b6a49c051cd..1dbbaba3c75b 100644
--- a/sound/soc/amd/acp/amd-acp63-acpi-match.c
+++ b/sound/soc/amd/acp/amd-acp63-acpi-match.c
@@ -30,6 +30,20 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = {
.group_id = 1
};
+static const struct snd_soc_acpi_endpoint spk_2_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 2,
+ .group_id = 1
+};
+
+static const struct snd_soc_acpi_endpoint spk_3_endpoint = {
+ .num = 0,
+ .aggregated = 1,
+ .group_position = 3,
+ .group_id = 1
+};
+
static const struct snd_soc_acpi_adr_device rt711_rt1316_group_adr[] = {
{
.adr = 0x000030025D071101ull,
@@ -103,6 +117,345 @@ static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = {
}
};
+static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = {
+ { /* Jack Playback Endpoint */
+ .num = 0,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* DMIC Capture Endpoint */
+ .num = 1,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Jack Capture Endpoint */
+ .num = 2,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+ { /* Speaker Playback Endpoint */
+ .num = 3,
+ .aggregated = 0,
+ .group_position = 0,
+ .group_id = 0,
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l56x4_l1u3210_adr[] = {
+ {
+ .adr = 0x00013301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63x2_l0u01_adr[] = {
+ {
+ .adr = 0x00003001FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003101FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63x2_l1u01_adr[] = {
+ {
+ .adr = 0x00013001FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013101FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63x2_l1u13_adr[] = {
+ {
+ .adr = 0x00013101FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013301FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs35l63x4_l0u0246_adr[] = {
+ {
+ .adr = 0x00003001FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00003201FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00003401FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00003601FA356301ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_l0u0_adr[] = {
+ {
+ .adr = 0x00003001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_l0u1_adr[] = {
+ {
+ .adr = 0x00003101FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43b_l0u1_adr[] = {
+ {
+ .adr = 0x00003101FA2A3B01ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l43_l1u0_cs35l56x4_l1u0123_adr[] = {
+ {
+ .adr = 0x00013001FA424301ull,
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints),
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l43"
+ },
+ {
+ .adr = 0x00013001FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_l_endpoint,
+ .name_prefix = "AMP1"
+ },
+ {
+ .adr = 0x00013101FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_r_endpoint,
+ .name_prefix = "AMP2"
+ },
+ {
+ .adr = 0x00013201FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_2_endpoint,
+ .name_prefix = "AMP3"
+ },
+ {
+ .adr = 0x00013301FA355601ull,
+ .num_endpoints = 1,
+ .endpoints = &spk_3_endpoint,
+ .name_prefix = "AMP4"
+ },
+};
+
+static const struct snd_soc_acpi_adr_device cs42l45_l0u0_adr[] = {
+ {
+ .adr = 0x00003001FA424501ull,
+ /* Re-use endpoints, but cs42l45 has no speaker */
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints) - 1,
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l45"
+ }
+};
+
+static const struct snd_soc_acpi_adr_device cs42l45_l1u0_adr[] = {
+ {
+ .adr = 0x00013001FA424501ull,
+ /* Re-use endpoints, but cs42l45 has no speaker */
+ .num_endpoints = ARRAY_SIZE(cs42l43_endpoints) - 1,
+ .endpoints = cs42l43_endpoints,
+ .name_prefix = "cs42l45"
+ }
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs35l56x4_l1u3210[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56x4_l1u3210_adr),
+ .adr_d = cs35l56x4_l1u3210_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs35l63x4_l0u0246[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l63x4_l0u0246_adr),
+ .adr_d = cs35l63x4_l0u0246_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l43_l0u1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_l0u1_adr),
+ .adr_d = cs42l43_l0u1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l43b_l0u1[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43b_l0u1_adr),
+ .adr_d = cs42l43b_l0u1_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l43_l0u0_cs35l56x4_l1u3210[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l43_l0u0_adr),
+ .adr_d = cs42l43_l0u0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l56x4_l1u3210_adr),
+ .adr_d = cs35l56x4_l1u3210_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l43_l1u0_cs35l56x4_l1u0123[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs42l43_l1u0_cs35l56x4_l1u0123_adr),
+ .adr_d = cs42l43_l1u0_cs35l56x4_l1u0123_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l0u0[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l45_l0u0_adr),
+ .adr_d = cs42l45_l0u0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l0u0_cs35l63x2_l1u01[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l45_l0u0_adr),
+ .adr_d = cs42l45_l0u0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l63x2_l1u01_adr),
+ .adr_d = cs35l63x2_l1u01_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l0u0_cs35l63x2_l1u13[] = {
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs42l45_l0u0_adr),
+ .adr_d = cs42l45_l0u0_adr,
+ },
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs35l63x2_l1u13_adr),
+ .adr_d = cs35l63x2_l1u13_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l1u0[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs42l45_l1u0_adr),
+ .adr_d = cs42l45_l1u0_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l1u0_cs35l63x2_l0u01[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs42l45_l1u0_adr),
+ .adr_d = cs42l45_l1u0_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l63x2_l0u01_adr),
+ .adr_d = cs35l63x2_l0u01_adr,
+ },
+ {}
+};
+
+static const struct snd_soc_acpi_link_adr acp63_cs42l45_l1u0_cs35l63x4_l0u0246[] = {
+ {
+ .mask = BIT(1),
+ .num_adr = ARRAY_SIZE(cs42l45_l1u0_adr),
+ .adr_d = cs42l45_l1u0_adr,
+ },
+ {
+ .mask = BIT(0),
+ .num_adr = ARRAY_SIZE(cs35l63x4_l0u0246_adr),
+ .adr_d = cs35l63x4_l0u0246_adr,
+ },
+ {}
+};
+
static const struct snd_soc_acpi_link_adr acp63_rt722_only[] = {
{
.mask = BIT(0),
@@ -135,6 +488,66 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[] = {
.links = acp63_4_in_1_sdca,
.drv_name = "amd_sdw",
},
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_cs42l43_l0u0_cs35l56x4_l1u3210,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_cs42l45_l1u0_cs35l63x4_l0u0246,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_cs42l45_l0u0_cs35l63x2_l1u01,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_cs42l45_l0u0_cs35l63x2_l1u13,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0) | BIT(1),
+ .links = acp63_cs42l45_l1u0_cs35l63x2_l0u01,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(1),
+ .links = acp63_cs42l43_l1u0_cs35l56x4_l1u0123,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(1),
+ .links = acp63_cs35l56x4_l1u3210,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = acp63_cs35l63x4_l0u0246,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = acp63_cs42l43_l0u1,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = acp63_cs42l43b_l0u1,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(0),
+ .links = acp63_cs42l45_l0u0,
+ .drv_name = "amd_sdw",
+ },
+ {
+ .link_mask = BIT(1),
+ .links = acp63_cs42l45_l1u0,
+ .drv_name = "amd_sdw",
+ },
{},
};
EXPORT_SYMBOL(snd_soc_acpi_amd_acp63_sdw_machines);
diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c
index 7af4daeb4c6f..1324543b42d7 100644
--- a/sound/soc/amd/yc/acp6x-mach.c
+++ b/sound/soc/amd/yc/acp6x-mach.c
@@ -710,6 +710,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "ASUS EXPERTBOOK BM1503CDA"),
}
},
+ {
+ .driver_data = &acp6x_card,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "PM1503CDA"),
+ }
+ },
{}
};
diff --git a/sound/soc/codecs/cs35l56-shared.c b/sound/soc/codecs/cs35l56-shared.c
index 4707f28bfca2..af87ebae98cb 100644
--- a/sound/soc/codecs/cs35l56-shared.c
+++ b/sound/soc/codecs/cs35l56-shared.c
@@ -26,7 +26,7 @@
#include "cs35l56.h"
-static const struct reg_sequence cs35l56_patch[] = {
+static const struct reg_sequence cs35l56_asp_patch[] = {
/*
* Firmware can change these to non-defaults to satisfy SDCA.
* Ensure that they are at known defaults.
@@ -43,6 +43,20 @@ static const struct reg_sequence cs35l56_patch[] = {
{ CS35L56_ASP1TX2_INPUT, 0x00000000 },
{ CS35L56_ASP1TX3_INPUT, 0x00000000 },
{ CS35L56_ASP1TX4_INPUT, 0x00000000 },
+};
+
+int cs35l56_set_asp_patch(struct cs35l56_base *cs35l56_base)
+{
+ return regmap_register_patch(cs35l56_base->regmap, cs35l56_asp_patch,
+ ARRAY_SIZE(cs35l56_asp_patch));
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_set_asp_patch, "SND_SOC_CS35L56_SHARED");
+
+static const struct reg_sequence cs35l56_patch[] = {
+ /*
+ * Firmware can change these to non-defaults to satisfy SDCA.
+ * Ensure that they are at known defaults.
+ */
{ CS35L56_SWIRE_DP3_CH1_INPUT, 0x00000018 },
{ CS35L56_SWIRE_DP3_CH2_INPUT, 0x00000019 },
{ CS35L56_SWIRE_DP3_CH3_INPUT, 0x00000029 },
diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c
index 2ff8b172b76e..37909a319f88 100644
--- a/sound/soc/codecs/cs35l56.c
+++ b/sound/soc/codecs/cs35l56.c
@@ -348,6 +348,13 @@ static int cs35l56_dsp_event(struct snd_soc_dapm_widget *w,
return wm_adsp_event(w, kcontrol, event);
}
+static int cs35l56_asp_dai_probe(struct snd_soc_dai *codec_dai)
+{
+ struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
+
+ return cs35l56_set_asp_patch(&cs35l56->base);
+}
+
static int cs35l56_asp_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct cs35l56_private *cs35l56 = snd_soc_component_get_drvdata(codec_dai->component);
@@ -552,6 +559,7 @@ static int cs35l56_asp_dai_set_sysclk(struct snd_soc_dai *dai,
}
static const struct snd_soc_dai_ops cs35l56_ops = {
+ .probe = cs35l56_asp_dai_probe,
.set_fmt = cs35l56_asp_dai_set_fmt,
.set_tdm_slot = cs35l56_asp_dai_set_tdm_slot,
.hw_params = cs35l56_asp_dai_hw_params,
@@ -1617,9 +1625,9 @@ static int cs35l56_process_xu_onchip_speaker_id(struct cs35l56_private *cs35l56,
if (num_pulls < 0)
return num_pulls;
- if (num_pulls != num_gpios) {
+ if (num_pulls && (num_pulls != num_gpios)) {
dev_warn(cs35l56->base.dev, "%s count(%d) != %s count(%d)\n",
- pull_name, num_pulls, gpio_name, num_gpios);
+ pull_name, num_pulls, gpio_name, num_gpios);
}
ret = cs35l56_check_and_save_onchip_spkid_gpios(&cs35l56->base,
diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index 50f65662e143..8bb7e8497c72 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -2629,7 +2629,7 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
struct sdw_port_config port_config;
struct sdw_port_config dmic_port_config[2];
struct sdw_stream_runtime *sdw_stream;
- int retval;
+ int retval, num_channels;
unsigned int sampling_rate;
dev_dbg(dai->dev, "%s %s", __func__, dai->name);
@@ -2661,7 +2661,8 @@ static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
dmic_port_config[1].num = 10;
break;
case RT1321_DEV_ID:
- dmic_port_config[0].ch_mask = BIT(0) | BIT(1);
+ num_channels = params_channels(params);
+ dmic_port_config[0].ch_mask = GENMASK(num_channels - 1, 0);
dmic_port_config[0].num = 8;
break;
default:
diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c
index c969eb38704e..5798d518d94c 100644
--- a/sound/soc/codecs/tas2781-fmwlib.c
+++ b/sound/soc/codecs/tas2781-fmwlib.c
@@ -32,6 +32,10 @@
#define TAS2781_YRAM1_PAGE 42
#define TAS2781_YRAM1_START_REG 88
+#define TAS2781_PG_REG TASDEVICE_REG(0x00, 0x00, 0x7c)
+#define TAS2781_PG_1_0 0xA0
+#define TAS2781_PG_2_0 0xA8
+
#define TAS2781_YRAM2_START_PAGE 43
#define TAS2781_YRAM2_END_PAGE 49
#define TAS2781_YRAM2_START_REG 8
@@ -98,6 +102,12 @@ struct blktyp_devidx_map {
unsigned char dev_idx;
};
+struct tas2781_cali_specific {
+ unsigned char sin_gni[4];
+ int sin_gni_reg;
+ bool is_sin_gn_flush;
+};
+
static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
};
@@ -2454,6 +2464,84 @@ static int tasdevice_load_data(struct tasdevice_priv *tas_priv,
return ret;
}
+static int tas2781_cali_preproc(struct tasdevice_priv *priv, int i)
+{
+ struct tas2781_cali_specific *spec = priv->tasdevice[i].cali_specific;
+ struct calidata *cali_data = &priv->cali_data;
+ struct cali_reg *p = &cali_data->cali_reg_array;
+ unsigned char *data = cali_data->data;
+ int rc;
+
+ /*
+ * On TAS2781, if the Speaker calibrated impedance is lower than
+ * default value hard-coded inside the TAS2781, it will cuase vol
+ * lower than normal. In order to fix this issue, the parameter of
+ * SineGainI need updating.
+ */
+ if (spec == NULL) {
+ int k = i * (cali_data->cali_dat_sz_per_dev + 1);
+ int re_org, re_cal, corrected_sin_gn, pg_id;
+ unsigned char r0_deflt[4];
+
+ spec = devm_kzalloc(priv->dev, sizeof(*spec), GFP_KERNEL);
+ if (spec == NULL)
+ return -ENOMEM;
+ priv->tasdevice[i].cali_specific = spec;
+ rc = tasdevice_dev_bulk_read(priv, i, p->r0_reg, r0_deflt, 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "invalid RE from %d = %d\n", i, rc);
+ return rc;
+ }
+ /*
+ * SineGainI need to be re-calculated, calculate the high 16
+ * bits.
+ */
+ re_org = r0_deflt[0] << 8 | r0_deflt[1];
+ re_cal = data[k + 1] << 8 | data[k + 2];
+ if (re_org > re_cal) {
+ rc = tasdevice_dev_read(priv, i, TAS2781_PG_REG,
+ &pg_id);
+ if (rc < 0) {
+ dev_err(priv->dev, "invalid PG id %d = %d\n",
+ i, rc);
+ return rc;
+ }
+
+ spec->sin_gni_reg = (pg_id == TAS2781_PG_1_0) ?
+ TASDEVICE_REG(0, 0x1b, 0x34) :
+ TASDEVICE_REG(0, 0x18, 0x1c);
+
+ rc = tasdevice_dev_bulk_read(priv, i,
+ spec->sin_gni_reg,
+ spec->sin_gni, 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "wrong sinegaini %d = %d\n",
+ i, rc);
+ return rc;
+ }
+ corrected_sin_gn = re_org * ((spec->sin_gni[0] << 8) +
+ spec->sin_gni[1]);
+ corrected_sin_gn /= re_cal;
+ spec->sin_gni[0] = corrected_sin_gn >> 8;
+ spec->sin_gni[1] = corrected_sin_gn & 0xff;
+
+ spec->is_sin_gn_flush = true;
+ }
+ }
+
+ if (spec->is_sin_gn_flush) {
+ rc = tasdevice_dev_bulk_write(priv, i, spec->sin_gni_reg,
+ spec->sin_gni, 4);
+ if (rc < 0) {
+ dev_err(priv->dev, "update failed %d = %d\n",
+ i, rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
{
struct calidata *cali_data = &priv->cali_data;
@@ -2469,6 +2557,12 @@ static void tasdev_load_calibrated_data(struct tasdevice_priv *priv, int i)
}
k++;
+ if (priv->chip_id == TAS2781) {
+ rc = tas2781_cali_preproc(priv, i);
+ if (rc < 0)
+ return;
+ }
+
rc = tasdevice_dev_bulk_write(priv, i, p->r0_reg, &(data[k]), 4);
if (rc < 0) {
dev_err(priv->dev, "chn %d r0_reg bulk_wr err = %d\n", i, rc);
diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c
index e64a0d97afd0..6c56134c60cc 100644
--- a/sound/soc/fsl/fsl_easrc.c
+++ b/sound/soc/fsl/fsl_easrc.c
@@ -52,10 +52,13 @@ static int fsl_easrc_iec958_put_bits(struct snd_kcontrol *kcontrol,
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
unsigned int regval = ucontrol->value.integer.value[0];
+ int ret;
+
+ ret = (easrc_priv->bps_iec958[mc->regbase] != regval);
easrc_priv->bps_iec958[mc->regbase] = regval;
- return 0;
+ return ret;
}
static int fsl_easrc_iec958_get_bits(struct snd_kcontrol *kcontrol,
@@ -93,14 +96,17 @@ static int fsl_easrc_set_reg(struct snd_kcontrol *kcontrol,
struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
struct soc_mreg_control *mc =
(struct soc_mreg_control *)kcontrol->private_value;
+ struct fsl_asrc *easrc = snd_soc_component_get_drvdata(component);
unsigned int regval = ucontrol->value.integer.value[0];
+ bool changed;
int ret;
- ret = snd_soc_component_write(component, mc->regbase, regval);
- if (ret < 0)
+ ret = regmap_update_bits_check(easrc->regmap, mc->regbase,
+ GENMASK(31, 0), regval, &changed);
+ if (ret != 0)
return ret;
- return 0;
+ return changed;
}
#define SOC_SINGLE_REG_RW(xname, xreg) \
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index f230991f5f8e..c18ec607e029 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -763,6 +763,14 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = {
},
.driver_data = (void *)(SOC_SDW_CODEC_SPKR),
},
+ {
+ .callback = sof_sdw_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CCD")
+ },
+ .driver_data = (void *)(SOC_SDW_CODEC_SPKR),
+ },
/* Pantherlake devices*/
{
.callback = sof_sdw_quirk_cb,
diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c
index 95b67bb904c3..e0ed593697ba 100644
--- a/sound/soc/sdca/sdca_functions.c
+++ b/sound/soc/sdca/sdca_functions.c
@@ -1156,9 +1156,12 @@ static int find_sdca_entity_iot(struct device *dev,
if (!terminal->is_dataport) {
const char *type_name = sdca_find_terminal_name(terminal->type);
- if (type_name)
+ if (type_name) {
entity->label = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
entity->label, type_name);
+ if (!entity->label)
+ return -ENOMEM;
+ }
}
ret = fwnode_property_read_u32(entity_node,
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index c6a78efbcaa3..d54a1a44a69b 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -2219,6 +2219,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
QUIRK_FLAG_ALIGN_TRANSFER),
DEVICE_FLG(0x05e1, 0x0480, /* Hauppauge Woodbury */
QUIRK_FLAG_SHARE_MEDIA_DEVICE | QUIRK_FLAG_ALIGN_TRANSFER),
+ DEVICE_FLG(0x0624, 0x3d3f, /* AB13X USB Audio */
+ QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
DEVICE_FLG(0x0644, 0x8043, /* TEAC UD-501/UD-501V2/UD-503/NT-503 */
QUIRK_FLAG_ITF_USB_DSD_DAC | QUIRK_FLAG_CTL_MSG_DELAY |
QUIRK_FLAG_IFACE_DELAY),
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c
index 011ea96e9779..f00b53346abd 100644
--- a/sound/usb/usx2y/us122l.c
+++ b/sound/usb/usx2y/us122l.c
@@ -520,8 +520,6 @@ static int us122l_usb_probe(struct usb_interface *intf,
return err;
}
- usb_get_intf(usb_ifnum_to_if(device, 0));
- usb_get_dev(device);
*cardp = card;
return 0;
}
@@ -542,11 +540,9 @@ static int snd_us122l_probe(struct usb_interface *intf,
if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
return 0;
- err = us122l_usb_probe(usb_get_intf(intf), id, &card);
- if (err < 0) {
- usb_put_intf(intf);
+ err = us122l_usb_probe(intf, id, &card);
+ if (err < 0)
return err;
- }
usb_set_intfdata(intf, card);
return 0;
@@ -574,10 +570,6 @@ static void snd_us122l_disconnect(struct usb_interface *intf)
snd_usbmidi_disconnect(p);
}
- usb_put_intf(usb_ifnum_to_if(us122l->dev, 0));
- usb_put_intf(usb_ifnum_to_if(us122l->dev, 1));
- usb_put_dev(us122l->dev);
-
snd_card_free_when_closed(card);
}
diff --git a/tools/bpf/resolve_btfids/Makefile b/tools/bpf/resolve_btfids/Makefile
index ef083602b73a..7672208f65e4 100644
--- a/tools/bpf/resolve_btfids/Makefile
+++ b/tools/bpf/resolve_btfids/Makefile
@@ -23,6 +23,7 @@ RM ?= rm
HOSTCC ?= gcc
HOSTLD ?= ld
HOSTAR ?= ar
+HOSTPKG_CONFIG ?= pkg-config
CROSS_COMPILE =
OUTPUT ?= $(srctree)/tools/bpf/resolve_btfids/
@@ -63,10 +64,14 @@ $(BPFOBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OU
$(abspath $@) install_headers
LIBELF_FLAGS := $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null)
+
+ifneq ($(filter -static,$(EXTRA_LDFLAGS)),)
+LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs --static 2>/dev/null || echo -lelf -lzstd)
+else
LIBELF_LIBS := $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || echo -lelf)
+endif
ZLIB_LIBS := $(shell $(HOSTPKG_CONFIG) zlib --libs 2>/dev/null || echo -lz)
-ZSTD_LIBS := $(shell $(HOSTPKG_CONFIG) libzstd --libs 2>/dev/null || echo -lzstd)
HOSTCFLAGS_resolve_btfids += -g \
-I$(srctree)/tools/include \
@@ -76,7 +81,7 @@ HOSTCFLAGS_resolve_btfids += -g \
$(LIBELF_FLAGS) \
-Wall -Werror
-LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS) $(ZSTD_LIBS)
+LIBS = $(LIBELF_LIBS) $(ZLIB_LIBS)
export srctree OUTPUT HOSTCFLAGS_resolve_btfids Q HOSTCC HOSTLD HOSTAR
include $(srctree)/tools/build/Makefile.include
diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile
index 6964175abdfd..76bcd4e85de3 100644
--- a/tools/objtool/Makefile
+++ b/tools/objtool/Makefile
@@ -142,13 +142,15 @@ $(LIBSUBCMD)-clean:
$(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
clean: $(LIBSUBCMD)-clean
- $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
- $(Q)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+ $(Q)find $(OUTPUT) \( -name '*.o' -o -name '\.*.cmd' -o -name '\.*.d' \) -type f -print | xargs $(RM)
$(Q)$(RM) $(OUTPUT)arch/x86/lib/cpu-feature-names.c $(OUTPUT)fixdep
$(Q)$(RM) $(OUTPUT)arch/x86/lib/inat-tables.c $(OUTPUT)fixdep
$(Q)$(RM) -- $(OUTPUT)FEATURE-DUMP.objtool
$(Q)$(RM) -r -- $(OUTPUT)feature
+mrproper: clean
+ $(call QUIET_CLEAN, objtool) $(RM) $(OBJTOOL)
+
FORCE:
-.PHONY: clean FORCE
+.PHONY: clean mrproper FORCE
diff --git a/tools/sched_ext/Kconfig b/tools/sched_ext/Kconfig
new file mode 100644
index 000000000000..275bd97ae62b
--- /dev/null
+++ b/tools/sched_ext/Kconfig
@@ -0,0 +1,61 @@
+# sched-ext mandatory options
+#
+CONFIG_BPF=y
+CONFIG_BPF_SYSCALL=y
+CONFIG_BPF_JIT=y
+CONFIG_DEBUG_INFO_BTF=y
+CONFIG_BPF_JIT_ALWAYS_ON=y
+CONFIG_BPF_JIT_DEFAULT_ON=y
+CONFIG_SCHED_CLASS_EXT=y
+
+# Required by some rust schedulers (e.g. scx_p2dq)
+#
+CONFIG_KALLSYMS_ALL=y
+
+# Required on arm64
+#
+# CONFIG_DEBUG_INFO_REDUCED is not set
+
+# LAVD tracks futex to give an additional time slice for futex holder
+# (i.e., avoiding lock holder preemption) for better system-wide progress.
+# LAVD first tries to use ftrace to trace futex function calls.
+# If that is not available, it tries to use a tracepoint.
+CONFIG_FUNCTION_TRACER=y
+
+# Enable scheduling debugging
+#
+CONFIG_SCHED_DEBUG=y
+
+# Enable extra scheduling features (for a better code coverage while testing
+# the schedulers)
+#
+CONFIG_SCHED_AUTOGROUP=y
+CONFIG_SCHED_CORE=y
+CONFIG_SCHED_MC=y
+
+# Enable fully preemptible kernel for a better test coverage of the schedulers
+#
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_DYNAMIC=y
+
+# Additional debugging information (useful to catch potential locking issues)
+CONFIG_DEBUG_LOCKDEP=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
+CONFIG_PROVE_LOCKING=y
+
+# Bpftrace headers (for additional debug info)
+CONFIG_BPF_EVENTS=y
+CONFIG_FTRACE_SYSCALLS=y
+CONFIG_DYNAMIC_FTRACE=y
+CONFIG_KPROBES=y
+CONFIG_KPROBE_EVENTS=y
+CONFIG_UPROBES=y
+CONFIG_UPROBE_EVENTS=y
+CONFIG_DEBUG_FS=y
+
+# Enable access to kernel configuration and headers at runtime
+CONFIG_IKHEADERS=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_IKCONFIG=y
diff --git a/tools/sched_ext/Makefile b/tools/sched_ext/Makefile
index 47ad7444677e..21554f089692 100644
--- a/tools/sched_ext/Makefile
+++ b/tools/sched_ext/Makefile
@@ -122,6 +122,8 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
-I../../include \
$(call get_sys_includes,$(CLANG)) \
-Wall -Wno-compare-distinct-pointer-types \
+ -Wno-microsoft-anon-tag \
+ -fms-extensions \
-O2 -mcpu=v3
# sort removes libbpf duplicates when not cross-building
diff --git a/tools/sched_ext/README.md b/tools/sched_ext/README.md
index 56a9d1557ac4..6e282bce453c 100644
--- a/tools/sched_ext/README.md
+++ b/tools/sched_ext/README.md
@@ -58,14 +58,8 @@ CONFIG_SCHED_CLASS_EXT=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT=y
CONFIG_DEBUG_INFO_BTF=y
-```
-
-It's also recommended that you also include the following Kconfig options:
-
-```
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_BPF_JIT_DEFAULT_ON=y
-CONFIG_PAHOLE_HAS_BTF_TAG=y
```
There is a `Kconfig` file in this directory whose contents you can append to
diff --git a/tools/sched_ext/include/scx/compat.h b/tools/sched_ext/include/scx/compat.h
index 8b4897fc8b99..edccc99c7294 100644
--- a/tools/sched_ext/include/scx/compat.h
+++ b/tools/sched_ext/include/scx/compat.h
@@ -125,6 +125,7 @@ static inline long scx_hotplug_seq(void)
{
int fd;
char buf[32];
+ char *endptr;
ssize_t len;
long val;
@@ -137,8 +138,10 @@ static inline long scx_hotplug_seq(void)
buf[len] = 0;
close(fd);
- val = strtoul(buf, NULL, 10);
- SCX_BUG_ON(val < 0, "invalid num hotplug events: %lu", val);
+ errno = 0;
+ val = strtoul(buf, &endptr, 10);
+ SCX_BUG_ON(errno == ERANGE || endptr == buf ||
+ (*endptr != '\n' && *endptr != '\0'), "invalid num hotplug events: %ld", val);
return val;
}
diff --git a/tools/sched_ext/scx_central.c b/tools/sched_ext/scx_central.c
index 2a805f1d6c8f..710fa03376e2 100644
--- a/tools/sched_ext/scx_central.c
+++ b/tools/sched_ext/scx_central.c
@@ -66,7 +66,7 @@ restart:
assert(skel->rodata->nr_cpu_ids > 0);
assert(skel->rodata->nr_cpu_ids <= INT32_MAX);
- while ((opt = getopt(argc, argv, "s:c:pvh")) != -1) {
+ while ((opt = getopt(argc, argv, "s:c:vh")) != -1) {
switch (opt) {
case 's':
skel->rodata->slice_ns = strtoull(optarg, NULL, 0) * 1000;
diff --git a/tools/sched_ext/scx_sdt.c b/tools/sched_ext/scx_sdt.c
index d8ca9aa316a5..a36405d8df30 100644
--- a/tools/sched_ext/scx_sdt.c
+++ b/tools/sched_ext/scx_sdt.c
@@ -54,7 +54,7 @@ restart:
optind = 1;
skel = SCX_OPS_OPEN(sdt_ops, scx_sdt);
- while ((opt = getopt(argc, argv, "fvh")) != -1) {
+ while ((opt = getopt(argc, argv, "vh")) != -1) {
switch (opt) {
case 'v':
verbose = true;
diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kunit_kernel.py
index 260d8d9aa1db..2998e1bc088b 100644
--- a/tools/testing/kunit/kunit_kernel.py
+++ b/tools/testing/kunit/kunit_kernel.py
@@ -346,8 +346,10 @@ class LinuxSourceTree:
return self.validate_config(build_dir)
def run_kernel(self, args: Optional[List[str]]=None, build_dir: str='', filter_glob: str='', filter: str='', filter_action: Optional[str]=None, timeout: Optional[int]=None) -> Iterator[str]:
- if not args:
- args = []
+ # Copy to avoid mutating the caller-supplied list. exec_tests() reuses
+ # the same args across repeated run_kernel() calls (e.g. --run_isolated),
+ # so appending to the original would accumulate stale flags on each call.
+ args = list(args) if args else []
if filter_glob:
args.append('kunit.filter_glob=' + filter_glob)
if filter:
diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/kunit_tool_test.py
index b67408147c1f..f6383884c599 100755
--- a/tools/testing/kunit/kunit_tool_test.py
+++ b/tools/testing/kunit/kunit_tool_test.py
@@ -503,6 +503,32 @@ class LinuxSourceTreeTest(unittest.TestCase):
with open(kunit_kernel.get_outfile_path(build_dir), 'rt') as outfile:
self.assertEqual(outfile.read(), 'hi\nbye\n', msg='Missing some output')
+ def test_run_kernel_args_not_mutated(self):
+ """Verify run_kernel() copies args so callers can reuse them."""
+ start_calls = []
+
+ def fake_start(start_args, unused_build_dir):
+ start_calls.append(list(start_args))
+ return subprocess.Popen(['printf', 'KTAP version 1\n'],
+ text=True, stdout=subprocess.PIPE)
+
+ with tempfile.TemporaryDirectory('') as build_dir:
+ tree = kunit_kernel.LinuxSourceTree(build_dir,
+ kunitconfig_paths=[os.devnull])
+ with mock.patch.object(tree._ops, 'start', side_effect=fake_start), \
+ mock.patch.object(kunit_kernel.subprocess, 'call'):
+ kernel_args = ['mem=1G']
+ for _ in tree.run_kernel(args=kernel_args, build_dir=build_dir,
+ filter_glob='suite.test1'):
+ pass
+ for _ in tree.run_kernel(args=kernel_args, build_dir=build_dir,
+ filter_glob='suite.test2'):
+ pass
+ self.assertEqual(kernel_args, ['mem=1G'],
+ 'run_kernel() should not modify caller args')
+ self.assertIn('kunit.filter_glob=suite.test1', start_calls[0])
+ self.assertIn('kunit.filter_glob=suite.test2', start_calls[1])
+
def test_build_reconfig_no_config(self):
with tempfile.TemporaryDirectory('') as build_dir:
with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f:
diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c
index 9d2df1f3e6bb..c2661a312fc9 100644
--- a/tools/testing/selftests/arm64/abi/hwcap.c
+++ b/tools/testing/selftests/arm64/abi/hwcap.c
@@ -475,8 +475,8 @@ static void sve2_sigill(void)
static void sve2p1_sigill(void)
{
- /* BFADD Z0.H, Z0.H, Z0.H */
- asm volatile(".inst 0x65000000" : : : "z0");
+ /* LD1Q {Z0.Q}, P0/Z, [Z0.D, X0] */
+ asm volatile(".inst 0xC400A000" : : : "z0");
}
static void sve2p2_sigill(void)
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 72a9ba41f95e..d5acbeba0383 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -409,6 +409,7 @@ $(RESOLVE_BTFIDS): $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/resolve_btfids \
CC="$(HOSTCC)" LD="$(HOSTLD)" AR="$(HOSTAR)" \
LIBBPF_INCLUDE=$(HOST_INCLUDE_DIR) \
EXTRA_LDFLAGS='$(SAN_LDFLAGS) $(EXTRA_LDFLAGS)' \
+ HOSTPKG_CONFIG=$(PKG_CONFIG) \
OUTPUT=$(HOST_BUILD_DIR)/resolve_btfids/ BPFOBJ=$(HOST_BPFOBJ)
# Get Clang's default includes on this system, as opposed to those seen by
diff --git a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
index 0322f817d07b..cb8dd2f63296 100644
--- a/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
+++ b/tools/testing/selftests/bpf/prog_tests/reg_bounds.c
@@ -422,15 +422,69 @@ static bool is_valid_range(enum num_t t, struct range x)
}
}
-static struct range range_improve(enum num_t t, struct range old, struct range new)
+static struct range range_intersection(enum num_t t, struct range old, struct range new)
{
return range(t, max_t(t, old.a, new.a), min_t(t, old.b, new.b));
}
+/*
+ * Result is precise when 'x' and 'y' overlap or form a continuous range,
+ * result is an over-approximation if 'x' and 'y' do not overlap.
+ */
+static struct range range_union(enum num_t t, struct range x, struct range y)
+{
+ if (!is_valid_range(t, x))
+ return y;
+ if (!is_valid_range(t, y))
+ return x;
+ return range(t, min_t(t, x.a, y.a), max_t(t, x.b, y.b));
+}
+
+/*
+ * This function attempts to improve x range intersecting it with y.
+ * range_cast(... to_t ...) looses precision for ranges that pass to_t
+ * min/max boundaries. To avoid such precision loses this function
+ * splits both x and y into halves corresponding to non-overflowing
+ * sub-ranges: [0, smin] and [smax, -1].
+ * Final result is computed as follows:
+ *
+ * ((x ∩ [0, smax]) ∩ (y ∩ [0, smax])) ∪
+ * ((x ∩ [smin,-1]) ∩ (y ∩ [smin,-1]))
+ *
+ * Precision might still be lost if final union is not a continuous range.
+ */
+static struct range range_refine_in_halves(enum num_t x_t, struct range x,
+ enum num_t y_t, struct range y)
+{
+ struct range x_pos, x_neg, y_pos, y_neg, r_pos, r_neg;
+ u64 smax, smin, neg_one;
+
+ if (t_is_32(x_t)) {
+ smax = (u64)(u32)S32_MAX;
+ smin = (u64)(u32)S32_MIN;
+ neg_one = (u64)(u32)(s32)(-1);
+ } else {
+ smax = (u64)S64_MAX;
+ smin = (u64)S64_MIN;
+ neg_one = U64_MAX;
+ }
+ x_pos = range_intersection(x_t, x, range(x_t, 0, smax));
+ x_neg = range_intersection(x_t, x, range(x_t, smin, neg_one));
+ y_pos = range_intersection(y_t, y, range(x_t, 0, smax));
+ y_neg = range_intersection(y_t, y, range(y_t, smin, neg_one));
+ r_pos = range_intersection(x_t, x_pos, range_cast(y_t, x_t, y_pos));
+ r_neg = range_intersection(x_t, x_neg, range_cast(y_t, x_t, y_neg));
+ return range_union(x_t, r_pos, r_neg);
+
+}
+
static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t, struct range y)
{
struct range y_cast;
+ if (t_is_32(x_t) == t_is_32(y_t))
+ x = range_refine_in_halves(x_t, x, y_t, y);
+
y_cast = range_cast(y_t, x_t, y);
/* If we know that
@@ -444,7 +498,7 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t,
*/
if (x_t == S64 && y_t == S32 && y_cast.a <= S32_MAX && y_cast.b <= S32_MAX &&
(s64)x.a >= S32_MIN && (s64)x.b <= S32_MAX)
- return range_improve(x_t, x, y_cast);
+ return range_intersection(x_t, x, y_cast);
/* the case when new range knowledge, *y*, is a 32-bit subregister
* range, while previous range knowledge, *x*, is a full register
@@ -462,25 +516,11 @@ static struct range range_refine(enum num_t x_t, struct range x, enum num_t y_t,
x_swap = range(x_t, swap_low32(x.a, y_cast.a), swap_low32(x.b, y_cast.b));
if (!is_valid_range(x_t, x_swap))
return x;
- return range_improve(x_t, x, x_swap);
- }
-
- if (!t_is_32(x_t) && !t_is_32(y_t) && x_t != y_t) {
- if (x_t == S64 && x.a > x.b) {
- if (x.b < y.a && x.a <= y.b)
- return range(x_t, x.a, y.b);
- if (x.a > y.b && x.b >= y.a)
- return range(x_t, y.a, x.b);
- } else if (x_t == U64 && y.a > y.b) {
- if (y.b < x.a && y.a <= x.b)
- return range(x_t, y.a, x.b);
- if (y.a > x.b && y.b >= x.a)
- return range(x_t, x.a, y.b);
- }
+ return range_intersection(x_t, x, x_swap);
}
/* otherwise, plain range cast and intersection works */
- return range_improve(x_t, x, y_cast);
+ return range_intersection(x_t, x, y_cast);
}
/* =======================
diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
index fb952703653e..e8ea26464349 100644
--- a/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
+++ b/tools/testing/selftests/bpf/prog_tests/xdp_bonding.c
@@ -610,6 +610,61 @@ out:
system("ip link del bond");
}
+/*
+ * Test that changing xmit_hash_policy to vlan+srcmac is rejected when a
+ * native XDP program is loaded on a bond in 802.3ad or balance-xor mode.
+ * These modes support XDP only when xmit_hash_policy != vlan+srcmac; freely
+ * changing the policy creates an inconsistency that triggers a WARNING in
+ * dev_xdp_uninstall() during device teardown.
+ */
+static void test_xdp_bonding_xmit_policy_compat(struct skeletons *skeletons)
+{
+ struct nstoken *nstoken = NULL;
+ int bond_ifindex = -1;
+ int xdp_fd, err;
+
+ SYS(out, "ip netns add ns_xmit_policy");
+ nstoken = open_netns("ns_xmit_policy");
+ if (!ASSERT_OK_PTR(nstoken, "open ns_xmit_policy"))
+ goto out;
+
+ /* 802.3ad with layer2+3 policy: native XDP is supported */
+ SYS(out, "ip link add bond0 type bond mode 802.3ad xmit_hash_policy layer2+3");
+ SYS(out, "ip link add veth0 type veth peer name veth0p");
+ SYS(out, "ip link set veth0 master bond0");
+ SYS(out, "ip link set bond0 up");
+
+ bond_ifindex = if_nametoindex("bond0");
+ if (!ASSERT_GT(bond_ifindex, 0, "bond0 ifindex"))
+ goto out;
+
+ xdp_fd = bpf_program__fd(skeletons->xdp_dummy->progs.xdp_dummy_prog);
+ if (!ASSERT_GE(xdp_fd, 0, "xdp_dummy fd"))
+ goto out;
+
+ err = bpf_xdp_attach(bond_ifindex, xdp_fd, XDP_FLAGS_DRV_MODE, NULL);
+ if (!ASSERT_OK(err, "attach XDP to bond0"))
+ goto out;
+
+ /* With XDP loaded, switching to vlan+srcmac must be rejected */
+ err = system("ip link set bond0 type bond xmit_hash_policy vlan+srcmac 2>/dev/null");
+ ASSERT_NEQ(err, 0, "vlan+srcmac change with XDP loaded should fail");
+
+ /* Detach XDP first, then the same change must succeed */
+ ASSERT_OK(bpf_xdp_detach(bond_ifindex, XDP_FLAGS_DRV_MODE, NULL),
+ "detach XDP from bond0");
+
+ bond_ifindex = -1;
+ err = system("ip link set bond0 type bond xmit_hash_policy vlan+srcmac 2>/dev/null");
+ ASSERT_OK(err, "vlan+srcmac change without XDP should succeed");
+
+out:
+ if (bond_ifindex > 0)
+ bpf_xdp_detach(bond_ifindex, XDP_FLAGS_DRV_MODE, NULL);
+ close_netns(nstoken);
+ SYS_NOFAIL("ip netns del ns_xmit_policy");
+}
+
static int libbpf_debug_print(enum libbpf_print_level level,
const char *format, va_list args)
{
@@ -677,6 +732,9 @@ void serial_test_xdp_bonding(void)
test_case->xmit_policy);
}
+ if (test__start_subtest("xdp_bonding_xmit_policy_compat"))
+ test_xdp_bonding_xmit_policy_compat(&skeletons);
+
if (test__start_subtest("xdp_bonding_redirect_multi"))
test_xdp_bonding_redirect_multi(&skeletons);
diff --git a/tools/testing/selftests/bpf/progs/exceptions_assert.c b/tools/testing/selftests/bpf/progs/exceptions_assert.c
index a01c2736890f..858af5988a38 100644
--- a/tools/testing/selftests/bpf/progs/exceptions_assert.c
+++ b/tools/testing/selftests/bpf/progs/exceptions_assert.c
@@ -18,43 +18,43 @@
return *(u64 *)num; \
}
-__msg(": R0=0xffffffff80000000")
+__msg("R{{.}}=0xffffffff80000000")
check_assert(s64, ==, eq_int_min, INT_MIN);
-__msg(": R0=0x7fffffff")
+__msg("R{{.}}=0x7fffffff")
check_assert(s64, ==, eq_int_max, INT_MAX);
-__msg(": R0=0")
+__msg("R{{.}}=0")
check_assert(s64, ==, eq_zero, 0);
-__msg(": R0=0x8000000000000000 R1=0x8000000000000000")
+__msg("R{{.}}=0x8000000000000000")
check_assert(s64, ==, eq_llong_min, LLONG_MIN);
-__msg(": R0=0x7fffffffffffffff R1=0x7fffffffffffffff")
+__msg("R{{.}}=0x7fffffffffffffff")
check_assert(s64, ==, eq_llong_max, LLONG_MAX);
-__msg(": R0=scalar(id=1,smax=0x7ffffffe)")
+__msg("R{{.}}=scalar(id=1,smax=0x7ffffffe)")
check_assert(s64, <, lt_pos, INT_MAX);
-__msg(": R0=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))")
+__msg("R{{.}}=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))")
check_assert(s64, <, lt_zero, 0);
-__msg(": R0=scalar(id=1,smax=0xffffffff7fffffff")
+__msg("R{{.}}=scalar(id=1,smax=0xffffffff7fffffff")
check_assert(s64, <, lt_neg, INT_MIN);
-__msg(": R0=scalar(id=1,smax=0x7fffffff)")
+__msg("R{{.}}=scalar(id=1,smax=0x7fffffff)")
check_assert(s64, <=, le_pos, INT_MAX);
-__msg(": R0=scalar(id=1,smax=0)")
+__msg("R{{.}}=scalar(id=1,smax=0)")
check_assert(s64, <=, le_zero, 0);
-__msg(": R0=scalar(id=1,smax=0xffffffff80000000")
+__msg("R{{.}}=scalar(id=1,smax=0xffffffff80000000")
check_assert(s64, <=, le_neg, INT_MIN);
-__msg(": R0=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
+__msg("R{{.}}=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
check_assert(s64, >, gt_pos, INT_MAX);
-__msg(": R0=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
+__msg("R{{.}}=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
check_assert(s64, >, gt_zero, 0);
-__msg(": R0=scalar(id=1,smin=0xffffffff80000001")
+__msg("R{{.}}=scalar(id=1,smin=0xffffffff80000001")
check_assert(s64, >, gt_neg, INT_MIN);
-__msg(": R0=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
+__msg("R{{.}}=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
check_assert(s64, >=, ge_pos, INT_MAX);
-__msg(": R0=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
+__msg("R{{.}}=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))")
check_assert(s64, >=, ge_zero, 0);
-__msg(": R0=scalar(id=1,smin=0xffffffff80000000")
+__msg("R{{.}}=scalar(id=1,smin=0xffffffff80000000")
check_assert(s64, >=, ge_neg, INT_MIN);
SEC("?tc")
diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c
index 97065a26cf70..e526315c718a 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bounds.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c
@@ -1148,7 +1148,7 @@ l0_%=: r0 = 0; \
SEC("xdp")
__description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")
__success __retval(0)
-__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */
+__flag(BPF_F_TEST_REG_INVARIANTS)
__naked void crossing_32_bit_signed_boundary_2(void)
{
asm volatile (" \
@@ -2000,4 +2000,41 @@ __naked void bounds_refinement_multiple_overlaps(void *ctx)
: __clobber_all);
}
+SEC("socket")
+__success
+__flag(BPF_F_TEST_REG_INVARIANTS)
+__naked void signed_unsigned_intersection32_case1(void *ctx)
+{
+ asm volatile(" \
+ call %[bpf_get_prandom_u32]; \
+ w0 &= 0xffffffff; \
+ if w0 < 0x3 goto 1f; /* on fall-through u32 range [3..U32_MAX] */ \
+ if w0 s> 0x1 goto 1f; /* on fall-through s32 range [S32_MIN..1] */ \
+ if w0 s< 0x0 goto 1f; /* range can be narrowed to [S32_MIN..-1] */ \
+ r10 = 0; /* thus predicting the jump. */ \
+1: exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
+SEC("socket")
+__success
+__flag(BPF_F_TEST_REG_INVARIANTS)
+__naked void signed_unsigned_intersection32_case2(void *ctx)
+{
+ asm volatile(" \
+ call %[bpf_get_prandom_u32]; \
+ w0 &= 0xffffffff; \
+ if w0 > 0x80000003 goto 1f; /* on fall-through u32 range [0..S32_MIN+3] */ \
+ if w0 s< -3 goto 1f; /* on fall-through s32 range [-3..S32_MAX] */ \
+ if w0 s> 5 goto 1f; /* on fall-through s32 range [-3..5] */ \
+ if w0 <= 5 goto 1f; /* range can be narrowed to [0..5] */ \
+ r10 = 0; /* thus predicting the jump */ \
+1: exit; \
+" :
+ : __imm(bpf_get_prandom_u32)
+ : __clobber_all);
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
index 2ef346c827c2..7bf7dbfd237d 100644
--- a/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
+++ b/tools/testing/selftests/bpf/progs/verifier_linked_scalars.c
@@ -363,4 +363,68 @@ void alu32_negative_offset(void)
__sink(path[0]);
}
+void dummy_calls(void)
+{
+ bpf_iter_num_new(0, 0, 0);
+ bpf_iter_num_next(0);
+ bpf_iter_num_destroy(0);
+}
+
+SEC("socket")
+__success
+__flag(BPF_F_TEST_STATE_FREQ)
+int spurious_precision_marks(void *ctx)
+{
+ struct bpf_iter_num iter;
+
+ asm volatile(
+ "r1 = %[iter];"
+ "r2 = 0;"
+ "r3 = 10;"
+ "call %[bpf_iter_num_new];"
+ "1:"
+ "r1 = %[iter];"
+ "call %[bpf_iter_num_next];"
+ "if r0 == 0 goto 4f;"
+ "r7 = *(u32 *)(r0 + 0);"
+ "r8 = *(u32 *)(r0 + 0);"
+ /* This jump can't be predicted and does not change r7 or r8 state. */
+ "if r7 > r8 goto 2f;"
+ /* Branch explored first ties r2 and r7 as having the same id. */
+ "r2 = r7;"
+ "goto 3f;"
+ "2:"
+ /* Branch explored second does not tie r2 and r7 but has a function call. */
+ "call %[bpf_get_prandom_u32];"
+ "3:"
+ /*
+ * A checkpoint.
+ * When first branch is explored, this would inject linked registers
+ * r2 and r7 into the jump history.
+ * When second branch is explored, this would be a cache hit point,
+ * triggering propagate_precision().
+ */
+ "if r7 <= 42 goto +0;"
+ /*
+ * Mark r7 as precise using an if condition that is always true.
+ * When reached via the second branch, this triggered a bug in the backtrack_insn()
+ * because r2 (tied to r7) was propagated as precise to a call.
+ */
+ "if r7 <= 0xffffFFFF goto +0;"
+ "goto 1b;"
+ "4:"
+ "r1 = %[iter];"
+ "call %[bpf_iter_num_destroy];"
+ :
+ : __imm_ptr(iter),
+ __imm(bpf_iter_num_new),
+ __imm(bpf_iter_num_next),
+ __imm(bpf_iter_num_destroy),
+ __imm(bpf_get_prandom_u32)
+ : __clobber_common, "r7", "r8"
+ );
+
+ return 0;
+}
+
char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
index 3072fee9a448..58c7704d61cd 100644
--- a/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
+++ b/tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
@@ -40,6 +40,9 @@ __naked void linked_regs_bpf_k(void)
*/
"r3 = r10;"
"r3 += r0;"
+ /* Mark r1 and r2 as alive. */
+ "r1 = r1;"
+ "r2 = r2;"
"r0 = 0;"
"exit;"
:
@@ -73,6 +76,9 @@ __naked void linked_regs_bpf_x_src(void)
*/
"r4 = r10;"
"r4 += r0;"
+ /* Mark r1 and r2 as alive. */
+ "r1 = r1;"
+ "r2 = r2;"
"r0 = 0;"
"exit;"
:
@@ -106,6 +112,10 @@ __naked void linked_regs_bpf_x_dst(void)
*/
"r4 = r10;"
"r4 += r3;"
+ /* Mark r1 and r2 as alive. */
+ "r0 = r0;"
+ "r1 = r1;"
+ "r2 = r2;"
"r0 = 0;"
"exit;"
:
@@ -143,6 +153,9 @@ __naked void linked_regs_broken_link(void)
*/
"r3 = r10;"
"r3 += r0;"
+ /* Mark r1 and r2 as alive. */
+ "r1 = r1;"
+ "r2 = r2;"
"r0 = 0;"
"exit;"
:
@@ -156,16 +169,16 @@ __naked void linked_regs_broken_link(void)
*/
SEC("socket")
__success __log_level(2)
-__msg("12: (0f) r2 += r1")
+__msg("17: (0f) r2 += r1")
/* Current state */
-__msg("frame2: last_idx 12 first_idx 11 subseq_idx -1 ")
-__msg("frame2: regs=r1 stack= before 11: (bf) r2 = r10")
+__msg("frame2: last_idx 17 first_idx 14 subseq_idx -1 ")
+__msg("frame2: regs=r1 stack= before 16: (bf) r2 = r10")
__msg("frame2: parent state regs=r1 stack=")
__msg("frame1: parent state regs= stack=")
__msg("frame0: parent state regs= stack=")
/* Parent state */
-__msg("frame2: last_idx 10 first_idx 10 subseq_idx 11 ")
-__msg("frame2: regs=r1 stack= before 10: (25) if r1 > 0x7 goto pc+0")
+__msg("frame2: last_idx 13 first_idx 13 subseq_idx 14 ")
+__msg("frame2: regs=r1 stack= before 13: (25) if r1 > 0x7 goto pc+0")
__msg("frame2: parent state regs=r1 stack=")
/* frame1.r{6,7} are marked because mark_precise_scalar_ids()
* looks for all registers with frame2.r1.id in the current state
@@ -173,20 +186,20 @@ __msg("frame2: parent state regs=r1 stack=")
__msg("frame1: parent state regs=r6,r7 stack=")
__msg("frame0: parent state regs=r6 stack=")
/* Parent state */
-__msg("frame2: last_idx 8 first_idx 8 subseq_idx 10")
-__msg("frame2: regs=r1 stack= before 8: (85) call pc+1")
+__msg("frame2: last_idx 9 first_idx 9 subseq_idx 13")
+__msg("frame2: regs=r1 stack= before 9: (85) call pc+3")
/* frame1.r1 is marked because of backtracking of call instruction */
__msg("frame1: parent state regs=r1,r6,r7 stack=")
__msg("frame0: parent state regs=r6 stack=")
/* Parent state */
-__msg("frame1: last_idx 7 first_idx 6 subseq_idx 8")
-__msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1")
-__msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1")
+__msg("frame1: last_idx 8 first_idx 7 subseq_idx 9")
+__msg("frame1: regs=r1,r6,r7 stack= before 8: (bf) r7 = r1")
+__msg("frame1: regs=r1,r6 stack= before 7: (bf) r6 = r1")
__msg("frame1: parent state regs=r1 stack=")
__msg("frame0: parent state regs=r6 stack=")
/* Parent state */
-__msg("frame1: last_idx 4 first_idx 4 subseq_idx 6")
-__msg("frame1: regs=r1 stack= before 4: (85) call pc+1")
+__msg("frame1: last_idx 4 first_idx 4 subseq_idx 7")
+__msg("frame1: regs=r1 stack= before 4: (85) call pc+2")
__msg("frame0: parent state regs=r1,r6 stack=")
/* Parent state */
__msg("frame0: last_idx 3 first_idx 1 subseq_idx 4")
@@ -204,6 +217,7 @@ __naked void precision_many_frames(void)
"r1 = r0;"
"r6 = r0;"
"call precision_many_frames__foo;"
+ "r6 = r6;" /* mark r6 as live */
"exit;"
:
: __imm(bpf_ktime_get_ns)
@@ -220,6 +234,8 @@ void precision_many_frames__foo(void)
"r6 = r1;"
"r7 = r1;"
"call precision_many_frames__bar;"
+ "r6 = r6;" /* mark r6 as live */
+ "r7 = r7;" /* mark r7 as live */
"exit"
::: __clobber_all);
}
@@ -229,6 +245,8 @@ void precision_many_frames__bar(void)
{
asm volatile (
"if r1 > 7 goto +0;"
+ "r6 = 0;" /* mark r6 as live */
+ "r7 = 0;" /* mark r7 as live */
/* force r1 to be precise, this eventually marks:
* - bar frame r1
* - foo frame r{1,6,7}
@@ -340,6 +358,8 @@ __naked void precision_two_ids(void)
"r3 += r7;"
/* force r9 to be precise, this also marks r8 */
"r3 += r9;"
+ "r6 = r6;" /* mark r6 as live */
+ "r8 = r8;" /* mark r8 as live */
"exit;"
:
: __imm(bpf_ktime_get_ns)
@@ -353,7 +373,7 @@ __flag(BPF_F_TEST_STATE_FREQ)
* collect_linked_regs() can't tie more than 6 registers for a single insn.
*/
__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1")
-__msg("9: (bf) r6 = r6 ; R6=scalar(id=2")
+__msg("14: (bf) r6 = r6 ; R6=scalar(id=2")
/* check that r{0-5} are marked precise after 'if' */
__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0")
__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:")
@@ -372,6 +392,12 @@ __naked void linked_regs_too_many_regs(void)
"r6 = r0;"
/* propagate range for r{0-6} */
"if r0 > 7 goto +0;"
+ /* keep r{1-5} live */
+ "r1 = r1;"
+ "r2 = r2;"
+ "r3 = r3;"
+ "r4 = r4;"
+ "r5 = r5;"
/* make r6 appear in the log */
"r6 = r6;"
/* force r0 to be precise,
@@ -517,7 +543,7 @@ __naked void check_ids_in_regsafe_2(void)
"*(u64*)(r10 - 8) = r1;"
/* r9 = pointer to stack */
"r9 = r10;"
- "r9 += -8;"
+ "r9 += -16;"
/* r8 = ktime_get_ns() */
"call %[bpf_ktime_get_ns];"
"r8 = r0;"
@@ -538,6 +564,8 @@ __naked void check_ids_in_regsafe_2(void)
"if r7 > 4 goto l2_%=;"
/* Access memory at r9[r6] */
"r9 += r6;"
+ "r9 += r7;"
+ "r9 += r8;"
"r0 = *(u8*)(r9 + 0);"
"l2_%=:"
"r0 = 0;"
diff --git a/tools/testing/selftests/bpf/verifier/precise.c b/tools/testing/selftests/bpf/verifier/precise.c
index 061d98f6e9bb..a9242103dc47 100644
--- a/tools/testing/selftests/bpf/verifier/precise.c
+++ b/tools/testing/selftests/bpf/verifier/precise.c
@@ -44,9 +44,9 @@
mark_precise: frame0: regs=r2 stack= before 23\
mark_precise: frame0: regs=r2 stack= before 22\
mark_precise: frame0: regs=r2 stack= before 20\
- mark_precise: frame0: parent state regs=r2,r9 stack=:\
+ mark_precise: frame0: parent state regs=r2 stack=:\
mark_precise: frame0: last_idx 19 first_idx 10\
- mark_precise: frame0: regs=r2,r9 stack= before 19\
+ mark_precise: frame0: regs=r2 stack= before 19\
mark_precise: frame0: regs=r9 stack= before 18\
mark_precise: frame0: regs=r8,r9 stack= before 17\
mark_precise: frame0: regs=r0,r9 stack= before 15\
@@ -107,9 +107,9 @@
mark_precise: frame0: parent state regs=r2 stack=:\
mark_precise: frame0: last_idx 20 first_idx 20\
mark_precise: frame0: regs=r2 stack= before 20\
- mark_precise: frame0: parent state regs=r2,r9 stack=:\
+ mark_precise: frame0: parent state regs=r2 stack=:\
mark_precise: frame0: last_idx 19 first_idx 17\
- mark_precise: frame0: regs=r2,r9 stack= before 19\
+ mark_precise: frame0: regs=r2 stack= before 19\
mark_precise: frame0: regs=r9 stack= before 18\
mark_precise: frame0: regs=r8,r9 stack= before 17\
mark_precise: frame0: parent state regs= stack=:",
diff --git a/tools/testing/selftests/cgroup/test_cpuset_prs.sh b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
index 5dff3ad53867..a56f4153c64d 100755
--- a/tools/testing/selftests/cgroup/test_cpuset_prs.sh
+++ b/tools/testing/selftests/cgroup/test_cpuset_prs.sh
@@ -196,7 +196,6 @@ test_add_proc()
# P<v> = set cpus.partition (0:member, 1:root, 2:isolated)
# C<l> = add cpu-list to cpuset.cpus
# X<l> = add cpu-list to cpuset.cpus.exclusive
-# S<p> = use prefix in subtree_control
# T = put a task into cgroup
# CX<l> = add cpu-list to both cpuset.cpus and cpuset.cpus.exclusive
# O<c>=<v> = Write <v> to CPU online file of <c>
@@ -209,44 +208,46 @@ test_add_proc()
# sched-debug matching which includes offline CPUs and single-CPU partitions
# while the second one is for matching cpuset.cpus.isolated.
#
-SETUP_A123_PARTITIONS="C1-3:P1:S+ C2-3:P1:S+ C3:P1"
+SETUP_A123_PARTITIONS="C1-3:P1 C2-3:P1 C3:P1"
TEST_MATRIX=(
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
- " C0-1 . . C2-3 S+ C4-5 . . 0 A2:0-1"
+ " C0-1 . . C2-3 . C4-5 . . 0 A2:0-1"
" C0-1 . . C2-3 P1 . . . 0 "
- " C0-1 . . C2-3 P1:S+ C0-1:P1 . . 0 "
- " C0-1 . . C2-3 P1:S+ C1:P1 . . 0 "
- " C0-1:S+ . . C2-3 . . . P1 0 "
- " C0-1:P1 . . C2-3 S+ C1 . . 0 "
- " C0-1:P1 . . C2-3 S+ C1:P1 . . 0 "
- " C0-1:P1 . . C2-3 S+ C1:P1 . P1 0 "
+ " C0-1 . . C2-3 P1 C0-1:P1 . . 0 "
+ " C0-1 . . C2-3 P1 C1:P1 . . 0 "
+ " C0-1 . . C2-3 . . . P1 0 "
+ " C0-1:P1 . . C2-3 . C1 . . 0 "
+ " C0-1:P1 . . C2-3 . C1:P1 . . 0 "
+ " C0-1:P1 . . C2-3 . C1:P1 . P1 0 "
" C0-1:P1 . . C2-3 C4-5 . . . 0 A1:4-5"
- " C0-1:P1 . . C2-3 S+:C4-5 . . . 0 A1:4-5"
" C0-1 . . C2-3:P1 . . . C2 0 "
" C0-1 . . C2-3:P1 . . . C4-5 0 B1:4-5"
- "C0-3:P1:S+ C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3"
- "C0-3:P1:S+ C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3"
- "C2-3:P1:S+ C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
- "C2-3:P1:S+ C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0"
- "C2-3:P1:S+ C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2"
- "C2-3:P1:S+ C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1"
+ " C0-3:P1 C2-3:P1 . . . . . . 0 A1:0-1|A2:2-3|XA2:2-3"
+ " C0-3:P1 C2-3:P1 . . C1-3 . . . 0 A1:1|A2:2-3|XA2:2-3"
+ " C2-3:P1 C3:P1 . . C3 . . . 0 A1:|A2:3|XA2:3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P1 . . C3 P0 . . 0 A1:3|A2:3 A1:P1|A2:P0"
+ " C2-3:P1 C2:P1 . . C2-4 . . . 0 A1:3-4|A2:2"
+ " C2-3:P1 C3:P1 . . C3 . . C0-2 0 A1:|B1:0-2 A1:P1|A2:P1"
"$SETUP_A123_PARTITIONS . C2-3 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
# CPU offlining cases:
- " C0-1 . . C2-3 S+ C4-5 . O2=0 0 A1:0-1|B1:3"
- "C0-3:P1:S+ C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3"
- "C0-3:P1:S+ C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3"
- "C0-3:P1:S+ C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3"
- "C0-3:P1:S+ C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3"
- "C2-3:P1:S+ C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
- "C2-3:P1:S+ C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
- "C2-3:P1:S+ C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
- "C2-3:P1:S+ C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
- "C2-3:P1:S+ C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1"
- "C2-3:P1:S+ C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1"
- "C2-3:P1:S+ C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1"
- "C2-3:P1:S+ C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1"
+ " C0-1 . . C2-3 . C4-5 . O2=0 0 A1:0-1|B1:3"
+ " C0-3:P1 C2-3:P1 . . O2=0 . . . 0 A1:0-1|A2:3"
+ " C0-3:P1 C2-3:P1 . . O2=0 O2=1 . . 0 A1:0-1|A2:2-3"
+ " C0-3:P1 C2-3:P1 . . O1=0 . . . 0 A1:0|A2:2-3"
+ " C0-3:P1 C2-3:P1 . . O1=0 O1=1 . . 0 A1:0-1|A2:2-3"
+ " C2-3:P1 C3:P1 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P2 . . O3=0 O3=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
+ " C2-3:P1 C3:P1 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P2 . . O2=0 O2=1 . . 0 A1:2|A2:3 A1:P1|A2:P2"
+ " C2-3:P1 C3:P1 . . O2=0 . . . 0 A1:|A2:3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P1 . . O3=0 . . . 0 A1:2|A2: A1:P1|A2:P1"
+ " C2-3:P1 C3:P1 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-1"
+ " C2-3:P1 C3:P1 . . . T:O3=0 . . 0 A1:2|A2:2 A1:P1|A2:P-1"
+ " C2-3:P1 C3:P2 . . T:O2=0 . . . 0 A1:3|A2:3 A1:P1|A2:P-2"
+ " C1-3:P1 C3:P2 . . . T:O3=0 . . 0 A1:1-2|A2:1-2 A1:P1|A2:P-2 3|"
+ " C1-3:P1 C3:P2 . . . T:O3=0 O3=1 . 0 A1:1-2|A2:3 A1:P1|A2:P2 3"
"$SETUP_A123_PARTITIONS . O1=0 . . . 0 A1:|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
"$SETUP_A123_PARTITIONS . O2=0 . . . 0 A1:1|A2:|A3:3 A1:P1|A2:P1|A3:P1"
"$SETUP_A123_PARTITIONS . O3=0 . . . 0 A1:1|A2:2|A3: A1:P1|A2:P1|A3:P1"
@@ -264,88 +265,87 @@ TEST_MATRIX=(
#
# Remote partition and cpuset.cpus.exclusive tests
#
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3"
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3"
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3"
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
- " C0-3:S+ C1-3:S+ C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2"
- " C0-3:S+ C1-3:S+ C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
- " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
- " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
- " C0-3:S+ C1-3:S+ C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3"
- " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
- " C4:X0-3:S+ X1-3:S+ X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
- " C4:X0-3:S+ X1-3:S+ X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
+ " C0-3 C1-3 C2-3 . X2-3 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:2-3"
+ " C0-3 C1-3 C2-3 . X2-3 X2-3:P2 . . 0 A1:0-1|A2:2-3|A3:2-3 A1:P0|A2:P2 2-3"
+ " C0-3 C1-3 C2-3 . X2-3 X3:P2 . . 0 A1:0-2|A2:3|A3:3 A1:P0|A2:P2 3"
+ " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
+ " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:C3 . 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
+ " C0-3 C1-3 C2-3 C2-3 . . . P2 0 A1:0-1|A2:1|A3:1|B1:2-3 A1:P0|A3:P0|B1:P2"
+ " C0-3 C1-3 C2-3 C4-5 . . . P2 0 B1:4-5 B1:P2 4-5"
+ " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
+ " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2:C1-3 P2 0 A3:2-3|B1:4 A3:P2|B1:P2 2-4"
+ " C0-3 C1-3 C2-3 C4 X1-3 X1-3:P2 P2 . 0 A2:1|A3:2-3 A2:P2|A3:P2 1-3"
+ " C0-3 C1-3 C2-3 C4 X2-3 X2-3 X2-3:P2 P2:C4-5 0 A3:2-3|B1:4-5 A3:P2|B1:P2 2-5"
+ " C4:X0-3 X1-3 X2-3 . . P2 . . 0 A1:4|A2:1-3|A3:1-3 A2:P2 1-3"
+ " C4:X0-3 X1-3 X2-3 . . . P2 . 0 A1:4|A2:4|A3:2-3 A3:P2 2-3"
# Nested remote/local partition tests
- " C0-3:S+ C1-3:S+ C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \
+ " C0-3 C1-3 C2-3 C4-5 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4-5 \
A1:P0|A2:P1|A3:P2|B1:P1 2-3"
- " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \
+ " C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:|A3:2-3|B1:4 \
A1:P0|A2:P1|A3:P2|B1:P1 2-4|2-3"
- " C0-3:S+ C1-3:S+ C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \
+ " C0-3 C1-3 C2-3 C4 X2-3 X2-3:P1 . P1 0 A1:0-1|A2:2-3|A3:2-3|B1:4 \
A1:P0|A2:P1|A3:P0|B1:P1"
- " C0-3:S+ C1-3:S+ C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \
+ " C0-3 C1-3 C3 C4 X2-3 X2-3:P1 P2 P1 0 A1:0-1|A2:2|A3:3|B1:4 \
A1:P0|A2:P1|A3:P2|B1:P1 2-4|3"
- " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \
+ " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X4:P1 . 0 A1:0-1|A2:2-3|A3:4 \
A1:P0|A2:P2|A3:P1 2-4|2-3"
- " C0-4:S+ C1-4:S+ C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \
+ " C0-4 C1-4 C2-4 . X2-4 X2-4:P2 X3-4:P1 . 0 A1:0-1|A2:2|A3:3-4 \
A1:P0|A2:P2|A3:P1 2"
- " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
+ " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
. . X5 . . 0 A1:0-4|A2:1-4|A3:2-4 \
A1:P0|A2:P-2|A3:P-1 ."
- " C0-4:X2-4:S+ C1-4:X2-4:S+:P2 C2-4:X4:P1 \
+ " C0-4:X2-4 C1-4:X2-4:P2 C2-4:X4:P1 \
. . . X1 . 0 A1:0-1|A2:2-4|A3:2-4 \
A1:P0|A2:P2|A3:P-1 2-4"
# Remote partition offline tests
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
- " C0-3:S+ C1-3:S+ C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
- " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3"
- " C0-3:S+ C1-3:S+ C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|"
+ " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 . 0 A1:0-1|A2:1|A3:3 A1:P0|A3:P2 2-3"
+ " C0-3 C1-3 C2-3 . X2-3 X2-3 X2-3:P2:O2=0 O2=1 0 A1:0-1|A2:1|A3:2-3 A1:P0|A3:P2 2-3"
+ " C0-3 C1-3 C3 . X2-3 X2-3 P2:O3=0 . 0 A1:0-2|A2:1-2|A3: A1:P0|A3:P2 3"
+ " C0-3 C1-3 C3 . X2-3 X2-3 T:P2:O3=0 . 0 A1:0-2|A2:1-2|A3:1-2 A1:P0|A3:P-2 3|"
# An invalidated remote partition cannot self-recover from hotplug
- " C0-3:S+ C1-3:S+ C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ."
+ " C0-3 C1-3 C2 . X2-3 X2-3 T:P2:O2=0 O2=1 0 A1:0-3|A2:1-3|A3:2 A1:P0|A3:P-2 ."
# cpus.exclusive.effective clearing test
- " C0-3:S+ C1-3:S+ C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:"
+ " C0-3 C1-3 C2 . X2-3:X . . . 0 A1:0-3|A2:1-3|A3:2|XA1:"
# Invalid to valid remote partition transition test
- " C0-3:S+ C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ."
- " C0-3:S+ C1-3:X3:P2
- . . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3"
+ " C0-3 C1-3 . . . X3:P2 . . 0 A1:0-3|A2:1-3|XA2: A2:P-2 ."
+ " C0-3 C1-3:X3:P2 . . X2-3 P2 . . 0 A1:0-2|A2:3|XA2:3 A2:P2 3"
# Invalid to valid local partition direct transition tests
- " C1-3:S+:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3"
- " C1-3:S+:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3"
- " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0"
- " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3"
+ " C1-3:P2 X4:P2 . . . . . . 0 A1:1-3|XA1:1-3|A2:1-3:XA2: A1:P2|A2:P-2 1-3"
+ " C1-3:P2 X4:P2 . . . X3:P2 . . 0 A1:1-2|XA1:1-3|A2:3:XA2:3 A1:P2|A2:P2 1-3"
+ " C0-3:P2 . . C4-6 C0-4 . . . 0 A1:0-4|B1:5-6 A1:P2|B1:P0"
+ " C0-3:P2 . . C4-6 C0-4:C0-3 . . . 0 A1:0-3|B1:4-6 A1:P2|B1:P0 0-3"
# Local partition invalidation tests
- " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
+ " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
. . . . . 0 A1:1|A2:2|A3:3 A1:P2|A2:P2|A3:P2 1-3"
- " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
+ " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
. . X4 . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
- " C0-3:X1-3:S+:P2 C1-3:X2-3:S+:P2 C2-3:X3:P2 \
+ " C0-3:X1-3:P2 C1-3:X2-3:P2 C2-3:X3:P2 \
. . C4:X . . 0 A1:1-3|A2:1-3|A3:2-3|XA2:|XA3: A1:P2|A2:P-2|A3:P-2 1-3"
# Local partition CPU change tests
- " C0-5:S+:P2 C4-5:S+:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
- " C0-5:S+:P2 C4-5:S+:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
+ " C0-5:P2 C4-5:P1 . . . C3-5 . . 0 A1:0-2|A2:3-5 A1:P2|A2:P1 0-2"
+ " C0-5:P2 C4-5:P1 . . C1-5 . . . 0 A1:1-3|A2:4-5 A1:P2|A2:P1 1-3"
# cpus_allowed/exclusive_cpus update tests
- " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
+ " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
. X:C4 . P2 . 0 A1:4|A2:4|XA2:|XA3:|A3:4 \
A1:P0|A3:P-2 ."
- " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
+ " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
. X1 . P2 . 0 A1:0-3|A2:1-3|XA1:1|XA2:|XA3:|A3:2-3 \
A1:P0|A3:P-2 ."
- " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3 \
+ " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3 \
. . X3 P2 . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3 \
A1:P0|A3:P2 3"
- " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
+ " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \
. . X3 . . 0 A1:0-2|A2:1-2|XA2:3|XA3:3|A3:3|XA3:3 \
A1:P0|A3:P2 3"
- " C0-3:X2-3:S+ C1-3:X2-3:S+ C2-3:X2-3:P2 \
+ " C0-3:X2-3 C1-3:X2-3 C2-3:X2-3:P2 \
. X4 . . . 0 A1:0-3|A2:1-3|A3:2-3|XA1:4|XA2:|XA3 \
A1:P0|A3:P-2"
@@ -356,37 +356,37 @@ TEST_MATRIX=(
#
# Adding CPUs to partition root that are not in parent's
# cpuset.cpus is allowed, but those extra CPUs are ignored.
- "C2-3:P1:S+ C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P1 . . . C2-4 . . 0 A1:|A2:2-3 A1:P1|A2:P1"
# Taking away all CPUs from parent or itself if there are tasks
# will make the partition invalid.
- "C2-3:P1:S+ C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
- " C3:P1:S+ C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1"
+ " C2-3:P1 C3:P1 . . T C2-3 . . 0 A1:2-3|A2:2-3 A1:P1|A2:P-1"
+ " C3:P1 C3 . . T P1 . . 0 A1:3|A2:3 A1:P1|A2:P-1"
"$SETUP_A123_PARTITIONS . T:C2-3 . . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P-1|A3:P-1"
"$SETUP_A123_PARTITIONS . T:C2-3:C1-3 . . . 0 A1:1|A2:2|A3:3 A1:P1|A2:P1|A3:P1"
# Changing a partition root to member makes child partitions invalid
- "C2-3:P1:S+ C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1"
+ " C2-3:P1 C3:P1 . . P0 . . . 0 A1:2-3|A2:3 A1:P0|A2:P-1"
"$SETUP_A123_PARTITIONS . C2-3 P0 . . 0 A1:2-3|A2:2-3|A3:3 A1:P1|A2:P0|A3:P-1"
# cpuset.cpus can contains cpus not in parent's cpuset.cpus as long
# as they overlap.
- "C2-3:P1:S+ . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
+ " C2-3:P1 . . . . C3-4:P1 . . 0 A1:2|A2:3 A1:P1|A2:P1"
# Deletion of CPUs distributed to child cgroup is allowed.
- "C0-1:P1:S+ C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5"
+ " C0-1:P1 C1 . C2-3 C4-5 . . . 0 A1:4-5|A2:4-5"
# To become a valid partition root, cpuset.cpus must overlap parent's
# cpuset.cpus.
- " C0-1:P1 . . C2-3 S+ C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1"
+ " C0-1:P1 . . C2-3 . C4-5:P1 . . 0 A1:0-1|A2:0-1 A1:P1|A2:P-1"
# Enabling partition with child cpusets is allowed
- " C0-1:S+ C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1"
+ " C0-1 C1 . C2-3 P1 . . . 0 A1:0-1|A2:1 A1:P1"
# A partition root with non-partition root parent is invalid| but it
# can be made valid if its parent becomes a partition root too.
- " C0-1:S+ C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2"
- " C0-1:S+ C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1"
+ " C0-1 C1 . C2-3 . P2 . . 0 A1:0-1|A2:1 A1:P0|A2:P-2"
+ " C0-1 C1:P2 . C2-3 P1 . . . 0 A1:0|A2:1 A1:P1|A2:P2 0-1|1"
# A non-exclusive cpuset.cpus change will not invalidate its siblings partition.
" C0-1:P1 . . C2-3 C0-2 . . . 0 A1:0-2|B1:3 A1:P1|B1:P0"
@@ -398,23 +398,23 @@ TEST_MATRIX=(
# Child partition root that try to take all CPUs from parent partition
# with tasks will remain invalid.
- " C1-4:P1:S+ P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
- " C1-4:P1:S+ P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1"
- " C1-4:P1:S+ P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
+ " C1-4:P1 P1 . . . . . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
+ " C1-4:P1 P1 . . . C1-4 . . 0 A1|A2:1-4 A1:P1|A2:P1"
+ " C1-4:P1 P1 . . T C1-4 . . 0 A1:1-4|A2:1-4 A1:P1|A2:P-1"
# Clearing of cpuset.cpus with a preset cpuset.cpus.exclusive shouldn't
# affect cpuset.cpus.exclusive.effective.
- " C1-4:X3:S+ C1:X3 . . . C . . 0 A2:1-4|XA2:3"
+ " C1-4:X3 C1:X3 . . . C . . 0 A2:1-4|XA2:3"
# cpuset.cpus can contain CPUs that overlap a sibling cpuset with cpus.exclusive
# but creating a local partition out of it is not allowed. Similarly and change
# in cpuset.cpus of a local partition that overlaps sibling exclusive CPUs will
# invalidate it.
- " CX1-4:S+ CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \
+ " CX1-4 CX2-4:P2 . C5-6 . . . P1 0 A1:1|A2:2-4|B1:5-6|XB1:5-6 \
A1:P0|A2:P2:B1:P1 2-4"
- " CX1-4:S+ CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \
+ " CX1-4 CX2-4:P2 . C3-6 . . . P1 0 A1:1|A2:2-4|B1:5-6 \
A1:P0|A2:P2:B1:P-1 2-4"
- " CX1-4:S+ CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \
+ " CX1-4 CX2-4:P2 . C5-6 . . . P1:C3-6 0 A1:1|A2:2-4|B1:5-6 \
A1:P0|A2:P2:B1:P-1 2-4"
# When multiple partitions with conflicting cpuset.cpus are created, the
@@ -426,14 +426,14 @@ TEST_MATRIX=(
" C1-3:X1-3 . . C4-5 . . . C1-2 0 A1:1-3|B1:1-2"
# cpuset.cpus can become empty with task in it as it inherits parent's effective CPUs
- " C1-3:S+ C2 . . . T:C . . 0 A1:1-3|A2:1-3"
+ " C1-3 C2 . . . T:C . . 0 A1:1-3|A2:1-3"
# old-A1 old-A2 old-A3 old-B1 new-A1 new-A2 new-A3 new-B1 fail ECPUs Pstate ISOLCPUS
# ------ ------ ------ ------ ------ ------ ------ ------ ---- ----- ------ --------
# Failure cases:
# A task cannot be added to a partition with no cpu
- "C2-3:P1:S+ C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1"
+ " C2-3:P1 C3:P1 . . O2=0:T . . . 1 A1:|A2:3 A1:P1|A2:P1"
# Changes to cpuset.cpus.exclusive that violate exclusivity rule is rejected
" C0-3 . . C4-5 X0-3 . . X3-5 1 A1:0-3|B1:4-5"
@@ -465,31 +465,31 @@ REMOTE_TEST_MATRIX=(
# old-p1 old-p2 old-c11 old-c12 old-c21 old-c22
# new-p1 new-p2 new-c11 new-c12 new-c21 new-c22 ECPUs Pstate ISOLCPUS
# ------ ------ ------- ------- ------- ------- ----- ------ --------
- " X1-3:S+ X4-6:S+ X1-2 X3 X4-5 X6 \
+ " X1-3 X4-6 X1-2 X3 X4-5 X6 \
. . P2 P2 P2 P2 c11:1-2|c12:3|c21:4-5|c22:6 \
c11:P2|c12:P2|c21:P2|c22:P2 1-6"
- " CX1-4:S+ . X1-2:P2 C3 . . \
+ " CX1-4 . X1-2:P2 C3 . . \
. . . C3-4 . . p1:3-4|c11:1-2|c12:3-4 \
p1:P0|c11:P2|c12:P0 1-2"
- " CX1-4:S+ . X1-2:P2 . . . \
+ " CX1-4 . X1-2:P2 . . . \
X2-4 . . . . . p1:1,3-4|c11:2 \
p1:P0|c11:P2 2"
- " CX1-5:S+ . X1-2:P2 X3-5:P1 . . \
+ " CX1-5 . X1-2:P2 X3-5:P1 . . \
X2-4 . . . . . p1:1,5|c11:2|c12:3-4 \
p1:P0|c11:P2|c12:P1 2"
- " CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
+ " CX1-4 . X1-2:P2 X3-4:P1 . . \
. . X2 . . . p1:1|c11:2|c12:3-4 \
p1:P0|c11:P2|c12:P1 2"
# p1 as member, will get its effective CPUs from its parent rtest
- " CX1-4:S+ . X1-2:P2 X3-4:P1 . . \
+ " CX1-4 . X1-2:P2 X3-4:P1 . . \
. . X1 CX2-4 . . p1:5-7|c11:1|c12:2-4 \
p1:P0|c11:P2|c12:P1 1"
- " CX1-4:S+ X5-6:P1:S+ . . . . \
- . . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \
+ " CX1-4 X5-6:P1 . . . . \
+ . . X1-2:P2 X4-5:P1 . X1-7:P2 p1:3|c11:1-2|c12:4:c22:5-6 \
p1:P0|p2:P1|c11:P2|c12:P1|c22:P2 \
1-2,4-6|1-2,5-6"
# c12 whose cpuset.cpus CPUs are all granted to c11 will become invalid partition
- " C1-5:P1:S+ . C1-4:P1 C2-3 . . \
+ " C1-5:P1 . C1-4:P1 C2-3 . . \
. . . P1 . . p1:5|c11:1-4|c12:5 \
p1:P1|c11:P1|c12:P-1"
)
@@ -530,7 +530,6 @@ set_ctrl_state()
CGRP=$1
STATE=$2
SHOWERR=${3}
- CTRL=${CTRL:=$CONTROLLER}
HASERR=0
REDIRECT="2> $TMPMSG"
[[ -z "$STATE" || "$STATE" = '.' ]] && return 0
@@ -540,15 +539,16 @@ set_ctrl_state()
for CMD in $(echo $STATE | sed -e "s/:/ /g")
do
TFILE=$CGRP/cgroup.procs
- SFILE=$CGRP/cgroup.subtree_control
PFILE=$CGRP/cpuset.cpus.partition
CFILE=$CGRP/cpuset.cpus
XFILE=$CGRP/cpuset.cpus.exclusive
- case $CMD in
- S*) PREFIX=${CMD#?}
- COMM="echo ${PREFIX}${CTRL} > $SFILE"
+
+ # Enable cpuset controller if not enabled yet
+ [[ -f $CFILE ]] || {
+ COMM="echo +cpuset > $CGRP/../cgroup.subtree_control"
eval $COMM $REDIRECT
- ;;
+ }
+ case $CMD in
X*)
CPUS=${CMD#?}
COMM="echo $CPUS > $XFILE"
@@ -764,7 +764,7 @@ check_cgroup_states()
# only CPUs in isolated partitions as well as those that are isolated at
# boot time.
#
-# $1 - expected isolated cpu list(s) <isolcpus1>{,<isolcpus2>}
+# $1 - expected isolated cpu list(s) <isolcpus1>{|<isolcpus2>}
# <isolcpus1> - expected sched/domains value
# <isolcpus2> - cpuset.cpus.isolated value = <isolcpus1> if not defined
#
@@ -773,6 +773,7 @@ check_isolcpus()
EXPECTED_ISOLCPUS=$1
ISCPUS=${CGROUP2}/cpuset.cpus.isolated
ISOLCPUS=$(cat $ISCPUS)
+ HKICPUS=$(cat /sys/devices/system/cpu/isolated)
LASTISOLCPU=
SCHED_DOMAINS=/sys/kernel/debug/sched/domains
if [[ $EXPECTED_ISOLCPUS = . ]]
@@ -811,6 +812,11 @@ check_isolcpus()
EXPECTED_ISOLCPUS=$EXPECTED_SDOMAIN
#
+ # The inverse of HK_TYPE_DOMAIN cpumask in $HKICPUS should match $ISOLCPUS
+ #
+ [[ "$ISOLCPUS" != "$HKICPUS" ]] && return 1
+
+ #
# Use the sched domain in debugfs to check isolated CPUs, if available
#
[[ -d $SCHED_DOMAINS ]] || return 0
@@ -947,7 +953,6 @@ check_test_results()
run_state_test()
{
TEST=$1
- CONTROLLER=cpuset
CGROUP_LIST=". A1 A1/A2 A1/A2/A3 B1"
RESET_LIST="A1/A2/A3 A1/A2 A1 B1"
I=0
@@ -1003,7 +1008,6 @@ run_state_test()
run_remote_state_test()
{
TEST=$1
- CONTROLLER=cpuset
[[ -d rtest ]] || mkdir rtest
cd rtest
echo +cpuset > cgroup.subtree_control
diff --git a/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c b/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c
index 61e55dfbf121..e19ff8168baf 100644
--- a/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c
+++ b/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c
@@ -37,17 +37,20 @@ FIXTURE(iterate_mount_namespaces) {
__u64 mnt_ns_id[MNT_NS_COUNT];
};
+static inline bool mntns_in_list(__u64 *mnt_ns_id, struct mnt_ns_info *info)
+{
+ for (int i = 0; i < MNT_NS_COUNT; i++) {
+ if (mnt_ns_id[i] == info->mnt_ns_id)
+ return true;
+ }
+ return false;
+}
+
FIXTURE_SETUP(iterate_mount_namespaces)
{
for (int i = 0; i < MNT_NS_COUNT; i++)
self->fd_mnt_ns[i] = -EBADF;
- /*
- * Creating a new user namespace let's us guarantee that we only see
- * mount namespaces that we did actually create.
- */
- ASSERT_EQ(unshare(CLONE_NEWUSER), 0);
-
for (int i = 0; i < MNT_NS_COUNT; i++) {
struct mnt_ns_info info = {};
@@ -75,13 +78,15 @@ TEST_F(iterate_mount_namespaces, iterate_all_forward)
fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[0], F_DUPFD_CLOEXEC);
ASSERT_GE(fd_mnt_ns_cur, 0);
- for (;; count++) {
+ for (;;) {
struct mnt_ns_info info = {};
int fd_mnt_ns_next;
fd_mnt_ns_next = ioctl(fd_mnt_ns_cur, NS_MNT_GET_NEXT, &info);
if (fd_mnt_ns_next < 0 && errno == ENOENT)
break;
+ if (mntns_in_list(self->mnt_ns_id, &info))
+ count++;
ASSERT_GE(fd_mnt_ns_next, 0);
ASSERT_EQ(close(fd_mnt_ns_cur), 0);
fd_mnt_ns_cur = fd_mnt_ns_next;
@@ -96,13 +101,15 @@ TEST_F(iterate_mount_namespaces, iterate_all_backwards)
fd_mnt_ns_cur = fcntl(self->fd_mnt_ns[MNT_NS_LAST_INDEX], F_DUPFD_CLOEXEC);
ASSERT_GE(fd_mnt_ns_cur, 0);
- for (;; count++) {
+ for (;;) {
struct mnt_ns_info info = {};
int fd_mnt_ns_prev;
fd_mnt_ns_prev = ioctl(fd_mnt_ns_cur, NS_MNT_GET_PREV, &info);
if (fd_mnt_ns_prev < 0 && errno == ENOENT)
break;
+ if (mntns_in_list(self->mnt_ns_id, &info))
+ count++;
ASSERT_GE(fd_mnt_ns_prev, 0);
ASSERT_EQ(close(fd_mnt_ns_cur), 0);
fd_mnt_ns_cur = fd_mnt_ns_prev;
@@ -125,7 +132,6 @@ TEST_F(iterate_mount_namespaces, iterate_forward)
ASSERT_GE(fd_mnt_ns_next, 0);
ASSERT_EQ(close(fd_mnt_ns_cur), 0);
fd_mnt_ns_cur = fd_mnt_ns_next;
- ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
}
}
@@ -144,7 +150,6 @@ TEST_F(iterate_mount_namespaces, iterate_backward)
ASSERT_GE(fd_mnt_ns_prev, 0);
ASSERT_EQ(close(fd_mnt_ns_cur), 0);
fd_mnt_ns_cur = fd_mnt_ns_prev;
- ASSERT_EQ(info.mnt_ns_id, self->mnt_ns_id[i]);
}
}
diff --git a/tools/testing/selftests/hid/tests/test_wacom_generic.py b/tools/testing/selftests/hid/tests/test_wacom_generic.py
index 2d6d04f0ff80..3903f479b15b 100644
--- a/tools/testing/selftests/hid/tests/test_wacom_generic.py
+++ b/tools/testing/selftests/hid/tests/test_wacom_generic.py
@@ -598,18 +598,6 @@ class BaseTest:
if unit_set:
assert required[usage].contains(field)
- def test_prop_direct(self):
- """
- Todo: Verify that INPUT_PROP_DIRECT is set on display devices.
- """
- pass
-
- def test_prop_pointer(self):
- """
- Todo: Verify that INPUT_PROP_POINTER is set on opaque devices.
- """
- pass
-
class PenTabletTest(BaseTest.TestTablet):
def assertName(self, uhdev):
@@ -677,6 +665,15 @@ class TestOpaqueTablet(PenTabletTest):
uhdev.event(130, 240, pressure=0), [], auto_syn=False, strict=True
)
+ def test_prop_pointer(self):
+ """
+ Verify that INPUT_PROP_POINTER is set and INPUT_PROP_DIRECT
+ is not set on opaque devices.
+ """
+ evdev = self.uhdev.get_evdev()
+ assert libevdev.INPUT_PROP_POINTER in evdev.properties
+ assert libevdev.INPUT_PROP_DIRECT not in evdev.properties
+
class TestOpaqueCTLTablet(TestOpaqueTablet):
def create_device(self):
@@ -862,7 +859,18 @@ class TestPTHX60_Pen(TestOpaqueCTLTablet):
)
-class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest):
+class DirectTabletTest():
+ def test_prop_direct(self):
+ """
+ Verify that INPUT_PROP_DIRECT is set and INPUT_PROP_POINTER
+ is not set on display devices.
+ """
+ evdev = self.uhdev.get_evdev()
+ assert libevdev.INPUT_PROP_DIRECT in evdev.properties
+ assert libevdev.INPUT_PROP_POINTER not in evdev.properties
+
+
+class TestDTH2452Tablet(test_multitouch.BaseTest.TestMultitouch, TouchTabletTest, DirectTabletTest):
ContactIds = namedtuple("ContactIds", "contact_id, tracking_id, slot_num")
def create_device(self):
diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 16a119a4656c..4afaef01c22e 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -76,6 +76,9 @@ static inline void __kselftest_memset_safe(void *s, int c, size_t n)
memset(s, c, n);
}
+#define KSELFTEST_PRIO_TEST_F 20000
+#define KSELFTEST_PRIO_XFAIL 20001
+
#define TEST_TIMEOUT_DEFAULT 30
/* Utilities exposed to the test definitions */
@@ -465,7 +468,7 @@ static inline void __kselftest_memset_safe(void *s, int c, size_t n)
fixture_name##_teardown(_metadata, self, variant); \
} \
static struct __test_metadata *_##fixture_name##_##test_name##_object; \
- static void __attribute__((constructor)) \
+ static void __attribute__((constructor(KSELFTEST_PRIO_TEST_F))) \
_register_##fixture_name##_##test_name(void) \
{ \
struct __test_metadata *object = mmap(NULL, sizeof(*object), \
@@ -880,7 +883,7 @@ struct __test_xfail {
.fixture = &_##fixture_name##_fixture_object, \
.variant = &_##fixture_name##_##variant_name##_object, \
}; \
- static void __attribute__((constructor)) \
+ static void __attribute__((constructor(KSELFTEST_PRIO_XFAIL))) \
_register_##fixture_name##_##variant_name##_##test_name##_xfail(void) \
{ \
_##fixture_name##_##variant_name##_##test_name##_xfail.test = \
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
index afdea6d95bde..605c54c0e8a3 100644
--- a/tools/testing/selftests/net/Makefile
+++ b/tools/testing/selftests/net/Makefile
@@ -15,6 +15,7 @@ TEST_PROGS := \
big_tcp.sh \
bind_bhash.sh \
bpf_offload.py \
+ bridge_vlan_dump.sh \
broadcast_ether_dst.sh \
broadcast_pmtu.sh \
busy_poll_test.sh \
diff --git a/tools/testing/selftests/net/bridge_vlan_dump.sh b/tools/testing/selftests/net/bridge_vlan_dump.sh
new file mode 100755
index 000000000000..ad66731d2a6f
--- /dev/null
+++ b/tools/testing/selftests/net/bridge_vlan_dump.sh
@@ -0,0 +1,204 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Test bridge VLAN range grouping. VLANs are collapsed into a range entry in
+# the dump if they have the same per-VLAN options. These tests verify that
+# VLANs with different per-VLAN option values are not grouped together.
+
+# shellcheck disable=SC1091,SC2034,SC2154,SC2317
+source lib.sh
+
+ALL_TESTS="
+ vlan_range_neigh_suppress
+ vlan_range_mcast_max_groups
+ vlan_range_mcast_n_groups
+ vlan_range_mcast_enabled
+"
+
+setup_prepare()
+{
+ setup_ns NS
+ defer cleanup_all_ns
+
+ ip -n "$NS" link add name br0 type bridge vlan_filtering 1 \
+ vlan_default_pvid 0 mcast_snooping 1 mcast_vlan_snooping 1
+ ip -n "$NS" link set dev br0 up
+
+ ip -n "$NS" link add name dummy0 type dummy
+ ip -n "$NS" link set dev dummy0 master br0
+ ip -n "$NS" link set dev dummy0 up
+}
+
+vlan_range_neigh_suppress()
+{
+ RET=0
+
+ # Add two new consecutive VLANs for range grouping test
+ bridge -n "$NS" vlan add vid 10 dev dummy0
+ defer bridge -n "$NS" vlan del vid 10 dev dummy0
+
+ bridge -n "$NS" vlan add vid 11 dev dummy0
+ defer bridge -n "$NS" vlan del vid 11 dev dummy0
+
+ # Configure different neigh_suppress values and verify no range grouping
+ bridge -n "$NS" vlan set vid 10 dev dummy0 neigh_suppress on
+ check_err $? "Failed to set neigh_suppress for VLAN 10"
+
+ bridge -n "$NS" vlan set vid 11 dev dummy0 neigh_suppress off
+ check_err $? "Failed to set neigh_suppress for VLAN 11"
+
+ # Verify VLANs are not shown as a range, but individual entries exist
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_fail $? "VLANs with different neigh_suppress incorrectly grouped"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$"
+ check_err $? "VLAN 10 individual entry not found"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$"
+ check_err $? "VLAN 11 individual entry not found"
+
+ # Configure same neigh_suppress value and verify range grouping
+ bridge -n "$NS" vlan set vid 11 dev dummy0 neigh_suppress on
+ check_err $? "Failed to set neigh_suppress for VLAN 11"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_err $? "VLANs with same neigh_suppress not grouped"
+
+ log_test "VLAN range grouping with neigh_suppress"
+}
+
+vlan_range_mcast_max_groups()
+{
+ RET=0
+
+ # Add two new consecutive VLANs for range grouping test
+ bridge -n "$NS" vlan add vid 10 dev dummy0
+ defer bridge -n "$NS" vlan del vid 10 dev dummy0
+
+ bridge -n "$NS" vlan add vid 11 dev dummy0
+ defer bridge -n "$NS" vlan del vid 11 dev dummy0
+
+ # Configure different mcast_max_groups values and verify no range grouping
+ bridge -n "$NS" vlan set vid 10 dev dummy0 mcast_max_groups 100
+ check_err $? "Failed to set mcast_max_groups for VLAN 10"
+
+ bridge -n "$NS" vlan set vid 11 dev dummy0 mcast_max_groups 200
+ check_err $? "Failed to set mcast_max_groups for VLAN 11"
+
+ # Verify VLANs are not shown as a range, but individual entries exist
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_fail $? "VLANs with different mcast_max_groups incorrectly grouped"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$"
+ check_err $? "VLAN 10 individual entry not found"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$"
+ check_err $? "VLAN 11 individual entry not found"
+
+ # Configure same mcast_max_groups value and verify range grouping
+ bridge -n "$NS" vlan set vid 11 dev dummy0 mcast_max_groups 100
+ check_err $? "Failed to set mcast_max_groups for VLAN 11"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_err $? "VLANs with same mcast_max_groups not grouped"
+
+ log_test "VLAN range grouping with mcast_max_groups"
+}
+
+vlan_range_mcast_n_groups()
+{
+ RET=0
+
+ # Add two new consecutive VLANs for range grouping test
+ bridge -n "$NS" vlan add vid 10 dev dummy0
+ defer bridge -n "$NS" vlan del vid 10 dev dummy0
+
+ bridge -n "$NS" vlan add vid 11 dev dummy0
+ defer bridge -n "$NS" vlan del vid 11 dev dummy0
+
+ # Add different numbers of multicast groups to each VLAN
+ bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.1 vid 10
+ check_err $? "Failed to add mdb entry to VLAN 10"
+ defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.1 vid 10
+
+ bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.2 vid 10
+ check_err $? "Failed to add second mdb entry to VLAN 10"
+ defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.2 vid 10
+
+ bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.1 vid 11
+ check_err $? "Failed to add mdb entry to VLAN 11"
+ defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.1 vid 11
+
+ # Verify VLANs are not shown as a range due to different mcast_n_groups
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_fail $? "VLANs with different mcast_n_groups incorrectly grouped"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$"
+ check_err $? "VLAN 10 individual entry not found"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$"
+ check_err $? "VLAN 11 individual entry not found"
+
+ # Add another group to VLAN 11 to match VLAN 10's count
+ bridge -n "$NS" mdb add dev br0 port dummy0 grp 239.1.1.2 vid 11
+ check_err $? "Failed to add second mdb entry to VLAN 11"
+ defer bridge -n "$NS" mdb del dev br0 port dummy0 grp 239.1.1.2 vid 11
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_err $? "VLANs with same mcast_n_groups not grouped"
+
+ log_test "VLAN range grouping with mcast_n_groups"
+}
+
+vlan_range_mcast_enabled()
+{
+ RET=0
+
+ # Add two new consecutive VLANs for range grouping test
+ bridge -n "$NS" vlan add vid 10 dev br0 self
+ defer bridge -n "$NS" vlan del vid 10 dev br0 self
+
+ bridge -n "$NS" vlan add vid 11 dev br0 self
+ defer bridge -n "$NS" vlan del vid 11 dev br0 self
+
+ bridge -n "$NS" vlan add vid 10 dev dummy0
+ defer bridge -n "$NS" vlan del vid 10 dev dummy0
+
+ bridge -n "$NS" vlan add vid 11 dev dummy0
+ defer bridge -n "$NS" vlan del vid 11 dev dummy0
+
+ # Configure different mcast_snooping for bridge VLANs
+ # Port VLANs inherit BR_VLFLAG_MCAST_ENABLED from bridge VLANs
+ bridge -n "$NS" vlan global set dev br0 vid 10 mcast_snooping 1
+ bridge -n "$NS" vlan global set dev br0 vid 11 mcast_snooping 0
+
+ # Verify port VLANs are not grouped due to different mcast_enabled
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_fail $? "VLANs with different mcast_enabled incorrectly grouped"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+10$|^\s+10$"
+ check_err $? "VLAN 10 individual entry not found"
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -Eq "^\S+\s+11$|^\s+11$"
+ check_err $? "VLAN 11 individual entry not found"
+
+ # Configure same mcast_snooping and verify range grouping
+ bridge -n "$NS" vlan global set dev br0 vid 11 mcast_snooping 1
+
+ bridge -n "$NS" -d vlan show dev dummy0 | grep -q "10-11"
+ check_err $? "VLANs with same mcast_enabled not grouped"
+
+ log_test "VLAN range grouping with mcast_enabled"
+}
+
+# Verify the newest tested option is supported
+if ! bridge vlan help 2>&1 | grep -q "neigh_suppress"; then
+ echo "SKIP: iproute2 too old, missing per-VLAN neighbor suppression support"
+ exit "$ksft_skip"
+fi
+
+trap defer_scopes_cleanup EXIT
+setup_prepare
+tests_run
+
+exit "$EXIT_STATUS"
diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
index 21026b667667..6eb7f95e70e1 100755
--- a/tools/testing/selftests/net/fib_nexthops.sh
+++ b/tools/testing/selftests/net/fib_nexthops.sh
@@ -1672,6 +1672,17 @@ ipv4_withv6_fcnal()
run_cmd "$IP ro replace 172.16.101.1/32 via inet6 2001:db8:50::1 dev veth1"
log_test $? 2 "IPv4 route with invalid IPv6 gateway"
+
+ # Test IPv4 route with loopback IPv6 nexthop
+ # Regression test: loopback IPv6 nexthop was misclassified as reject
+ # route, skipping nhc_pcpu_rth_output allocation, causing panic when
+ # an IPv4 route references it and triggers __mkroute_output().
+ run_cmd "$IP -6 nexthop add id 20 dev lo"
+ run_cmd "$IP ro add 172.20.20.0/24 nhid 20"
+ run_cmd "ip netns exec $me ping -c1 -W1 172.20.20.1"
+ log_test $? 1 "IPv4 route with loopback IPv6 nexthop (no crash)"
+ run_cmd "$IP ro del 172.20.20.0/24"
+ run_cmd "$IP nexthop del id 20"
}
ipv4_fcnal_runtime()
diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh
index dc1f200aaa81..a3144d7298a5 100755
--- a/tools/testing/selftests/net/mptcp/mptcp_join.sh
+++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh
@@ -104,6 +104,24 @@ CBPF_MPTCP_SUBOPTION_ADD_ADDR="14,
6 0 0 65535,
6 0 0 0"
+# IPv4: TCP hdr of 48B, a first suboption of 12B (DACK8), the RM_ADDR suboption
+# generated using "nfbpf_compile '(ip[32] & 0xf0) == 0xc0 && ip[53] == 0x0c &&
+# (ip[66] & 0xf0) == 0x40'"
+CBPF_MPTCP_SUBOPTION_RM_ADDR="13,
+ 48 0 0 0,
+ 84 0 0 240,
+ 21 0 9 64,
+ 48 0 0 32,
+ 84 0 0 240,
+ 21 0 6 192,
+ 48 0 0 53,
+ 21 0 4 12,
+ 48 0 0 66,
+ 84 0 0 240,
+ 21 0 1 64,
+ 6 0 0 65535,
+ 6 0 0 0"
+
init_partial()
{
capout=$(mktemp)
@@ -2608,6 +2626,19 @@ remove_tests()
chk_rst_nr 0 0
fi
+ # signal+subflow with limits, remove
+ if reset "remove signal+subflow with limits"; then
+ pm_nl_set_limits $ns1 0 0
+ pm_nl_add_endpoint $ns1 10.0.2.1 flags signal,subflow
+ pm_nl_set_limits $ns2 0 0
+ addr_nr_ns1=-1 speed=slow \
+ run_tests $ns1 $ns2 10.0.1.1
+ chk_join_nr 0 0 0
+ chk_add_nr 1 1
+ chk_rm_nr 1 0 invert
+ chk_rst_nr 0 0
+ fi
+
# addresses remove
if reset "remove addresses"; then
pm_nl_set_limits $ns1 3 3
@@ -4217,6 +4248,14 @@ endpoint_tests()
chk_subflow_nr "after no reject" 3
chk_mptcp_info subflows 2 subflows 2
+ # To make sure RM_ADDR are sent over a different subflow, but
+ # allow the rest to quickly and cleanly close the subflow
+ local ipt=1
+ ip netns exec "${ns2}" ${iptables} -I OUTPUT -s "10.0.1.2" \
+ -p tcp -m tcp --tcp-option 30 \
+ -m bpf --bytecode \
+ "$CBPF_MPTCP_SUBOPTION_RM_ADDR" \
+ -j DROP || ipt=0
local i
for i in $(seq 3); do
pm_nl_del_endpoint $ns2 1 10.0.1.2
@@ -4229,6 +4268,7 @@ endpoint_tests()
chk_subflow_nr "after re-add id 0 ($i)" 3
chk_mptcp_info subflows 3 subflows 3
done
+ [ ${ipt} = 1 ] && ip netns exec "${ns2}" ${iptables} -D OUTPUT 1
mptcp_lib_kill_group_wait $tests_pid
@@ -4288,11 +4328,20 @@ endpoint_tests()
chk_mptcp_info subflows 2 subflows 2
chk_mptcp_info add_addr_signal 2 add_addr_accepted 2
+ # To make sure RM_ADDR are sent over a different subflow, but
+ # allow the rest to quickly and cleanly close the subflow
+ local ipt=1
+ ip netns exec "${ns1}" ${iptables} -I OUTPUT -s "10.0.1.1" \
+ -p tcp -m tcp --tcp-option 30 \
+ -m bpf --bytecode \
+ "$CBPF_MPTCP_SUBOPTION_RM_ADDR" \
+ -j DROP || ipt=0
pm_nl_del_endpoint $ns1 42 10.0.1.1
sleep 0.5
chk_subflow_nr "after delete ID 0" 2
chk_mptcp_info subflows 2 subflows 2
chk_mptcp_info add_addr_signal 2 add_addr_accepted 2
+ [ ${ipt} = 1 ] && ip netns exec "${ns1}" ${iptables} -D OUTPUT 1
pm_nl_add_endpoint $ns1 10.0.1.1 id 99 flags signal
wait_mpj 4
diff --git a/tools/testing/selftests/net/mptcp/simult_flows.sh b/tools/testing/selftests/net/mptcp/simult_flows.sh
index 806aaa7d2d61..d11a8b949aab 100755
--- a/tools/testing/selftests/net/mptcp/simult_flows.sh
+++ b/tools/testing/selftests/net/mptcp/simult_flows.sh
@@ -237,10 +237,13 @@ run_test()
for dev in ns2eth1 ns2eth2; do
tc -n $ns2 qdisc del dev $dev root >/dev/null 2>&1
done
- tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1
- tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2
- tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1
- tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2
+
+ # keep the queued pkts number low, or the RTT estimator will see
+ # increasing latency over time.
+ tc -n $ns1 qdisc add dev ns1eth1 root netem rate ${rate1}mbit $delay1 limit 50
+ tc -n $ns1 qdisc add dev ns1eth2 root netem rate ${rate2}mbit $delay2 limit 50
+ tc -n $ns2 qdisc add dev ns2eth1 root netem rate ${rate1}mbit $delay1 limit 50
+ tc -n $ns2 qdisc add dev ns2eth2 root netem rate ${rate2}mbit $delay2 limit 50
# time is measured in ms, account for transfer size, aggregated link speed
# and header overhead (10%)
diff --git a/tools/testing/selftests/net/netfilter/nf_queue.c b/tools/testing/selftests/net/netfilter/nf_queue.c
index 9e56b9d47037..116c0ca0eabb 100644
--- a/tools/testing/selftests/net/netfilter/nf_queue.c
+++ b/tools/testing/selftests/net/netfilter/nf_queue.c
@@ -18,6 +18,7 @@
struct options {
bool count_packets;
bool gso_enabled;
+ bool failopen;
int verbose;
unsigned int queue_num;
unsigned int timeout;
@@ -30,7 +31,7 @@ static struct options opts;
static void help(const char *p)
{
- printf("Usage: %s [-c|-v [-vv] ] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
+ printf("Usage: %s [-c|-v [-vv] ] [-o] [-t timeout] [-q queue_num] [-Qdst_queue ] [ -d ms_delay ] [-G]\n", p);
}
static int parse_attr_cb(const struct nlattr *attr, void *data)
@@ -236,6 +237,8 @@ struct mnl_socket *open_queue(void)
flags = opts.gso_enabled ? NFQA_CFG_F_GSO : 0;
flags |= NFQA_CFG_F_UID_GID;
+ if (opts.failopen)
+ flags |= NFQA_CFG_F_FAIL_OPEN;
mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(flags));
mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(flags));
@@ -329,7 +332,7 @@ static void parse_opts(int argc, char **argv)
{
int c;
- while ((c = getopt(argc, argv, "chvt:q:Q:d:G")) != -1) {
+ while ((c = getopt(argc, argv, "chvot:q:Q:d:G")) != -1) {
switch (c) {
case 'c':
opts.count_packets = true;
@@ -366,6 +369,9 @@ static void parse_opts(int argc, char **argv)
case 'G':
opts.gso_enabled = false;
break;
+ case 'o':
+ opts.failopen = true;
+ break;
case 'v':
opts.verbose++;
break;
diff --git a/tools/testing/selftests/net/netfilter/nft_queue.sh b/tools/testing/selftests/net/netfilter/nft_queue.sh
index 139bc1211878..ea766bdc5d04 100755
--- a/tools/testing/selftests/net/netfilter/nft_queue.sh
+++ b/tools/testing/selftests/net/netfilter/nft_queue.sh
@@ -591,6 +591,7 @@ EOF
test_udp_gro_ct()
{
local errprefix="FAIL: test_udp_gro_ct:"
+ local timeout=5
ip netns exec "$nsrouter" conntrack -F 2>/dev/null
@@ -630,10 +631,10 @@ table inet udpq {
}
}
EOF
- timeout 10 ip netns exec "$ns2" socat UDP-LISTEN:12346,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc &
+ timeout "$timeout" ip netns exec "$ns2" socat UDP-LISTEN:12346,fork,pf=ipv4 OPEN:"$TMPFILE1",trunc &
local rpid=$!
- ip netns exec "$nsrouter" ./nf_queue -G -c -q 1 -t 2 > "$TMPFILE2" &
+ ip netns exec "$nsrouter" nice -n -19 ./nf_queue -G -c -q 1 -o -t 2 > "$TMPFILE2" &
local nfqpid=$!
ip netns exec "$nsrouter" ethtool -K "veth0" rx-udp-gro-forwarding on rx-gro-list on generic-receive-offload on
@@ -643,8 +644,12 @@ EOF
local bs=512
local count=$(((32 * 1024 * 1024) / bs))
- dd if=/dev/zero bs="$bs" count="$count" 2>/dev/null | for i in $(seq 1 16); do
- timeout 5 ip netns exec "$ns1" \
+
+ local nprocs=$(nproc)
+ [ $nprocs -gt 1 ] && nprocs=$((nprocs - 1))
+
+ dd if=/dev/zero bs="$bs" count="$count" 2>/dev/null | for i in $(seq 1 $nprocs); do
+ timeout "$timeout" nice -n 19 ip netns exec "$ns1" \
socat -u -b 512 STDIN UDP-DATAGRAM:10.0.2.99:12346,reuseport,bind=0.0.0.0:55221 &
done
diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_big_endseq.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_big_endseq.pkt
index 3848b419e68c..6c0f32c40f19 100644
--- a/tools/testing/selftests/net/packetdrill/tcp_rcv_big_endseq.pkt
+++ b/tools/testing/selftests/net/packetdrill/tcp_rcv_big_endseq.pkt
@@ -38,7 +38,7 @@
// If queue is empty, accept a packet even if its end_seq is above wup + rcv_wnd
+0 < P. 4001:54001(50000) ack 1 win 257
- +0 > . 1:1(0) ack 54001 win 0
+ * > . 1:1(0) ack 54001 win 0
// Check LINUX_MIB_BEYOND_WINDOW has been incremented 3 times.
+0 `nstat | grep TcpExtBeyondWindow | grep -q " 3 "`
diff --git a/tools/testing/selftests/net/packetdrill/tcp_rcv_toobig.pkt b/tools/testing/selftests/net/packetdrill/tcp_rcv_toobig.pkt
deleted file mode 100644
index f575c0ff89da..000000000000
--- a/tools/testing/selftests/net/packetdrill/tcp_rcv_toobig.pkt
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-
---mss=1000
-
-`./defaults.sh`
-
- 0 `nstat -n`
-
-// Establish a connection.
- +0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
- +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
- +0 setsockopt(3, SOL_SOCKET, SO_RCVBUF, [20000], 4) = 0
- +0 bind(3, ..., ...) = 0
- +0 listen(3, 1) = 0
-
- +0 < S 0:0(0) win 32792 <mss 1000,nop,wscale 7>
- +0 > S. 0:0(0) ack 1 win 18980 <mss 1460,nop,wscale 0>
- +.1 < . 1:1(0) ack 1 win 257
-
- +0 accept(3, ..., ...) = 4
-
- +0 < P. 1:20001(20000) ack 1 win 257
- +.04 > . 1:1(0) ack 20001 win 18000
-
- +0 setsockopt(4, SOL_SOCKET, SO_RCVBUF, [12000], 4) = 0
- +0 < P. 20001:80001(60000) ack 1 win 257
- +0 > . 1:1(0) ack 20001 win 18000
-
- +0 read(4, ..., 20000) = 20000
-// A too big packet is accepted if the receive queue is empty
- +0 < P. 20001:80001(60000) ack 1 win 257
- +0 > . 1:1(0) ack 80001 win 0
-
diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c
index 8a5cd5cb5472..cf106a49b55e 100644
--- a/tools/testing/selftests/net/tun.c
+++ b/tools/testing/selftests/net/tun.c
@@ -944,8 +944,8 @@ TEST_F(tun_vnet_udptnl, send_gso_packet)
ASSERT_EQ(ret, off);
ret = receive_gso_packet_from_tunnel(self, variant, &r_num_mss);
- ASSERT_EQ(ret, variant->data_size);
- ASSERT_EQ(r_num_mss, variant->r_num_mss);
+ EXPECT_EQ(ret, variant->data_size);
+ EXPECT_EQ(r_num_mss, variant->r_num_mss);
}
TEST_F(tun_vnet_udptnl, recv_gso_packet)
@@ -955,18 +955,18 @@ TEST_F(tun_vnet_udptnl, recv_gso_packet)
int ret, gso_type = VIRTIO_NET_HDR_GSO_UDP_L4;
ret = send_gso_packet_into_tunnel(self, variant);
- ASSERT_EQ(ret, variant->data_size);
+ EXPECT_EQ(ret, variant->data_size);
memset(&vnet_hdr, 0, sizeof(vnet_hdr));
ret = receive_gso_packet_from_tun(self, variant, &vnet_hdr);
- ASSERT_EQ(ret, variant->data_size);
+ EXPECT_EQ(ret, variant->data_size);
if (!variant->no_gso) {
- ASSERT_EQ(vh->gso_size, variant->gso_size);
+ EXPECT_EQ(vh->gso_size, variant->gso_size);
gso_type |= (variant->tunnel_type & UDP_TUNNEL_OUTER_IPV4) ?
(VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV4) :
(VIRTIO_NET_HDR_GSO_UDP_TUNNEL_IPV6);
- ASSERT_EQ(vh->gso_type, gso_type);
+ EXPECT_EQ(vh->gso_type, gso_type);
}
}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
index 07f5e0a70ae7..f943cdfb0a74 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-N
@@ -2,7 +2,9 @@ CONFIG_RCU_TRACE=n
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_DYNAMIC=n
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
#CHECK#CONFIG_RCU_EXPERT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-T b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-T
index c70cf0405f24..06e4d1030279 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-T
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-U b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-U
index bc9eeabaa1b1..71da6e3e9488 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/SRCU-U
+++ b/tools/testing/selftests/rcutorture/configs/rcu/SRCU-U
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
@@ -7,4 +8,3 @@ CONFIG_PREEMPT_DYNAMIC=n
CONFIG_RCU_TRACE=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PREEMPT_COUNT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
index 2f9fcffff5ae..dd2bd4e08da4 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS02
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY01 b/tools/testing/selftests/rcutorture/configs/rcu/TINY01
index 0953c52fcfd7..2be53bf60d65 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TINY01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY01
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
@@ -11,4 +12,3 @@ CONFIG_RCU_TRACE=n
#CHECK#CONFIG_RCU_STALL_COMMON=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
-CONFIG_PREEMPT_COUNT=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
index 30439f6fc20e..be8860342ef7 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TINY02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TRACE01 b/tools/testing/selftests/rcutorture/configs/rcu/TRACE01
index 18efab346381..8fb124c28f28 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TRACE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TRACE01
@@ -1,7 +1,8 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=5
CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 67caf4276bb0..ac857d5bcb22 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -1,10 +1,12 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=8
+CONFIG_PREEMPT_LAZY=y
CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=y
+CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
#CHECK#CONFIG_TREE_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=n
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
index 9f48c73709ec..61d15b1b54d1 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
@@ -1,6 +1,8 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_DYNAMIC=n
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
#CHECK#CONFIG_TREE_RCU=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
index db27651de04b..0e090bb68a0f 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
@@ -1,9 +1,12 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_DYNAMIC=n
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
#CHECK#CONFIG_TREE_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=n
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE10 b/tools/testing/selftests/rcutorture/configs/rcu/TREE10
index 420632b030dc..b2ce37861e71 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE10
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE10
@@ -6,6 +6,7 @@ CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
#CHECK#CONFIG_TREE_RCU=y
+CONFIG_PREEMPT_RCU=n
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL b/tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL
index 5d546efa68e8..696fba9968c6 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TRIVIAL
@@ -1,6 +1,8 @@
CONFIG_SMP=y
CONFIG_NR_CPUS=8
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_DYNAMIC=n
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_HZ_PERIODIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcuscale/TINY b/tools/testing/selftests/rcutorture/configs/rcuscale/TINY
index 0fa2dc086e10..c1a7d38823fb 100644
--- a/tools/testing/selftests/rcutorture/configs/rcuscale/TINY
+++ b/tools/testing/selftests/rcutorture/configs/rcuscale/TINY
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01 b/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01
index 0059592c7408..f3f1368b8386 100644
--- a/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01
+++ b/tools/testing/selftests/rcutorture/configs/rcuscale/TRACE01
@@ -1,5 +1,6 @@
CONFIG_SMP=y
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT b/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT
index 67f9d2998afd..1f215e17cbae 100644
--- a/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT
+++ b/tools/testing/selftests/rcutorture/configs/refscale/NOPREEMPT
@@ -1,5 +1,6 @@
CONFIG_SMP=y
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/refscale/TINY b/tools/testing/selftests/rcutorture/configs/refscale/TINY
index 759343980b80..9a11b578ff34 100644
--- a/tools/testing/selftests/rcutorture/configs/refscale/TINY
+++ b/tools/testing/selftests/rcutorture/configs/refscale/TINY
@@ -1,5 +1,6 @@
CONFIG_SMP=n
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT b/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT
index 6133f54ce2a7..f9621e2770a4 100644
--- a/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT
+++ b/tools/testing/selftests/rcutorture/configs/scf/NOPREEMPT
@@ -1,5 +1,6 @@
CONFIG_SMP=y
-CONFIG_PREEMPT_NONE=y
+CONFIG_PREEMPT_LAZY=y
+CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=n
CONFIG_PREEMPT_DYNAMIC=n
diff --git a/tools/testing/selftests/sched_ext/Makefile b/tools/testing/selftests/sched_ext/Makefile
index 2c601a7eaff5..006300ac6dff 100644
--- a/tools/testing/selftests/sched_ext/Makefile
+++ b/tools/testing/selftests/sched_ext/Makefile
@@ -93,6 +93,8 @@ BPF_CFLAGS = -g -D__TARGET_ARCH_$(SRCARCH) \
$(CLANG_SYS_INCLUDES) \
-Wall -Wno-compare-distinct-pointer-types \
-Wno-incompatible-function-pointer-types \
+ -Wno-microsoft-anon-tag \
+ -fms-extensions \
-O2 -mcpu=v3
# sort removes libbpf duplicates when not cross-building
diff --git a/tools/testing/selftests/sched_ext/init_enable_count.c b/tools/testing/selftests/sched_ext/init_enable_count.c
index 82c71653977b..44577e30e764 100644
--- a/tools/testing/selftests/sched_ext/init_enable_count.c
+++ b/tools/testing/selftests/sched_ext/init_enable_count.c
@@ -57,7 +57,8 @@ static enum scx_test_status run_test(bool global)
char buf;
close(pipe_fds[1]);
- read(pipe_fds[0], &buf, 1);
+ if (read(pipe_fds[0], &buf, 1) < 0)
+ exit(1);
close(pipe_fds[0]);
exit(0);
}
diff --git a/tools/testing/selftests/sched_ext/peek_dsq.bpf.c b/tools/testing/selftests/sched_ext/peek_dsq.bpf.c
index a3faf5bb49d6..784f2f6c1af9 100644
--- a/tools/testing/selftests/sched_ext/peek_dsq.bpf.c
+++ b/tools/testing/selftests/sched_ext/peek_dsq.bpf.c
@@ -58,14 +58,14 @@ static void record_peek_result(long pid)
{
u32 slot_key;
long *slot_pid_ptr;
- int ix;
+ u32 ix;
if (pid <= 0)
return;
/* Find an empty slot or one with the same PID */
bpf_for(ix, 0, 10) {
- slot_key = (pid + ix) % MAX_SAMPLES;
+ slot_key = ((u64)pid + ix) % MAX_SAMPLES;
slot_pid_ptr = bpf_map_lookup_elem(&peek_results, &slot_key);
if (!slot_pid_ptr)
continue;
diff --git a/tools/testing/selftests/sched_ext/rt_stall.c b/tools/testing/selftests/sched_ext/rt_stall.c
index ab772e336f86..81ea9b4883e5 100644
--- a/tools/testing/selftests/sched_ext/rt_stall.c
+++ b/tools/testing/selftests/sched_ext/rt_stall.c
@@ -15,7 +15,6 @@
#include <signal.h>
#include <bpf/bpf.h>
#include <scx/common.h>
-#include <unistd.h>
#include "rt_stall.bpf.skel.h"
#include "scx_test.h"
#include "../kselftest.h"
diff --git a/tools/testing/selftests/sched_ext/runner.c b/tools/testing/selftests/sched_ext/runner.c
index 5748d2c69903..761c21f96404 100644
--- a/tools/testing/selftests/sched_ext/runner.c
+++ b/tools/testing/selftests/sched_ext/runner.c
@@ -166,6 +166,9 @@ int main(int argc, char **argv)
enum scx_test_status status;
struct scx_test *test = &__scx_tests[i];
+ if (exit_req)
+ break;
+
if (list) {
printf("%s\n", test->name);
if (i == (__scx_num_tests - 1))
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
index 7d07c55bb668..33bb8f3ff8ed 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ct.json
@@ -505,5 +505,164 @@
"teardown": [
"$TC qdisc del dev $DEV1 ingress"
]
+ },
+ {
+ "id": "8883",
+ "name": "Try to attach act_ct to an ets qdisc",
+ "category": [
+ "actions",
+ "ct"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ct",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 root handle 1: ets bands 2"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV1 parent 1: prio 1 protocol ip matchall action ct index 42",
+ "expExitCode": "2",
+ "verifyCmd": "$TC -j filter ls dev $DEV1 parent 1: prio 1 protocol ip",
+ "matchJSON": [],
+ "teardown": [
+ "$TC qdisc del dev $DEV1 root"
+ ]
+ },
+ {
+ "id": "3b10",
+ "name": "Attach act_ct to an ingress qdisc",
+ "category": [
+ "actions",
+ "ct"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ct",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 ingress"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV1 ingress prio 1 protocol ip matchall action ct index 42",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -j filter ls dev $DEV1 ingress prio 1 protocol ip",
+ "matchJSON": [
+ {
+ "kind": "matchall"
+ },
+ {
+ "options": {
+ "actions": [
+ {
+ "order": 1,
+ "kind": "ct",
+ "index": 42,
+ "ref": 1,
+ "bind": 1
+ }
+ ]
+ }
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DEV1 ingress"
+ ]
+ },
+ {
+ "id": "0337",
+ "name": "Attach act_ct to a clsact/egress qdisc",
+ "category": [
+ "actions",
+ "ct"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ct",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 clsact"
+ ],
+ "cmdUnderTest": "$TC filter add dev $DEV1 egress prio 1 protocol ip matchall action ct index 42",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -j filter ls dev $DEV1 egress prio 1 protocol ip",
+ "matchJSON": [
+ {
+ "kind": "matchall"
+ },
+ {
+ "options": {
+ "actions": [
+ {
+ "order": 1,
+ "kind": "ct",
+ "index": 42,
+ "ref": 1,
+ "bind": 1
+ }
+ ]
+ }
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DEV1 clsact"
+ ]
+ },
+ {
+ "id": "4f60",
+ "name": "Attach act_ct to a shared block",
+ "category": [
+ "actions",
+ "ct"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ct",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC qdisc add dev $DEV1 ingress_block 21 clsact"
+ ],
+ "cmdUnderTest": "$TC filter add block 21 prio 1 protocol ip matchall action ct index 42",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -j filter ls block 21 prio 1 protocol ip",
+ "matchJSON": [
+ {
+ "kind": "matchall"
+ },
+ {
+ "options": {
+ "actions": [
+ {
+ "order": 1,
+ "kind": "ct",
+ "index": 42,
+ "ref": 1,
+ "bind": 1
+ }
+ ]
+ }
+ }
+ ],
+ "teardown": [
+ "$TC qdisc del dev $DEV1 ingress_block 21 clsact"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
index f587a32e44c4..808aef4afe22 100644
--- a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
+++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json
@@ -1279,5 +1279,104 @@
"teardown": [
"$TC actions flush action ife"
]
+ },
+ {
+ "id": "f2a0",
+ "name": "Update decode ife action with encode metadata",
+ "category": [
+ "actions",
+ "ife"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ife",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC actions add action ife decode index 10"
+ ],
+ "cmdUnderTest": "$TC actions replace action ife encode use tcindex 1 index 10",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -j actions get action ife index 10",
+ "matchJSON": [
+ {
+ "total acts": 0
+ },
+ {
+ "actions": [
+ {
+ "order": 1,
+ "kind": "ife",
+ "mode": "encode",
+ "control_action": {
+ "type": "pipe"
+ },
+ "type": "0xed3e",
+ "tcindex": 1,
+ "index": 10,
+ "ref": 1,
+ "bind": 0,
+ "not_in_hw": true
+ }
+ ]
+ }
+ ],
+ "teardown": [
+ "$TC actions flush action ife"
+ ]
+ },
+ {
+ "id": "d352",
+ "name": "Update decode ife action into encode with multiple metadata",
+ "category": [
+ "actions",
+ "ife"
+ ],
+ "plugins": {
+ "requires": "nsPlugin"
+ },
+ "setup": [
+ [
+ "$TC actions flush action ife",
+ 0,
+ 1,
+ 255
+ ],
+ "$TC actions add action ife decode index 10"
+ ],
+ "cmdUnderTest": "$TC actions replace action ife encode use tcindex 1 use mark 22 index 10",
+ "expExitCode": "0",
+ "verifyCmd": "$TC -j actions get action ife index 10",
+ "matchJSON": [
+ {
+ "total acts": 0
+ },
+ {
+ "actions": [
+ {
+ "order": 1,
+ "kind": "ife",
+ "mode": "encode",
+ "control_action": {
+ "type": "pipe"
+ },
+ "type": "0xed3e",
+ "tcindex": 1,
+ "mark": 22,
+ "index": 10,
+ "ref": 1,
+ "bind": 0,
+ "not_in_hw": true
+ }
+ ]
+ }
+ ],
+ "teardown": [
+ "$TC actions flush action ife"
+ ]
}
]
diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py
index 0440d252c4c5..bc447ca57333 100644
--- a/tools/testing/selftests/tc-testing/tdc_helper.py
+++ b/tools/testing/selftests/tc-testing/tdc_helper.py
@@ -38,10 +38,14 @@ def list_test_cases(testlist):
def list_categories(testlist):
- """ Show all categories that are present in a test case file. """
- categories = set(map(lambda x: x['category'], testlist))
+ """Show all unique categories present in the test cases."""
+ categories = set()
+ for t in testlist:
+ if 'category' in t:
+ categories.update(t['category'])
+
print("Available categories:")
- print(", ".join(str(s) for s in categories))
+ print(", ".join(sorted(categories)))
print("")