From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 70C161581FD for ; Thu, 04 Sep 2025 14:31:08 +0000 (UTC) Received: from lists.gentoo.org (bobolink.gentoo.org [140.211.166.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: relay-lists.gentoo.org@gentoo.org) by smtp.gentoo.org (Postfix) with ESMTPSA id 5B791335DB4 for ; Thu, 04 Sep 2025 14:31:08 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id 0881B11027A; Thu, 04 Sep 2025 14:31:07 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bobolink.gentoo.org (Postfix) with ESMTPS id EFBF011027A for ; Thu, 04 Sep 2025 14:31:06 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 2F219335DB2 for ; Thu, 04 Sep 2025 14:31:06 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 6ED6738AF for ; Thu, 04 Sep 2025 14:31:04 +0000 (UTC) From: "Arisu Tachibana" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Arisu Tachibana" Message-ID: <1756996250.8ed82018abed6a75d7afd94c3fc8a0dad9638ee2.alicef@gentoo> Subject: [gentoo-commits] proj/linux-patches:6.6 commit in: / X-VCS-Repository: proj/linux-patches X-VCS-Files: 0000_README 1103_linux-6.6.104.patch X-VCS-Directories: / X-VCS-Committer: alicef X-VCS-Committer-Name: Arisu Tachibana X-VCS-Revision: 8ed82018abed6a75d7afd94c3fc8a0dad9638ee2 X-VCS-Branch: 6.6 Date: Thu, 04 Sep 2025 14:31:04 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 4f7b03f8-683a-4a91-8e99-6b96ffbb8f48 X-Archives-Hash: cc69c9675aa86433abcbca2dfed2695f commit: 8ed82018abed6a75d7afd94c3fc8a0dad9638ee2 Author: Arisu Tachibana gentoo org> AuthorDate: Thu Sep 4 14:30:50 2025 +0000 Commit: Arisu Tachibana gentoo org> CommitDate: Thu Sep 4 14:30:50 2025 +0000 URL: https://gitweb.gentoo.org/proj/linux-patches.git/commit/?id=8ed82018 Linux patch 6.6.104 Signed-off-by: Arisu Tachibana gentoo.org> 0000_README | 4 + 1103_linux-6.6.104.patch | 3677 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3681 insertions(+) diff --git a/0000_README b/0000_README index e1cf707d..f1c91278 100644 --- a/0000_README +++ b/0000_README @@ -455,6 +455,10 @@ Patch: 1102_linux-6.6.103.patch From: https://www.kernel.org Desc: Linux 6.6.103 +Patch: 1103_linux-6.6.104.patch +From: https://www.kernel.org +Desc: Linux 6.6.104 + Patch: 1510_fs-enable-link-security-restrictions-by-default.patch From: http://sources.debian.net/src/linux/3.16.7-ckt4-3/debian/patches/debian/fs-enable-link-security-restrictions-by-default.patch Desc: Enable link security restrictions by default. diff --git a/1103_linux-6.6.104.patch b/1103_linux-6.6.104.patch new file mode 100644 index 00000000..eb7ea28a --- /dev/null +++ b/1103_linux-6.6.104.patch @@ -0,0 +1,3677 @@ +diff --git a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml +index 91c774f106ceb1..ab1196d1ec2dd4 100644 +--- a/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml ++++ b/Documentation/devicetree/bindings/display/msm/qcom,mdp5.yaml +@@ -59,7 +59,6 @@ properties: + - const: bus + - const: core + - const: vsync +- - const: lut + - const: tbu + - const: tbu_rt + # MSM8996 has additional iommu clock +diff --git a/Makefile b/Makefile +index 9b288ccccd6495..ae57f816375ebd 100644 +--- a/Makefile ++++ b/Makefile +@@ -1,7 +1,7 @@ + # SPDX-License-Identifier: GPL-2.0 + VERSION = 6 + PATCHLEVEL = 6 +-SUBLEVEL = 103 ++SUBLEVEL = 104 + EXTRAVERSION = + NAME = Pinguïn Aangedreven + +diff --git a/arch/mips/boot/dts/lantiq/danube_easy50712.dts b/arch/mips/boot/dts/lantiq/danube_easy50712.dts +index 1ce20b7d05cb8c..c4d7aa5753b043 100644 +--- a/arch/mips/boot/dts/lantiq/danube_easy50712.dts ++++ b/arch/mips/boot/dts/lantiq/danube_easy50712.dts +@@ -82,13 +82,16 @@ conf_out { + }; + }; + +- etop@e180000 { ++ ethernet@e180000 { + compatible = "lantiq,etop-xway"; + reg = <0xe180000 0x40000>; + interrupt-parent = <&icu0>; + interrupts = <73 78>; ++ interrupt-names = "tx", "rx"; + phy-mode = "rmii"; + mac-address = [ 00 11 22 33 44 55 ]; ++ lantiq,rx-burst-length = <4>; ++ lantiq,tx-burst-length = <4>; + }; + + stp0: stp@e100bb0 { +diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c +index 3ed0782252229a..4c72b59fdf98cc 100644 +--- a/arch/mips/lantiq/xway/sysctrl.c ++++ b/arch/mips/lantiq/xway/sysctrl.c +@@ -478,7 +478,7 @@ void __init ltq_soc_init(void) + ifccr = CGU_IFCCR_VR9; + pcicr = CGU_PCICR_VR9; + } else { +- clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE); ++ clkdev_add_pmu("1e180000.ethernet", NULL, 1, 0, PMU_PPE); + } + + if (!of_machine_is_compatible("lantiq,ase")) +@@ -512,9 +512,9 @@ void __init ltq_soc_init(void) + CLOCK_133M, CLOCK_133M); + clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); + clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); +- clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE); +- clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY); +- clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY); ++ clkdev_add_pmu("1e180000.ethernet", "ppe", 1, 0, PMU_PPE); ++ clkdev_add_cgu("1e180000.ethernet", "ephycgu", CGU_EPHY); ++ clkdev_add_pmu("1e180000.ethernet", "ephy", 1, 0, PMU_EPHY); + clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO); + clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); + } else if (of_machine_is_compatible("lantiq,grx390")) { +@@ -573,7 +573,7 @@ void __init ltq_soc_init(void) + clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM); + clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P); + clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM); +- clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH); ++ clkdev_add_pmu("1e180000.ethernet", "switch", 1, 0, PMU_SWITCH); + clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); + clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); + clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); +diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c +index 5b3c093611baf1..7209d00a9c2576 100644 +--- a/arch/powerpc/kernel/kvm.c ++++ b/arch/powerpc/kernel/kvm.c +@@ -632,19 +632,19 @@ static void __init kvm_check_ins(u32 *inst, u32 features) + #endif + } + +- switch (inst_no_rt & ~KVM_MASK_RB) { + #ifdef CONFIG_PPC_BOOK3S_32 ++ switch (inst_no_rt & ~KVM_MASK_RB) { + case KVM_INST_MTSRIN: + if (features & KVM_MAGIC_FEAT_SR) { + u32 inst_rb = _inst & KVM_MASK_RB; + kvm_patch_ins_mtsrin(inst, inst_rt, inst_rb); + } + break; +-#endif + } ++#endif + +- switch (_inst) { + #ifdef CONFIG_BOOKE ++ switch (_inst) { + case KVM_INST_WRTEEI_0: + kvm_patch_ins_wrteei_0(inst); + break; +@@ -652,8 +652,8 @@ static void __init kvm_check_ins(u32 *inst, u32 features) + case KVM_INST_WRTEEI_1: + kvm_patch_ins_wrtee(inst, 0, 1); + break; +-#endif + } ++#endif + } + + extern u32 kvm_template_start[]; +diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c +index 7444fe0e3d08cd..2cb30d9c5b4ae7 100644 +--- a/arch/x86/kernel/cpu/microcode/amd.c ++++ b/arch/x86/kernel/cpu/microcode/amd.c +@@ -161,8 +161,28 @@ static int cmp_id(const void *key, const void *elem) + return 1; + } + ++static u32 cpuid_to_ucode_rev(unsigned int val) ++{ ++ union zen_patch_rev p = {}; ++ union cpuid_1_eax c; ++ ++ c.full = val; ++ ++ p.stepping = c.stepping; ++ p.model = c.model; ++ p.ext_model = c.ext_model; ++ p.ext_fam = c.ext_fam; ++ ++ return p.ucode_rev; ++} ++ + static bool need_sha_check(u32 cur_rev) + { ++ if (!cur_rev) { ++ cur_rev = cpuid_to_ucode_rev(bsp_cpuid_1_eax); ++ pr_info_once("No current revision, generating the lowest one: 0x%x\n", cur_rev); ++ } ++ + switch (cur_rev >> 8) { + case 0x80012: return cur_rev <= 0x800126f; break; + case 0x80082: return cur_rev <= 0x800820f; break; +@@ -744,8 +764,6 @@ static struct ucode_patch *cache_find_patch(struct ucode_cpu_info *uci, u16 equi + n.equiv_cpu = equiv_cpu; + n.patch_id = uci->cpu_sig.rev; + +- WARN_ON_ONCE(!n.patch_id); +- + list_for_each_entry(p, µcode_cache, plist) + if (patch_cpus_equivalent(p, &n, false)) + return p; +diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c +index ba1c2a7f74f766..af4ae9216667ea 100644 +--- a/arch/x86/kvm/lapic.c ++++ b/arch/x86/kvm/lapic.c +@@ -847,6 +847,8 @@ static int __pv_send_ipi(unsigned long *ipi_bitmap, struct kvm_apic_map *map, + if (min > map->max_apic_id) + return 0; + ++ min = array_index_nospec(min, map->max_apic_id + 1); ++ + for_each_set_bit(i, ipi_bitmap, + min((u32)BITS_PER_LONG, (map->max_apic_id - min + 1))) { + if (map->phys_map[min + i]) { +diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c +index af0b2b3bc991e2..5088065ac704be 100644 +--- a/arch/x86/kvm/x86.c ++++ b/arch/x86/kvm/x86.c +@@ -9802,8 +9802,11 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu, unsigned long dest_id) + rcu_read_lock(); + map = rcu_dereference(vcpu->kvm->arch.apic_map); + +- if (likely(map) && dest_id <= map->max_apic_id && map->phys_map[dest_id]) +- target = map->phys_map[dest_id]->vcpu; ++ if (likely(map) && dest_id <= map->max_apic_id) { ++ dest_id = array_index_nospec(dest_id, map->max_apic_id + 1); ++ if (map->phys_map[dest_id]) ++ target = map->phys_map[dest_id]->vcpu; ++ } + + rcu_read_unlock(); + +diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c +index 77d6af61158936..8e304efde3429e 100644 +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -2329,6 +2329,12 @@ static const struct dmi_system_id acpi_ec_no_wakeup[] = { + DMI_MATCH(DMI_PRODUCT_NAME, "83Q3"), + } + }, ++ { ++ // TUXEDO InfinityBook Pro AMD Gen9 ++ .matches = { ++ DMI_MATCH(DMI_BOARD_NAME, "GXxHRXx"), ++ }, ++ }, + { }, + }; + +diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c +index ff558908897f3e..9c83fb29b2f1b2 100644 +--- a/drivers/atm/atmtcp.c ++++ b/drivers/atm/atmtcp.c +@@ -279,6 +279,19 @@ static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) + return NULL; + } + ++static int atmtcp_c_pre_send(struct atm_vcc *vcc, struct sk_buff *skb) ++{ ++ struct atmtcp_hdr *hdr; ++ ++ if (skb->len < sizeof(struct atmtcp_hdr)) ++ return -EINVAL; ++ ++ hdr = (struct atmtcp_hdr *)skb->data; ++ if (hdr->length == ATMTCP_HDR_MAGIC) ++ return -EINVAL; ++ ++ return 0; ++} + + static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) + { +@@ -288,9 +301,6 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb) + struct sk_buff *new_skb; + int result = 0; + +- if (skb->len < sizeof(struct atmtcp_hdr)) +- goto done; +- + dev = vcc->dev_data; + hdr = (struct atmtcp_hdr *) skb->data; + if (hdr->length == ATMTCP_HDR_MAGIC) { +@@ -347,6 +357,7 @@ static const struct atmdev_ops atmtcp_v_dev_ops = { + + static const struct atmdev_ops atmtcp_c_dev_ops = { + .close = atmtcp_c_close, ++ .pre_send = atmtcp_c_pre_send, + .send = atmtcp_c_send + }; + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +index 384834fbd59011..7200110197415f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_csa.c +@@ -89,8 +89,8 @@ int amdgpu_map_static_csa(struct amdgpu_device *adev, struct amdgpu_vm *vm, + } + + r = amdgpu_vm_bo_map(adev, *bo_va, csa_addr, 0, size, +- AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | +- AMDGPU_VM_PAGE_EXECUTABLE); ++ AMDGPU_PTE_READABLE | AMDGPU_PTE_WRITEABLE | ++ AMDGPU_PTE_EXECUTABLE); + + if (r) { + DRM_ERROR("failed to do bo_map on static CSA, err=%d\n", r); +diff --git a/drivers/gpu/drm/display/drm_dp_helper.c b/drivers/gpu/drm/display/drm_dp_helper.c +index 772d8e662278b9..851f0baf94600c 100644 +--- a/drivers/gpu/drm/display/drm_dp_helper.c ++++ b/drivers/gpu/drm/display/drm_dp_helper.c +@@ -663,7 +663,7 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset, + * monitor doesn't power down exactly after the throw away read. + */ + if (!aux->is_remote) { +- ret = drm_dp_dpcd_probe(aux, DP_LANE0_1_STATUS); ++ ret = drm_dp_dpcd_probe(aux, DP_DPCD_REV); + if (ret < 0) + return ret; + } +diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c +index bbe4f1665b6039..dc142f9e4f6028 100644 +--- a/drivers/gpu/drm/msm/msm_gem_submit.c ++++ b/drivers/gpu/drm/msm/msm_gem_submit.c +@@ -981,12 +981,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, + + if (ret == 0 && args->flags & MSM_SUBMIT_FENCE_FD_OUT) { + sync_file = sync_file_create(submit->user_fence); +- if (!sync_file) { ++ if (!sync_file) + ret = -ENOMEM; +- } else { +- fd_install(out_fence_fd, sync_file->file); +- args->fence_fd = out_fence_fd; +- } + } + + submit_attach_object_fences(submit); +@@ -1013,10 +1009,14 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, + out_unlock: + mutex_unlock(&queue->lock); + out_post_unlock: +- if (ret && (out_fence_fd >= 0)) { +- put_unused_fd(out_fence_fd); ++ if (ret) { ++ if (out_fence_fd >= 0) ++ put_unused_fd(out_fence_fd); + if (sync_file) + fput(sync_file->file); ++ } else if (sync_file) { ++ fd_install(out_fence_fd, sync_file->file); ++ args->fence_fd = out_fence_fd; + } + + if (!IS_ERR_OR_NULL(submit)) { +diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c +index 7a2cceaee6e97f..1199dfc1194c80 100644 +--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c ++++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c +@@ -663,6 +663,10 @@ static bool nv50_plane_format_mod_supported(struct drm_plane *plane, + struct nouveau_drm *drm = nouveau_drm(plane->dev); + uint8_t i; + ++ /* All chipsets can display all formats in linear layout */ ++ if (modifier == DRM_FORMAT_MOD_LINEAR) ++ return true; ++ + if (drm->client.device.info.chipset < 0xc0) { + const struct drm_format_info *info = drm_format_info(format); + const uint8_t kind = (modifier >> 12) & 0xff; +diff --git a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c +index b7da3ab44c277d..7c43397c19e61d 100644 +--- a/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c ++++ b/drivers/gpu/drm/nouveau/nvkm/falcon/gm200.c +@@ -103,7 +103,7 @@ gm200_flcn_pio_imem_wr_init(struct nvkm_falcon *falcon, u8 port, bool sec, u32 i + static void + gm200_flcn_pio_imem_wr(struct nvkm_falcon *falcon, u8 port, const u8 *img, int len, u16 tag) + { +- nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag++); ++ nvkm_falcon_wr32(falcon, 0x188 + (port * 0x10), tag); + while (len >= 4) { + nvkm_falcon_wr32(falcon, 0x184 + (port * 0x10), *(u32 *)img); + img += 4; +@@ -249,9 +249,11 @@ int + gm200_flcn_fw_load(struct nvkm_falcon_fw *fw) + { + struct nvkm_falcon *falcon = fw->falcon; +- int target, ret; ++ int ret; + + if (fw->inst) { ++ int target; ++ + nvkm_falcon_mask(falcon, 0x048, 0x00000001, 0x00000001); + + switch (nvkm_memory_target(fw->inst)) { +@@ -285,15 +287,6 @@ gm200_flcn_fw_load(struct nvkm_falcon_fw *fw) + } + + if (fw->boot) { +- switch (nvkm_memory_target(&fw->fw.mem.memory)) { +- case NVKM_MEM_TARGET_VRAM: target = 4; break; +- case NVKM_MEM_TARGET_HOST: target = 5; break; +- case NVKM_MEM_TARGET_NCOH: target = 6; break; +- default: +- WARN_ON(1); +- return -EINVAL; +- } +- + ret = nvkm_falcon_pio_wr(falcon, fw->boot, 0, 0, + IMEM, falcon->code.limit - fw->boot_size, fw->boot_size, + fw->boot_addr >> 8, false); +diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c +index 84625e817ce950..896f73aa4d2c82 100644 +--- a/drivers/hid/hid-asus.c ++++ b/drivers/hid/hid-asus.c +@@ -1108,7 +1108,13 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) + return ret; + } + +- if (!drvdata->input) { ++ /* ++ * Check that input registration succeeded. Checking that ++ * HID_CLAIMED_INPUT is set prevents a UAF when all input devices ++ * were freed during registration due to no usages being mapped, ++ * leaving drvdata->input pointing to freed memory. ++ */ ++ if (!drvdata->input || !(hdev->claimed & HID_CLAIMED_INPUT)) { + hid_err(hdev, "Asus input not registered\n"); + ret = -ENOMEM; + goto err_stop_hw; +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index 0d1d7162814f32..3f74633070b6ec 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -818,6 +818,8 @@ + #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019 + #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e + #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093 ++#define USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT 0x6184 ++#define USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT 0x61ed + + #define USB_VENDOR_ID_LETSKETCH 0x6161 + #define USB_DEVICE_ID_WP9620N 0x4d15 +@@ -891,6 +893,7 @@ + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534 + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539 + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f ++#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2 0xc543 + #define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a + #define USB_DEVICE_ID_LOGITECH_BOLT_RECEIVER 0xc548 + #define USB_DEVICE_ID_SPACETRAVELLER 0xc623 +diff --git a/drivers/hid/hid-input-test.c b/drivers/hid/hid-input-test.c +index 77c2d45ac62a7f..6f5c71660d823b 100644 +--- a/drivers/hid/hid-input-test.c ++++ b/drivers/hid/hid-input-test.c +@@ -7,7 +7,7 @@ + + #include + +-static void hid_test_input_set_battery_charge_status(struct kunit *test) ++static void hid_test_input_update_battery_charge_status(struct kunit *test) + { + struct hid_device *dev; + bool handled; +@@ -15,15 +15,15 @@ static void hid_test_input_set_battery_charge_status(struct kunit *test) + dev = kunit_kzalloc(test, sizeof(*dev), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + +- handled = hidinput_set_battery_charge_status(dev, HID_DG_HEIGHT, 0); ++ handled = hidinput_update_battery_charge_status(dev, HID_DG_HEIGHT, 0); + KUNIT_EXPECT_FALSE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_UNKNOWN); + +- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 0); ++ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 0); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_DISCHARGING); + +- handled = hidinput_set_battery_charge_status(dev, HID_BAT_CHARGING, 1); ++ handled = hidinput_update_battery_charge_status(dev, HID_BAT_CHARGING, 1); + KUNIT_EXPECT_TRUE(test, handled); + KUNIT_EXPECT_EQ(test, dev->battery_charge_status, POWER_SUPPLY_STATUS_CHARGING); + } +@@ -63,7 +63,7 @@ static void hid_test_input_get_battery_property(struct kunit *test) + } + + static struct kunit_case hid_input_tests[] = { +- KUNIT_CASE(hid_test_input_set_battery_charge_status), ++ KUNIT_CASE(hid_test_input_update_battery_charge_status), + KUNIT_CASE(hid_test_input_get_battery_property), + { } + }; +diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c +index 9d80635a91ebd8..f5c217ac4bfaa7 100644 +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -595,13 +595,33 @@ static void hidinput_cleanup_battery(struct hid_device *dev) + dev->battery = NULL; + } + +-static void hidinput_update_battery(struct hid_device *dev, int value) ++static bool hidinput_update_battery_charge_status(struct hid_device *dev, ++ unsigned int usage, int value) ++{ ++ switch (usage) { ++ case HID_BAT_CHARGING: ++ dev->battery_charge_status = value ? ++ POWER_SUPPLY_STATUS_CHARGING : ++ POWER_SUPPLY_STATUS_DISCHARGING; ++ return true; ++ } ++ ++ return false; ++} ++ ++static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, ++ int value) + { + int capacity; + + if (!dev->battery) + return; + ++ if (hidinput_update_battery_charge_status(dev, usage, value)) { ++ power_supply_changed(dev->battery); ++ return; ++ } ++ + if (value == 0 || value < dev->battery_min || value > dev->battery_max) + return; + +@@ -617,20 +637,6 @@ static void hidinput_update_battery(struct hid_device *dev, int value) + power_supply_changed(dev->battery); + } + } +- +-static bool hidinput_set_battery_charge_status(struct hid_device *dev, +- unsigned int usage, int value) +-{ +- switch (usage) { +- case HID_BAT_CHARGING: +- dev->battery_charge_status = value ? +- POWER_SUPPLY_STATUS_CHARGING : +- POWER_SUPPLY_STATUS_DISCHARGING; +- return true; +- } +- +- return false; +-} + #else /* !CONFIG_HID_BATTERY_STRENGTH */ + static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type, + struct hid_field *field, bool is_percentage) +@@ -642,14 +648,9 @@ static void hidinput_cleanup_battery(struct hid_device *dev) + { + } + +-static void hidinput_update_battery(struct hid_device *dev, int value) +-{ +-} +- +-static bool hidinput_set_battery_charge_status(struct hid_device *dev, +- unsigned int usage, int value) ++static void hidinput_update_battery(struct hid_device *dev, unsigned int usage, ++ int value) + { +- return false; + } + #endif /* CONFIG_HID_BATTERY_STRENGTH */ + +@@ -1515,11 +1516,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct + return; + + if (usage->type == EV_PWR) { +- bool handled = hidinput_set_battery_charge_status(hid, usage->hid, value); +- +- if (!handled) +- hidinput_update_battery(hid, value); +- ++ hidinput_update_battery(hid, usage->hid, value); + return; + } + +diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c +index 37958edec55f5f..e2d5b3f699146d 100644 +--- a/drivers/hid/hid-logitech-dj.c ++++ b/drivers/hid/hid-logitech-dj.c +@@ -1983,6 +1983,10 @@ static const struct hid_device_id logi_dj_receivers[] = { + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, + USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1), + .driver_data = recvr_type_gaming_hidpp}, ++ { /* Logitech lightspeed receiver (0xc543) */ ++ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, ++ USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_2), ++ .driver_data = recvr_type_gaming_hidpp}, + + { /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER), +diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c +index 4519ee377aa767..3a2c1e48aba20c 100644 +--- a/drivers/hid/hid-logitech-hidpp.c ++++ b/drivers/hid/hid-logitech-hidpp.c +@@ -4652,6 +4652,8 @@ static const struct hid_device_id hidpp_devices[] = { + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC094) }, + { /* Logitech G Pro X Superlight 2 Gaming Mouse over USB */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xC09b) }, ++ { /* Logitech G PRO 2 LIGHTSPEED Wireless Mouse over USB */ ++ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0xc09a) }, + + { /* G935 Gaming Headset */ + HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, 0x0a87), +diff --git a/drivers/hid/hid-mcp2221.c b/drivers/hid/hid-mcp2221.c +index c5bfca8ac5e6e8..a985301a4135f5 100644 +--- a/drivers/hid/hid-mcp2221.c ++++ b/drivers/hid/hid-mcp2221.c +@@ -49,6 +49,7 @@ enum { + MCP2221_I2C_MASK_ADDR_NACK = 0x40, + MCP2221_I2C_WRADDRL_SEND = 0x21, + MCP2221_I2C_ADDR_NACK = 0x25, ++ MCP2221_I2C_READ_PARTIAL = 0x54, + MCP2221_I2C_READ_COMPL = 0x55, + MCP2221_ALT_F_NOT_GPIOV = 0xEE, + MCP2221_ALT_F_NOT_GPIOD = 0xEF, +@@ -187,6 +188,25 @@ static int mcp_cancel_last_cmd(struct mcp2221 *mcp) + return mcp_send_data_req_status(mcp, mcp->txbuf, 8); + } + ++/* Check if the last command succeeded or failed and return the result. ++ * If the command did fail, cancel that command which will free the i2c bus. ++ */ ++static int mcp_chk_last_cmd_status_free_bus(struct mcp2221 *mcp) ++{ ++ int ret; ++ ++ ret = mcp_chk_last_cmd_status(mcp); ++ if (ret) { ++ /* The last command was a failure. ++ * Send a cancel which will also free the bus. ++ */ ++ usleep_range(980, 1000); ++ mcp_cancel_last_cmd(mcp); ++ } ++ ++ return ret; ++} ++ + static int mcp_set_i2c_speed(struct mcp2221 *mcp) + { + int ret; +@@ -241,7 +261,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp, + usleep_range(980, 1000); + + if (last_status) { +- ret = mcp_chk_last_cmd_status(mcp); ++ ret = mcp_chk_last_cmd_status_free_bus(mcp); + if (ret) + return ret; + } +@@ -278,6 +298,7 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, + { + int ret; + u16 total_len; ++ int retries = 0; + + mcp->txbuf[0] = type; + if (msg) { +@@ -301,20 +322,31 @@ static int mcp_i2c_smbus_read(struct mcp2221 *mcp, + mcp->rxbuf_idx = 0; + + do { ++ /* Wait for the data to be read by the device */ ++ usleep_range(980, 1000); ++ + memset(mcp->txbuf, 0, 4); + mcp->txbuf[0] = MCP2221_I2C_GET_DATA; + + ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1); +- if (ret) +- return ret; +- +- ret = mcp_chk_last_cmd_status(mcp); +- if (ret) +- return ret; +- +- usleep_range(980, 1000); ++ if (ret) { ++ if (retries < 5) { ++ /* The data wasn't ready to read. ++ * Wait a bit longer and try again. ++ */ ++ usleep_range(90, 100); ++ retries++; ++ } else { ++ return ret; ++ } ++ } else { ++ retries = 0; ++ } + } while (mcp->rxbuf_idx < total_len); + ++ usleep_range(980, 1000); ++ ret = mcp_chk_last_cmd_status_free_bus(mcp); ++ + return ret; + } + +@@ -328,11 +360,6 @@ static int mcp_i2c_xfer(struct i2c_adapter *adapter, + + mutex_lock(&mcp->lock); + +- /* Setting speed before every transaction is required for mcp2221 */ +- ret = mcp_set_i2c_speed(mcp); +- if (ret) +- goto exit; +- + if (num == 1) { + if (msgs->flags & I2C_M_RD) { + ret = mcp_i2c_smbus_read(mcp, msgs, MCP2221_I2C_RD_DATA, +@@ -417,9 +444,7 @@ static int mcp_smbus_write(struct mcp2221 *mcp, u16 addr, + if (last_status) { + usleep_range(980, 1000); + +- ret = mcp_chk_last_cmd_status(mcp); +- if (ret) +- return ret; ++ ret = mcp_chk_last_cmd_status_free_bus(mcp); + } + + return ret; +@@ -437,10 +462,6 @@ static int mcp_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + + mutex_lock(&mcp->lock); + +- ret = mcp_set_i2c_speed(mcp); +- if (ret) +- goto exit; +- + switch (size) { + + case I2C_SMBUS_QUICK: +@@ -791,7 +812,8 @@ static int mcp2221_raw_event(struct hid_device *hdev, + mcp->status = -EIO; + break; + } +- if (data[2] == MCP2221_I2C_READ_COMPL) { ++ if (data[2] == MCP2221_I2C_READ_COMPL || ++ data[2] == MCP2221_I2C_READ_PARTIAL) { + buf = mcp->rxbuf; + memcpy(&buf[mcp->rxbuf_idx], &data[4], data[3]); + mcp->rxbuf_idx = mcp->rxbuf_idx + data[3]; +@@ -1152,6 +1174,11 @@ static int mcp2221_probe(struct hid_device *hdev, + if (i2c_clk_freq < 50) + i2c_clk_freq = 50; + mcp->cur_i2c_clk_div = (12000000 / (i2c_clk_freq * 1000)) - 3; ++ ret = mcp_set_i2c_speed(mcp); ++ if (ret) { ++ hid_err(hdev, "can't set i2c speed: %d\n", ret); ++ return ret; ++ } + + mcp->adapter.owner = THIS_MODULE; + mcp->adapter.class = I2C_CLASS_HWMON; +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index becd4c1ccf93c1..a85581cd511fd3 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -1448,6 +1448,14 @@ static __u8 *mt_report_fixup(struct hid_device *hdev, __u8 *rdesc, + if (hdev->vendor == I2C_VENDOR_ID_GOODIX && + (hdev->product == I2C_DEVICE_ID_GOODIX_01E8 || + hdev->product == I2C_DEVICE_ID_GOODIX_01E9)) { ++ if (*size < 608) { ++ dev_info( ++ &hdev->dev, ++ "GT7868Q fixup: report descriptor is only %u bytes, skipping\n", ++ *size); ++ return rdesc; ++ } ++ + if (rdesc[607] == 0x15) { + rdesc[607] = 0x25; + dev_info( +diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c +index b5d26f03fe6bb7..a1128c5315fffa 100644 +--- a/drivers/hid/hid-ntrig.c ++++ b/drivers/hid/hid-ntrig.c +@@ -144,6 +144,9 @@ static void ntrig_report_version(struct hid_device *hdev) + struct usb_device *usb_dev = hid_to_usb_dev(hdev); + unsigned char *data = kmalloc(8, GFP_KERNEL); + ++ if (!hid_is_usb(hdev)) ++ return; ++ + if (!data) + goto err_free; + +diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c +index 80372342c176af..64f9728018b885 100644 +--- a/drivers/hid/hid-quirks.c ++++ b/drivers/hid/hid-quirks.c +@@ -124,6 +124,8 @@ static const struct hid_device_id hid_quirks[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_T609A), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_ODDOR_HANDBRAKE), HID_QUIRK_ALWAYS_POLL }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_LEGION_GO2_DUAL_DINPUT), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_OPTICAL_USB_MOUSE_600E), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL }, +diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c +index dd44373ba930e2..42bc8f05e26358 100644 +--- a/drivers/hid/wacom_wac.c ++++ b/drivers/hid/wacom_wac.c +@@ -684,6 +684,7 @@ static bool wacom_is_art_pen(int tool_id) + case 0x885: /* Intuos3 Marker Pen */ + case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ + case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ ++ case 0x204: /* Art Pen 2 */ + is_art_pen = true; + break; + } +diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c +index fad5a72d3b1671..f1208591ed67e3 100644 +--- a/drivers/net/ethernet/dlink/dl2k.c ++++ b/drivers/net/ethernet/dlink/dl2k.c +@@ -1092,7 +1092,7 @@ get_stats (struct net_device *dev) + dev->stats.rx_bytes += dr32(OctetRcvOk); + dev->stats.tx_bytes += dr32(OctetXmtOk); + +- dev->stats.multicast = dr32(McstFramesRcvdOk); ++ dev->stats.multicast += dr32(McstFramesRcvdOk); + dev->stats.collisions += dr32(SingleColFrames) + + dr32(MultiColFrames); + +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c +index f5023ac9ab8323..eae4376c685952 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.c ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.c +@@ -527,14 +527,14 @@ int ice_setup_rx_ring(struct ice_rx_ring *rx_ring) + * @xdp: xdp_buff used as input to the XDP program + * @xdp_prog: XDP program to run + * @xdp_ring: ring to be used for XDP_TX action +- * @rx_buf: Rx buffer to store the XDP action ++ * @eop_desc: Last descriptor in packet to read metadata from + * + * Returns any of ICE_XDP_{PASS, CONSUMED, TX, REDIR} + */ +-static void ++static u32 + ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + struct bpf_prog *xdp_prog, struct ice_tx_ring *xdp_ring, +- struct ice_rx_buf *rx_buf) ++ union ice_32b_rx_flex_desc *eop_desc) + { + unsigned int ret = ICE_XDP_PASS; + u32 act; +@@ -542,6 +542,8 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + if (!xdp_prog) + goto exit; + ++ ice_xdp_meta_set_desc(xdp, eop_desc); ++ + act = bpf_prog_run_xdp(xdp_prog, xdp); + switch (act) { + case XDP_PASS: +@@ -571,7 +573,7 @@ ice_run_xdp(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + ret = ICE_XDP_CONSUMED; + } + exit: +- ice_set_rx_bufs_act(xdp, rx_ring, ret); ++ return ret; + } + + /** +@@ -857,10 +859,8 @@ ice_add_xdp_frag(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + xdp_buff_set_frags_flag(xdp); + } + +- if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) { +- ice_set_rx_bufs_act(xdp, rx_ring, ICE_XDP_CONSUMED); ++ if (unlikely(sinfo->nr_frags == MAX_SKB_FRAGS)) + return -ENOMEM; +- } + + __skb_fill_page_desc_noacc(sinfo, sinfo->nr_frags++, rx_buf->page, + rx_buf->page_offset, size); +@@ -921,7 +921,6 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, + struct ice_rx_buf *rx_buf; + + rx_buf = &rx_ring->rx_buf[ntc]; +- rx_buf->pgcnt = page_count(rx_buf->page); + prefetchw(rx_buf->page); + + if (!size) +@@ -937,6 +936,31 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size, + return rx_buf; + } + ++/** ++ * ice_get_pgcnts - grab page_count() for gathered fragments ++ * @rx_ring: Rx descriptor ring to store the page counts on ++ * ++ * This function is intended to be called right before running XDP ++ * program so that the page recycling mechanism will be able to take ++ * a correct decision regarding underlying pages; this is done in such ++ * way as XDP program can change the refcount of page ++ */ ++static void ice_get_pgcnts(struct ice_rx_ring *rx_ring) ++{ ++ u32 nr_frags = rx_ring->nr_frags + 1; ++ u32 idx = rx_ring->first_desc; ++ struct ice_rx_buf *rx_buf; ++ u32 cnt = rx_ring->count; ++ ++ for (int i = 0; i < nr_frags; i++) { ++ rx_buf = &rx_ring->rx_buf[idx]; ++ rx_buf->pgcnt = page_count(rx_buf->page); ++ ++ if (++idx == cnt) ++ idx = 0; ++ } ++} ++ + /** + * ice_build_skb - Build skb around an existing buffer + * @rx_ring: Rx descriptor ring to transact packets on +@@ -1049,12 +1073,12 @@ ice_construct_skb(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp) + rx_buf->page_offset + headlen, size, + xdp->frame_sz); + } else { +- /* buffer is unused, change the act that should be taken later +- * on; data was copied onto skb's linear part so there's no ++ /* buffer is unused, restore biased page count in Rx buffer; ++ * data was copied onto skb's linear part so there's no + * need for adjusting page offset and we can reuse this buffer + * as-is + */ +- rx_buf->act = ICE_SKB_CONSUMED; ++ rx_buf->pagecnt_bias++; + } + + if (unlikely(xdp_buff_has_frags(xdp))) { +@@ -1107,29 +1131,34 @@ ice_put_rx_buf(struct ice_rx_ring *rx_ring, struct ice_rx_buf *rx_buf) + * @xdp: XDP buffer carrying linear + frags part + * @xdp_xmit: XDP_TX/XDP_REDIRECT verdict storage + * @ntc: a current next_to_clean value to be stored at rx_ring ++ * @verdict: return code from XDP program execution + * + * Walk through gathered fragments and satisfy internal page + * recycle mechanism; we take here an action related to verdict + * returned by XDP program; + */ + static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, +- u32 *xdp_xmit, u32 ntc) ++ u32 *xdp_xmit, u32 ntc, u32 verdict) + { + u32 nr_frags = rx_ring->nr_frags + 1; + u32 idx = rx_ring->first_desc; + u32 cnt = rx_ring->count; ++ u32 post_xdp_frags = 1; + struct ice_rx_buf *buf; + int i; + +- for (i = 0; i < nr_frags; i++) { ++ if (unlikely(xdp_buff_has_frags(xdp))) ++ post_xdp_frags += xdp_get_shared_info_from_buff(xdp)->nr_frags; ++ ++ for (i = 0; i < post_xdp_frags; i++) { + buf = &rx_ring->rx_buf[idx]; + +- if (buf->act & (ICE_XDP_TX | ICE_XDP_REDIR)) { ++ if (verdict & (ICE_XDP_TX | ICE_XDP_REDIR)) { + ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); +- *xdp_xmit |= buf->act; +- } else if (buf->act & ICE_XDP_CONSUMED) { ++ *xdp_xmit |= verdict; ++ } else if (verdict & ICE_XDP_CONSUMED) { + buf->pagecnt_bias++; +- } else if (buf->act == ICE_XDP_PASS) { ++ } else if (verdict == ICE_XDP_PASS) { + ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz); + } + +@@ -1138,6 +1167,17 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp, + if (++idx == cnt) + idx = 0; + } ++ /* handle buffers that represented frags released by XDP prog; ++ * for these we keep pagecnt_bias as-is; refcount from struct page ++ * has been decremented within XDP prog and we do not have to increase ++ * the biased refcnt ++ */ ++ for (; i < nr_frags; i++) { ++ buf = &rx_ring->rx_buf[idx]; ++ ice_put_rx_buf(rx_ring, buf); ++ if (++idx == cnt) ++ idx = 0; ++ } + + xdp->data = NULL; + rx_ring->first_desc = ntc; +@@ -1164,9 +1204,9 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + struct ice_tx_ring *xdp_ring = NULL; + struct bpf_prog *xdp_prog = NULL; + u32 ntc = rx_ring->next_to_clean; ++ u32 cached_ntu, xdp_verdict; + u32 cnt = rx_ring->count; + u32 xdp_xmit = 0; +- u32 cached_ntu; + bool failure; + + xdp_prog = READ_ONCE(rx_ring->xdp_prog); +@@ -1230,7 +1270,7 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + xdp_prepare_buff(xdp, hard_start, offset, size, !!offset); + xdp_buff_clear_frags_flag(xdp); + } else if (ice_add_xdp_frag(rx_ring, xdp, rx_buf, size)) { +- ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc); ++ ice_put_rx_mbuf(rx_ring, xdp, NULL, ntc, ICE_XDP_CONSUMED); + break; + } + if (++ntc == cnt) +@@ -1240,13 +1280,14 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + if (ice_is_non_eop(rx_ring, rx_desc)) + continue; + +- ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_buf); +- if (rx_buf->act == ICE_XDP_PASS) ++ ice_get_pgcnts(rx_ring); ++ xdp_verdict = ice_run_xdp(rx_ring, xdp, xdp_prog, xdp_ring, rx_desc); ++ if (xdp_verdict == ICE_XDP_PASS) + goto construct_skb; + total_rx_bytes += xdp_get_buff_len(xdp); + total_rx_pkts++; + +- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc); ++ ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); + + continue; + construct_skb: +@@ -1256,13 +1297,10 @@ int ice_clean_rx_irq(struct ice_rx_ring *rx_ring, int budget) + skb = ice_construct_skb(rx_ring, xdp); + /* exit if we failed to retrieve a buffer */ + if (!skb) { +- rx_ring->ring_stats->rx_stats.alloc_page_failed++; +- rx_buf->act = ICE_XDP_CONSUMED; +- if (unlikely(xdp_buff_has_frags(xdp))) +- ice_set_rx_bufs_act(xdp, rx_ring, +- ICE_XDP_CONSUMED); ++ rx_ring->ring_stats->rx_stats.alloc_buf_failed++; ++ xdp_verdict = ICE_XDP_CONSUMED; + } +- ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc); ++ ice_put_rx_mbuf(rx_ring, xdp, &xdp_xmit, ntc, xdp_verdict); + + if (!skb) + break; +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h +index 407d4c320097f6..53a155dde3e320 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx.h ++++ b/drivers/net/ethernet/intel/ice/ice_txrx.h +@@ -201,7 +201,6 @@ struct ice_rx_buf { + struct page *page; + unsigned int page_offset; + unsigned int pgcnt; +- unsigned int act; + unsigned int pagecnt_bias; + }; + +@@ -257,6 +256,14 @@ enum ice_rx_dtype { + ICE_RX_DTYPE_SPLIT_ALWAYS = 2, + }; + ++struct ice_xdp_buff { ++ struct xdp_buff xdp_buff; ++ const union ice_32b_rx_flex_desc *eop_desc; ++}; ++ ++/* Required for compatibility with xdp_buffs from xsk_pool */ ++static_assert(offsetof(struct ice_xdp_buff, xdp_buff) == 0); ++ + /* indices into GLINT_ITR registers */ + #define ICE_RX_ITR ICE_IDX_ITR0 + #define ICE_TX_ITR ICE_IDX_ITR1 +@@ -298,7 +305,6 @@ enum ice_dynamic_itr { + /* descriptor ring, associated with a VSI */ + struct ice_rx_ring { + /* CL1 - 1st cacheline starts here */ +- struct ice_rx_ring *next; /* pointer to next ring in q_vector */ + void *desc; /* Descriptor ring memory */ + struct device *dev; /* Used for DMA mapping */ + struct net_device *netdev; /* netdev ring maps to */ +@@ -310,12 +316,16 @@ struct ice_rx_ring { + u16 count; /* Number of descriptors */ + u16 reg_idx; /* HW register index of the ring */ + u16 next_to_alloc; +- /* CL2 - 2nd cacheline starts here */ ++ + union { + struct ice_rx_buf *rx_buf; + struct xdp_buff **xdp_buf; + }; +- struct xdp_buff xdp; ++ /* CL2 - 2nd cacheline starts here */ ++ union { ++ struct ice_xdp_buff xdp_ext; ++ struct xdp_buff xdp; ++ }; + /* CL3 - 3rd cacheline starts here */ + struct bpf_prog *xdp_prog; + u16 rx_offset; +@@ -332,6 +342,7 @@ struct ice_rx_ring { + /* CL4 - 4th cacheline starts here */ + struct ice_channel *ch; + struct ice_tx_ring *xdp_ring; ++ struct ice_rx_ring *next; /* pointer to next ring in q_vector */ + struct xsk_buff_pool *xsk_pool; + u32 nr_frags; + dma_addr_t dma; /* physical address of ring */ +diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +index b0e56675f98b2a..41efafc5eb386a 100644 +--- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h ++++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +@@ -5,49 +5,6 @@ + #define _ICE_TXRX_LIB_H_ + #include "ice.h" + +-/** +- * ice_set_rx_bufs_act - propagate Rx buffer action to frags +- * @xdp: XDP buffer representing frame (linear and frags part) +- * @rx_ring: Rx ring struct +- * act: action to store onto Rx buffers related to XDP buffer parts +- * +- * Set action that should be taken before putting Rx buffer from first frag +- * to the last. +- */ +-static inline void +-ice_set_rx_bufs_act(struct xdp_buff *xdp, const struct ice_rx_ring *rx_ring, +- const unsigned int act) +-{ +- u32 sinfo_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags; +- u32 nr_frags = rx_ring->nr_frags + 1; +- u32 idx = rx_ring->first_desc; +- u32 cnt = rx_ring->count; +- struct ice_rx_buf *buf; +- +- for (int i = 0; i < nr_frags; i++) { +- buf = &rx_ring->rx_buf[idx]; +- buf->act = act; +- +- if (++idx == cnt) +- idx = 0; +- } +- +- /* adjust pagecnt_bias on frags freed by XDP prog */ +- if (sinfo_frags < rx_ring->nr_frags && act == ICE_XDP_CONSUMED) { +- u32 delta = rx_ring->nr_frags - sinfo_frags; +- +- while (delta) { +- if (idx == 0) +- idx = cnt - 1; +- else +- idx--; +- buf = &rx_ring->rx_buf[idx]; +- buf->pagecnt_bias--; +- delta--; +- } +- } +-} +- + /** + * ice_test_staterr - tests bits in Rx descriptor status and error fields + * @status_err_n: Rx descriptor status_error0 or status_error1 bits +@@ -164,4 +121,14 @@ ice_process_skb_fields(struct ice_rx_ring *rx_ring, + struct sk_buff *skb, u16 ptype); + void + ice_receive_skb(struct ice_rx_ring *rx_ring, struct sk_buff *skb, u16 vlan_tag); ++ ++static inline void ++ice_xdp_meta_set_desc(struct xdp_buff *xdp, ++ union ice_32b_rx_flex_desc *eop_desc) ++{ ++ struct ice_xdp_buff *xdp_ext = container_of(xdp, struct ice_xdp_buff, ++ xdp_buff); ++ ++ xdp_ext->eop_desc = eop_desc; ++} + #endif /* !_ICE_TXRX_LIB_H_ */ +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +index f66788a2ed77ec..8489b5087d9c60 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +@@ -107,7 +107,7 @@ static int mlx5_devlink_reload_fw_activate(struct devlink *devlink, struct netli + if (err) + return err; + +- mlx5_unload_one_devl_locked(dev, true); ++ mlx5_sync_reset_unload_flow(dev, true); + err = mlx5_health_wait_pci_up(dev); + if (err) + NL_SET_ERR_MSG_MOD(extack, "FW activate aborted, PCI reads fail after reset"); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +index 3efa8bf1d14ef4..4720523813b976 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.c +@@ -575,7 +575,6 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, + if (err) + return err; + } +- priv->dcbx.xoff = xoff; + + /* Apply the settings */ + if (update_buffer) { +@@ -584,6 +583,8 @@ int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, + return err; + } + ++ priv->dcbx.xoff = xoff; ++ + if (update_prio2buffer) + err = mlx5e_port_set_priority2buffer(priv->mdev, prio2buffer); + +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h +index f4a19ffbb641c0..66d276a1be836a 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en/port_buffer.h +@@ -66,11 +66,23 @@ struct mlx5e_port_buffer { + struct mlx5e_bufferx_reg buffer[MLX5E_MAX_NETWORK_BUFFER]; + }; + ++#ifdef CONFIG_MLX5_CORE_EN_DCB + int mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, + u32 change, unsigned int mtu, + struct ieee_pfc *pfc, + u32 *buffer_size, + u8 *prio2buffer); ++#else ++static inline int ++mlx5e_port_manual_buffer_config(struct mlx5e_priv *priv, ++ u32 change, unsigned int mtu, ++ void *pfc, ++ u32 *buffer_size, ++ u8 *prio2buffer) ++{ ++ return 0; ++} ++#endif + + int mlx5e_port_query_buffer(struct mlx5e_priv *priv, + struct mlx5e_port_buffer *port_buffer); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +index 5c6f01abdcb91d..d378aa55f22f90 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +@@ -44,6 +44,7 @@ + #include "eswitch.h" + #include "en.h" + #include "en/txrx.h" ++#include "en/port_buffer.h" + #include "en_tc.h" + #include "en_rep.h" + #include "en_accel/ipsec.h" +@@ -108,6 +109,8 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv) + if (up) { + netdev_info(priv->netdev, "Link up\n"); + netif_carrier_on(priv->netdev); ++ mlx5e_port_manual_buffer_config(priv, 0, priv->netdev->mtu, ++ NULL, NULL, NULL); + } else { + netdev_info(priv->netdev, "Link down\n"); + netif_carrier_off(priv->netdev); +@@ -2722,9 +2725,11 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) + struct mlx5e_params *params = &priv->channels.params; + struct net_device *netdev = priv->netdev; + struct mlx5_core_dev *mdev = priv->mdev; +- u16 mtu; ++ u16 mtu, prev_mtu; + int err; + ++ mlx5e_query_mtu(mdev, params, &prev_mtu); ++ + err = mlx5e_set_mtu(mdev, params, params->sw_mtu); + if (err) + return err; +@@ -2734,6 +2739,18 @@ int mlx5e_set_dev_port_mtu(struct mlx5e_priv *priv) + netdev_warn(netdev, "%s: VPort MTU %d is different than netdev mtu %d\n", + __func__, mtu, params->sw_mtu); + ++ if (mtu != prev_mtu && MLX5_BUFFER_SUPPORTED(mdev)) { ++ err = mlx5e_port_manual_buffer_config(priv, 0, mtu, ++ NULL, NULL, NULL); ++ if (err) { ++ netdev_warn(netdev, "%s: Failed to set Xon/Xoff values with MTU %d (err %d), setting back to previous MTU %d\n", ++ __func__, mtu, err, prev_mtu); ++ ++ mlx5e_set_mtu(mdev, params, prev_mtu); ++ return err; ++ } ++ } ++ + params->sw_mtu = mtu; + return 0; + } +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +index 6b17346aa4cef2..1547704c89767f 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.c +@@ -6,13 +6,15 @@ + #include "fw_reset.h" + #include "diag/fw_tracer.h" + #include "lib/tout.h" ++#include "sf/sf.h" + + enum { + MLX5_FW_RESET_FLAGS_RESET_REQUESTED, + MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, + MLX5_FW_RESET_FLAGS_PENDING_COMP, + MLX5_FW_RESET_FLAGS_DROP_NEW_REQUESTS, +- MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED ++ MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, ++ MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, + }; + + struct mlx5_fw_reset { +@@ -26,6 +28,7 @@ struct mlx5_fw_reset { + struct work_struct reset_now_work; + struct work_struct reset_abort_work; + unsigned long reset_flags; ++ u8 reset_method; + struct timer_list timer; + struct completion done; + int ret; +@@ -94,7 +97,7 @@ static int mlx5_reg_mfrl_set(struct mlx5_core_dev *dev, u8 reset_level, + } + + static int mlx5_reg_mfrl_query(struct mlx5_core_dev *dev, u8 *reset_level, +- u8 *reset_type, u8 *reset_state) ++ u8 *reset_type, u8 *reset_state, u8 *reset_method) + { + u32 out[MLX5_ST_SZ_DW(mfrl_reg)] = {}; + u32 in[MLX5_ST_SZ_DW(mfrl_reg)] = {}; +@@ -110,13 +113,26 @@ static int mlx5_reg_mfrl_query(struct mlx5_core_dev *dev, u8 *reset_level, + *reset_type = MLX5_GET(mfrl_reg, out, reset_type); + if (reset_state) + *reset_state = MLX5_GET(mfrl_reg, out, reset_state); ++ if (reset_method) ++ *reset_method = MLX5_GET(mfrl_reg, out, pci_reset_req_method); + + return 0; + } + + int mlx5_fw_reset_query(struct mlx5_core_dev *dev, u8 *reset_level, u8 *reset_type) + { +- return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL); ++ return mlx5_reg_mfrl_query(dev, reset_level, reset_type, NULL, NULL); ++} ++ ++static int mlx5_fw_reset_get_reset_method(struct mlx5_core_dev *dev, ++ u8 *reset_method) ++{ ++ if (!MLX5_CAP_GEN(dev, pcie_reset_using_hotreset_method)) { ++ *reset_method = MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE; ++ return 0; ++ } ++ ++ return mlx5_reg_mfrl_query(dev, NULL, NULL, NULL, reset_method); + } + + static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev, +@@ -124,7 +140,7 @@ static int mlx5_fw_reset_get_reset_state_err(struct mlx5_core_dev *dev, + { + u8 reset_state; + +- if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state)) ++ if (mlx5_reg_mfrl_query(dev, NULL, NULL, &reset_state, NULL)) + goto out; + + if (!reset_state) +@@ -203,7 +219,7 @@ int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev) + return mlx5_reg_mfrl_set(dev, MLX5_MFRL_REG_RESET_LEVEL0, 0, 0, false); + } + +-static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unloaded) ++static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev) + { + struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; + struct devlink *devlink = priv_to_devlink(dev); +@@ -212,8 +228,7 @@ static void mlx5_fw_reset_complete_reload(struct mlx5_core_dev *dev, bool unload + if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) { + complete(&fw_reset->done); + } else { +- if (!unloaded) +- mlx5_unload_one(dev, false); ++ mlx5_sync_reset_unload_flow(dev, false); + if (mlx5_health_wait_pci_up(dev)) + mlx5_core_err(dev, "reset reload flow aborted, PCI reads still not working\n"); + else +@@ -256,7 +271,7 @@ static void mlx5_sync_reset_reload_work(struct work_struct *work) + + mlx5_sync_reset_clear_reset_requested(dev, false); + mlx5_enter_error_state(dev, true); +- mlx5_fw_reset_complete_reload(dev, false); ++ mlx5_fw_reset_complete_reload(dev); + } + + #define MLX5_RESET_POLL_INTERVAL (HZ / 10) +@@ -383,6 +398,11 @@ static bool mlx5_is_reset_now_capable(struct mlx5_core_dev *dev) + return false; + } + ++ if (!mlx5_core_is_ecpf(dev) && !mlx5_sf_table_empty(dev)) { ++ mlx5_core_warn(dev, "SFs should be removed before reset\n"); ++ return false; ++ } ++ + #if IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE) + err = mlx5_check_hotplug_interrupt(dev); + if (err) +@@ -402,7 +422,11 @@ static void mlx5_sync_reset_request_event(struct work_struct *work) + struct mlx5_core_dev *dev = fw_reset->dev; + int err; + +- if (test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) || ++ err = mlx5_fw_reset_get_reset_method(dev, &fw_reset->reset_method); ++ if (err) ++ mlx5_core_warn(dev, "Failed reading MFRL, err %d\n", err); ++ ++ if (err || test_bit(MLX5_FW_RESET_FLAGS_NACK_RESET_REQUEST, &fw_reset->reset_flags) || + !mlx5_is_reset_now_capable(dev)) { + err = mlx5_fw_reset_set_reset_sync_nack(dev); + mlx5_core_warn(dev, "PCI Sync FW Update Reset Nack %s", +@@ -419,21 +443,15 @@ static void mlx5_sync_reset_request_event(struct work_struct *work) + mlx5_core_warn(dev, "PCI Sync FW Update Reset Ack. Device reset is expected.\n"); + } + +-static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev) ++static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev, u16 dev_id) + { + struct pci_bus *bridge_bus = dev->pdev->bus; + struct pci_dev *bridge = bridge_bus->self; + unsigned long timeout; + struct pci_dev *sdev; +- u16 reg16, dev_id; + int cap, err; ++ u16 reg16; + +- err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id); +- if (err) +- return pcibios_err_to_errno(err); +- err = mlx5_check_dev_ids(dev, dev_id); +- if (err) +- return err; + cap = pci_find_capability(bridge, PCI_CAP_ID_EXP); + if (!cap) + return -EOPNOTSUPP; +@@ -503,64 +521,60 @@ static int mlx5_pci_link_toggle(struct mlx5_core_dev *dev) + return err; + } + +-static void mlx5_sync_reset_now_event(struct work_struct *work) ++static int mlx5_pci_reset_bus(struct mlx5_core_dev *dev) + { +- struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset, +- reset_now_work); +- struct mlx5_core_dev *dev = fw_reset->dev; +- int err; ++ if (!MLX5_CAP_GEN(dev, pcie_reset_using_hotreset_method)) ++ return -EOPNOTSUPP; + +- if (mlx5_sync_reset_clear_reset_requested(dev, false)) +- return; ++ return pci_reset_bus(dev->pdev); ++} + +- mlx5_core_warn(dev, "Sync Reset now. Device is going to reset.\n"); ++static int mlx5_sync_pci_reset(struct mlx5_core_dev *dev, u8 reset_method) ++{ ++ u16 dev_id; ++ int err; + +- err = mlx5_cmd_fast_teardown_hca(dev); +- if (err) { +- mlx5_core_warn(dev, "Fast teardown failed, no reset done, err %d\n", err); +- goto done; +- } ++ err = pci_read_config_word(dev->pdev, PCI_DEVICE_ID, &dev_id); ++ if (err) ++ return pcibios_err_to_errno(err); ++ err = mlx5_check_dev_ids(dev, dev_id); ++ if (err) ++ return err; + +- err = mlx5_pci_link_toggle(dev); +- if (err) { +- mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, no reset done, err %d\n", err); +- set_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags); ++ switch (reset_method) { ++ case MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE: ++ err = mlx5_pci_link_toggle(dev, dev_id); ++ if (err) ++ mlx5_core_warn(dev, "mlx5_pci_link_toggle failed\n"); ++ break; ++ case MLX5_MFRL_REG_PCI_RESET_METHOD_HOT_RESET: ++ err = mlx5_pci_reset_bus(dev); ++ if (err) ++ mlx5_core_warn(dev, "mlx5_pci_reset_bus failed\n"); ++ break; ++ default: ++ return -EOPNOTSUPP; + } + +- mlx5_enter_error_state(dev, true); +-done: +- fw_reset->ret = err; +- mlx5_fw_reset_complete_reload(dev, false); ++ return err; + } + +-static void mlx5_sync_reset_unload_event(struct work_struct *work) ++void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked) + { +- struct mlx5_fw_reset *fw_reset; +- struct mlx5_core_dev *dev; ++ struct mlx5_fw_reset *fw_reset = dev->priv.fw_reset; + unsigned long timeout; + bool reset_action; + u8 rst_state; + int err; + +- fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work); +- dev = fw_reset->dev; +- +- if (mlx5_sync_reset_clear_reset_requested(dev, false)) +- return; +- +- mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n"); +- +- err = mlx5_cmd_fast_teardown_hca(dev); +- if (err) +- mlx5_core_warn(dev, "Fast teardown failed, unloading, err %d\n", err); +- else +- mlx5_enter_error_state(dev, true); +- +- if (test_bit(MLX5_FW_RESET_FLAGS_PENDING_COMP, &fw_reset->reset_flags)) ++ if (locked) + mlx5_unload_one_devl_locked(dev, false); + else + mlx5_unload_one(dev, false); + ++ if (!test_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags)) ++ return; ++ + mlx5_set_fw_rst_ack(dev); + mlx5_core_warn(dev, "Sync Reset Unload done, device reset expected\n"); + +@@ -583,17 +597,73 @@ static void mlx5_sync_reset_unload_event(struct work_struct *work) + goto done; + } + +- mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", rst_state); ++ mlx5_core_warn(dev, "Sync Reset, got reset action. rst_state = %u\n", ++ rst_state); + if (rst_state == MLX5_FW_RST_STATE_TOGGLE_REQ) { +- err = mlx5_pci_link_toggle(dev); ++ err = mlx5_sync_pci_reset(dev, fw_reset->reset_method); + if (err) { +- mlx5_core_warn(dev, "mlx5_pci_link_toggle failed, err %d\n", err); ++ mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, err %d\n", ++ err); + fw_reset->ret = err; + } + } + + done: +- mlx5_fw_reset_complete_reload(dev, true); ++ clear_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags); ++} ++ ++static void mlx5_sync_reset_now_event(struct work_struct *work) ++{ ++ struct mlx5_fw_reset *fw_reset = container_of(work, struct mlx5_fw_reset, ++ reset_now_work); ++ struct mlx5_core_dev *dev = fw_reset->dev; ++ int err; ++ ++ if (mlx5_sync_reset_clear_reset_requested(dev, false)) ++ return; ++ ++ mlx5_core_warn(dev, "Sync Reset now. Device is going to reset.\n"); ++ ++ err = mlx5_cmd_fast_teardown_hca(dev); ++ if (err) { ++ mlx5_core_warn(dev, "Fast teardown failed, no reset done, err %d\n", err); ++ goto done; ++ } ++ ++ err = mlx5_sync_pci_reset(dev, fw_reset->reset_method); ++ if (err) { ++ mlx5_core_warn(dev, "mlx5_sync_pci_reset failed, no reset done, err %d\n", err); ++ set_bit(MLX5_FW_RESET_FLAGS_RELOAD_REQUIRED, &fw_reset->reset_flags); ++ } ++ ++ mlx5_enter_error_state(dev, true); ++done: ++ fw_reset->ret = err; ++ mlx5_fw_reset_complete_reload(dev); ++} ++ ++static void mlx5_sync_reset_unload_event(struct work_struct *work) ++{ ++ struct mlx5_fw_reset *fw_reset; ++ struct mlx5_core_dev *dev; ++ int err; ++ ++ fw_reset = container_of(work, struct mlx5_fw_reset, reset_unload_work); ++ dev = fw_reset->dev; ++ ++ if (mlx5_sync_reset_clear_reset_requested(dev, false)) ++ return; ++ ++ set_bit(MLX5_FW_RESET_FLAGS_UNLOAD_EVENT, &fw_reset->reset_flags); ++ mlx5_core_warn(dev, "Sync Reset Unload. Function is forced down.\n"); ++ ++ err = mlx5_cmd_fast_teardown_hca(dev); ++ if (err) ++ mlx5_core_warn(dev, "Fast teardown failed, unloading, err %d\n", err); ++ else ++ mlx5_enter_error_state(dev, true); ++ ++ mlx5_fw_reset_complete_reload(dev); + } + + static void mlx5_sync_reset_abort_event(struct work_struct *work) +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h +index ea527d06a85f07..d5b28525c960dc 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/fw_reset.h +@@ -12,6 +12,7 @@ int mlx5_fw_reset_set_reset_sync(struct mlx5_core_dev *dev, u8 reset_type_sel, + int mlx5_fw_reset_set_live_patch(struct mlx5_core_dev *dev); + + int mlx5_fw_reset_wait_reset_done(struct mlx5_core_dev *dev); ++void mlx5_sync_reset_unload_flow(struct mlx5_core_dev *dev, bool locked); + int mlx5_fw_reset_verify_fw_complete(struct mlx5_core_dev *dev, + struct netlink_ext_ack *extack); + void mlx5_fw_reset_events_start(struct mlx5_core_dev *dev); +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c +index 62a85f09b52fd7..8a11e410f7c135 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c +@@ -627,6 +627,9 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) + if (MLX5_CAP_GEN_MAX(dev, pci_sync_for_fw_update_with_driver_unload)) + MLX5_SET(cmd_hca_cap, set_hca_cap, + pci_sync_for_fw_update_with_driver_unload, 1); ++ if (MLX5_CAP_GEN_MAX(dev, pcie_reset_using_hotreset_method)) ++ MLX5_SET(cmd_hca_cap, set_hca_cap, ++ pcie_reset_using_hotreset_method, 1); + + if (MLX5_CAP_GEN_MAX(dev, num_vhca_ports)) + MLX5_SET(cmd_hca_cap, +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +index e34a8f88c518c1..d5b2b6cfc8d21d 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c ++++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/devlink.c +@@ -20,9 +20,16 @@ struct mlx5_sf { + u16 hw_state; + }; + ++static void *mlx5_sf_by_dl_port(struct devlink_port *dl_port) ++{ ++ struct mlx5_devlink_port *mlx5_dl_port = mlx5_devlink_port_get(dl_port); ++ ++ return container_of(mlx5_dl_port, struct mlx5_sf, dl_port); ++} ++ + struct mlx5_sf_table { + struct mlx5_core_dev *dev; /* To refer from notifier context. */ +- struct xarray port_indices; /* port index based lookup. */ ++ struct xarray function_ids; /* function id based lookup. */ + refcount_t refcount; + struct completion disable_complete; + struct mutex sf_state_lock; /* Serializes sf state among user cmds & vhca event handler. */ +@@ -30,33 +37,20 @@ struct mlx5_sf_table { + struct notifier_block vhca_nb; + }; + +-static struct mlx5_sf * +-mlx5_sf_lookup_by_index(struct mlx5_sf_table *table, unsigned int port_index) +-{ +- return xa_load(&table->port_indices, port_index); +-} +- + static struct mlx5_sf * + mlx5_sf_lookup_by_function_id(struct mlx5_sf_table *table, unsigned int fn_id) + { +- unsigned long index; +- struct mlx5_sf *sf; +- +- xa_for_each(&table->port_indices, index, sf) { +- if (sf->hw_fn_id == fn_id) +- return sf; +- } +- return NULL; ++ return xa_load(&table->function_ids, fn_id); + } + +-static int mlx5_sf_id_insert(struct mlx5_sf_table *table, struct mlx5_sf *sf) ++static int mlx5_sf_function_id_insert(struct mlx5_sf_table *table, struct mlx5_sf *sf) + { +- return xa_insert(&table->port_indices, sf->port_index, sf, GFP_KERNEL); ++ return xa_insert(&table->function_ids, sf->hw_fn_id, sf, GFP_KERNEL); + } + +-static void mlx5_sf_id_erase(struct mlx5_sf_table *table, struct mlx5_sf *sf) ++static void mlx5_sf_function_id_erase(struct mlx5_sf_table *table, struct mlx5_sf *sf) + { +- xa_erase(&table->port_indices, sf->port_index); ++ xa_erase(&table->function_ids, sf->hw_fn_id); + } + + static struct mlx5_sf * +@@ -93,7 +87,7 @@ mlx5_sf_alloc(struct mlx5_sf_table *table, struct mlx5_eswitch *esw, + sf->hw_state = MLX5_VHCA_STATE_ALLOCATED; + sf->controller = controller; + +- err = mlx5_sf_id_insert(table, sf); ++ err = mlx5_sf_function_id_insert(table, sf); + if (err) + goto insert_err; + +@@ -111,7 +105,6 @@ mlx5_sf_alloc(struct mlx5_sf_table *table, struct mlx5_eswitch *esw, + + static void mlx5_sf_free(struct mlx5_sf_table *table, struct mlx5_sf *sf) + { +- mlx5_sf_id_erase(table, sf); + mlx5_sf_hw_table_sf_free(table->dev, sf->controller, sf->id); + trace_mlx5_sf_free(table->dev, sf->port_index, sf->controller, sf->hw_fn_id); + kfree(sf); +@@ -172,26 +165,19 @@ int mlx5_devlink_sf_port_fn_state_get(struct devlink_port *dl_port, + struct netlink_ext_ack *extack) + { + struct mlx5_core_dev *dev = devlink_priv(dl_port->devlink); ++ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port); + struct mlx5_sf_table *table; +- struct mlx5_sf *sf; +- int err = 0; + + table = mlx5_sf_table_try_get(dev); + if (!table) + return -EOPNOTSUPP; + +- sf = mlx5_sf_lookup_by_index(table, dl_port->index); +- if (!sf) { +- err = -EOPNOTSUPP; +- goto sf_err; +- } + mutex_lock(&table->sf_state_lock); + *state = mlx5_sf_to_devlink_state(sf->hw_state); + *opstate = mlx5_sf_to_devlink_opstate(sf->hw_state); + mutex_unlock(&table->sf_state_lock); +-sf_err: + mlx5_sf_table_put(table); +- return err; ++ return 0; + } + + static int mlx5_sf_activate(struct mlx5_core_dev *dev, struct mlx5_sf *sf, +@@ -257,8 +243,8 @@ int mlx5_devlink_sf_port_fn_state_set(struct devlink_port *dl_port, + struct netlink_ext_ack *extack) + { + struct mlx5_core_dev *dev = devlink_priv(dl_port->devlink); ++ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port); + struct mlx5_sf_table *table; +- struct mlx5_sf *sf; + int err; + + table = mlx5_sf_table_try_get(dev); +@@ -267,14 +253,7 @@ int mlx5_devlink_sf_port_fn_state_set(struct devlink_port *dl_port, + "Port state set is only supported in eswitch switchdev mode or SF ports are disabled."); + return -EOPNOTSUPP; + } +- sf = mlx5_sf_lookup_by_index(table, dl_port->index); +- if (!sf) { +- err = -ENODEV; +- goto out; +- } +- + err = mlx5_sf_state_set(dev, table, sf, state, extack); +-out: + mlx5_sf_table_put(table); + return err; + } +@@ -301,6 +280,7 @@ static int mlx5_sf_add(struct mlx5_core_dev *dev, struct mlx5_sf_table *table, + return 0; + + esw_err: ++ mlx5_sf_function_id_erase(table, sf); + mlx5_sf_free(table, sf); + return err; + } +@@ -361,6 +341,8 @@ int mlx5_devlink_sf_port_new(struct devlink *devlink, + + static void mlx5_sf_dealloc(struct mlx5_sf_table *table, struct mlx5_sf *sf) + { ++ mlx5_sf_function_id_erase(table, sf); ++ + if (sf->hw_state == MLX5_VHCA_STATE_ALLOCATED) { + mlx5_sf_free(table, sf); + } else if (mlx5_sf_is_active(sf)) { +@@ -383,10 +365,9 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink, + struct netlink_ext_ack *extack) + { + struct mlx5_core_dev *dev = devlink_priv(devlink); ++ struct mlx5_sf *sf = mlx5_sf_by_dl_port(dl_port); + struct mlx5_eswitch *esw = dev->priv.eswitch; + struct mlx5_sf_table *table; +- struct mlx5_sf *sf; +- int err = 0; + + table = mlx5_sf_table_try_get(dev); + if (!table) { +@@ -394,21 +375,14 @@ int mlx5_devlink_sf_port_del(struct devlink *devlink, + "Port del is only supported in eswitch switchdev mode or SF ports are disabled."); + return -EOPNOTSUPP; + } +- sf = mlx5_sf_lookup_by_index(table, dl_port->index); +- if (!sf) { +- err = -ENODEV; +- goto sf_err; +- } + + mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id); +- mlx5_sf_id_erase(table, sf); + + mutex_lock(&table->sf_state_lock); + mlx5_sf_dealloc(table, sf); + mutex_unlock(&table->sf_state_lock); +-sf_err: + mlx5_sf_table_put(table); +- return err; ++ return 0; + } + + static bool mlx5_sf_state_update_check(const struct mlx5_sf *sf, u8 new_state) +@@ -471,9 +445,8 @@ static void mlx5_sf_deactivate_all(struct mlx5_sf_table *table) + /* At this point, no new user commands can start and no vhca event can + * arrive. It is safe to destroy all user created SFs. + */ +- xa_for_each(&table->port_indices, index, sf) { ++ xa_for_each(&table->function_ids, index, sf) { + mlx5_eswitch_unload_sf_vport(esw, sf->hw_fn_id); +- mlx5_sf_id_erase(table, sf); + mlx5_sf_dealloc(table, sf); + } + } +@@ -531,7 +504,7 @@ int mlx5_sf_table_init(struct mlx5_core_dev *dev) + + mutex_init(&table->sf_state_lock); + table->dev = dev; +- xa_init(&table->port_indices); ++ xa_init(&table->function_ids); + dev->priv.sf_table = table; + refcount_set(&table->refcount, 0); + table->esw_nb.notifier_call = mlx5_sf_esw_event; +@@ -566,6 +539,16 @@ void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) + mlx5_esw_event_notifier_unregister(dev->priv.eswitch, &table->esw_nb); + WARN_ON(refcount_read(&table->refcount)); + mutex_destroy(&table->sf_state_lock); +- WARN_ON(!xa_empty(&table->port_indices)); ++ WARN_ON(!xa_empty(&table->function_ids)); + kfree(table); + } ++ ++bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) ++{ ++ struct mlx5_sf_table *table = dev->priv.sf_table; ++ ++ if (!table) ++ return true; ++ ++ return xa_empty(&table->function_ids); ++} +diff --git a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +index 860f9ddb7107b8..89559a37997ad6 100644 +--- a/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h ++++ b/drivers/net/ethernet/mellanox/mlx5/core/sf/sf.h +@@ -17,6 +17,7 @@ void mlx5_sf_hw_table_destroy(struct mlx5_core_dev *dev); + + int mlx5_sf_table_init(struct mlx5_core_dev *dev); + void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev); ++bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev); + + int mlx5_devlink_sf_port_new(struct devlink *devlink, + const struct devlink_port_new_attrs *add_attr, +@@ -61,6 +62,11 @@ static inline void mlx5_sf_table_cleanup(struct mlx5_core_dev *dev) + { + } + ++static inline bool mlx5_sf_table_empty(const struct mlx5_core_dev *dev) ++{ ++ return true; ++} ++ + #endif + + #endif +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +index a9837985a483d8..bdb4f527289d2d 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +@@ -69,7 +69,7 @@ static void dwmac4_core_init(struct mac_device_info *hw, + init_waitqueue_head(&priv->tstamp_busy_wait); + } + +-static void dwmac4_phylink_get_caps(struct stmmac_priv *priv) ++static void dwmac4_update_caps(struct stmmac_priv *priv) + { + if (priv->plat->tx_queues_to_use > 1) + priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD | MAC_1000HD); +@@ -1161,7 +1161,7 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, + + const struct stmmac_ops dwmac4_ops = { + .core_init = dwmac4_core_init, +- .phylink_get_caps = dwmac4_phylink_get_caps, ++ .update_caps = dwmac4_update_caps, + .set_mac = stmmac_set_mac, + .rx_ipc = dwmac4_rx_ipc_enable, + .rx_queue_enable = dwmac4_rx_queue_enable, +@@ -1204,7 +1204,7 @@ const struct stmmac_ops dwmac4_ops = { + + const struct stmmac_ops dwmac410_ops = { + .core_init = dwmac4_core_init, +- .phylink_get_caps = dwmac4_phylink_get_caps, ++ .update_caps = dwmac4_update_caps, + .set_mac = stmmac_dwmac4_set_mac, + .rx_ipc = dwmac4_rx_ipc_enable, + .rx_queue_enable = dwmac4_rx_queue_enable, +@@ -1253,7 +1253,7 @@ const struct stmmac_ops dwmac410_ops = { + + const struct stmmac_ops dwmac510_ops = { + .core_init = dwmac4_core_init, +- .phylink_get_caps = dwmac4_phylink_get_caps, ++ .update_caps = dwmac4_update_caps, + .set_mac = stmmac_dwmac4_set_mac, + .rx_ipc = dwmac4_rx_ipc_enable, + .rx_queue_enable = dwmac4_rx_queue_enable, +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +index 052566f5b7f361..0bcb378fa0bc91 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +@@ -47,6 +47,14 @@ static void dwxgmac2_core_init(struct mac_device_info *hw, + writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); + } + ++static void dwxgmac2_update_caps(struct stmmac_priv *priv) ++{ ++ if (!priv->dma_cap.mbps_10_100) ++ priv->hw->link.caps &= ~(MAC_10 | MAC_100); ++ else if (!priv->dma_cap.half_duplex) ++ priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD); ++} ++ + static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable) + { + u32 tx = readl(ioaddr + XGMAC_TX_CONFIG); +@@ -1583,6 +1591,7 @@ static void dwxgmac3_fpe_configure(void __iomem *ioaddr, struct stmmac_fpe_cfg * + + const struct stmmac_ops dwxgmac210_ops = { + .core_init = dwxgmac2_core_init, ++ .update_caps = dwxgmac2_update_caps, + .set_mac = dwxgmac2_set_mac, + .rx_ipc = dwxgmac2_rx_ipc, + .rx_queue_enable = dwxgmac2_rx_queue_enable, +@@ -1705,8 +1714,8 @@ int dwxgmac2_setup(struct stmmac_priv *priv) + mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); + + mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | +- MAC_1000FD | MAC_2500FD | MAC_5000FD | +- MAC_10000FD; ++ MAC_10 | MAC_100 | MAC_1000FD | ++ MAC_2500FD | MAC_5000FD | MAC_10000FD; + mac->link.duplex = 0; + mac->link.speed10 = XGMAC_CONFIG_SS_10_MII; + mac->link.speed100 = XGMAC_CONFIG_SS_100_MII; +diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +index 05ea74e9379399..b2c03cb65c7cc8 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +@@ -203,10 +203,6 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, + } + + writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); +- +- /* Enable MTL RX overflow */ +- value = readl(ioaddr + XGMAC_MTL_QINTEN(channel)); +- writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel)); + } + + static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, +@@ -386,8 +382,11 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, + static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, + struct dma_features *dma_cap) + { ++ struct stmmac_priv *priv; + u32 hw_cap; + ++ priv = container_of(dma_cap, struct stmmac_priv, dma_cap); ++ + /* MAC HW feature 0 */ + hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); + dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31; +@@ -410,6 +409,8 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, + dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4; + dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3; + dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1; ++ if (dma_cap->mbps_1000 && priv->synopsys_id >= DWXGMAC_CORE_2_20) ++ dma_cap->mbps_10_100 = 1; + + /* MAC HW feature 1 */ + hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1); +diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h +index 47fb8e1646c2e9..ee9a7d98648b01 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h ++++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h +@@ -300,8 +300,8 @@ struct stmmac_est; + struct stmmac_ops { + /* MAC core initialization */ + void (*core_init)(struct mac_device_info *hw, struct net_device *dev); +- /* Get phylink capabilities */ +- void (*phylink_get_caps)(struct stmmac_priv *priv); ++ /* Update MAC capabilities */ ++ void (*update_caps)(struct stmmac_priv *priv); + /* Enable the MAC RX/TX */ + void (*set_mac)(void __iomem *ioaddr, bool enable); + /* Enable and verify that the IPC module is supported */ +@@ -423,8 +423,8 @@ struct stmmac_ops { + + #define stmmac_core_init(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, core_init, __args) +-#define stmmac_mac_phylink_get_caps(__priv) \ +- stmmac_do_void_callback(__priv, mac, phylink_get_caps, __priv) ++#define stmmac_mac_update_caps(__priv) \ ++ stmmac_do_void_callback(__priv, mac, update_caps, __priv) + #define stmmac_mac_set(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, set_mac, __args) + #define stmmac_rx_ipc(__priv, __args...) \ +diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +index 615d25a0e46be5..ff5389a8efc33a 100644 +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -1230,8 +1230,8 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) + xpcs_get_interfaces(priv->hw->xpcs, + priv->phylink_config.supported_interfaces); + +- /* Get the MAC specific capabilities */ +- stmmac_mac_phylink_get_caps(priv); ++ /* Refresh the MAC-specific capabilities */ ++ stmmac_mac_update_caps(priv); + + priv->phylink_config.mac_capabilities = priv->hw->link.caps; + +@@ -2426,6 +2426,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); + struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; ++ bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; + struct xsk_buff_pool *pool = tx_q->xsk_pool; + unsigned int entry = tx_q->cur_tx; + struct dma_desc *tx_desc = NULL; +@@ -2496,7 +2497,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) + } + + stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len, +- true, priv->mode, true, true, ++ csum, priv->mode, true, true, + xdp_desc.len); + + stmmac_enable_dma_transmission(priv, priv->ioaddr); +@@ -4789,6 +4790,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, + { + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; + struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; ++ bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; + unsigned int entry = tx_q->cur_tx; + struct dma_desc *tx_desc; + dma_addr_t dma_addr; +@@ -4833,7 +4835,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, + stmmac_set_desc_addr(priv, tx_desc, dma_addr); + + stmmac_prepare_tx_desc(priv, tx_desc, 1, xdpf->len, +- true, priv->mode, true, true, ++ csum, priv->mode, true, true, + xdpf->len); + + tx_q->tx_count_frames++; +@@ -7232,7 +7234,7 @@ int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt) + priv->rss.table[i] = ethtool_rxfh_indir_default(i, + rx_cnt); + +- stmmac_mac_phylink_get_caps(priv); ++ stmmac_mac_update_caps(priv); + + priv->phylink_config.mac_capabilities = priv->hw->link.caps; + +diff --git a/drivers/net/phy/mscc/mscc.h b/drivers/net/phy/mscc/mscc.h +index cdb343779a8fb5..4ba6e32cf6d8d1 100644 +--- a/drivers/net/phy/mscc/mscc.h ++++ b/drivers/net/phy/mscc/mscc.h +@@ -476,6 +476,7 @@ static inline void vsc8584_config_macsec_intr(struct phy_device *phydev) + void vsc85xx_link_change_notify(struct phy_device *phydev); + void vsc8584_config_ts_intr(struct phy_device *phydev); + int vsc8584_ptp_init(struct phy_device *phydev); ++void vsc8584_ptp_deinit(struct phy_device *phydev); + int vsc8584_ptp_probe_once(struct phy_device *phydev); + int vsc8584_ptp_probe(struct phy_device *phydev); + irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev); +@@ -490,6 +491,9 @@ static inline int vsc8584_ptp_init(struct phy_device *phydev) + { + return 0; + } ++static inline void vsc8584_ptp_deinit(struct phy_device *phydev) ++{ ++} + static inline int vsc8584_ptp_probe_once(struct phy_device *phydev) + { + return 0; +diff --git a/drivers/net/phy/mscc/mscc_main.c b/drivers/net/phy/mscc/mscc_main.c +index 3de72d9cc22bd0..3a932b30f4358f 100644 +--- a/drivers/net/phy/mscc/mscc_main.c ++++ b/drivers/net/phy/mscc/mscc_main.c +@@ -2337,9 +2337,7 @@ static int vsc85xx_probe(struct phy_device *phydev) + + static void vsc85xx_remove(struct phy_device *phydev) + { +- struct vsc8531_private *priv = phydev->priv; +- +- skb_queue_purge(&priv->rx_skbs_list); ++ vsc8584_ptp_deinit(phydev); + } + + /* Microsemi VSC85xx PHYs */ +diff --git a/drivers/net/phy/mscc/mscc_ptp.c b/drivers/net/phy/mscc/mscc_ptp.c +index add1a9ee721afa..1f6237705b44b7 100644 +--- a/drivers/net/phy/mscc/mscc_ptp.c ++++ b/drivers/net/phy/mscc/mscc_ptp.c +@@ -1297,7 +1297,6 @@ static void vsc8584_set_input_clk_configured(struct phy_device *phydev) + + static int __vsc8584_init_ptp(struct phy_device *phydev) + { +- struct vsc8531_private *vsc8531 = phydev->priv; + static const u32 ltc_seq_e[] = { 0, 400000, 0, 0, 0 }; + static const u8 ltc_seq_a[] = { 8, 6, 5, 4, 2 }; + u32 val; +@@ -1514,17 +1513,7 @@ static int __vsc8584_init_ptp(struct phy_device *phydev) + + vsc85xx_ts_eth_cmp1_sig(phydev); + +- vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp; +- vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp; +- vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp; +- vsc8531->mii_ts.ts_info = vsc85xx_ts_info; +- phydev->mii_ts = &vsc8531->mii_ts; +- +- memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps)); +- +- vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps, +- &phydev->mdio.dev); +- return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock); ++ return 0; + } + + void vsc8584_config_ts_intr(struct phy_device *phydev) +@@ -1551,6 +1540,16 @@ int vsc8584_ptp_init(struct phy_device *phydev) + return 0; + } + ++void vsc8584_ptp_deinit(struct phy_device *phydev) ++{ ++ struct vsc8531_private *vsc8531 = phydev->priv; ++ ++ if (vsc8531->ptp->ptp_clock) { ++ ptp_clock_unregister(vsc8531->ptp->ptp_clock); ++ skb_queue_purge(&vsc8531->rx_skbs_list); ++ } ++} ++ + irqreturn_t vsc8584_handle_ts_interrupt(struct phy_device *phydev) + { + struct vsc8531_private *priv = phydev->priv; +@@ -1608,7 +1607,16 @@ int vsc8584_ptp_probe(struct phy_device *phydev) + + vsc8531->ptp->phydev = phydev; + +- return 0; ++ vsc8531->mii_ts.rxtstamp = vsc85xx_rxtstamp; ++ vsc8531->mii_ts.txtstamp = vsc85xx_txtstamp; ++ vsc8531->mii_ts.hwtstamp = vsc85xx_hwtstamp; ++ vsc8531->mii_ts.ts_info = vsc85xx_ts_info; ++ phydev->mii_ts = &vsc8531->mii_ts; ++ ++ memcpy(&vsc8531->ptp->caps, &vsc85xx_clk_caps, sizeof(vsc85xx_clk_caps)); ++ vsc8531->ptp->ptp_clock = ptp_clock_register(&vsc8531->ptp->caps, ++ &phydev->mdio.dev); ++ return PTR_ERR_OR_ZERO(vsc8531->ptp->ptp_clock); + } + + int vsc8584_ptp_probe_once(struct phy_device *phydev) +diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c +index 3976bc4295dd19..eba755b584a459 100644 +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -1363,6 +1363,9 @@ static const struct usb_device_id products[] = { + {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ + {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1034, 2)}, /* Telit LE910C4-WWX */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1037, 4)}, /* Telit LE910C4-WWX */ ++ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1038, 3)}, /* Telit LE910C4-WWX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x103a, 0)}, /* Telit LE910C4-WWX */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x1050, 2)}, /* Telit FN980 */ +diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c +index 4d57a4e3410546..18393800546c11 100644 +--- a/drivers/of/dynamic.c ++++ b/drivers/of/dynamic.c +@@ -306,15 +306,20 @@ int of_detach_node(struct device_node *np) + } + EXPORT_SYMBOL_GPL(of_detach_node); + ++void __of_prop_free(struct property *prop) ++{ ++ kfree(prop->name); ++ kfree(prop->value); ++ kfree(prop); ++} ++ + static void property_list_free(struct property *prop_list) + { + struct property *prop, *next; + + for (prop = prop_list; prop != NULL; prop = next) { + next = prop->next; +- kfree(prop->name); +- kfree(prop->value); +- kfree(prop); ++ __of_prop_free(prop); + } + } + +@@ -427,9 +432,7 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) + return new; + + err_free: +- kfree(new->name); +- kfree(new->value); +- kfree(new); ++ __of_prop_free(new); + return NULL; + } + +@@ -471,9 +474,7 @@ struct device_node *__of_node_dup(const struct device_node *np, + if (!new_pp) + goto err_prop; + if (__of_add_property(node, new_pp)) { +- kfree(new_pp->name); +- kfree(new_pp->value); +- kfree(new_pp); ++ __of_prop_free(new_pp); + goto err_prop; + } + } +@@ -934,12 +935,14 @@ static int of_changeset_add_prop_helper(struct of_changeset *ocs, + + ret = of_changeset_add_property(ocs, np, new_pp); + if (ret) { +- kfree(new_pp->name); +- kfree(new_pp->value); +- kfree(new_pp); ++ __of_prop_free(new_pp); ++ return ret; + } + +- return ret; ++ new_pp->next = np->deadprops; ++ np->deadprops = new_pp; ++ ++ return 0; + } + + /** +diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h +index 21f8f5e80917d1..73b55f4f84a3cc 100644 +--- a/drivers/of/of_private.h ++++ b/drivers/of/of_private.h +@@ -123,6 +123,7 @@ extern void *__unflatten_device_tree(const void *blob, + * own the devtree lock or work on detached trees only. + */ + struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); ++void __of_prop_free(struct property *prop); + struct device_node *__of_node_dup(const struct device_node *np, + const char *full_name); + +diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c +index a9a292d6d59b26..dc13299586414f 100644 +--- a/drivers/of/overlay.c ++++ b/drivers/of/overlay.c +@@ -262,9 +262,7 @@ static struct property *dup_and_fixup_symbol_prop( + return new_prop; + + err_free_new_prop: +- kfree(new_prop->name); +- kfree(new_prop->value); +- kfree(new_prop); ++ __of_prop_free(new_prop); + err_free_target_path: + kfree(target_path); + +@@ -361,11 +359,8 @@ static int add_changeset_property(struct overlay_changeset *ovcs, + pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n", + target->np, new_prop->name); + +- if (ret) { +- kfree(new_prop->name); +- kfree(new_prop->value); +- kfree(new_prop); +- } ++ if (ret) ++ __of_prop_free(new_prop); + return ret; + } + +diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c +index 3b22c36bfb0b7c..5bfec440b4fd70 100644 +--- a/drivers/of/unittest.c ++++ b/drivers/of/unittest.c +@@ -800,15 +800,11 @@ static void __init of_unittest_property_copy(void) + + new = __of_prop_dup(&p1, GFP_KERNEL); + unittest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); +- kfree(new->value); +- kfree(new->name); +- kfree(new); ++ __of_prop_free(new); + + new = __of_prop_dup(&p2, GFP_KERNEL); + unittest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); +- kfree(new->value); +- kfree(new->name); +- kfree(new); ++ __of_prop_free(new); + #endif + } + +@@ -3665,9 +3661,7 @@ static __init void of_unittest_overlay_high_level(void) + goto err_unlock; + } + if (__of_add_property(of_symbols, new_prop)) { +- kfree(new_prop->name); +- kfree(new_prop->value); +- kfree(new_prop); ++ __of_prop_free(new_prop); + /* "name" auto-generated by unflatten */ + if (!strcmp(prop->name, "name")) + continue; +diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig +index 7dfb7190580efa..ab3908a923e3a0 100644 +--- a/drivers/pinctrl/Kconfig ++++ b/drivers/pinctrl/Kconfig +@@ -438,6 +438,7 @@ config PINCTRL_STMFX + tristate "STMicroelectronics STMFX GPIO expander pinctrl driver" + depends on I2C + depends on OF_GPIO ++ depends on HAS_IOMEM + select GENERIC_PINCONF + select GPIOLIB_IRQCHIP + select MFD_STMFX +diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c +index 24f6eefb68030d..df37ac81620e62 100644 +--- a/drivers/scsi/scsi_sysfs.c ++++ b/drivers/scsi/scsi_sysfs.c +@@ -265,7 +265,7 @@ show_shost_supported_mode(struct device *dev, struct device_attribute *attr, + return show_shost_mode(supported_mode, buf); + } + +-static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); ++static DEVICE_ATTR(supported_mode, S_IRUGO, show_shost_supported_mode, NULL); + + static ssize_t + show_shost_active_mode(struct device *dev, +@@ -279,7 +279,7 @@ show_shost_active_mode(struct device *dev, + return show_shost_mode(shost->active_mode, buf); + } + +-static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); ++static DEVICE_ATTR(active_mode, S_IRUGO, show_shost_active_mode, NULL); + + static int check_reset_type(const char *str) + { +diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c +index f2ed7167c84809..5ad237d77a9a9f 100644 +--- a/drivers/vhost/net.c ++++ b/drivers/vhost/net.c +@@ -96,6 +96,7 @@ struct vhost_net_ubuf_ref { + atomic_t refcount; + wait_queue_head_t wait; + struct vhost_virtqueue *vq; ++ struct rcu_head rcu; + }; + + #define VHOST_NET_BATCH 64 +@@ -249,9 +250,13 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) + + static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) + { +- int r = atomic_sub_return(1, &ubufs->refcount); ++ int r; ++ ++ rcu_read_lock(); ++ r = atomic_sub_return(1, &ubufs->refcount); + if (unlikely(!r)) + wake_up(&ubufs->wait); ++ rcu_read_unlock(); + return r; + } + +@@ -264,7 +269,7 @@ static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) + static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) + { + vhost_net_ubuf_put_and_wait(ubufs); +- kfree(ubufs); ++ kfree_rcu(ubufs, rcu); + } + + static void vhost_net_clear_ubuf_info(struct vhost_net *n) +diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c +index 586c5709dfb554..34438981ddd805 100644 +--- a/fs/efivarfs/super.c ++++ b/fs/efivarfs/super.c +@@ -90,6 +90,10 @@ static int efivarfs_d_compare(const struct dentry *dentry, + { + int guid = len - EFI_VARIABLE_GUID_LEN; + ++ /* Parallel lookups may produce a temporary invalid filename */ ++ if (guid <= 0) ++ return 1; ++ + if (name->len != len) + return 1; + +diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c +index d852b43ac43e32..c1f802ecc47b2c 100644 +--- a/fs/erofs/zdata.c ++++ b/fs/erofs/zdata.c +@@ -1401,6 +1401,16 @@ static void z_erofs_decompressqueue_kthread_work(struct kthread_work *work) + } + #endif + ++/* Use (kthread_)work in atomic contexts to minimize scheduling overhead */ ++static inline bool z_erofs_in_atomic(void) ++{ ++ if (IS_ENABLED(CONFIG_PREEMPTION) && rcu_preempt_depth()) ++ return true; ++ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT)) ++ return true; ++ return !preemptible(); ++} ++ + static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + int bios) + { +@@ -1415,8 +1425,7 @@ static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io, + + if (atomic_add_return(bios, &io->pending_bios)) + return; +- /* Use (kthread_)work and sync decompression for atomic contexts only */ +- if (!in_task() || irqs_disabled() || rcu_read_lock_any_held()) { ++ if (z_erofs_in_atomic()) { + #ifdef CONFIG_EROFS_FS_PCPU_KTHREAD + struct kthread_worker *worker; + +diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c +index 040b6b79c75e59..0ea3916ed1dcb1 100644 +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -206,83 +206,6 @@ nfs_page_group_lock_head(struct nfs_page *req) + return head; + } + +-/* +- * nfs_unroll_locks - unlock all newly locked reqs and wait on @req +- * @head: head request of page group, must be holding head lock +- * @req: request that couldn't lock and needs to wait on the req bit lock +- * +- * This is a helper function for nfs_lock_and_join_requests +- * returns 0 on success, < 0 on error. +- */ +-static void +-nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req) +-{ +- struct nfs_page *tmp; +- +- /* relinquish all the locks successfully grabbed this run */ +- for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) { +- if (!kref_read(&tmp->wb_kref)) +- continue; +- nfs_unlock_and_release_request(tmp); +- } +-} +- +-/* +- * nfs_page_group_lock_subreq - try to lock a subrequest +- * @head: head request of page group +- * @subreq: request to lock +- * +- * This is a helper function for nfs_lock_and_join_requests which +- * must be called with the head request and page group both locked. +- * On error, it returns with the page group unlocked. +- */ +-static int +-nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq) +-{ +- int ret; +- +- if (!kref_get_unless_zero(&subreq->wb_kref)) +- return 0; +- while (!nfs_lock_request(subreq)) { +- nfs_page_group_unlock(head); +- ret = nfs_wait_on_request(subreq); +- if (!ret) +- ret = nfs_page_group_lock(head); +- if (ret < 0) { +- nfs_unroll_locks(head, subreq); +- nfs_release_request(subreq); +- return ret; +- } +- } +- return 0; +-} +- +-/* +- * nfs_page_group_lock_subrequests - try to lock the subrequests +- * @head: head request of page group +- * +- * This is a helper function for nfs_lock_and_join_requests which +- * must be called with the head request locked. +- */ +-int nfs_page_group_lock_subrequests(struct nfs_page *head) +-{ +- struct nfs_page *subreq; +- int ret; +- +- ret = nfs_page_group_lock(head); +- if (ret < 0) +- return ret; +- /* lock each request in the page group */ +- for (subreq = head->wb_this_page; subreq != head; +- subreq = subreq->wb_this_page) { +- ret = nfs_page_group_lock_subreq(head, subreq); +- if (ret < 0) +- return ret; +- } +- nfs_page_group_unlock(head); +- return 0; +-} +- + /* + * nfs_page_set_headlock - set the request PG_HEADLOCK + * @req: request that is to be locked +@@ -349,13 +272,14 @@ nfs_page_group_unlock(struct nfs_page *req) + nfs_page_clear_headlock(req); + } + +-/* +- * nfs_page_group_sync_on_bit_locked ++/** ++ * nfs_page_group_sync_on_bit_locked - Test if all requests have @bit set ++ * @req: request in page group ++ * @bit: PG_* bit that is used to sync page group + * + * must be called with page group lock held + */ +-static bool +-nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit) ++bool nfs_page_group_sync_on_bit_locked(struct nfs_page *req, unsigned int bit) + { + struct nfs_page *head = req->wb_head; + struct nfs_page *tmp; +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 7d03811f44a4bb..cb1e9996fcc8ec 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -156,20 +156,10 @@ nfs_page_set_inode_ref(struct nfs_page *req, struct inode *inode) + } + } + +-static int +-nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode) ++static void nfs_cancel_remove_inode(struct nfs_page *req, struct inode *inode) + { +- int ret; +- +- if (!test_bit(PG_REMOVE, &req->wb_flags)) +- return 0; +- ret = nfs_page_group_lock(req); +- if (ret) +- return ret; + if (test_and_clear_bit(PG_REMOVE, &req->wb_flags)) + nfs_page_set_inode_ref(req, inode); +- nfs_page_group_unlock(req); +- return 0; + } + + static struct nfs_page *nfs_folio_private_request(struct folio *folio) +@@ -238,36 +228,6 @@ static struct nfs_page *nfs_folio_find_head_request(struct folio *folio) + return req; + } + +-static struct nfs_page *nfs_folio_find_and_lock_request(struct folio *folio) +-{ +- struct inode *inode = folio_file_mapping(folio)->host; +- struct nfs_page *req, *head; +- int ret; +- +- for (;;) { +- req = nfs_folio_find_head_request(folio); +- if (!req) +- return req; +- head = nfs_page_group_lock_head(req); +- if (head != req) +- nfs_release_request(req); +- if (IS_ERR(head)) +- return head; +- ret = nfs_cancel_remove_inode(head, inode); +- if (ret < 0) { +- nfs_unlock_and_release_request(head); +- return ERR_PTR(ret); +- } +- /* Ensure that nobody removed the request before we locked it */ +- if (head == nfs_folio_private_request(folio)) +- break; +- if (folio_test_swapcache(folio)) +- break; +- nfs_unlock_and_release_request(head); +- } +- return head; +-} +- + /* Adjust the file length if we're writing beyond the end */ + static void nfs_grow_file(struct folio *folio, unsigned int offset, + unsigned int count) +@@ -548,6 +508,57 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo, + nfs_destroy_unlinked_subrequests(destroy_list, head, inode); + } + ++/* ++ * nfs_unroll_locks - unlock all newly locked reqs and wait on @req ++ * @head: head request of page group, must be holding head lock ++ * @req: request that couldn't lock and needs to wait on the req bit lock ++ * ++ * This is a helper function for nfs_lock_and_join_requests ++ * returns 0 on success, < 0 on error. ++ */ ++static void ++nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req) ++{ ++ struct nfs_page *tmp; ++ ++ /* relinquish all the locks successfully grabbed this run */ ++ for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) { ++ if (!kref_read(&tmp->wb_kref)) ++ continue; ++ nfs_unlock_and_release_request(tmp); ++ } ++} ++ ++/* ++ * nfs_page_group_lock_subreq - try to lock a subrequest ++ * @head: head request of page group ++ * @subreq: request to lock ++ * ++ * This is a helper function for nfs_lock_and_join_requests which ++ * must be called with the head request and page group both locked. ++ * On error, it returns with the page group unlocked. ++ */ ++static int ++nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq) ++{ ++ int ret; ++ ++ if (!kref_get_unless_zero(&subreq->wb_kref)) ++ return 0; ++ while (!nfs_lock_request(subreq)) { ++ nfs_page_group_unlock(head); ++ ret = nfs_wait_on_request(subreq); ++ if (!ret) ++ ret = nfs_page_group_lock(head); ++ if (ret < 0) { ++ nfs_unroll_locks(head, subreq); ++ nfs_release_request(subreq); ++ return ret; ++ } ++ } ++ return 0; ++} ++ + /* + * nfs_lock_and_join_requests - join all subreqs to the head req + * @folio: the folio used to lookup the "page group" of nfs_page structures +@@ -566,30 +577,59 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo, + static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio) + { + struct inode *inode = folio_file_mapping(folio)->host; +- struct nfs_page *head; ++ struct nfs_page *head, *subreq; + struct nfs_commit_info cinfo; + int ret; + +- nfs_init_cinfo_from_inode(&cinfo, inode); + /* + * A reference is taken only on the head request which acts as a + * reference to the whole page group - the group will not be destroyed + * until the head reference is released. + */ +- head = nfs_folio_find_and_lock_request(folio); +- if (IS_ERR_OR_NULL(head)) +- return head; ++retry: ++ head = nfs_folio_find_head_request(folio); ++ if (!head) ++ return NULL; + +- /* lock each request in the page group */ +- ret = nfs_page_group_lock_subrequests(head); +- if (ret < 0) { ++ while (!nfs_lock_request(head)) { ++ ret = nfs_wait_on_request(head); ++ if (ret < 0) { ++ nfs_release_request(head); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ ret = nfs_page_group_lock(head); ++ if (ret < 0) ++ goto out_unlock; ++ ++ /* Ensure that nobody removed the request before we locked it */ ++ if (head != folio->private && !folio_test_swapcache(folio)) { ++ nfs_page_group_unlock(head); + nfs_unlock_and_release_request(head); +- return ERR_PTR(ret); ++ goto retry; + } + +- nfs_join_page_group(head, &cinfo, inode); ++ nfs_cancel_remove_inode(head, inode); ++ ++ /* lock each request in the page group */ ++ for (subreq = head->wb_this_page; ++ subreq != head; ++ subreq = subreq->wb_this_page) { ++ ret = nfs_page_group_lock_subreq(head, subreq); ++ if (ret < 0) ++ goto out_unlock; ++ } + ++ nfs_page_group_unlock(head); ++ ++ nfs_init_cinfo_from_inode(&cinfo, inode); ++ nfs_join_page_group(head, &cinfo, inode); + return head; ++ ++out_unlock: ++ nfs_unlock_and_release_request(head); ++ return ERR_PTR(ret); + } + + static void nfs_write_error(struct nfs_page *req, int error) +@@ -792,7 +832,8 @@ static void nfs_inode_remove_request(struct nfs_page *req) + { + struct nfs_inode *nfsi = NFS_I(nfs_page_to_inode(req)); + +- if (nfs_page_group_sync_on_bit(req, PG_REMOVE)) { ++ nfs_page_group_lock(req); ++ if (nfs_page_group_sync_on_bit_locked(req, PG_REMOVE)) { + struct folio *folio = nfs_page_to_folio(req->wb_head); + struct address_space *mapping = folio_file_mapping(folio); + +@@ -804,6 +845,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) + } + spin_unlock(&mapping->private_lock); + } ++ nfs_page_group_unlock(req); + + if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) { + atomic_long_dec(&nfsi->nrequests); +diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c +index a1ab95f382d566..2744d5580d195f 100644 +--- a/fs/smb/client/cifsfs.c ++++ b/fs/smb/client/cifsfs.c +@@ -1371,6 +1371,20 @@ static loff_t cifs_remap_file_range(struct file *src_file, loff_t off, + netfs_resize_file(&target_cifsi->netfs, new_size); + fscache_resize_cookie(cifs_inode_cookie(target_inode), + new_size); ++ } else if (rc == -EOPNOTSUPP) { ++ /* ++ * copy_file_range syscall man page indicates EINVAL ++ * is returned e.g when "fd_in and fd_out refer to the ++ * same file and the source and target ranges overlap." ++ * Test generic/157 was what showed these cases where ++ * we need to remap EOPNOTSUPP to EINVAL ++ */ ++ if (off >= src_inode->i_size) { ++ rc = -EINVAL; ++ } else if (src_inode == target_inode) { ++ if (off + len > destoff) ++ rc = -EINVAL; ++ } + } + } + +diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c +index d93ebd58ecae16..6c16c4f34d8824 100644 +--- a/fs/smb/client/inode.c ++++ b/fs/smb/client/inode.c +@@ -1856,15 +1856,24 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) + struct cifs_sb_info *cifs_sb = CIFS_SB(sb); + struct tcon_link *tlink; + struct cifs_tcon *tcon; ++ __u32 dosattr = 0, origattr = 0; + struct TCP_Server_Info *server; + struct iattr *attrs = NULL; +- __u32 dosattr = 0, origattr = 0; ++ bool rehash = false; + + cifs_dbg(FYI, "cifs_unlink, dir=0x%p, dentry=0x%p\n", dir, dentry); + + if (unlikely(cifs_forced_shutdown(cifs_sb))) + return -EIO; + ++ /* Unhash dentry in advance to prevent any concurrent opens */ ++ spin_lock(&dentry->d_lock); ++ if (!d_unhashed(dentry)) { ++ __d_drop(dentry); ++ rehash = true; ++ } ++ spin_unlock(&dentry->d_lock); ++ + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); +@@ -1915,7 +1924,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) + cifs_drop_nlink(inode); + } + } else if (rc == -ENOENT) { +- d_drop(dentry); ++ if (simple_positive(dentry)) ++ d_delete(dentry); + } else if (rc == -EBUSY) { + if (server->ops->rename_pending_delete) { + rc = server->ops->rename_pending_delete(full_path, +@@ -1968,6 +1978,8 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry) + kfree(attrs); + free_xid(xid); + cifs_put_tlink(tlink); ++ if (rehash) ++ d_rehash(dentry); + return rc; + } + +@@ -2367,6 +2379,7 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + struct cifs_sb_info *cifs_sb; + struct tcon_link *tlink; + struct cifs_tcon *tcon; ++ bool rehash = false; + unsigned int xid; + int rc, tmprc; + int retry_count = 0; +@@ -2382,6 +2395,17 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + if (unlikely(cifs_forced_shutdown(cifs_sb))) + return -EIO; + ++ /* ++ * Prevent any concurrent opens on the target by unhashing the dentry. ++ * VFS already unhashes the target when renaming directories. ++ */ ++ if (d_is_positive(target_dentry) && !d_is_dir(target_dentry)) { ++ if (!d_unhashed(target_dentry)) { ++ d_drop(target_dentry); ++ rehash = true; ++ } ++ } ++ + tlink = cifs_sb_tlink(cifs_sb); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); +@@ -2421,6 +2445,8 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + } + } + ++ if (!rc) ++ rehash = false; + /* + * No-replace is the natural behavior for CIFS, so skip unlink hacks. + */ +@@ -2479,12 +2505,16 @@ cifs_rename2(struct mnt_idmap *idmap, struct inode *source_dir, + goto cifs_rename_exit; + rc = cifs_do_rename(xid, source_dentry, from_name, + target_dentry, to_name); ++ if (!rc) ++ rehash = false; + } + + /* force revalidate to go get info when needed */ + CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0; + + cifs_rename_exit: ++ if (rehash) ++ d_rehash(target_dentry); + kfree(info_buf_source); + free_dentry_path(page2); + free_dentry_path(page1); +diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c +index e1078a1decdfa3..0cc80f472432ad 100644 +--- a/fs/smb/client/smb2inode.c ++++ b/fs/smb/client/smb2inode.c +@@ -206,8 +206,10 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, + server = cifs_pick_channel(ses); + + vars = kzalloc(sizeof(*vars), GFP_ATOMIC); +- if (vars == NULL) +- return -ENOMEM; ++ if (vars == NULL) { ++ rc = -ENOMEM; ++ goto out; ++ } + rqst = &vars->rqst[0]; + rsp_iov = &vars->rsp_iov[0]; + +@@ -828,6 +830,7 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon, + smb2_should_replay(tcon, &retries, &cur_sleep)) + goto replay_again; + ++out: + if (cfile) + cifsFileInfo_put(cfile); + +diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c +index 54de405cbab5ac..4d369876487bde 100644 +--- a/fs/xfs/libxfs/xfs_attr_remote.c ++++ b/fs/xfs/libxfs/xfs_attr_remote.c +@@ -418,6 +418,13 @@ xfs_attr_rmtval_get( + dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); + error = xfs_buf_read(mp->m_ddev_targp, dblkno, dblkcnt, + 0, &bp, &xfs_attr3_rmt_buf_ops); ++ /* ++ * ENODATA from disk implies a disk medium failure; ++ * ENODATA for xattrs means attribute not found, so ++ * disambiguate that here. ++ */ ++ if (error == -ENODATA) ++ error = -EIO; + if (error) + return error; + +diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c +index 28bbfc31039c0e..1efd45076ee2ae 100644 +--- a/fs/xfs/libxfs/xfs_da_btree.c ++++ b/fs/xfs/libxfs/xfs_da_btree.c +@@ -2649,6 +2649,12 @@ xfs_da_read_buf( + + error = xfs_trans_read_buf_map(mp, tp, mp->m_ddev_targp, mapp, nmap, 0, + &bp, ops); ++ /* ++ * ENODATA from disk implies a disk medium failure; ENODATA for ++ * xattrs means attribute not found, so disambiguate that here. ++ */ ++ if (error == -ENODATA && whichfork == XFS_ATTR_FORK) ++ error = -EIO; + if (error) + goto out_free; + +diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h +index 45f2f278b50a8a..70807c679f1abc 100644 +--- a/include/linux/atmdev.h ++++ b/include/linux/atmdev.h +@@ -185,6 +185,7 @@ struct atmdev_ops { /* only send is required */ + int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd, + void __user *arg); + #endif ++ int (*pre_send)(struct atm_vcc *vcc, struct sk_buff *skb); + int (*send)(struct atm_vcc *vcc,struct sk_buff *skb); + int (*send_bh)(struct atm_vcc *vcc, struct sk_buff *skb); + int (*send_oam)(struct atm_vcc *vcc,void *cell,int flags); +diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h +index 9106771bb92f01..4913d364e97747 100644 +--- a/include/linux/mlx5/mlx5_ifc.h ++++ b/include/linux/mlx5/mlx5_ifc.h +@@ -1731,7 +1731,8 @@ struct mlx5_ifc_cmd_hca_cap_bits { + u8 reserved_at_328[0x2]; + u8 relaxed_ordering_read[0x1]; + u8 log_max_pd[0x5]; +- u8 reserved_at_330[0x6]; ++ u8 reserved_at_330[0x5]; ++ u8 pcie_reset_using_hotreset_method[0x1]; + u8 pci_sync_for_fw_update_with_driver_unload[0x1]; + u8 vnic_env_cnt_steering_fail[0x1]; + u8 vport_counter_local_loopback[0x1]; +@@ -10824,6 +10825,11 @@ struct mlx5_ifc_mcda_reg_bits { + u8 data[][0x20]; + }; + ++enum { ++ MLX5_MFRL_REG_PCI_RESET_METHOD_LINK_TOGGLE = 0, ++ MLX5_MFRL_REG_PCI_RESET_METHOD_HOT_RESET = 1, ++}; ++ + enum { + MLX5_MFRL_REG_RESET_STATE_IDLE = 0, + MLX5_MFRL_REG_RESET_STATE_IN_NEGOTIATION = 1, +@@ -10851,7 +10857,8 @@ struct mlx5_ifc_mfrl_reg_bits { + u8 pci_sync_for_fw_update_start[0x1]; + u8 pci_sync_for_fw_update_resp[0x2]; + u8 rst_type_sel[0x3]; +- u8 reserved_at_28[0x4]; ++ u8 pci_reset_req_method[0x3]; ++ u8 reserved_at_2b[0x1]; + u8 reset_state[0x4]; + u8 reset_type[0x8]; + u8 reset_level[0x8]; +diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h +index 1c315f854ea801..6a46069c5a3689 100644 +--- a/include/linux/nfs_page.h ++++ b/include/linux/nfs_page.h +@@ -156,13 +156,13 @@ extern int nfs_wait_on_request(struct nfs_page *); + extern void nfs_unlock_request(struct nfs_page *req); + extern void nfs_unlock_and_release_request(struct nfs_page *); + extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req); +-extern int nfs_page_group_lock_subrequests(struct nfs_page *head); + extern void nfs_join_page_group(struct nfs_page *head, + struct nfs_commit_info *cinfo, + struct inode *inode); + extern int nfs_page_group_lock(struct nfs_page *); + extern void nfs_page_group_unlock(struct nfs_page *); + extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); ++extern bool nfs_page_group_sync_on_bit_locked(struct nfs_page *, unsigned int); + extern int nfs_page_set_headlock(struct nfs_page *req); + extern void nfs_page_clear_headlock(struct nfs_page *req); + extern bool nfs_async_iocounter_wait(struct rpc_task *, struct nfs_lock_context *); +diff --git a/include/net/bluetooth/hci_sync.h b/include/net/bluetooth/hci_sync.h +index 3cb2d10cac930b..e2e588b08fe90a 100644 +--- a/include/net/bluetooth/hci_sync.h ++++ b/include/net/bluetooth/hci_sync.h +@@ -72,7 +72,7 @@ int hci_update_class_sync(struct hci_dev *hdev); + + int hci_update_eir_sync(struct hci_dev *hdev); + int hci_update_class_sync(struct hci_dev *hdev); +-int hci_update_name_sync(struct hci_dev *hdev); ++int hci_update_name_sync(struct hci_dev *hdev, const u8 *name); + int hci_write_ssp_mode_sync(struct hci_dev *hdev, u8 mode); + + int hci_get_random_address(struct hci_dev *hdev, bool require_privacy, +diff --git a/include/net/rose.h b/include/net/rose.h +index 23267b4efcfa32..2b5491bbf39ab5 100644 +--- a/include/net/rose.h ++++ b/include/net/rose.h +@@ -8,6 +8,7 @@ + #ifndef _ROSE_H + #define _ROSE_H + ++#include + #include + #include + #include +@@ -96,7 +97,7 @@ struct rose_neigh { + ax25_cb *ax25; + struct net_device *dev; + unsigned short count; +- unsigned short use; ++ refcount_t use; + unsigned int number; + char restarted; + char dce_mode; +@@ -151,6 +152,21 @@ struct rose_sock { + + #define rose_sk(sk) ((struct rose_sock *)(sk)) + ++static inline void rose_neigh_hold(struct rose_neigh *rose_neigh) ++{ ++ refcount_inc(&rose_neigh->use); ++} ++ ++static inline void rose_neigh_put(struct rose_neigh *rose_neigh) ++{ ++ if (refcount_dec_and_test(&rose_neigh->use)) { ++ if (rose_neigh->ax25) ++ ax25_cb_put(rose_neigh->ax25); ++ kfree(rose_neigh->digipeat); ++ kfree(rose_neigh); ++ } ++} ++ + /* af_rose.c */ + extern ax25_address rose_callsign; + extern int sysctl_rose_restart_request_timeout; +diff --git a/kernel/dma/pool.c b/kernel/dma/pool.c +index b481c48a31a630..6b0be9598a973f 100644 +--- a/kernel/dma/pool.c ++++ b/kernel/dma/pool.c +@@ -102,8 +102,8 @@ static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size, + + #ifdef CONFIG_DMA_DIRECT_REMAP + addr = dma_common_contiguous_remap(page, pool_size, +- pgprot_dmacoherent(PAGE_KERNEL), +- __builtin_return_address(0)); ++ pgprot_decrypted(pgprot_dmacoherent(PAGE_KERNEL)), ++ __builtin_return_address(0)); + if (!addr) + goto free_page; + #else +diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c +index 907e45361939be..a32c8637503d14 100644 +--- a/kernel/trace/trace.c ++++ b/kernel/trace/trace.c +@@ -10162,10 +10162,10 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) + ret = print_trace_line(&iter); + if (ret != TRACE_TYPE_NO_CONSUME) + trace_consume(&iter); ++ ++ trace_printk_seq(&iter.seq); + } + touch_nmi_watchdog(); +- +- trace_printk_seq(&iter.seq); + } + + if (!cnt) +diff --git a/net/atm/common.c b/net/atm/common.c +index 9cc82acbc73588..48bb3f66a3f2ab 100644 +--- a/net/atm/common.c ++++ b/net/atm/common.c +@@ -635,18 +635,27 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) + + skb->dev = NULL; /* for paths shared with net_device interfaces */ + if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { +- atm_return_tx(vcc, skb); +- kfree_skb(skb); + error = -EFAULT; +- goto out; ++ goto free_skb; + } + if (eff != size) + memset(skb->data + size, 0, eff-size); ++ ++ if (vcc->dev->ops->pre_send) { ++ error = vcc->dev->ops->pre_send(vcc, skb); ++ if (error) ++ goto free_skb; ++ } ++ + error = vcc->dev->ops->send(vcc, skb); + error = error ? error : size; + out: + release_sock(sk); + return error; ++free_skb: ++ atm_return_tx(vcc, skb); ++ kfree_skb(skb); ++ goto out; + } + + __poll_t vcc_poll(struct file *file, struct socket *sock, poll_table *wait) +diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c +index c06010c0d88293..5eed23b8d6c332 100644 +--- a/net/bluetooth/hci_event.c ++++ b/net/bluetooth/hci_event.c +@@ -2692,7 +2692,7 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) + if (!conn) + goto unlock; + +- if (status) { ++ if (status && status != HCI_ERROR_UNKNOWN_CONN_ID) { + mgmt_disconnect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, status); + +@@ -2707,6 +2707,12 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status) + goto done; + } + ++ /* During suspend, mark connection as closed immediately ++ * since we might not receive HCI_EV_DISCONN_COMPLETE ++ */ ++ if (hdev->suspended) ++ conn->state = BT_CLOSED; ++ + mgmt_conn = test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags); + + if (conn->type == ACL_LINK) { +@@ -4386,7 +4392,17 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, void *data, + if (!conn) + continue; + +- conn->sent -= count; ++ /* Check if there is really enough packets outstanding before ++ * attempting to decrease the sent counter otherwise it could ++ * underflow.. ++ */ ++ if (conn->sent >= count) { ++ conn->sent -= count; ++ } else { ++ bt_dev_warn(hdev, "hcon %p sent %u < count %u", ++ conn, conn->sent, count); ++ conn->sent = 0; ++ } + + switch (conn->type) { + case ACL_LINK: +diff --git a/net/bluetooth/hci_sync.c b/net/bluetooth/hci_sync.c +index 01aca077071174..020f1809fc9946 100644 +--- a/net/bluetooth/hci_sync.c ++++ b/net/bluetooth/hci_sync.c +@@ -3491,13 +3491,13 @@ int hci_update_scan_sync(struct hci_dev *hdev) + return hci_write_scan_enable_sync(hdev, scan); + } + +-int hci_update_name_sync(struct hci_dev *hdev) ++int hci_update_name_sync(struct hci_dev *hdev, const u8 *name) + { + struct hci_cp_write_local_name cp; + + memset(&cp, 0, sizeof(cp)); + +- memcpy(cp.name, hdev->dev_name, sizeof(cp.name)); ++ memcpy(cp.name, name, sizeof(cp.name)); + + return __hci_cmd_sync_status(hdev, HCI_OP_WRITE_LOCAL_NAME, + sizeof(cp), &cp, +@@ -3550,7 +3550,7 @@ int hci_powered_update_sync(struct hci_dev *hdev) + hci_write_fast_connectable_sync(hdev, false); + hci_update_scan_sync(hdev); + hci_update_class_sync(hdev); +- hci_update_name_sync(hdev); ++ hci_update_name_sync(hdev, hdev->dev_name); + hci_update_eir_sync(hdev); + } + +diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c +index 82fa8c28438f25..9b01eaaa0eb2d6 100644 +--- a/net/bluetooth/mgmt.c ++++ b/net/bluetooth/mgmt.c +@@ -3819,8 +3819,11 @@ static void set_name_complete(struct hci_dev *hdev, void *data, int err) + + static int set_name_sync(struct hci_dev *hdev, void *data) + { ++ struct mgmt_pending_cmd *cmd = data; ++ struct mgmt_cp_set_local_name *cp = cmd->param; ++ + if (lmp_bredr_capable(hdev)) { +- hci_update_name_sync(hdev); ++ hci_update_name_sync(hdev, cp->name); + hci_update_eir_sync(hdev); + } + +diff --git a/net/ipv4/route.c b/net/ipv4/route.c +index 8672ebbace980b..20f5c8307443d3 100644 +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -2547,12 +2547,16 @@ static struct rtable *__mkroute_output(const struct fib_result *res, + !netif_is_l3_master(dev_out)) + return ERR_PTR(-EINVAL); + +- if (ipv4_is_lbcast(fl4->daddr)) ++ if (ipv4_is_lbcast(fl4->daddr)) { + type = RTN_BROADCAST; +- else if (ipv4_is_multicast(fl4->daddr)) ++ ++ /* reset fi to prevent gateway resolution */ ++ fi = NULL; ++ } else if (ipv4_is_multicast(fl4->daddr)) { + type = RTN_MULTICAST; +- else if (ipv4_is_zeronet(fl4->daddr)) ++ } else if (ipv4_is_zeronet(fl4->daddr)) { + return ERR_PTR(-EINVAL); ++ } + + if (dev_out->flags & IFF_LOOPBACK) + flags |= RTCF_LOCAL; +diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c +index 66e9ceaaa43a14..614695444b6acb 100644 +--- a/net/rose/af_rose.c ++++ b/net/rose/af_rose.c +@@ -170,7 +170,7 @@ void rose_kill_by_neigh(struct rose_neigh *neigh) + + if (rose->neighbour == neigh) { + rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + rose->neighbour = NULL; + } + } +@@ -212,7 +212,7 @@ static void rose_kill_by_device(struct net_device *dev) + if (rose->device == dev) { + rose_disconnect(sk, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); + if (rose->neighbour) +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + netdev_put(rose->device, &rose->dev_tracker); + rose->device = NULL; + } +@@ -655,7 +655,7 @@ static int rose_release(struct socket *sock) + break; + + case ROSE_STATE_2: +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + release_sock(sk); + rose_disconnect(sk, 0, -1, -1); + lock_sock(sk); +@@ -823,6 +823,7 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le + rose->lci = rose_new_lci(rose->neighbour); + if (!rose->lci) { + err = -ENETUNREACH; ++ rose_neigh_put(rose->neighbour); + goto out_release; + } + +@@ -834,12 +835,14 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le + dev = rose_dev_first(); + if (!dev) { + err = -ENETUNREACH; ++ rose_neigh_put(rose->neighbour); + goto out_release; + } + + user = ax25_findbyuid(current_euid()); + if (!user) { + err = -EINVAL; ++ rose_neigh_put(rose->neighbour); + dev_put(dev); + goto out_release; + } +@@ -874,8 +877,6 @@ static int rose_connect(struct socket *sock, struct sockaddr *uaddr, int addr_le + + rose->state = ROSE_STATE_1; + +- rose->neighbour->use++; +- + rose_write_internal(sk, ROSE_CALL_REQUEST); + rose_start_heartbeat(sk); + rose_start_t1timer(sk); +@@ -1077,7 +1078,7 @@ int rose_rx_call_request(struct sk_buff *skb, struct net_device *dev, struct ros + GFP_ATOMIC); + make_rose->facilities = facilities; + +- make_rose->neighbour->use++; ++ rose_neigh_hold(make_rose->neighbour); + + if (rose_sk(sk)->defer) { + make_rose->state = ROSE_STATE_5; +diff --git a/net/rose/rose_in.c b/net/rose/rose_in.c +index 4d67f36dce1b49..7caae93937ee9b 100644 +--- a/net/rose/rose_in.c ++++ b/net/rose/rose_in.c +@@ -56,7 +56,7 @@ static int rose_state1_machine(struct sock *sk, struct sk_buff *skb, int framety + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, ECONNREFUSED, skb->data[3], skb->data[4]); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + break; + + default: +@@ -79,12 +79,12 @@ static int rose_state2_machine(struct sock *sk, struct sk_buff *skb, int framety + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + break; + + case ROSE_CLEAR_CONFIRMATION: + rose_disconnect(sk, 0, -1, -1); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + break; + + default: +@@ -120,7 +120,7 @@ static int rose_state3_machine(struct sock *sk, struct sk_buff *skb, int framety + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + break; + + case ROSE_RR: +@@ -233,7 +233,7 @@ static int rose_state4_machine(struct sock *sk, struct sk_buff *skb, int framety + case ROSE_CLEAR_REQUEST: + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + break; + + default: +@@ -253,7 +253,7 @@ static int rose_state5_machine(struct sock *sk, struct sk_buff *skb, int framety + if (frametype == ROSE_CLEAR_REQUEST) { + rose_write_internal(sk, ROSE_CLEAR_CONFIRMATION); + rose_disconnect(sk, 0, skb->data[3], skb->data[4]); +- rose_sk(sk)->neighbour->use--; ++ rose_neigh_put(rose_sk(sk)->neighbour); + } + + return 0; +diff --git a/net/rose/rose_route.c b/net/rose/rose_route.c +index a7054546f52dfa..28746ae5a25828 100644 +--- a/net/rose/rose_route.c ++++ b/net/rose/rose_route.c +@@ -93,11 +93,11 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, + rose_neigh->ax25 = NULL; + rose_neigh->dev = dev; + rose_neigh->count = 0; +- rose_neigh->use = 0; + rose_neigh->dce_mode = 0; + rose_neigh->loopback = 0; + rose_neigh->number = rose_neigh_no++; + rose_neigh->restarted = 0; ++ refcount_set(&rose_neigh->use, 1); + + skb_queue_head_init(&rose_neigh->queue); + +@@ -178,6 +178,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, + } + } + rose_neigh->count++; ++ rose_neigh_hold(rose_neigh); + + goto out; + } +@@ -187,6 +188,7 @@ static int __must_check rose_add_node(struct rose_route_struct *rose_route, + rose_node->neighbour[rose_node->count] = rose_neigh; + rose_node->count++; + rose_neigh->count++; ++ rose_neigh_hold(rose_neigh); + } + + out: +@@ -234,20 +236,12 @@ static void rose_remove_neigh(struct rose_neigh *rose_neigh) + + if ((s = rose_neigh_list) == rose_neigh) { + rose_neigh_list = rose_neigh->next; +- if (rose_neigh->ax25) +- ax25_cb_put(rose_neigh->ax25); +- kfree(rose_neigh->digipeat); +- kfree(rose_neigh); + return; + } + + while (s != NULL && s->next != NULL) { + if (s->next == rose_neigh) { + s->next = rose_neigh->next; +- if (rose_neigh->ax25) +- ax25_cb_put(rose_neigh->ax25); +- kfree(rose_neigh->digipeat); +- kfree(rose_neigh); + return; + } + +@@ -263,10 +257,10 @@ static void rose_remove_route(struct rose_route *rose_route) + struct rose_route *s; + + if (rose_route->neigh1 != NULL) +- rose_route->neigh1->use--; ++ rose_neigh_put(rose_route->neigh1); + + if (rose_route->neigh2 != NULL) +- rose_route->neigh2->use--; ++ rose_neigh_put(rose_route->neigh2); + + if ((s = rose_route_list) == rose_route) { + rose_route_list = rose_route->next; +@@ -330,9 +324,12 @@ static int rose_del_node(struct rose_route_struct *rose_route, + for (i = 0; i < rose_node->count; i++) { + if (rose_node->neighbour[i] == rose_neigh) { + rose_neigh->count--; ++ rose_neigh_put(rose_neigh); + +- if (rose_neigh->count == 0 && rose_neigh->use == 0) ++ if (rose_neigh->count == 0) { + rose_remove_neigh(rose_neigh); ++ rose_neigh_put(rose_neigh); ++ } + + rose_node->count--; + +@@ -381,11 +378,11 @@ void rose_add_loopback_neigh(void) + sn->ax25 = NULL; + sn->dev = NULL; + sn->count = 0; +- sn->use = 0; + sn->dce_mode = 1; + sn->loopback = 1; + sn->number = rose_neigh_no++; + sn->restarted = 1; ++ refcount_set(&sn->use, 1); + + skb_queue_head_init(&sn->queue); + +@@ -436,6 +433,7 @@ int rose_add_loopback_node(const rose_address *address) + rose_node_list = rose_node; + + rose_loopback_neigh->count++; ++ rose_neigh_hold(rose_loopback_neigh); + + out: + spin_unlock_bh(&rose_node_list_lock); +@@ -467,6 +465,7 @@ void rose_del_loopback_node(const rose_address *address) + rose_remove_node(rose_node); + + rose_loopback_neigh->count--; ++ rose_neigh_put(rose_loopback_neigh); + + out: + spin_unlock_bh(&rose_node_list_lock); +@@ -506,6 +505,7 @@ void rose_rt_device_down(struct net_device *dev) + memmove(&t->neighbour[i], &t->neighbour[i + 1], + sizeof(t->neighbour[0]) * + (t->count - i)); ++ rose_neigh_put(s); + } + + if (t->count <= 0) +@@ -513,6 +513,7 @@ void rose_rt_device_down(struct net_device *dev) + } + + rose_remove_neigh(s); ++ rose_neigh_put(s); + } + spin_unlock_bh(&rose_neigh_list_lock); + spin_unlock_bh(&rose_node_list_lock); +@@ -548,6 +549,7 @@ static int rose_clear_routes(void) + { + struct rose_neigh *s, *rose_neigh; + struct rose_node *t, *rose_node; ++ int i; + + spin_lock_bh(&rose_node_list_lock); + spin_lock_bh(&rose_neigh_list_lock); +@@ -558,17 +560,21 @@ static int rose_clear_routes(void) + while (rose_node != NULL) { + t = rose_node; + rose_node = rose_node->next; +- if (!t->loopback) ++ ++ if (!t->loopback) { ++ for (i = 0; i < t->count; i++) ++ rose_neigh_put(t->neighbour[i]); + rose_remove_node(t); ++ } + } + + while (rose_neigh != NULL) { + s = rose_neigh; + rose_neigh = rose_neigh->next; + +- if (s->use == 0 && !s->loopback) { +- s->count = 0; ++ if (!s->loopback) { + rose_remove_neigh(s); ++ rose_neigh_put(s); + } + } + +@@ -684,6 +690,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, + for (i = 0; i < node->count; i++) { + if (node->neighbour[i]->restarted) { + res = node->neighbour[i]; ++ rose_neigh_hold(node->neighbour[i]); + goto out; + } + } +@@ -695,6 +702,7 @@ struct rose_neigh *rose_get_neigh(rose_address *addr, unsigned char *cause, + for (i = 0; i < node->count; i++) { + if (!rose_ftimer_running(node->neighbour[i])) { + res = node->neighbour[i]; ++ rose_neigh_hold(node->neighbour[i]); + goto out; + } + failed = 1; +@@ -784,13 +792,13 @@ static void rose_del_route_by_neigh(struct rose_neigh *rose_neigh) + } + + if (rose_route->neigh1 == rose_neigh) { +- rose_route->neigh1->use--; ++ rose_neigh_put(rose_route->neigh1); + rose_route->neigh1 = NULL; + rose_transmit_clear_request(rose_route->neigh2, rose_route->lci2, ROSE_OUT_OF_ORDER, 0); + } + + if (rose_route->neigh2 == rose_neigh) { +- rose_route->neigh2->use--; ++ rose_neigh_put(rose_route->neigh2); + rose_route->neigh2 = NULL; + rose_transmit_clear_request(rose_route->neigh1, rose_route->lci1, ROSE_OUT_OF_ORDER, 0); + } +@@ -919,7 +927,7 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) + rose_clear_queues(sk); + rose->cause = ROSE_NETWORK_CONGESTION; + rose->diagnostic = 0; +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + rose->neighbour = NULL; + rose->lci = 0; + rose->state = ROSE_STATE_0; +@@ -1044,12 +1052,12 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) + + if ((new_lci = rose_new_lci(new_neigh)) == 0) { + rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 71); +- goto out; ++ goto put_neigh; + } + + if ((rose_route = kmalloc(sizeof(*rose_route), GFP_ATOMIC)) == NULL) { + rose_transmit_clear_request(rose_neigh, lci, ROSE_NETWORK_CONGESTION, 120); +- goto out; ++ goto put_neigh; + } + + rose_route->lci1 = lci; +@@ -1062,8 +1070,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) + rose_route->lci2 = new_lci; + rose_route->neigh2 = new_neigh; + +- rose_route->neigh1->use++; +- rose_route->neigh2->use++; ++ rose_neigh_hold(rose_route->neigh1); ++ rose_neigh_hold(rose_route->neigh2); + + rose_route->next = rose_route_list; + rose_route_list = rose_route; +@@ -1075,6 +1083,8 @@ int rose_route_frame(struct sk_buff *skb, ax25_cb *ax25) + rose_transmit_link(skb, rose_route->neigh2); + res = 1; + ++put_neigh: ++ rose_neigh_put(new_neigh); + out: + spin_unlock_bh(&rose_route_list_lock); + spin_unlock_bh(&rose_neigh_list_lock); +@@ -1190,7 +1200,7 @@ static int rose_neigh_show(struct seq_file *seq, void *v) + (rose_neigh->loopback) ? "RSLOOP-0" : ax2asc(buf, &rose_neigh->callsign), + rose_neigh->dev ? rose_neigh->dev->name : "???", + rose_neigh->count, +- rose_neigh->use, ++ refcount_read(&rose_neigh->use) - rose_neigh->count - 1, + (rose_neigh->dce_mode) ? "DCE" : "DTE", + (rose_neigh->restarted) ? "yes" : "no", + ax25_display_timer(&rose_neigh->t0timer) / HZ, +@@ -1295,18 +1305,22 @@ void __exit rose_rt_free(void) + struct rose_neigh *s, *rose_neigh = rose_neigh_list; + struct rose_node *t, *rose_node = rose_node_list; + struct rose_route *u, *rose_route = rose_route_list; ++ int i; + + while (rose_neigh != NULL) { + s = rose_neigh; + rose_neigh = rose_neigh->next; + + rose_remove_neigh(s); ++ rose_neigh_put(s); + } + + while (rose_node != NULL) { + t = rose_node; + rose_node = rose_node->next; + ++ for (i = 0; i < t->count; i++) ++ rose_neigh_put(t->neighbour[i]); + rose_remove_node(t); + } + +diff --git a/net/rose/rose_timer.c b/net/rose/rose_timer.c +index 1525773e94aa17..c52d7d20c5199b 100644 +--- a/net/rose/rose_timer.c ++++ b/net/rose/rose_timer.c +@@ -180,7 +180,7 @@ static void rose_timer_expiry(struct timer_list *t) + break; + + case ROSE_STATE_2: /* T3 */ +- rose->neighbour->use--; ++ rose_neigh_put(rose->neighbour); + rose_disconnect(sk, ETIMEDOUT, -1, -1); + break; + +diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c +index 717828e531621a..0673857cb3d8b1 100644 +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -547,7 +547,9 @@ static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk) + { + addr->v6.sin6_family = AF_INET6; + addr->v6.sin6_port = 0; ++ addr->v6.sin6_flowinfo = 0; + addr->v6.sin6_addr = sk->sk_v6_rcv_saddr; ++ addr->v6.sin6_scope_id = 0; + } + + /* Initialize sk->sk_rcv_saddr from sctp_addr. */ +diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c +index ebddfa74ce0a07..150ed10c8377ab 100644 +--- a/sound/soc/codecs/lpass-tx-macro.c ++++ b/sound/soc/codecs/lpass-tx-macro.c +@@ -1940,7 +1940,7 @@ static int tx_macro_register_mclk_output(struct tx_macro *tx) + } + + static const struct snd_soc_component_driver tx_macro_component_drv = { +- .name = "RX-MACRO", ++ .name = "TX-MACRO", + .probe = tx_macro_component_probe, + .controls = tx_macro_snd_controls, + .num_controls = ARRAY_SIZE(tx_macro_snd_controls),