]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.15
authorSasha Levin <sashal@kernel.org>
Sun, 22 Jun 2025 20:53:59 +0000 (16:53 -0400)
committerSasha Levin <sashal@kernel.org>
Sun, 22 Jun 2025 20:53:59 +0000 (16:53 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
52 files changed:
queue-6.15/aoe-clean-device-rq_list-in-aoedev_downdev.patch [new file with mode: 0644]
queue-6.15/atm-atmtcp-free-invalid-length-skb-in-atmtcp_c_send.patch [new file with mode: 0644]
queue-6.15/bnxt_en-add-a-helper-function-to-configure-mru-and-r.patch [new file with mode: 0644]
queue-6.15/bnxt_en-fix-double-invocation-of-bnxt_ulp_stop-bnxt_.patch [new file with mode: 0644]
queue-6.15/bnxt_en-update-mru-and-rss-table-of-rss-contexts-on-.patch [new file with mode: 0644]
queue-6.15/calipso-fix-null-ptr-deref-in-calipso_req_-set-del-a.patch [new file with mode: 0644]
queue-6.15/drm-amdkfd-move-sdma-queue-reset-capability-check-to.patch [new file with mode: 0644]
queue-6.15/drm-i915-pmu-fix-build-error-with-gcov-and-autofdo-e.patch [new file with mode: 0644]
queue-6.15/drm-msm-a7xx-call-cp_reset_context_state.patch [new file with mode: 0644]
queue-6.15/drm-msm-disp-correct-porch-timing-for-sdm845.patch [new file with mode: 0644]
queue-6.15/drm-msm-dp-disable-wide-bus-support-for-sdm845.patch [new file with mode: 0644]
queue-6.15/drm-msm-dsi-dsi_phy_10nm-fix-missing-initial-vco-rat.patch [new file with mode: 0644]
queue-6.15/drm-msm-fix-cp_reset_context_state-bitfield-names.patch [new file with mode: 0644]
queue-6.15/drm-nouveau-bl-increase-buffer-size-to-avoid-truncat.patch [new file with mode: 0644]
queue-6.15/drm-nouveau-fix-a-use-after-free-in-r535_gsp_rpc_pus.patch [new file with mode: 0644]
queue-6.15/drm-nouveau-gsp-split-rpc-handling-out-on-its-own.patch [new file with mode: 0644]
queue-6.15/drm-ssd130x-fix-ssd132x_clear_screen-columns.patch [new file with mode: 0644]
queue-6.15/drm-xe-bmg-update-wa_16023588340.patch [new file with mode: 0644]
queue-6.15/e1000e-set-fixed-clock-frequency-indication-for-nahu.patch [new file with mode: 0644]
queue-6.15/eth-fbnic-avoid-double-free-when-failing-to-dma-map-.patch [new file with mode: 0644]
queue-6.15/hwmon-ltc4282-avoid-repeated-register-write.patch [new file with mode: 0644]
queue-6.15/hwmon-occ-fix-unaligned-accesses.patch [new file with mode: 0644]
queue-6.15/hwmon-occ-rework-attribute-registration-for-stack-us.patch [new file with mode: 0644]
queue-6.15/ice-fix-eswitch-code-memory-leak-in-reset-scenario.patch [new file with mode: 0644]
queue-6.15/io_uring-fix-potential-page-leak-in-io_sqe_buffer_re.patch [new file with mode: 0644]
queue-6.15/io_uring-sqpoll-don-t-put-task_struct-on-tctx-setup-.patch [new file with mode: 0644]
queue-6.15/ionic-prevent-driver-fw-getting-out-of-sync-on-devcm.patch [new file with mode: 0644]
queue-6.15/ksmbd-add-free_transport-ops-in-ksmbd-connection.patch [new file with mode: 0644]
queue-6.15/mlxbf_gige-return-eprobe_defer-if-phy-irq-is-not-ava.patch [new file with mode: 0644]
queue-6.15/mpls-use-rcu_dereference_rtnl-in-mpls_route_input_rc.patch [new file with mode: 0644]
queue-6.15/net-atm-add-lec_mutex.patch [new file with mode: 0644]
queue-6.15/net-atm-fix-proc-net-atm-lec-handling.patch [new file with mode: 0644]
queue-6.15/net-ice-perform-accurate-arfs-flow-match.patch [new file with mode: 0644]
queue-6.15/net-lan743x-fix-potential-out-of-bounds-write-in-lan.patch [new file with mode: 0644]
queue-6.15/net-netmem-fix-skb_ensure_writable-with-unreadable-s.patch [new file with mode: 0644]
queue-6.15/net-ti-icssg-prueth-fix-packet-handling-for-xdp_tx.patch [new file with mode: 0644]
queue-6.15/octeontx2-pf-fix-backpresure-configuration.patch [new file with mode: 0644]
queue-6.15/pldmfw-select-crc32-when-pldmfw-is-selected.patch [new file with mode: 0644]
queue-6.15/ptp-allow-reading-of-currently-dialed-frequency-to-s.patch [new file with mode: 0644]
queue-6.15/ptp-fix-breakage-after-ptp_vclock_in_use-rework.patch [new file with mode: 0644]
queue-6.15/rust-devres-do-not-dereference-to-the-internal-revoc.patch [new file with mode: 0644]
queue-6.15/rust-devres-fix-race-in-devres-drop.patch [new file with mode: 0644]
queue-6.15/rust-devres-implement-devres-access.patch [new file with mode: 0644]
queue-6.15/series
queue-6.15/tcp-fix-passive-tfo-socket-having-invalid-napi-id.patch [new file with mode: 0644]
queue-6.15/tcp-fix-tcp_packet_delayed-for-tcp_is_non_sack_preve.patch [new file with mode: 0644]
queue-6.15/tipc-fix-null-ptr-deref-when-acquiring-remote-ip-of-.patch [new file with mode: 0644]
queue-6.15/tools-ynl-fix-mixing-ops-and-notifications-on-one-so.patch [new file with mode: 0644]
queue-6.15/tools-ynl-parse-extack-for-sub-messages.patch [new file with mode: 0644]
queue-6.15/ublk-santizize-the-arguments-from-userspace-when-add.patch [new file with mode: 0644]
queue-6.15/wifi-carl9170-do-not-ping-device-which-has-failed-to.patch [new file with mode: 0644]
queue-6.15/workqueue-initialize-wq_isolated_cpumask-in-workqueu.patch [new file with mode: 0644]

diff --git a/queue-6.15/aoe-clean-device-rq_list-in-aoedev_downdev.patch b/queue-6.15/aoe-clean-device-rq_list-in-aoedev_downdev.patch
new file mode 100644 (file)
index 0000000..71f94a7
--- /dev/null
@@ -0,0 +1,56 @@
+From 1ff46c372fa696bd8772418791004be3d5fca1b7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Jun 2025 17:05:59 +0000
+Subject: aoe: clean device rq_list in aoedev_downdev()
+
+From: Justin Sanders <jsanders.devel@gmail.com>
+
+[ Upstream commit 7f90d45e57cb2ef1f0adcaf925ddffdfc5e680ca ]
+
+An aoe device's rq_list contains accepted block requests that are
+waiting to be transmitted to the aoe target. This queue was added as
+part of the conversion to blk_mq. However, the queue was not cleaned out
+when an aoe device is downed which caused blk_mq_freeze_queue() to sleep
+indefinitely waiting for those requests to complete, causing a hang. This
+fix cleans out the queue before calling blk_mq_freeze_queue().
+
+Link: https://bugzilla.kernel.org/show_bug.cgi?id=212665
+Fixes: 3582dd291788 ("aoe: convert aoeblk to blk-mq")
+Signed-off-by: Justin Sanders <jsanders.devel@gmail.com>
+Link: https://lore.kernel.org/r/20250610170600.869-1-jsanders.devel@gmail.com
+Tested-By: Valentin Kleibel <valentin@vrvis.at>
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/aoe/aoedev.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
+index 141b2a0e03f2c..8c18034cb3d69 100644
+--- a/drivers/block/aoe/aoedev.c
++++ b/drivers/block/aoe/aoedev.c
+@@ -198,6 +198,7 @@ aoedev_downdev(struct aoedev *d)
+ {
+       struct aoetgt *t, **tt, **te;
+       struct list_head *head, *pos, *nx;
++      struct request *rq, *rqnext;
+       int i;
+       d->flags &= ~DEVFL_UP;
+@@ -223,6 +224,13 @@ aoedev_downdev(struct aoedev *d)
+       /* clean out the in-process request (if any) */
+       aoe_failip(d);
++      /* clean out any queued block requests */
++      list_for_each_entry_safe(rq, rqnext, &d->rq_list, queuelist) {
++              list_del_init(&rq->queuelist);
++              blk_mq_start_request(rq);
++              blk_mq_end_request(rq, BLK_STS_IOERR);
++      }
++
+       /* fast fail all pending I/O */
+       if (d->blkq) {
+               /* UP is cleared, freeze+quiesce to insure all are errored */
+-- 
+2.39.5
+
diff --git a/queue-6.15/atm-atmtcp-free-invalid-length-skb-in-atmtcp_c_send.patch b/queue-6.15/atm-atmtcp-free-invalid-length-skb-in-atmtcp_c_send.patch
new file mode 100644 (file)
index 0000000..226b261
--- /dev/null
@@ -0,0 +1,95 @@
+From b6a75a18d4967ae6fe072537e2299f2c3064f5e0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 11:21:14 -0700
+Subject: atm: atmtcp: Free invalid length skb in atmtcp_c_send().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 2f370ae1fb6317985f3497b1bb80d457508ca2f7 ]
+
+syzbot reported the splat below. [0]
+
+vcc_sendmsg() copies data passed from userspace to skb and passes
+it to vcc->dev->ops->send().
+
+atmtcp_c_send() accesses skb->data as struct atmtcp_hdr after
+checking if skb->len is 0, but it's not enough.
+
+Also, when skb->len == 0, skb and sk (vcc) were leaked because
+dev_kfree_skb() is not called and sk_wmem_alloc adjustment is missing
+to revert atm_account_tx() in vcc_sendmsg(), which is expected
+to be done in atm_pop_raw().
+
+Let's properly free skb with an invalid length in atmtcp_c_send().
+
+[0]:
+BUG: KMSAN: uninit-value in atmtcp_c_send+0x255/0xed0 drivers/atm/atmtcp.c:294
+ atmtcp_c_send+0x255/0xed0 drivers/atm/atmtcp.c:294
+ vcc_sendmsg+0xd7c/0xff0 net/atm/common.c:644
+ sock_sendmsg_nosec net/socket.c:712 [inline]
+ __sock_sendmsg+0x330/0x3d0 net/socket.c:727
+ ____sys_sendmsg+0x7e0/0xd80 net/socket.c:2566
+ ___sys_sendmsg+0x271/0x3b0 net/socket.c:2620
+ __sys_sendmsg net/socket.c:2652 [inline]
+ __do_sys_sendmsg net/socket.c:2657 [inline]
+ __se_sys_sendmsg net/socket.c:2655 [inline]
+ __x64_sys_sendmsg+0x211/0x3e0 net/socket.c:2655
+ x64_sys_call+0x32fb/0x3db0 arch/x86/include/generated/asm/syscalls_64.h:47
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0xd9/0x210 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Uninit was created at:
+ slab_post_alloc_hook mm/slub.c:4154 [inline]
+ slab_alloc_node mm/slub.c:4197 [inline]
+ kmem_cache_alloc_node_noprof+0x818/0xf00 mm/slub.c:4249
+ kmalloc_reserve+0x13c/0x4b0 net/core/skbuff.c:579
+ __alloc_skb+0x347/0x7d0 net/core/skbuff.c:670
+ alloc_skb include/linux/skbuff.h:1336 [inline]
+ vcc_sendmsg+0xb40/0xff0 net/atm/common.c:628
+ sock_sendmsg_nosec net/socket.c:712 [inline]
+ __sock_sendmsg+0x330/0x3d0 net/socket.c:727
+ ____sys_sendmsg+0x7e0/0xd80 net/socket.c:2566
+ ___sys_sendmsg+0x271/0x3b0 net/socket.c:2620
+ __sys_sendmsg net/socket.c:2652 [inline]
+ __do_sys_sendmsg net/socket.c:2657 [inline]
+ __se_sys_sendmsg net/socket.c:2655 [inline]
+ __x64_sys_sendmsg+0x211/0x3e0 net/socket.c:2655
+ x64_sys_call+0x32fb/0x3db0 arch/x86/include/generated/asm/syscalls_64.h:47
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0xd9/0x210 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+CPU: 1 UID: 0 PID: 5798 Comm: syz-executor192 Not tainted 6.16.0-rc1-syzkaller-00010-g2c4a1f3fe03e #0 PREEMPT(undef)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+1d3c235276f62963e93a@syzkaller.appspotmail.com
+Closes: https://syzkaller.appspot.com/bug?extid=1d3c235276f62963e93a
+Tested-by: syzbot+1d3c235276f62963e93a@syzkaller.appspotmail.com
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20250616182147.963333-2-kuni1840@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/atm/atmtcp.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
+index d4aa0f353b6c8..eeae160c898d3 100644
+--- a/drivers/atm/atmtcp.c
++++ b/drivers/atm/atmtcp.c
+@@ -288,7 +288,9 @@ static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
+       struct sk_buff *new_skb;
+       int result = 0;
+-      if (!skb->len) return 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) {
+-- 
+2.39.5
+
diff --git a/queue-6.15/bnxt_en-add-a-helper-function-to-configure-mru-and-r.patch b/queue-6.15/bnxt_en-add-a-helper-function-to-configure-mru-and-r.patch
new file mode 100644 (file)
index 0000000..f31c45c
--- /dev/null
@@ -0,0 +1,104 @@
+From 279e083561958a00e26dbc5b4bb094b987560aa5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 16:18:40 -0700
+Subject: bnxt_en: Add a helper function to configure MRU and RSS
+
+From: Pavan Chebbi <pavan.chebbi@broadcom.com>
+
+[ Upstream commit e11baaea94e2923739a98abeee85eb0667c04fd3 ]
+
+Add a new helper function that will configure MRU and RSS table
+of a VNIC. This will be useful when we configure both on a VNIC
+when resetting an RX ring.  This function will be used again in
+the next bug fix patch where we have to reconfigure VNICs for RSS
+contexts.
+
+Suggested-by: Michael Chan <michael.chan@broadcom.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: David Wei <dw@davidwei.uk>
+Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20250613231841.377988-3-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 5dacc94c6fe6 ("bnxt_en: Update MRU and RSS table of RSS contexts on queue reset")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 37 ++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 6afc2ab6fad22..3d975e50f9438 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -10738,6 +10738,26 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
+       bp->num_rss_ctx--;
+ }
++static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
++                              u16 mru)
++{
++      int rc;
++
++      if (mru) {
++              rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
++              if (rc) {
++                      netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
++                                 vnic->vnic_id, rc);
++                      return rc;
++              }
++      }
++      vnic->mru = mru;
++      bnxt_hwrm_vnic_update(bp, vnic,
++                            VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
++
++      return 0;
++}
++
+ static void bnxt_hwrm_realloc_rss_ctx_vnic(struct bnxt *bp)
+ {
+       bool set_tpa = !!(bp->flags & BNXT_FLAG_TPA);
+@@ -15884,6 +15904,7 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
+       struct bnxt_vnic_info *vnic;
+       struct bnxt_napi *bnapi;
+       int i, rc;
++      u16 mru;
+       rxr = &bp->rx_ring[idx];
+       clone = qmem;
+@@ -15933,18 +15954,13 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
+       napi_enable_locked(&bnapi->napi);
+       bnxt_db_nq_arm(bp, &cpr->cp_db, cpr->cp_raw_cons);
++      mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
+       for (i = 0; i < bp->nr_vnics; i++) {
+               vnic = &bp->vnic_info[i];
+-              rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
+-              if (rc) {
+-                      netdev_err(bp->dev, "hwrm vnic %d set rss failure rc: %d\n",
+-                                 vnic->vnic_id, rc);
++              rc = bnxt_set_vnic_mru_p5(bp, vnic, mru);
++              if (rc)
+                       return rc;
+-              }
+-              vnic->mru = bp->dev->mtu + ETH_HLEN + VLAN_HLEN;
+-              bnxt_hwrm_vnic_update(bp, vnic,
+-                                    VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
+       }
+       return 0;
+@@ -15969,9 +15985,8 @@ static int bnxt_queue_stop(struct net_device *dev, void *qmem, int idx)
+       for (i = 0; i < bp->nr_vnics; i++) {
+               vnic = &bp->vnic_info[i];
+-              vnic->mru = 0;
+-              bnxt_hwrm_vnic_update(bp, vnic,
+-                                    VNIC_UPDATE_REQ_ENABLES_MRU_VALID);
++
++              bnxt_set_vnic_mru_p5(bp, vnic, 0);
+       }
+       /* Make sure NAPI sees that the VNIC is disabled */
+       synchronize_net();
+-- 
+2.39.5
+
diff --git a/queue-6.15/bnxt_en-fix-double-invocation-of-bnxt_ulp_stop-bnxt_.patch b/queue-6.15/bnxt_en-fix-double-invocation-of-bnxt_ulp_stop-bnxt_.patch
new file mode 100644 (file)
index 0000000..350894f
--- /dev/null
@@ -0,0 +1,134 @@
+From 72be04af37a1cf4ea2a7b541875af757e0183766 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 16:18:39 -0700
+Subject: bnxt_en: Fix double invocation of bnxt_ulp_stop()/bnxt_ulp_start()
+
+From: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+
+[ Upstream commit 1e9ac33fa271be0d2480fd732f9642d81542500b ]
+
+Before the commit under the Fixes tag below, bnxt_ulp_stop() and
+bnxt_ulp_start() were always invoked in pairs.  After that commit,
+the new bnxt_ulp_restart() can be invoked after bnxt_ulp_stop()
+has been called.  This may result in the RoCE driver's aux driver
+.suspend() method being invoked twice.  The 2nd bnxt_re_suspend()
+call will crash when it dereferences a NULL pointer:
+
+(NULL ib_device): Handle device suspend call
+BUG: kernel NULL pointer dereference, address: 0000000000000b78
+PGD 0 P4D 0
+Oops: Oops: 0000 [#1] SMP PTI
+CPU: 20 UID: 0 PID: 181 Comm: kworker/u96:5 Tainted: G S                  6.15.0-rc1 #4 PREEMPT(voluntary)
+Tainted: [S]=CPU_OUT_OF_SPEC
+Hardware name: Dell Inc. PowerEdge R730/072T6D, BIOS 2.4.3 01/17/2017
+Workqueue: bnxt_pf_wq bnxt_sp_task [bnxt_en]
+RIP: 0010:bnxt_re_suspend+0x45/0x1f0 [bnxt_re]
+Code: 8b 05 a7 3c 5b f5 48 89 44 24 18 31 c0 49 8b 5c 24 08 4d 8b 2c 24 e8 ea 06 0a f4 48 c7 c6 04 60 52 c0 48 89 df e8 1b ce f9 ff <48> 8b 83 78 0b 00 00 48 8b 80 38 03 00 00 a8 40 0f 85 b5 00 00 00
+RSP: 0018:ffffa2e84084fd88 EFLAGS: 00010246
+RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000001
+RDX: 0000000000000000 RSI: ffffffffb4b6b934 RDI: 00000000ffffffff
+RBP: ffffa1760954c9c0 R08: 0000000000000000 R09: c0000000ffffdfff
+R10: 0000000000000001 R11: ffffa2e84084fb50 R12: ffffa176031ef070
+R13: ffffa17609775000 R14: ffffa17603adc180 R15: 0000000000000000
+FS:  0000000000000000(0000) GS:ffffa17daa397000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 0000000000000b78 CR3: 00000004aaa30003 CR4: 00000000003706f0
+DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+Call Trace:
+<TASK>
+bnxt_ulp_stop+0x69/0x90 [bnxt_en]
+bnxt_sp_task+0x678/0x920 [bnxt_en]
+? __schedule+0x514/0xf50
+process_scheduled_works+0x9d/0x400
+worker_thread+0x11c/0x260
+? __pfx_worker_thread+0x10/0x10
+kthread+0xfe/0x1e0
+? __pfx_kthread+0x10/0x10
+ret_from_fork+0x2b/0x40
+? __pfx_kthread+0x10/0x10
+ret_from_fork_asm+0x1a/0x30
+
+Check the BNXT_EN_FLAG_ULP_STOPPED flag and do not proceed if the flag
+is already set.  This will preserve the original symmetrical
+bnxt_ulp_stop() and bnxt_ulp_start().
+
+Also, inside bnxt_ulp_start(), clear the BNXT_EN_FLAG_ULP_STOPPED
+flag after taking the mutex to avoid any race condition.  And for
+symmetry, only proceed in bnxt_ulp_start() if the
+BNXT_EN_FLAG_ULP_STOPPED is set.
+
+Fixes: 3c163f35bd50 ("bnxt_en: Optimize recovery path ULP locking in the driver")
+Signed-off-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Co-developed-by: Michael Chan <michael.chan@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250613231841.377988-2-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c | 24 ++++++++-----------
+ 1 file changed, 10 insertions(+), 14 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+index 84c4812414fd4..2450a369b7920 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ulp.c
+@@ -231,10 +231,9 @@ void bnxt_ulp_stop(struct bnxt *bp)
+               return;
+       mutex_lock(&edev->en_dev_lock);
+-      if (!bnxt_ulp_registered(edev)) {
+-              mutex_unlock(&edev->en_dev_lock);
+-              return;
+-      }
++      if (!bnxt_ulp_registered(edev) ||
++          (edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
++              goto ulp_stop_exit;
+       edev->flags |= BNXT_EN_FLAG_ULP_STOPPED;
+       if (aux_priv) {
+@@ -250,6 +249,7 @@ void bnxt_ulp_stop(struct bnxt *bp)
+                       adrv->suspend(adev, pm);
+               }
+       }
++ulp_stop_exit:
+       mutex_unlock(&edev->en_dev_lock);
+ }
+@@ -258,19 +258,13 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
+       struct bnxt_aux_priv *aux_priv = bp->aux_priv;
+       struct bnxt_en_dev *edev = bp->edev;
+-      if (!edev)
+-              return;
+-
+-      edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
+-
+-      if (err)
++      if (!edev || err)
+               return;
+       mutex_lock(&edev->en_dev_lock);
+-      if (!bnxt_ulp_registered(edev)) {
+-              mutex_unlock(&edev->en_dev_lock);
+-              return;
+-      }
++      if (!bnxt_ulp_registered(edev) ||
++          !(edev->flags & BNXT_EN_FLAG_ULP_STOPPED))
++              goto ulp_start_exit;
+       if (edev->ulp_tbl->msix_requested)
+               bnxt_fill_msix_vecs(bp, edev->msix_entries);
+@@ -287,6 +281,8 @@ void bnxt_ulp_start(struct bnxt *bp, int err)
+                       adrv->resume(adev);
+               }
+       }
++ulp_start_exit:
++      edev->flags &= ~BNXT_EN_FLAG_ULP_STOPPED;
+       mutex_unlock(&edev->en_dev_lock);
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/bnxt_en-update-mru-and-rss-table-of-rss-contexts-on-.patch b/queue-6.15/bnxt_en-update-mru-and-rss-table-of-rss-contexts-on-.patch
new file mode 100644 (file)
index 0000000..1e028fe
--- /dev/null
@@ -0,0 +1,137 @@
+From 1df34aac57367fdd8ab16b324a2d6711e0cd54eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 16:18:41 -0700
+Subject: bnxt_en: Update MRU and RSS table of RSS contexts on queue reset
+
+From: Pavan Chebbi <pavan.chebbi@broadcom.com>
+
+[ Upstream commit 5dacc94c6fe61cde6f700e95cf35af9944b022c4 ]
+
+The commit under the Fixes tag below which updates the VNICs' RSS
+and MRU during .ndo_queue_start(), needs to be extended to cover any
+non-default RSS contexts which have their own VNICs.  Without this
+step, packets that are destined to a non-default RSS context may be
+dropped after .ndo_queue_start().
+
+We further optimize this scheme by updating the VNIC only if the
+RX ring being restarted is in the RSS table of the VNIC.  Updating
+the VNIC (in particular setting the MRU to 0) will momentarily stop
+all traffic to all rings in the RSS table.  Any VNIC that has the
+RX ring excluded from the RSS table can skip this step and avoid the
+traffic disruption.
+
+Note that this scheme is just an improvement.  A VNIC with multiple
+rings in the RSS table will still see traffic disruptions to all rings
+in the RSS table when one of the rings is being restarted.  We are
+working on a FW scheme that will improve upon this further.
+
+Fixes: 5ac066b7b062 ("bnxt_en: Fix queue start to update vnic RSS table")
+Reported-by: David Wei <dw@davidwei.uk>
+Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
+Signed-off-by: Michael Chan <michael.chan@broadcom.com>
+Link: https://patch.msgid.link/20250613231841.377988-4-michael.chan@broadcom.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/broadcom/bnxt/bnxt.c | 56 +++++++++++++++++++++--
+ 1 file changed, 51 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+index 3d975e50f9438..c365a9e64f728 100644
+--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
++++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+@@ -10738,11 +10738,39 @@ void bnxt_del_one_rss_ctx(struct bnxt *bp, struct bnxt_rss_ctx *rss_ctx,
+       bp->num_rss_ctx--;
+ }
++static bool bnxt_vnic_has_rx_ring(struct bnxt *bp, struct bnxt_vnic_info *vnic,
++                                int rxr_id)
++{
++      u16 tbl_size = bnxt_get_rxfh_indir_size(bp->dev);
++      int i, vnic_rx;
++
++      /* Ntuple VNIC always has all the rx rings. Any change of ring id
++       * must be updated because a future filter may use it.
++       */
++      if (vnic->flags & BNXT_VNIC_NTUPLE_FLAG)
++              return true;
++
++      for (i = 0; i < tbl_size; i++) {
++              if (vnic->flags & BNXT_VNIC_RSSCTX_FLAG)
++                      vnic_rx = ethtool_rxfh_context_indir(vnic->rss_ctx)[i];
++              else
++                      vnic_rx = bp->rss_indir_tbl[i];
++
++              if (rxr_id == vnic_rx)
++                      return true;
++      }
++
++      return false;
++}
++
+ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
+-                              u16 mru)
++                              u16 mru, int rxr_id)
+ {
+       int rc;
++      if (!bnxt_vnic_has_rx_ring(bp, vnic, rxr_id))
++              return 0;
++
+       if (mru) {
+               rc = bnxt_hwrm_vnic_set_rss_p5(bp, vnic, true);
+               if (rc) {
+@@ -10758,6 +10786,24 @@ static int bnxt_set_vnic_mru_p5(struct bnxt *bp, struct bnxt_vnic_info *vnic,
+       return 0;
+ }
++static int bnxt_set_rss_ctx_vnic_mru(struct bnxt *bp, u16 mru, int rxr_id)
++{
++      struct ethtool_rxfh_context *ctx;
++      unsigned long context;
++      int rc;
++
++      xa_for_each(&bp->dev->ethtool->rss_ctx, context, ctx) {
++              struct bnxt_rss_ctx *rss_ctx = ethtool_rxfh_context_priv(ctx);
++              struct bnxt_vnic_info *vnic = &rss_ctx->vnic;
++
++              rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, rxr_id);
++              if (rc)
++                      return rc;
++      }
++
++      return 0;
++}
++
+ static void bnxt_hwrm_realloc_rss_ctx_vnic(struct bnxt *bp)
+ {
+       bool set_tpa = !!(bp->flags & BNXT_FLAG_TPA);
+@@ -15958,12 +16004,11 @@ static int bnxt_queue_start(struct net_device *dev, void *qmem, int idx)
+       for (i = 0; i < bp->nr_vnics; i++) {
+               vnic = &bp->vnic_info[i];
+-              rc = bnxt_set_vnic_mru_p5(bp, vnic, mru);
++              rc = bnxt_set_vnic_mru_p5(bp, vnic, mru, idx);
+               if (rc)
+                       return rc;
+       }
+-
+-      return 0;
++      return bnxt_set_rss_ctx_vnic_mru(bp, mru, idx);
+ err_reset:
+       netdev_err(bp->dev, "Unexpected HWRM error during queue start rc: %d\n",
+@@ -15986,8 +16031,9 @@ static int bnxt_queue_stop(struct net_device *dev, void *qmem, int idx)
+       for (i = 0; i < bp->nr_vnics; i++) {
+               vnic = &bp->vnic_info[i];
+-              bnxt_set_vnic_mru_p5(bp, vnic, 0);
++              bnxt_set_vnic_mru_p5(bp, vnic, 0, idx);
+       }
++      bnxt_set_rss_ctx_vnic_mru(bp, 0, idx);
+       /* Make sure NAPI sees that the VNIC is disabled */
+       synchronize_net();
+       rxr = &bp->rx_ring[idx];
+-- 
+2.39.5
+
diff --git a/queue-6.15/calipso-fix-null-ptr-deref-in-calipso_req_-set-del-a.patch b/queue-6.15/calipso-fix-null-ptr-deref-in-calipso_req_-set-del-a.patch
new file mode 100644 (file)
index 0000000..81aa83e
--- /dev/null
@@ -0,0 +1,196 @@
+From dd1c96752884071fbac1c0ad66584466b7439803 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 15:40:42 -0700
+Subject: calipso: Fix null-ptr-deref in calipso_req_{set,del}attr().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 10876da918fa1aec0227fb4c67647513447f53a9 ]
+
+syzkaller reported a null-ptr-deref in sock_omalloc() while allocating
+a CALIPSO option.  [0]
+
+The NULL is of struct sock, which was fetched by sk_to_full_sk() in
+calipso_req_setattr().
+
+Since commit a1a5344ddbe8 ("tcp: avoid two atomic ops for syncookies"),
+reqsk->rsk_listener could be NULL when SYN Cookie is returned to its
+client, as hinted by the leading SYN Cookie log.
+
+Here are 3 options to fix the bug:
+
+  1) Return 0 in calipso_req_setattr()
+  2) Return an error in calipso_req_setattr()
+  3) Alaways set rsk_listener
+
+1) is no go as it bypasses LSM, but 2) effectively disables SYN Cookie
+for CALIPSO.  3) is also no go as there have been many efforts to reduce
+atomic ops and make TCP robust against DDoS.  See also commit 3b24d854cb35
+("tcp/dccp: do not touch listener sk_refcnt under synflood").
+
+As of the blamed commit, SYN Cookie already did not need refcounting,
+and no one has stumbled on the bug for 9 years, so no CALIPSO user will
+care about SYN Cookie.
+
+Let's return an error in calipso_req_setattr() and calipso_req_delattr()
+in the SYN Cookie case.
+
+This can be reproduced by [1] on Fedora and now connect() of nc times out.
+
+[0]:
+TCP: request_sock_TCPv6: Possible SYN flooding on port [::]:20002. Sending cookies.
+Oops: general protection fault, probably for non-canonical address 0xdffffc0000000006: 0000 [#1] PREEMPT SMP KASAN NOPTI
+KASAN: null-ptr-deref in range [0x0000000000000030-0x0000000000000037]
+CPU: 3 UID: 0 PID: 12262 Comm: syz.1.2611 Not tainted 6.14.0 #2
+Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.16.3-0-ga6ed6b701f0a-prebuilt.qemu.org 04/01/2014
+RIP: 0010:read_pnet include/net/net_namespace.h:406 [inline]
+RIP: 0010:sock_net include/net/sock.h:655 [inline]
+RIP: 0010:sock_kmalloc+0x35/0x170 net/core/sock.c:2806
+Code: 89 d5 41 54 55 89 f5 53 48 89 fb e8 25 e3 c6 fd e8 f0 91 e3 00 48 8d 7b 30 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 <80> 3c 02 00 0f 85 26 01 00 00 48 b8 00 00 00 00 00 fc ff df 4c 8b
+RSP: 0018:ffff88811af89038 EFLAGS: 00010216
+RAX: dffffc0000000000 RBX: 0000000000000000 RCX: ffff888105266400
+RDX: 0000000000000006 RSI: ffff88800c890000 RDI: 0000000000000030
+RBP: 0000000000000050 R08: 0000000000000000 R09: ffff88810526640e
+R10: ffffed1020a4cc81 R11: ffff88810526640f R12: 0000000000000000
+R13: 0000000000000820 R14: ffff888105266400 R15: 0000000000000050
+FS:  00007f0653a07640(0000) GS:ffff88811af80000(0000) knlGS:0000000000000000
+CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+CR2: 00007f863ba096f4 CR3: 00000000163c0005 CR4: 0000000000770ef0
+PKRU: 80000000
+Call Trace:
+ <IRQ>
+ ipv6_renew_options+0x279/0x950 net/ipv6/exthdrs.c:1288
+ calipso_req_setattr+0x181/0x340 net/ipv6/calipso.c:1204
+ calipso_req_setattr+0x56/0x80 net/netlabel/netlabel_calipso.c:597
+ netlbl_req_setattr+0x18a/0x440 net/netlabel/netlabel_kapi.c:1249
+ selinux_netlbl_inet_conn_request+0x1fb/0x320 security/selinux/netlabel.c:342
+ selinux_inet_conn_request+0x1eb/0x2c0 security/selinux/hooks.c:5551
+ security_inet_conn_request+0x50/0xa0 security/security.c:4945
+ tcp_v6_route_req+0x22c/0x550 net/ipv6/tcp_ipv6.c:825
+ tcp_conn_request+0xec8/0x2b70 net/ipv4/tcp_input.c:7275
+ tcp_v6_conn_request+0x1e3/0x440 net/ipv6/tcp_ipv6.c:1328
+ tcp_rcv_state_process+0xafa/0x52b0 net/ipv4/tcp_input.c:6781
+ tcp_v6_do_rcv+0x8a6/0x1a40 net/ipv6/tcp_ipv6.c:1667
+ tcp_v6_rcv+0x505e/0x5b50 net/ipv6/tcp_ipv6.c:1904
+ ip6_protocol_deliver_rcu+0x17c/0x1da0 net/ipv6/ip6_input.c:436
+ ip6_input_finish+0x103/0x180 net/ipv6/ip6_input.c:480
+ NF_HOOK include/linux/netfilter.h:314 [inline]
+ NF_HOOK include/linux/netfilter.h:308 [inline]
+ ip6_input+0x13c/0x6b0 net/ipv6/ip6_input.c:491
+ dst_input include/net/dst.h:469 [inline]
+ ip6_rcv_finish net/ipv6/ip6_input.c:79 [inline]
+ ip6_rcv_finish+0xb6/0x490 net/ipv6/ip6_input.c:69
+ NF_HOOK include/linux/netfilter.h:314 [inline]
+ NF_HOOK include/linux/netfilter.h:308 [inline]
+ ipv6_rcv+0xf9/0x490 net/ipv6/ip6_input.c:309
+ __netif_receive_skb_one_core+0x12e/0x1f0 net/core/dev.c:5896
+ __netif_receive_skb+0x1d/0x170 net/core/dev.c:6009
+ process_backlog+0x41e/0x13b0 net/core/dev.c:6357
+ __napi_poll+0xbd/0x710 net/core/dev.c:7191
+ napi_poll net/core/dev.c:7260 [inline]
+ net_rx_action+0x9de/0xde0 net/core/dev.c:7382
+ handle_softirqs+0x19a/0x770 kernel/softirq.c:561
+ do_softirq.part.0+0x36/0x70 kernel/softirq.c:462
+ </IRQ>
+ <TASK>
+ do_softirq arch/x86/include/asm/preempt.h:26 [inline]
+ __local_bh_enable_ip+0xf1/0x110 kernel/softirq.c:389
+ local_bh_enable include/linux/bottom_half.h:33 [inline]
+ rcu_read_unlock_bh include/linux/rcupdate.h:919 [inline]
+ __dev_queue_xmit+0xc2a/0x3c40 net/core/dev.c:4679
+ dev_queue_xmit include/linux/netdevice.h:3313 [inline]
+ neigh_hh_output include/net/neighbour.h:523 [inline]
+ neigh_output include/net/neighbour.h:537 [inline]
+ ip6_finish_output2+0xd69/0x1f80 net/ipv6/ip6_output.c:141
+ __ip6_finish_output net/ipv6/ip6_output.c:215 [inline]
+ ip6_finish_output+0x5dc/0xd60 net/ipv6/ip6_output.c:226
+ NF_HOOK_COND include/linux/netfilter.h:303 [inline]
+ ip6_output+0x24b/0x8d0 net/ipv6/ip6_output.c:247
+ dst_output include/net/dst.h:459 [inline]
+ NF_HOOK include/linux/netfilter.h:314 [inline]
+ NF_HOOK include/linux/netfilter.h:308 [inline]
+ ip6_xmit+0xbbc/0x20d0 net/ipv6/ip6_output.c:366
+ inet6_csk_xmit+0x39a/0x720 net/ipv6/inet6_connection_sock.c:135
+ __tcp_transmit_skb+0x1a7b/0x3b40 net/ipv4/tcp_output.c:1471
+ tcp_transmit_skb net/ipv4/tcp_output.c:1489 [inline]
+ tcp_send_syn_data net/ipv4/tcp_output.c:4059 [inline]
+ tcp_connect+0x1c0c/0x4510 net/ipv4/tcp_output.c:4148
+ tcp_v6_connect+0x156c/0x2080 net/ipv6/tcp_ipv6.c:333
+ __inet_stream_connect+0x3a7/0xed0 net/ipv4/af_inet.c:677
+ tcp_sendmsg_fastopen+0x3e2/0x710 net/ipv4/tcp.c:1039
+ tcp_sendmsg_locked+0x1e82/0x3570 net/ipv4/tcp.c:1091
+ tcp_sendmsg+0x2f/0x50 net/ipv4/tcp.c:1358
+ inet6_sendmsg+0xb9/0x150 net/ipv6/af_inet6.c:659
+ sock_sendmsg_nosec net/socket.c:718 [inline]
+ __sock_sendmsg+0xf4/0x2a0 net/socket.c:733
+ __sys_sendto+0x29a/0x390 net/socket.c:2187
+ __do_sys_sendto net/socket.c:2194 [inline]
+ __se_sys_sendto net/socket.c:2190 [inline]
+ __x64_sys_sendto+0xe1/0x1c0 net/socket.c:2190
+ do_syscall_x64 arch/x86/entry/common.c:52 [inline]
+ do_syscall_64+0xc3/0x1d0 arch/x86/entry/common.c:83
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7f06553c47ed
+Code: 02 b8 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007f0653a06fc8 EFLAGS: 00000246 ORIG_RAX: 000000000000002c
+RAX: ffffffffffffffda RBX: 00007f0655605fa0 RCX: 00007f06553c47ed
+RDX: 0000000000000000 RSI: 0000000000000000 RDI: 000000000000000b
+RBP: 00007f065545db38 R08: 0000200000000140 R09: 000000000000001c
+R10: f7384d4ea84b01bd R11: 0000000000000246 R12: 0000000000000000
+R13: 00007f0655605fac R14: 00007f0655606038 R15: 00007f06539e7000
+ </TASK>
+Modules linked in:
+
+[1]:
+dnf install -y selinux-policy-targeted policycoreutils netlabel_tools procps-ng nmap-ncat
+mount -t selinuxfs none /sys/fs/selinux
+load_policy
+netlabelctl calipso add pass doi:1
+netlabelctl map del default
+netlabelctl map add default address:::1 protocol:calipso,1
+sysctl net.ipv4.tcp_syncookies=2
+nc -l ::1 80 &
+nc ::1 80
+
+Fixes: e1adea927080 ("calipso: Allow request sockets to be relabelled by the lsm.")
+Reported-by: syzkaller <syzkaller@googlegroups.com>
+Reported-by: John Cheung <john.cs.hey@gmail.com>
+Closes: https://lore.kernel.org/netdev/CAP=Rh=MvfhrGADy+-WJiftV2_WzMH4VEhEFmeT28qY+4yxNu4w@mail.gmail.com/
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Acked-by: Paul Moore <paul@paul-moore.com>
+Link: https://patch.msgid.link/20250617224125.17299-1-kuni1840@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/calipso.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/net/ipv6/calipso.c b/net/ipv6/calipso.c
+index 62618a058b8fa..a247bb93908bf 100644
+--- a/net/ipv6/calipso.c
++++ b/net/ipv6/calipso.c
+@@ -1207,6 +1207,10 @@ static int calipso_req_setattr(struct request_sock *req,
+       struct ipv6_opt_hdr *old, *new;
+       struct sock *sk = sk_to_full_sk(req_to_sk(req));
++      /* sk is NULL for SYN+ACK w/ SYN Cookie */
++      if (!sk)
++              return -ENOMEM;
++
+       if (req_inet->ipv6_opt && req_inet->ipv6_opt->hopopt)
+               old = req_inet->ipv6_opt->hopopt;
+       else
+@@ -1247,6 +1251,10 @@ static void calipso_req_delattr(struct request_sock *req)
+       struct ipv6_txoptions *txopts;
+       struct sock *sk = sk_to_full_sk(req_to_sk(req));
++      /* sk is NULL for SYN+ACK w/ SYN Cookie */
++      if (!sk)
++              return;
++
+       if (!req_inet->ipv6_opt || !req_inet->ipv6_opt->hopopt)
+               return;
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-amdkfd-move-sdma-queue-reset-capability-check-to.patch b/queue-6.15/drm-amdkfd-move-sdma-queue-reset-capability-check-to.patch
new file mode 100644 (file)
index 0000000..e96c547
--- /dev/null
@@ -0,0 +1,50 @@
+From 0e9b453fd4b6a88711ed7dea24fe6a27018d1d7a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 29 May 2025 11:27:37 +0800
+Subject: drm/amdkfd: move SDMA queue reset capability check to node_show
+
+From: Jesse.Zhang <Jesse.Zhang@amd.com>
+
+[ Upstream commit a55737dab6ba63eb4241e9c6547629058af31e12 ]
+
+Relocate the per-SDMA queue reset capability check from
+kfd_topology_set_capabilities() to node_show() to ensure we read the
+latest value of sdma.supported_reset after all IP blocks are initialized.
+
+Fixes: ceb7114c961b ("drm/amdkfd: flag per-sdma queue reset supported to user space")
+Reviewed-by: Jonathan Kim <jonathan.kim@amd.com>
+Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com>
+Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
+(cherry picked from commit e17df7b086cf908cedd919f448da9e00028419bb)
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+index 9bbee484d57cc..d6653e39e1477 100644
+--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
++++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+@@ -510,6 +510,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
+                       dev->node_props.capability |=
+                                       HSA_CAP_AQL_QUEUE_DOUBLE_MAP;
++              if (KFD_GC_VERSION(dev->gpu) < IP_VERSION(10, 0, 0) &&
++                      (dev->gpu->adev->sdma.supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE))
++                              dev->node_props.capability2 |= HSA_CAP2_PER_SDMA_QUEUE_RESET_SUPPORTED;
++
+               sysfs_show_32bit_prop(buffer, offs, "max_engine_clk_fcompute",
+                       dev->node_props.max_engine_clk_fcompute);
+@@ -2001,8 +2005,6 @@ static void kfd_topology_set_capabilities(struct kfd_topology_device *dev)
+               if (!amdgpu_sriov_vf(dev->gpu->adev))
+                       dev->node_props.capability |= HSA_CAP_PER_QUEUE_RESET_SUPPORTED;
+-              if (dev->gpu->adev->sdma.supported_reset & AMDGPU_RESET_TYPE_PER_QUEUE)
+-                      dev->node_props.capability2 |= HSA_CAP2_PER_SDMA_QUEUE_RESET_SUPPORTED;
+       } else {
+               dev->node_props.debug_prop |= HSA_DBG_WATCH_ADDR_MASK_LO_BIT_GFX10 |
+                                       HSA_DBG_WATCH_ADDR_MASK_HI_BIT;
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-i915-pmu-fix-build-error-with-gcov-and-autofdo-e.patch b/queue-6.15/drm-i915-pmu-fix-build-error-with-gcov-and-autofdo-e.patch
new file mode 100644 (file)
index 0000000..17c42b9
--- /dev/null
@@ -0,0 +1,81 @@
+From 17e82b9a80c5d0c6303e92c7b1dcda22d9e8395c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Jun 2025 08:30:23 +0000
+Subject: drm/i915/pmu: Fix build error with GCOV and AutoFDO enabled
+
+From: Tzung-Bi Shih <tzungbi@kernel.org>
+
+[ Upstream commit a7137b1825b535eb7258b25beeb0d5425e0037d2 ]
+
+i915_pmu.c may fail to build with GCOV and AutoFDO enabled.
+
+../drivers/gpu/drm/i915/i915_pmu.c:116:3: error: call to '__compiletime_assert_487' declared with 'error' attribute: BUILD_BUG_ON failed: bit > BITS_PER_TYPE(typeof_member(struct i915_pmu, enable)) - 1
+  116 |                 BUILD_BUG_ON(bit >
+      |                 ^
+
+Here is a way to reproduce the issue:
+$ git checkout v6.15
+$ mkdir build
+$ ./scripts/kconfig/merge_config.sh -O build -n -m <(cat <<EOF
+CONFIG_DRM=y
+CONFIG_PCI=y
+CONFIG_DRM_I915=y
+
+CONFIG_PERF_EVENTS=y
+
+CONFIG_DEBUG_FS=y
+CONFIG_GCOV_KERNEL=y
+CONFIG_GCOV_PROFILE_ALL=y
+
+CONFIG_AUTOFDO_CLANG=y
+EOF
+)
+$ PATH=${PATH}:${HOME}/llvm-20.1.5-x86_64/bin make LLVM=1 O=build \
+       olddefconfig
+$ PATH=${PATH}:${HOME}/llvm-20.1.5-x86_64/bin make LLVM=1 O=build \
+       CLANG_AUTOFDO_PROFILE=...PATH_TO_SOME_AFDO_PROFILE... \
+       drivers/gpu/drm/i915/i915_pmu.o
+
+Although not super sure what happened, by reviewing the code, it should
+depend on `__builtin_constant_p(bit)` directly instead of assuming
+`__builtin_constant_p(config)` makes `bit` a builtin constant.
+
+Also fix a nit, to reuse the `bit` local variable.
+
+Fixes: a644fde77ff7 ("drm/i915/pmu: Change bitmask of enabled events to u32")
+Reviewed-by: Nathan Chancellor <nathan@kernel.org>
+Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
+Signed-off-by: Tvrtko Ursulin <tursulin@ursulin.net>
+Link: https://lore.kernel.org/r/20250612083023.562585-1-tzungbi@kernel.org
+(cherry picked from commit 686d773186bf72b739bab7e12eb8665d914676ee)
+Signed-off-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/i915/i915_pmu.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
+index e5a188ce31857..990bfaba3ce4e 100644
+--- a/drivers/gpu/drm/i915/i915_pmu.c
++++ b/drivers/gpu/drm/i915/i915_pmu.c
+@@ -112,7 +112,7 @@ static u32 config_mask(const u64 config)
+ {
+       unsigned int bit = config_bit(config);
+-      if (__builtin_constant_p(config))
++      if (__builtin_constant_p(bit))
+               BUILD_BUG_ON(bit >
+                            BITS_PER_TYPE(typeof_member(struct i915_pmu,
+                                                        enable)) - 1);
+@@ -121,7 +121,7 @@ static u32 config_mask(const u64 config)
+                            BITS_PER_TYPE(typeof_member(struct i915_pmu,
+                                                        enable)) - 1);
+-      return BIT(config_bit(config));
++      return BIT(bit);
+ }
+ static bool is_engine_event(struct perf_event *event)
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-msm-a7xx-call-cp_reset_context_state.patch b/queue-6.15/drm-msm-a7xx-call-cp_reset_context_state.patch
new file mode 100644 (file)
index 0000000..5688635
--- /dev/null
@@ -0,0 +1,54 @@
+From e0b82770292a9b6a631b13c6c809330ef2126871 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 May 2025 18:28:06 -0400
+Subject: drm/msm/a7xx: Call CP_RESET_CONTEXT_STATE
+
+From: Connor Abbott <cwabbott0@gmail.com>
+
+[ Upstream commit 2b520c6104f34e3a548525173c38ebca4402cac3 ]
+
+Calling this packet is necessary when we switch contexts because there
+are various pieces of state used by userspace to synchronize between BR
+and BV that are persistent across submits and we need to make sure that
+they are in a "safe" state when switching contexts. Otherwise a
+userspace submission in one context could cause another context to
+function incorrectly and hang, effectively a denial of service (although
+without leaking data). This was missed during initial a7xx bringup.
+
+Fixes: af66706accdf ("drm/msm/a6xx: Add skeleton A7xx support")
+Signed-off-by: Connor Abbott <cwabbott0@gmail.com>
+Patchwork: https://patchwork.freedesktop.org/patch/654924/
+Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+index 90991ba5a4ae1..742132feb19cc 100644
+--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
++++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+@@ -130,6 +130,20 @@ static void a6xx_set_pagetable(struct a6xx_gpu *a6xx_gpu,
+               OUT_RING(ring, lower_32_bits(rbmemptr(ring, fence)));
+               OUT_RING(ring, upper_32_bits(rbmemptr(ring, fence)));
+               OUT_RING(ring, submit->seqno - 1);
++
++              OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
++              OUT_RING(ring, CP_SET_THREAD_BOTH);
++
++              /* Reset state used to synchronize BR and BV */
++              OUT_PKT7(ring, CP_RESET_CONTEXT_STATE, 1);
++              OUT_RING(ring,
++                       CP_RESET_CONTEXT_STATE_0_CLEAR_ON_CHIP_TS |
++                       CP_RESET_CONTEXT_STATE_0_CLEAR_RESOURCE_TABLE |
++                       CP_RESET_CONTEXT_STATE_0_CLEAR_BV_BR_COUNTER |
++                       CP_RESET_CONTEXT_STATE_0_RESET_GLOBAL_LOCAL_TS);
++
++              OUT_PKT7(ring, CP_THREAD_CONTROL, 1);
++              OUT_RING(ring, CP_SET_THREAD_BR);
+       }
+       if (!sysprof) {
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-msm-disp-correct-porch-timing-for-sdm845.patch b/queue-6.15/drm-msm-disp-correct-porch-timing-for-sdm845.patch
new file mode 100644 (file)
index 0000000..5e640dc
--- /dev/null
@@ -0,0 +1,57 @@
+From faeb287e4778b32abf83dc940b218c8dad9bc48b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 15:03:47 -0800
+Subject: drm/msm/disp: Correct porch timing for SDM845
+
+From: James A. MacInnes <james.a.macinnes@gmail.com>
+
+[ Upstream commit 146e87f3e11de0dfa091ff87e34b4bc6eec761a4 ]
+
+Type-C DisplayPort inoperable due to incorrect porch settings.
+- Re-used wide_bus_en as flag to prevent porch shifting
+
+Fixes: c943b4948b58 ("drm/msm/dp: add displayPort driver support")
+Signed-off-by: James A. MacInnes <james.a.macinnes@gmail.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Patchwork: https://patchwork.freedesktop.org/patch/636945/
+Link: https://lore.kernel.org/r/20250212-sdm845_dp-v2-2-4954e51458f4@gmail.com
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c   | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+index 8220a4012846b..c3c7a0d56c410 100644
+--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
++++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c
+@@ -94,17 +94,21 @@ static void drm_mode_to_intf_timing_params(
+               timing->vsync_polarity = 0;
+       }
+-      /* for DP/EDP, Shift timings to align it to bottom right */
+-      if (phys_enc->hw_intf->cap->type == INTF_DP) {
++      timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent);
++      timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent);
++
++      /*
++       *  For DP/EDP, Shift timings to align it to bottom right.
++       *  wide_bus_en is set for everything excluding SDM845 &
++       *  porch changes cause DisplayPort failure and HDMI tearing.
++       */
++      if (phys_enc->hw_intf->cap->type == INTF_DP && timing->wide_bus_en) {
+               timing->h_back_porch += timing->h_front_porch;
+               timing->h_front_porch = 0;
+               timing->v_back_porch += timing->v_front_porch;
+               timing->v_front_porch = 0;
+       }
+-      timing->wide_bus_en = dpu_encoder_is_widebus_enabled(phys_enc->parent);
+-      timing->compression_en = dpu_encoder_is_dsc_enabled(phys_enc->parent);
+-
+       /*
+        * for DP, divide the horizonal parameters by 2 when
+        * widebus is enabled
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-msm-dp-disable-wide-bus-support-for-sdm845.patch b/queue-6.15/drm-msm-dp-disable-wide-bus-support-for-sdm845.patch
new file mode 100644 (file)
index 0000000..226fdb1
--- /dev/null
@@ -0,0 +1,61 @@
+From e0b3c2f94a71e5e90ecb7e04d91ede5c78065d92 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 12 Feb 2025 15:03:46 -0800
+Subject: drm/msm/dp: Disable wide bus support for SDM845
+
+From: James A. MacInnes <james.a.macinnes@gmail.com>
+
+[ Upstream commit 83c4c67076c209787515e06fffd41dd0bdab09b9 ]
+
+When widebus was enabled for DisplayPort in commit c7c412202623
+("drm/msm/dp: enable widebus on all relevant chipsets") it was clarified
+that it is only supported on DPU 5.0.0 onwards which includes SC7180 on
+DPU revision 6.2.  However, this patch missed that the description
+structure for SC7180 is also reused for SDM845 (because of identical
+io_start address) which is only DPU 4.0.0, leading to a wrongly enbled
+widebus feature and corruption on that platform.
+
+Create a separate msm_dp_desc_sdm845 structure for this SoC compatible,
+with the wide_bus_supported flag turned off.
+
+Fixes: c7c412202623 ("drm/msm/dp: enable widebus on all relevant chipsets")
+Signed-off-by: James A. MacInnes <james.a.macinnes@gmail.com>
+[DB: reworded commit text following Marijn's suggestion]
+Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
+Patchwork: https://patchwork.freedesktop.org/patch/636944/
+Link: https://lore.kernel.org/r/20250212-sdm845_dp-v2-1-4954e51458f4@gmail.com
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/dp/dp_display.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
+index ab8c1f19dcb42..c7503a7a6123f 100644
+--- a/drivers/gpu/drm/msm/dp/dp_display.c
++++ b/drivers/gpu/drm/msm/dp/dp_display.c
+@@ -127,6 +127,11 @@ static const struct msm_dp_desc msm_dp_desc_sa8775p[] = {
+       {}
+ };
++static const struct msm_dp_desc msm_dp_desc_sdm845[] = {
++      { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0 },
++      {}
++};
++
+ static const struct msm_dp_desc msm_dp_desc_sc7180[] = {
+       { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .wide_bus_supported = true },
+       {}
+@@ -179,7 +184,7 @@ static const struct of_device_id msm_dp_dt_match[] = {
+       { .compatible = "qcom,sc8180x-edp", .data = &msm_dp_desc_sc8180x },
+       { .compatible = "qcom,sc8280xp-dp", .data = &msm_dp_desc_sc8280xp },
+       { .compatible = "qcom,sc8280xp-edp", .data = &msm_dp_desc_sc8280xp },
+-      { .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sc7180 },
++      { .compatible = "qcom,sdm845-dp", .data = &msm_dp_desc_sdm845 },
+       { .compatible = "qcom,sm8350-dp", .data = &msm_dp_desc_sc7180 },
+       { .compatible = "qcom,sm8650-dp", .data = &msm_dp_desc_sm8650 },
+       { .compatible = "qcom,x1e80100-dp", .data = &msm_dp_desc_x1e80100 },
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-msm-dsi-dsi_phy_10nm-fix-missing-initial-vco-rat.patch b/queue-6.15/drm-msm-dsi-dsi_phy_10nm-fix-missing-initial-vco-rat.patch
new file mode 100644 (file)
index 0000000..0502747
--- /dev/null
@@ -0,0 +1,58 @@
+From 050c7d7f1cd9864e59fae96c3af1839fcd86c5f6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 May 2025 13:13:26 +0200
+Subject: drm/msm/dsi/dsi_phy_10nm: Fix missing initial VCO rate
+
+From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+
+[ Upstream commit 8a48e35becb214743214f5504e726c3ec131cd6d ]
+
+Driver unconditionally saves current state on first init in
+dsi_pll_10nm_init(), but does not save the VCO rate, only some of the
+divider registers.  The state is then restored during probe/enable via
+msm_dsi_phy_enable() -> msm_dsi_phy_pll_restore_state() ->
+dsi_10nm_pll_restore_state().
+
+Restoring calls dsi_pll_10nm_vco_set_rate() with
+pll_10nm->vco_current_rate=0, which basically overwrites existing rate of
+VCO and messes with clock hierarchy, by setting frequency to 0 to clock
+tree.  This makes anyway little sense - VCO rate was not saved, so
+should not be restored.
+
+If PLL was not configured configure it to minimum rate to avoid glitches
+and configuring entire in clock hierarchy to 0 Hz.
+
+Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Link: https://lore.kernel.org/r/sz4kbwy5nwsebgf64ia7uq4ee7wbsa5uy3xmlqwcstsbntzcov@ew3dcyjdzmi2/
+Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
+Fixes: a4ccc37693a2 ("drm/msm/dsi_pll_10nm: restore VCO rate during
+Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Patchwork: https://patchwork.freedesktop.org/patch/654796/
+Link: https://lore.kernel.org/r/20250520111325.92352-2-krzysztof.kozlowski@linaro.org
+Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+index 9812b4d691979..af2e30f3f842a 100644
+--- a/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
++++ b/drivers/gpu/drm/msm/dsi/phy/dsi_phy_10nm.c
+@@ -704,6 +704,13 @@ static int dsi_pll_10nm_init(struct msm_dsi_phy *phy)
+       /* TODO: Remove this when we have proper display handover support */
+       msm_dsi_phy_pll_save_state(phy);
++      /*
++       * Store also proper vco_current_rate, because its value will be used in
++       * dsi_10nm_pll_restore_state().
++       */
++      if (!dsi_pll_10nm_vco_recalc_rate(&pll_10nm->clk_hw, VCO_REF_CLK_RATE))
++              pll_10nm->vco_current_rate = pll_10nm->phy->cfg->min_pll_rate;
++
+       return 0;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-msm-fix-cp_reset_context_state-bitfield-names.patch b/queue-6.15/drm-msm-fix-cp_reset_context_state-bitfield-names.patch
new file mode 100644 (file)
index 0000000..612a93c
--- /dev/null
@@ -0,0 +1,37 @@
+From 7fb1fe85b2632896e68475e2c38260b81ad2af0c Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 May 2025 18:28:05 -0400
+Subject: drm/msm: Fix CP_RESET_CONTEXT_STATE bitfield names
+
+From: Connor Abbott <cwabbott0@gmail.com>
+
+[ Upstream commit b1c9e797ad37d188675505b66a3a4bbeea5d9560 ]
+
+Based on kgsl.
+
+Fixes: af66706accdf ("drm/msm/a6xx: Add skeleton A7xx support")
+Signed-off-by: Connor Abbott <cwabbott0@gmail.com>
+Patchwork: https://patchwork.freedesktop.org/patch/654922/
+Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml
+index 5a6ae9fc31945..4627134016228 100644
+--- a/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml
++++ b/drivers/gpu/drm/msm/registers/adreno/adreno_pm4.xml
+@@ -2255,7 +2255,8 @@ opcode: CP_LOAD_STATE4 (30) (4 dwords)
+       <reg32 offset="0" name="0">
+               <bitfield name="CLEAR_ON_CHIP_TS" pos="0" type="boolean"/>
+               <bitfield name="CLEAR_RESOURCE_TABLE" pos="1" type="boolean"/>
+-              <bitfield name="CLEAR_GLOBAL_LOCAL_TS" pos="2" type="boolean"/>
++              <bitfield name="CLEAR_BV_BR_COUNTER" pos="2" type="boolean"/>
++              <bitfield name="RESET_GLOBAL_LOCAL_TS" pos="3" type="boolean"/>
+       </reg32>
+ </domain>
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-nouveau-bl-increase-buffer-size-to-avoid-truncat.patch b/queue-6.15/drm-nouveau-bl-increase-buffer-size-to-avoid-truncat.patch
new file mode 100644 (file)
index 0000000..62c1ac7
--- /dev/null
@@ -0,0 +1,81 @@
+From 9c2f7ae1bda7c8904024ee277ec8da5070b913b8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Jun 2025 14:54:51 -0700
+Subject: drm/nouveau/bl: increase buffer size to avoid truncate warning
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jacob Keller <jacob.e.keller@intel.com>
+
+[ Upstream commit 61b2b3737499f1fb361a54a16828db24a8345e85 ]
+
+The nouveau_get_backlight_name() function generates a unique name for the
+backlight interface, appending an id from 1 to 99 for all backlight devices
+after the first.
+
+GCC 15 (and likely other compilers) produce the following
+-Wformat-truncation warning:
+
+nouveau_backlight.c: In function â€˜nouveau_backlight_init’:
+nouveau_backlight.c:56:69: error: â€˜%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 3 [-Werror=format-truncation=]
+   56 |                 snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
+      |                                                                     ^~
+In function â€˜nouveau_get_backlight_name’,
+    inlined from â€˜nouveau_backlight_init’ at nouveau_backlight.c:351:7:
+nouveau_backlight.c:56:56: note: directive argument in the range [1, 2147483647]
+   56 |                 snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
+      |                                                        ^~~~~~~~~~~~~~~~
+nouveau_backlight.c:56:17: note: â€˜snprintf’ output between 14 and 23 bytes into a destination of size 15
+   56 |                 snprintf(backlight_name, BL_NAME_SIZE, "nv_backlight%d", nb);
+      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The warning started appearing after commit ab244be47a8f ("drm/nouveau:
+Fix a potential theorical leak in nouveau_get_backlight_name()") This fix
+for the ida usage removed the explicit value check for ids larger than 99.
+The compiler is unable to intuit that the ida_alloc_max() limits the
+returned value range between 0 and 99.
+
+Because the compiler can no longer infer that the number ranges from 0 to
+99, it thinks that it could use as many as 11 digits (10 + the potential -
+sign for negative numbers).
+
+The warning has gone unfixed for some time, with at least one kernel test
+robot report. The code breaks W=1 builds, which is especially frustrating
+with the introduction of CONFIG_WERROR.
+
+The string is stored temporarily on the stack and then copied into the
+device name. Its not a big deal to use 11 more bytes of stack rounding out
+to an even 24 bytes. Increase BL_NAME_SIZE to 24 to avoid the truncation
+warning. This fixes the W=1 builds that include this driver.
+
+Compile tested only.
+
+Fixes: ab244be47a8f ("drm/nouveau: Fix a potential theorical leak in nouveau_get_backlight_name()")
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202312050324.0kv4PnfZ-lkp@intel.com/
+Suggested-by: Timur Tabi <ttabi@nvidia.com>
+Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://lore.kernel.org/r/20250610-jk-nouveua-drm-bl-snprintf-fix-v2-1-7fdd4b84b48e@intel.com
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/nouveau/nouveau_backlight.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
+index d47442125fa18..9aae26eb7d8fb 100644
+--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
++++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
+@@ -42,7 +42,7 @@
+ #include "nouveau_acpi.h"
+ static struct ida bl_ida;
+-#define BL_NAME_SIZE 15 // 12 for name + 2 for digits + 1 for '\0'
++#define BL_NAME_SIZE 24 // 12 for name + 11 for digits + 1 for '\0'
+ static bool
+ nouveau_get_backlight_name(char backlight_name[BL_NAME_SIZE],
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-nouveau-fix-a-use-after-free-in-r535_gsp_rpc_pus.patch b/queue-6.15/drm-nouveau-fix-a-use-after-free-in-r535_gsp_rpc_pus.patch
new file mode 100644 (file)
index 0000000..9b427b2
--- /dev/null
@@ -0,0 +1,77 @@
+From e26a002a6dbb43e0c462bf528dbc8a0124f72276 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 27 May 2025 16:37:12 +0000
+Subject: drm/nouveau: fix a use-after-free in r535_gsp_rpc_push()
+
+From: Zhi Wang <zhiw@nvidia.com>
+
+[ Upstream commit 9802f0a63b641f4cddb2139c814c2e95cb825099 ]
+
+The RPC container is released after being passed to r535_gsp_rpc_send().
+
+When sending the initial fragment of a large RPC and passing the
+caller's RPC container, the container will be freed prematurely. Subsequent
+attempts to send remaining fragments will therefore result in a
+use-after-free.
+
+Allocate a temporary RPC container for holding the initial fragment of a
+large RPC when sending. Free the caller's container when all fragments
+are successfully sent.
+
+Fixes: 176fdcbddfd2 ("drm/nouveau/gsp/r535: add support for booting GSP-RM")
+Signed-off-by: Zhi Wang <zhiw@nvidia.com>
+Link: https://lore.kernel.org/r/20250527163712.3444-1-zhiw@nvidia.com
+[ Rebase onto Blackwell changes. - Danilo ]
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ .../drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c   | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
+index ffb4104a7d8cd..d558b0f62b010 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
+@@ -638,12 +638,18 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload,
+       if (payload_size > max_payload_size) {
+               const u32 fn = rpc->function;
+               u32 remain_payload_size = payload_size;
++              void *next;
+-              /* Adjust length, and send initial RPC. */
+-              rpc->length = sizeof(*rpc) + max_payload_size;
+-              msg->checksum = rpc->length;
++              /* Send initial RPC. */
++              next = r535_gsp_rpc_get(gsp, fn, max_payload_size);
++              if (IS_ERR(next)) {
++                      repv = next;
++                      goto done;
++              }
+-              repv = r535_gsp_rpc_send(gsp, payload, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
++              memcpy(next, payload, max_payload_size);
++
++              repv = r535_gsp_rpc_send(gsp, next, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
+               if (IS_ERR(repv))
+                       goto done;
+@@ -654,7 +660,6 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload,
+               while (remain_payload_size) {
+                       u32 size = min(remain_payload_size,
+                                      max_payload_size);
+-                      void *next;
+                       next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size);
+                       if (IS_ERR(next)) {
+@@ -675,6 +680,8 @@ r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload,
+               /* Wait for reply. */
+               repv = r535_gsp_rpc_handle_reply(gsp, fn, policy, payload_size +
+                                                sizeof(*rpc));
++              if (!IS_ERR(repv))
++                      kvfree(msg);
+       } else {
+               repv = r535_gsp_rpc_send(gsp, payload, policy, gsp_rpc_len);
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-nouveau-gsp-split-rpc-handling-out-on-its-own.patch b/queue-6.15/drm-nouveau-gsp-split-rpc-handling-out-on-its-own.patch
new file mode 100644 (file)
index 0000000..b50ae99
--- /dev/null
@@ -0,0 +1,1593 @@
+From 0cc7d69ff6f363bfebacfe02c6bf94d9335b17ff Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 14 Nov 2024 13:02:36 +1000
+Subject: drm/nouveau/gsp: split rpc handling out on its own
+
+From: Ben Skeggs <bskeggs@nvidia.com>
+
+[ Upstream commit 8a8b1ec5261f20d86c76c8fb235ee2441744bc10 ]
+
+Later patches in the series add HALs around various RM APIs in order to
+support a newer version of GSP-RM firmware.  In order to do this, begin
+by splitting the code up into "modules" that roughly represent RM's API
+boundaries so they can be more easily managed.
+
+Aside from moving the RPC function pointers, no code change is indended.
+
+Signed-off-by: Ben Skeggs <bskeggs@nvidia.com>
+Reviewed-by: Dave Airlie <airlied@redhat.com>
+Reviewed-by: Timur Tabi <ttabi@nvidia.com>
+Tested-by: Timur Tabi <ttabi@nvidia.com>
+Signed-off-by: Dave Airlie <airlied@redhat.com>
+Stable-dep-of: 9802f0a63b64 ("drm/nouveau: fix a use-after-free in r535_gsp_rpc_push()")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/nouveau/Kbuild                |   1 +
+ .../gpu/drm/nouveau/include/nvkm/subdev/gsp.h |  13 +-
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild    |   2 +
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/r535.c    | 665 +----------------
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild |   5 +
+ .../nouveau/nvkm/subdev/gsp/rm/r535/Kbuild    |   6 +
+ .../drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c  |  10 +
+ .../drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c | 692 ++++++++++++++++++
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h   |  20 +
+ .../gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h  |  18 +
+ 10 files changed, 762 insertions(+), 670 deletions(-)
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
+ create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h
+
+diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
+index 7b863355c5c67..0759ba15954be 100644
+--- a/drivers/gpu/drm/nouveau/Kbuild
++++ b/drivers/gpu/drm/nouveau/Kbuild
+@@ -2,6 +2,7 @@
+ ccflags-y += -I $(src)/include
+ ccflags-y += -I $(src)/include/nvkm
+ ccflags-y += -I $(src)/nvkm
++ccflags-y += -I $(src)/nvkm/subdev/gsp
+ ccflags-y += -I $(src)
+ # NVKM - HW resource manager
+diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
+index 1c12854a85505..b543c31d3d320 100644
+--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
++++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gsp.h
+@@ -210,10 +210,7 @@ struct nvkm_gsp {
+       } gr;
+       const struct nvkm_gsp_rm {
+-              void *(*rpc_get)(struct nvkm_gsp *, u32 fn, u32 argc);
+-              void *(*rpc_push)(struct nvkm_gsp *gsp, void *argv,
+-                                enum nvkm_gsp_rpc_reply_policy policy, u32 repc);
+-              void (*rpc_done)(struct nvkm_gsp *gsp, void *repv);
++              const struct nvkm_rm_api *api;
+               void *(*rm_ctrl_get)(struct nvkm_gsp_object *, u32 cmd, u32 argc);
+               int (*rm_ctrl_push)(struct nvkm_gsp_object *, void **argv, u32 repc);
+@@ -272,17 +269,19 @@ nvkm_gsp_rm(struct nvkm_gsp *gsp)
+       return gsp && (gsp->fws.rm || gsp->fw.img);
+ }
++#include <rm/rm.h>
++
+ static inline void *
+ nvkm_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 argc)
+ {
+-      return gsp->rm->rpc_get(gsp, fn, argc);
++      return gsp->rm->api->rpc->get(gsp, fn, argc);
+ }
+ static inline void *
+ nvkm_gsp_rpc_push(struct nvkm_gsp *gsp, void *argv,
+                 enum nvkm_gsp_rpc_reply_policy policy, u32 repc)
+ {
+-      return gsp->rm->rpc_push(gsp, argv, policy, repc);
++      return gsp->rm->api->rpc->push(gsp, argv, policy, repc);
+ }
+ static inline void *
+@@ -311,7 +310,7 @@ nvkm_gsp_rpc_wr(struct nvkm_gsp *gsp, void *argv,
+ static inline void
+ nvkm_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv)
+ {
+-      gsp->rm->rpc_done(gsp, repv);
++      gsp->rm->api->rpc->done(gsp, repv);
+ }
+ static inline void *
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
+index 16bf2f1bb7801..af6e55603763d 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/Kbuild
+@@ -10,3 +10,5 @@ nvkm-y += nvkm/subdev/gsp/ga102.o
+ nvkm-y += nvkm/subdev/gsp/ad102.o
+ nvkm-y += nvkm/subdev/gsp/r535.o
++
++include $(src)/nvkm/subdev/gsp/rm/Kbuild
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+index 64b58efd31322..53a4af0010392 100644
+--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/r535.c
+@@ -19,6 +19,7 @@
+  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  * OTHER DEALINGS IN THE SOFTWARE.
+  */
++#include <rm/rpc.h>
+ #include "priv.h"
+ #include <core/pci.h>
+@@ -60,578 +61,6 @@
+ extern struct dentry *nouveau_debugfs_root;
+-#define GSP_MSG_MIN_SIZE GSP_PAGE_SIZE
+-#define GSP_MSG_MAX_SIZE (GSP_MSG_MIN_SIZE * 16)
+-
+-/**
+- * DOC: GSP message queue element
+- *
+- * https://github.com/NVIDIA/open-gpu-kernel-modules/blob/535/src/nvidia/inc/kernel/gpu/gsp/message_queue_priv.h
+- *
+- * The GSP command queue and status queue are message queues for the
+- * communication between software and GSP. The software submits the GSP
+- * RPC via the GSP command queue, GSP writes the status of the submitted
+- * RPC in the status queue.
+- *
+- * A GSP message queue element consists of three parts:
+- *
+- * - message element header (struct r535_gsp_msg), which mostly maintains
+- *   the metadata for queuing the element.
+- *
+- * - RPC message header (struct nvfw_gsp_rpc), which maintains the info
+- *   of the RPC. E.g., the RPC function number.
+- *
+- * - The payload, where the RPC message stays. E.g. the params of a
+- *   specific RPC function. Some RPC functions also have their headers
+- *   in the payload. E.g. rm_alloc, rm_control.
+- *
+- * The memory layout of a GSP message element can be illustrated below::
+- *
+- *    +------------------------+
+- *    | Message Element Header |
+- *    |    (r535_gsp_msg)      |
+- *    |                        |
+- *    | (r535_gsp_msg.data)    |
+- *    |          |             |
+- *    |----------V-------------|
+- *    |    GSP RPC Header      |
+- *    |    (nvfw_gsp_rpc)      |
+- *    |                        |
+- *    | (nvfw_gsp_rpc.data)    |
+- *    |          |             |
+- *    |----------V-------------|
+- *    |       Payload          |
+- *    |                        |
+- *    |   header(optional)     |
+- *    |        params          |
+- *    +------------------------+
+- *
+- * The max size of a message queue element is 16 pages (including the
+- * headers). When a GSP message to be sent is larger than 16 pages, the
+- * message should be split into multiple elements and sent accordingly.
+- *
+- * In the bunch of the split elements, the first element has the expected
+- * function number, while the rest of the elements are sent with the
+- * function number NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD.
+- *
+- * GSP consumes the elements from the cmdq and always writes the result
+- * back to the msgq. The result is also formed as split elements.
+- *
+- * Terminology:
+- *
+- * - gsp_msg(msg): GSP message element (element header + GSP RPC header +
+- *   payload)
+- * - gsp_rpc(rpc): GSP RPC (RPC header + payload)
+- * - gsp_rpc_buf: buffer for (GSP RPC header + payload)
+- * - gsp_rpc_len: size of (GSP RPC header + payload)
+- * - params_size: size of params in the payload
+- * - payload_size: size of (header if exists + params) in the payload
+- */
+-
+-struct r535_gsp_msg {
+-      u8 auth_tag_buffer[16];
+-      u8 aad_buffer[16];
+-      u32 checksum;
+-      u32 sequence;
+-      u32 elem_count;
+-      u32 pad;
+-      u8  data[];
+-};
+-
+-struct nvfw_gsp_rpc {
+-      u32 header_version;
+-      u32 signature;
+-      u32 length;
+-      u32 function;
+-      u32 rpc_result;
+-      u32 rpc_result_private;
+-      u32 sequence;
+-      union {
+-              u32 spare;
+-              u32 cpuRmGfid;
+-      };
+-      u8  data[];
+-};
+-
+-#define GSP_MSG_HDR_SIZE offsetof(struct r535_gsp_msg, data)
+-
+-#define to_gsp_hdr(p, header) \
+-      container_of((void *)p, typeof(*header), data)
+-
+-#define to_payload_hdr(p, header) \
+-      container_of((void *)p, typeof(*header), params)
+-
+-static int
+-r535_rpc_status_to_errno(uint32_t rpc_status)
+-{
+-      switch (rpc_status) {
+-      case 0x55: /* NV_ERR_NOT_READY */
+-      case 0x66: /* NV_ERR_TIMEOUT_RETRY */
+-              return -EBUSY;
+-      case 0x51: /* NV_ERR_NO_MEMORY */
+-              return -ENOMEM;
+-      default:
+-              return -EINVAL;
+-      }
+-}
+-
+-static int
+-r535_gsp_msgq_wait(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *ptime)
+-{
+-      u32 size, rptr = *gsp->msgq.rptr;
+-      int used;
+-
+-      size = DIV_ROUND_UP(GSP_MSG_HDR_SIZE + gsp_rpc_len,
+-                          GSP_PAGE_SIZE);
+-      if (WARN_ON(!size || size >= gsp->msgq.cnt))
+-              return -EINVAL;
+-
+-      do {
+-              u32 wptr = *gsp->msgq.wptr;
+-
+-              used = wptr + gsp->msgq.cnt - rptr;
+-              if (used >= gsp->msgq.cnt)
+-                      used -= gsp->msgq.cnt;
+-              if (used >= size)
+-                      break;
+-
+-              usleep_range(1, 2);
+-      } while (--(*ptime));
+-
+-      if (WARN_ON(!*ptime))
+-              return -ETIMEDOUT;
+-
+-      return used;
+-}
+-
+-static struct r535_gsp_msg *
+-r535_gsp_msgq_get_entry(struct nvkm_gsp *gsp)
+-{
+-      u32 rptr = *gsp->msgq.rptr;
+-
+-      /* Skip the first page, which is the message queue info */
+-      return (void *)((u8 *)gsp->shm.msgq.ptr + GSP_PAGE_SIZE +
+-             rptr * GSP_PAGE_SIZE);
+-}
+-
+-/**
+- * DOC: Receive a GSP message queue element
+- *
+- * Receiving a GSP message queue element from the message queue consists of
+- * the following steps:
+- *
+- * - Peek the element from the queue: r535_gsp_msgq_peek().
+- *   Peek the first page of the element to determine the total size of the
+- *   message before allocating the proper memory.
+- *
+- * - Allocate memory for the message.
+- *   Once the total size of the message is determined from the GSP message
+- *   queue element, the caller of r535_gsp_msgq_recv() allocates the
+- *   required memory.
+- *
+- * - Receive the message: r535_gsp_msgq_recv().
+- *   Copy the message into the allocated memory. Advance the read pointer.
+- *   If the message is a large GSP message, r535_gsp_msgq_recv() calls
+- *   r535_gsp_msgq_recv_one_elem() repeatedly to receive continuation parts
+- *   until the complete message is received.
+- *   r535_gsp_msgq_recv() assembles the payloads of cotinuation parts into
+- *   the return of the large GSP message.
+- *
+- * - Free the allocated memory: r535_gsp_msg_done().
+- *   The user is responsible for freeing the memory allocated for the GSP
+- *   message pages after they have been processed.
+- */
+-static void *
+-r535_gsp_msgq_peek(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
+-{
+-      struct r535_gsp_msg *mqe;
+-      int ret;
+-
+-      ret = r535_gsp_msgq_wait(gsp, gsp_rpc_len, retries);
+-      if (ret < 0)
+-              return ERR_PTR(ret);
+-
+-      mqe = r535_gsp_msgq_get_entry(gsp);
+-
+-      return mqe->data;
+-}
+-
+-struct r535_gsp_msg_info {
+-      int *retries;
+-      u32 gsp_rpc_len;
+-      void *gsp_rpc_buf;
+-      bool continuation;
+-};
+-
+-static void
+-r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl);
+-
+-static void *
+-r535_gsp_msgq_recv_one_elem(struct nvkm_gsp *gsp,
+-                          struct r535_gsp_msg_info *info)
+-{
+-      u8 *buf = info->gsp_rpc_buf;
+-      u32 rptr = *gsp->msgq.rptr;
+-      struct r535_gsp_msg *mqe;
+-      u32 size, expected, len;
+-      int ret;
+-
+-      expected = info->gsp_rpc_len;
+-
+-      ret = r535_gsp_msgq_wait(gsp, expected, info->retries);
+-      if (ret < 0)
+-              return ERR_PTR(ret);
+-
+-      mqe = r535_gsp_msgq_get_entry(gsp);
+-
+-      if (info->continuation) {
+-              struct nvfw_gsp_rpc *rpc = (struct nvfw_gsp_rpc *)mqe->data;
+-
+-              if (rpc->function != NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD) {
+-                      nvkm_error(&gsp->subdev,
+-                                 "Not a continuation of a large RPC\n");
+-                      r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
+-                      return ERR_PTR(-EIO);
+-              }
+-      }
+-
+-      size = ALIGN(expected + GSP_MSG_HDR_SIZE, GSP_PAGE_SIZE);
+-
+-      len = ((gsp->msgq.cnt - rptr) * GSP_PAGE_SIZE) - sizeof(*mqe);
+-      len = min_t(u32, expected, len);
+-
+-      if (info->continuation)
+-              memcpy(buf, mqe->data + sizeof(struct nvfw_gsp_rpc),
+-                     len - sizeof(struct nvfw_gsp_rpc));
+-      else
+-              memcpy(buf, mqe->data, len);
+-
+-      expected -= len;
+-
+-      if (expected) {
+-              mqe = (void *)((u8 *)gsp->shm.msgq.ptr + 0x1000 + 0 * 0x1000);
+-              memcpy(buf + len, mqe, expected);
+-      }
+-
+-      rptr = (rptr + DIV_ROUND_UP(size, GSP_PAGE_SIZE)) % gsp->msgq.cnt;
+-
+-      mb();
+-      (*gsp->msgq.rptr) = rptr;
+-      return buf;
+-}
+-
+-static void *
+-r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
+-{
+-      struct r535_gsp_msg *mqe;
+-      const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*mqe);
+-      struct nvfw_gsp_rpc *rpc;
+-      struct r535_gsp_msg_info info = {0};
+-      u32 expected = gsp_rpc_len;
+-      void *buf;
+-
+-      mqe = r535_gsp_msgq_get_entry(gsp);
+-      rpc = (struct nvfw_gsp_rpc *)mqe->data;
+-
+-      if (WARN_ON(rpc->length > max_rpc_size))
+-              return NULL;
+-
+-      buf = kvmalloc(max_t(u32, rpc->length, expected), GFP_KERNEL);
+-      if (!buf)
+-              return ERR_PTR(-ENOMEM);
+-
+-      info.gsp_rpc_buf = buf;
+-      info.retries = retries;
+-      info.gsp_rpc_len = rpc->length;
+-
+-      buf = r535_gsp_msgq_recv_one_elem(gsp, &info);
+-      if (IS_ERR(buf)) {
+-              kvfree(info.gsp_rpc_buf);
+-              info.gsp_rpc_buf = NULL;
+-              return buf;
+-      }
+-
+-      if (expected <= max_rpc_size)
+-              return buf;
+-
+-      info.gsp_rpc_buf += info.gsp_rpc_len;
+-      expected -= info.gsp_rpc_len;
+-
+-      while (expected) {
+-              u32 size;
+-
+-              rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries);
+-              if (IS_ERR_OR_NULL(rpc)) {
+-                      kfree(buf);
+-                      return rpc;
+-              }
+-
+-              info.gsp_rpc_len = rpc->length;
+-              info.continuation = true;
+-
+-              rpc = r535_gsp_msgq_recv_one_elem(gsp, &info);
+-              if (IS_ERR_OR_NULL(rpc)) {
+-                      kfree(buf);
+-                      return rpc;
+-              }
+-
+-              size = info.gsp_rpc_len - sizeof(*rpc);
+-              expected -= size;
+-              info.gsp_rpc_buf += size;
+-      }
+-
+-      rpc = buf;
+-      rpc->length = gsp_rpc_len;
+-      return buf;
+-}
+-
+-static int
+-r535_gsp_cmdq_push(struct nvkm_gsp *gsp, void *rpc)
+-{
+-      struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg);
+-      struct r535_gsp_msg *cqe;
+-      u32 gsp_rpc_len = msg->checksum;
+-      u64 *ptr = (void *)msg;
+-      u64 *end;
+-      u64 csum = 0;
+-      int free, time = 1000000;
+-      u32 wptr, size, step, len;
+-      u32 off = 0;
+-
+-      len = ALIGN(GSP_MSG_HDR_SIZE + gsp_rpc_len, GSP_PAGE_SIZE);
+-
+-      end = (u64 *)((char *)ptr + len);
+-      msg->pad = 0;
+-      msg->checksum = 0;
+-      msg->sequence = gsp->cmdq.seq++;
+-      msg->elem_count = DIV_ROUND_UP(len, 0x1000);
+-
+-      while (ptr < end)
+-              csum ^= *ptr++;
+-
+-      msg->checksum = upper_32_bits(csum) ^ lower_32_bits(csum);
+-
+-      wptr = *gsp->cmdq.wptr;
+-      do {
+-              do {
+-                      free = *gsp->cmdq.rptr + gsp->cmdq.cnt - wptr - 1;
+-                      if (free >= gsp->cmdq.cnt)
+-                              free -= gsp->cmdq.cnt;
+-                      if (free >= 1)
+-                              break;
+-
+-                      usleep_range(1, 2);
+-              } while(--time);
+-
+-              if (WARN_ON(!time)) {
+-                      kvfree(msg);
+-                      return -ETIMEDOUT;
+-              }
+-
+-              cqe = (void *)((u8 *)gsp->shm.cmdq.ptr + 0x1000 + wptr * 0x1000);
+-              step = min_t(u32, free, (gsp->cmdq.cnt - wptr));
+-              size = min_t(u32, len, step * GSP_PAGE_SIZE);
+-
+-              memcpy(cqe, (u8 *)msg + off, size);
+-
+-              wptr += DIV_ROUND_UP(size, 0x1000);
+-              if (wptr == gsp->cmdq.cnt)
+-                      wptr = 0;
+-
+-              off  += size;
+-              len -= size;
+-      } while (len);
+-
+-      nvkm_trace(&gsp->subdev, "cmdq: wptr %d\n", wptr);
+-      wmb();
+-      (*gsp->cmdq.wptr) = wptr;
+-      mb();
+-
+-      nvkm_falcon_wr32(&gsp->falcon, 0xc00, 0x00000000);
+-
+-      kvfree(msg);
+-      return 0;
+-}
+-
+-static void *
+-r535_gsp_cmdq_get(struct nvkm_gsp *gsp, u32 gsp_rpc_len)
+-{
+-      struct r535_gsp_msg *msg;
+-      u32 size = GSP_MSG_HDR_SIZE + gsp_rpc_len;
+-
+-      size = ALIGN(size, GSP_MSG_MIN_SIZE);
+-      msg = kvzalloc(size, GFP_KERNEL);
+-      if (!msg)
+-              return ERR_PTR(-ENOMEM);
+-
+-      msg->checksum = gsp_rpc_len;
+-      return msg->data;
+-}
+-
+-static void
+-r535_gsp_msg_done(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg)
+-{
+-      kvfree(msg);
+-}
+-
+-static void
+-r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl)
+-{
+-      if (gsp->subdev.debug >= lvl) {
+-              nvkm_printk__(&gsp->subdev, lvl, info,
+-                            "msg fn:%d len:0x%x/0x%zx res:0x%x resp:0x%x\n",
+-                            msg->function, msg->length, msg->length - sizeof(*msg),
+-                            msg->rpc_result, msg->rpc_result_private);
+-              print_hex_dump(KERN_INFO, "msg: ", DUMP_PREFIX_OFFSET, 16, 1,
+-                             msg->data, msg->length - sizeof(*msg), true);
+-      }
+-}
+-
+-static struct nvfw_gsp_rpc *
+-r535_gsp_msg_recv(struct nvkm_gsp *gsp, int fn, u32 gsp_rpc_len)
+-{
+-      struct nvkm_subdev *subdev = &gsp->subdev;
+-      struct nvfw_gsp_rpc *rpc;
+-      int retries = 4000000, i;
+-
+-retry:
+-      rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), &retries);
+-      if (IS_ERR_OR_NULL(rpc))
+-              return rpc;
+-
+-      rpc = r535_gsp_msgq_recv(gsp, gsp_rpc_len, &retries);
+-      if (IS_ERR_OR_NULL(rpc))
+-              return rpc;
+-
+-      if (rpc->rpc_result) {
+-              r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
+-              r535_gsp_msg_done(gsp, rpc);
+-              return ERR_PTR(-EINVAL);
+-      }
+-
+-      r535_gsp_msg_dump(gsp, rpc, NV_DBG_TRACE);
+-
+-      if (fn && rpc->function == fn) {
+-              if (gsp_rpc_len) {
+-                      if (rpc->length < gsp_rpc_len) {
+-                              nvkm_error(subdev, "rpc len %d < %d\n",
+-                                         rpc->length, gsp_rpc_len);
+-                              r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
+-                              r535_gsp_msg_done(gsp, rpc);
+-                              return ERR_PTR(-EIO);
+-                      }
+-
+-                      return rpc;
+-              }
+-
+-              r535_gsp_msg_done(gsp, rpc);
+-              return NULL;
+-      }
+-
+-      for (i = 0; i < gsp->msgq.ntfy_nr; i++) {
+-              struct nvkm_gsp_msgq_ntfy *ntfy = &gsp->msgq.ntfy[i];
+-
+-              if (ntfy->fn == rpc->function) {
+-                      if (ntfy->func)
+-                              ntfy->func(ntfy->priv, ntfy->fn, rpc->data,
+-                                         rpc->length - sizeof(*rpc));
+-                      break;
+-              }
+-      }
+-
+-      if (i == gsp->msgq.ntfy_nr)
+-              r535_gsp_msg_dump(gsp, rpc, NV_DBG_WARN);
+-
+-      r535_gsp_msg_done(gsp, rpc);
+-      if (fn)
+-              goto retry;
+-
+-      if (*gsp->msgq.rptr != *gsp->msgq.wptr)
+-              goto retry;
+-
+-      return NULL;
+-}
+-
+-static int
+-r535_gsp_msg_ntfy_add(struct nvkm_gsp *gsp, u32 fn, nvkm_gsp_msg_ntfy_func func, void *priv)
+-{
+-      int ret = 0;
+-
+-      mutex_lock(&gsp->msgq.mutex);
+-      if (WARN_ON(gsp->msgq.ntfy_nr >= ARRAY_SIZE(gsp->msgq.ntfy))) {
+-              ret = -ENOSPC;
+-      } else {
+-              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].fn = fn;
+-              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].func = func;
+-              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].priv = priv;
+-              gsp->msgq.ntfy_nr++;
+-      }
+-      mutex_unlock(&gsp->msgq.mutex);
+-      return ret;
+-}
+-
+-static int
+-r535_gsp_rpc_poll(struct nvkm_gsp *gsp, u32 fn)
+-{
+-      void *repv;
+-
+-      mutex_lock(&gsp->cmdq.mutex);
+-      repv = r535_gsp_msg_recv(gsp, fn, 0);
+-      mutex_unlock(&gsp->cmdq.mutex);
+-      if (IS_ERR(repv))
+-              return PTR_ERR(repv);
+-
+-      return 0;
+-}
+-
+-static void *
+-r535_gsp_rpc_handle_reply(struct nvkm_gsp *gsp, u32 fn,
+-                        enum nvkm_gsp_rpc_reply_policy policy,
+-                        u32 gsp_rpc_len)
+-{
+-      struct nvfw_gsp_rpc *reply;
+-      void *repv = NULL;
+-
+-      switch (policy) {
+-      case NVKM_GSP_RPC_REPLY_NOWAIT:
+-              break;
+-      case NVKM_GSP_RPC_REPLY_RECV:
+-              reply = r535_gsp_msg_recv(gsp, fn, gsp_rpc_len);
+-              if (!IS_ERR_OR_NULL(reply))
+-                      repv = reply->data;
+-              else
+-                      repv = reply;
+-              break;
+-      case NVKM_GSP_RPC_REPLY_POLL:
+-              repv = r535_gsp_msg_recv(gsp, fn, 0);
+-              break;
+-      }
+-
+-      return repv;
+-}
+-
+-static void *
+-r535_gsp_rpc_send(struct nvkm_gsp *gsp, void *payload,
+-                enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len)
+-{
+-      struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc);
+-      u32 fn = rpc->function;
+-      int ret;
+-
+-      if (gsp->subdev.debug >= NV_DBG_TRACE) {
+-              nvkm_trace(&gsp->subdev, "rpc fn:%d len:0x%x/0x%zx\n", rpc->function,
+-                         rpc->length, rpc->length - sizeof(*rpc));
+-              print_hex_dump(KERN_INFO, "rpc: ", DUMP_PREFIX_OFFSET, 16, 1,
+-                             rpc->data, rpc->length - sizeof(*rpc), true);
+-      }
+-
+-      ret = r535_gsp_cmdq_push(gsp, rpc);
+-      if (ret)
+-              return ERR_PTR(ret);
+-
+-      return r535_gsp_rpc_handle_reply(gsp, fn, policy, gsp_rpc_len);
+-}
+-
+ static void
+ r535_gsp_event_dtor(struct nvkm_gsp_event *event)
+ {
+@@ -936,99 +365,9 @@ r535_gsp_rpc_rm_ctrl_get(struct nvkm_gsp_object *object, u32 cmd, u32 params_siz
+       return rpc->params;
+ }
+-static void
+-r535_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv)
+-{
+-      struct nvfw_gsp_rpc *rpc = container_of(repv, typeof(*rpc), data);
+-
+-      r535_gsp_msg_done(gsp, rpc);
+-}
+-
+-static void *
+-r535_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 payload_size)
+-{
+-      struct nvfw_gsp_rpc *rpc;
+-
+-      rpc = r535_gsp_cmdq_get(gsp, ALIGN(sizeof(*rpc) + payload_size,
+-                                         sizeof(u64)));
+-      if (IS_ERR(rpc))
+-              return ERR_CAST(rpc);
+-
+-      rpc->header_version = 0x03000000;
+-      rpc->signature = ('C' << 24) | ('P' << 16) | ('R' << 8) | 'V';
+-      rpc->function = fn;
+-      rpc->rpc_result = 0xffffffff;
+-      rpc->rpc_result_private = 0xffffffff;
+-      rpc->length = sizeof(*rpc) + payload_size;
+-      return rpc->data;
+-}
+-
+-static void *
+-r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload,
+-                enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len)
+-{
+-      struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc);
+-      struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg);
+-      const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*msg);
+-      const u32 max_payload_size = max_rpc_size - sizeof(*rpc);
+-      u32 payload_size = rpc->length - sizeof(*rpc);
+-      void *repv;
+-
+-      mutex_lock(&gsp->cmdq.mutex);
+-      if (payload_size > max_payload_size) {
+-              const u32 fn = rpc->function;
+-              u32 remain_payload_size = payload_size;
+-
+-              /* Adjust length, and send initial RPC. */
+-              rpc->length = sizeof(*rpc) + max_payload_size;
+-              msg->checksum = rpc->length;
+-
+-              repv = r535_gsp_rpc_send(gsp, payload, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
+-              if (IS_ERR(repv))
+-                      goto done;
+-
+-              payload += max_payload_size;
+-              remain_payload_size -= max_payload_size;
+-
+-              /* Remaining chunks sent as CONTINUATION_RECORD RPCs. */
+-              while (remain_payload_size) {
+-                      u32 size = min(remain_payload_size,
+-                                     max_payload_size);
+-                      void *next;
+-
+-                      next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size);
+-                      if (IS_ERR(next)) {
+-                              repv = next;
+-                              goto done;
+-                      }
+-
+-                      memcpy(next, payload, size);
+-
+-                      repv = r535_gsp_rpc_send(gsp, next, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
+-                      if (IS_ERR(repv))
+-                              goto done;
+-
+-                      payload += size;
+-                      remain_payload_size -= size;
+-              }
+-
+-              /* Wait for reply. */
+-              repv = r535_gsp_rpc_handle_reply(gsp, fn, policy, payload_size +
+-                                               sizeof(*rpc));
+-      } else {
+-              repv = r535_gsp_rpc_send(gsp, payload, policy, gsp_rpc_len);
+-      }
+-
+-done:
+-      mutex_unlock(&gsp->cmdq.mutex);
+-      return repv;
+-}
+-
+ const struct nvkm_gsp_rm
+ r535_gsp_rm = {
+-      .rpc_get = r535_gsp_rpc_get,
+-      .rpc_push = r535_gsp_rpc_push,
+-      .rpc_done = r535_gsp_rpc_done,
++      .api = &r535_rm,
+       .rm_ctrl_get = r535_gsp_rpc_rm_ctrl_get,
+       .rm_ctrl_push = r535_gsp_rpc_rm_ctrl_push,
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
+new file mode 100644
+index 0000000000000..1c07740215ec5
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/Kbuild
+@@ -0,0 +1,5 @@
++# SPDX-License-Identifier: MIT
++#
++# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
++
++include $(src)/nvkm/subdev/gsp/rm/r535/Kbuild
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild
+new file mode 100644
+index 0000000000000..21c818ec07016
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/Kbuild
+@@ -0,0 +1,6 @@
++# SPDX-License-Identifier: MIT
++#
++# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
++
++nvkm-y += nvkm/subdev/gsp/rm/r535/rm.o
++nvkm-y += nvkm/subdev/gsp/rm/r535/rpc.o
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c
+new file mode 100644
+index 0000000000000..f28b781abc5c7
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rm.c
+@@ -0,0 +1,10 @@
++/* SPDX-License-Identifier: MIT
++ *
++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
++ */
++#include <rm/rm.h>
++
++const struct nvkm_rm_api
++r535_rm = {
++      .rpc = &r535_rpc,
++};
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
+new file mode 100644
+index 0000000000000..ffb4104a7d8cd
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/rpc.c
+@@ -0,0 +1,692 @@
++/*
++ * Copyright 2023 Red Hat Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ */
++#include <rm/rpc.h>
++
++#include <nvrm/nvtypes.h>
++#include <nvrm/535.113.01/nvidia/kernel/inc/vgpu/rpc_global_enums.h>
++
++#define GSP_MSG_MIN_SIZE GSP_PAGE_SIZE
++#define GSP_MSG_MAX_SIZE (GSP_MSG_MIN_SIZE * 16)
++
++/**
++ * DOC: GSP message queue element
++ *
++ * https://github.com/NVIDIA/open-gpu-kernel-modules/blob/535/src/nvidia/inc/kernel/gpu/gsp/message_queue_priv.h
++ *
++ * The GSP command queue and status queue are message queues for the
++ * communication between software and GSP. The software submits the GSP
++ * RPC via the GSP command queue, GSP writes the status of the submitted
++ * RPC in the status queue.
++ *
++ * A GSP message queue element consists of three parts:
++ *
++ * - message element header (struct r535_gsp_msg), which mostly maintains
++ *   the metadata for queuing the element.
++ *
++ * - RPC message header (struct nvfw_gsp_rpc), which maintains the info
++ *   of the RPC. E.g., the RPC function number.
++ *
++ * - The payload, where the RPC message stays. E.g. the params of a
++ *   specific RPC function. Some RPC functions also have their headers
++ *   in the payload. E.g. rm_alloc, rm_control.
++ *
++ * The memory layout of a GSP message element can be illustrated below::
++ *
++ *    +------------------------+
++ *    | Message Element Header |
++ *    |    (r535_gsp_msg)      |
++ *    |                        |
++ *    | (r535_gsp_msg.data)    |
++ *    |          |             |
++ *    |----------V-------------|
++ *    |    GSP RPC Header      |
++ *    |    (nvfw_gsp_rpc)      |
++ *    |                        |
++ *    | (nvfw_gsp_rpc.data)    |
++ *    |          |             |
++ *    |----------V-------------|
++ *    |       Payload          |
++ *    |                        |
++ *    |   header(optional)     |
++ *    |        params          |
++ *    +------------------------+
++ *
++ * The max size of a message queue element is 16 pages (including the
++ * headers). When a GSP message to be sent is larger than 16 pages, the
++ * message should be split into multiple elements and sent accordingly.
++ *
++ * In the bunch of the split elements, the first element has the expected
++ * function number, while the rest of the elements are sent with the
++ * function number NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD.
++ *
++ * GSP consumes the elements from the cmdq and always writes the result
++ * back to the msgq. The result is also formed as split elements.
++ *
++ * Terminology:
++ *
++ * - gsp_msg(msg): GSP message element (element header + GSP RPC header +
++ *   payload)
++ * - gsp_rpc(rpc): GSP RPC (RPC header + payload)
++ * - gsp_rpc_buf: buffer for (GSP RPC header + payload)
++ * - gsp_rpc_len: size of (GSP RPC header + payload)
++ * - params_size: size of params in the payload
++ * - payload_size: size of (header if exists + params) in the payload
++ */
++
++struct r535_gsp_msg {
++      u8 auth_tag_buffer[16];
++      u8 aad_buffer[16];
++      u32 checksum;
++      u32 sequence;
++      u32 elem_count;
++      u32 pad;
++      u8  data[];
++};
++
++struct nvfw_gsp_rpc {
++      u32 header_version;
++      u32 signature;
++      u32 length;
++      u32 function;
++      u32 rpc_result;
++      u32 rpc_result_private;
++      u32 sequence;
++      union {
++              u32 spare;
++              u32 cpuRmGfid;
++      };
++      u8  data[];
++};
++
++#define GSP_MSG_HDR_SIZE offsetof(struct r535_gsp_msg, data)
++
++#define to_gsp_hdr(p, header) \
++      container_of((void *)p, typeof(*header), data)
++
++#define to_payload_hdr(p, header) \
++      container_of((void *)p, typeof(*header), params)
++
++int
++r535_rpc_status_to_errno(uint32_t rpc_status)
++{
++      switch (rpc_status) {
++      case 0x55: /* NV_ERR_NOT_READY */
++      case 0x66: /* NV_ERR_TIMEOUT_RETRY */
++              return -EBUSY;
++      case 0x51: /* NV_ERR_NO_MEMORY */
++              return -ENOMEM;
++      default:
++              return -EINVAL;
++      }
++}
++
++static int
++r535_gsp_msgq_wait(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *ptime)
++{
++      u32 size, rptr = *gsp->msgq.rptr;
++      int used;
++
++      size = DIV_ROUND_UP(GSP_MSG_HDR_SIZE + gsp_rpc_len,
++                          GSP_PAGE_SIZE);
++      if (WARN_ON(!size || size >= gsp->msgq.cnt))
++              return -EINVAL;
++
++      do {
++              u32 wptr = *gsp->msgq.wptr;
++
++              used = wptr + gsp->msgq.cnt - rptr;
++              if (used >= gsp->msgq.cnt)
++                      used -= gsp->msgq.cnt;
++              if (used >= size)
++                      break;
++
++              usleep_range(1, 2);
++      } while (--(*ptime));
++
++      if (WARN_ON(!*ptime))
++              return -ETIMEDOUT;
++
++      return used;
++}
++
++static struct r535_gsp_msg *
++r535_gsp_msgq_get_entry(struct nvkm_gsp *gsp)
++{
++      u32 rptr = *gsp->msgq.rptr;
++
++      /* Skip the first page, which is the message queue info */
++      return (void *)((u8 *)gsp->shm.msgq.ptr + GSP_PAGE_SIZE +
++             rptr * GSP_PAGE_SIZE);
++}
++
++/**
++ * DOC: Receive a GSP message queue element
++ *
++ * Receiving a GSP message queue element from the message queue consists of
++ * the following steps:
++ *
++ * - Peek the element from the queue: r535_gsp_msgq_peek().
++ *   Peek the first page of the element to determine the total size of the
++ *   message before allocating the proper memory.
++ *
++ * - Allocate memory for the message.
++ *   Once the total size of the message is determined from the GSP message
++ *   queue element, the caller of r535_gsp_msgq_recv() allocates the
++ *   required memory.
++ *
++ * - Receive the message: r535_gsp_msgq_recv().
++ *   Copy the message into the allocated memory. Advance the read pointer.
++ *   If the message is a large GSP message, r535_gsp_msgq_recv() calls
++ *   r535_gsp_msgq_recv_one_elem() repeatedly to receive continuation parts
++ *   until the complete message is received.
++ *   r535_gsp_msgq_recv() assembles the payloads of cotinuation parts into
++ *   the return of the large GSP message.
++ *
++ * - Free the allocated memory: r535_gsp_msg_done().
++ *   The user is responsible for freeing the memory allocated for the GSP
++ *   message pages after they have been processed.
++ */
++static void *
++r535_gsp_msgq_peek(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
++{
++      struct r535_gsp_msg *mqe;
++      int ret;
++
++      ret = r535_gsp_msgq_wait(gsp, gsp_rpc_len, retries);
++      if (ret < 0)
++              return ERR_PTR(ret);
++
++      mqe = r535_gsp_msgq_get_entry(gsp);
++
++      return mqe->data;
++}
++
++struct r535_gsp_msg_info {
++      int *retries;
++      u32 gsp_rpc_len;
++      void *gsp_rpc_buf;
++      bool continuation;
++};
++
++static void
++r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl);
++
++static void *
++r535_gsp_msgq_recv_one_elem(struct nvkm_gsp *gsp,
++                          struct r535_gsp_msg_info *info)
++{
++      u8 *buf = info->gsp_rpc_buf;
++      u32 rptr = *gsp->msgq.rptr;
++      struct r535_gsp_msg *mqe;
++      u32 size, expected, len;
++      int ret;
++
++      expected = info->gsp_rpc_len;
++
++      ret = r535_gsp_msgq_wait(gsp, expected, info->retries);
++      if (ret < 0)
++              return ERR_PTR(ret);
++
++      mqe = r535_gsp_msgq_get_entry(gsp);
++
++      if (info->continuation) {
++              struct nvfw_gsp_rpc *rpc = (struct nvfw_gsp_rpc *)mqe->data;
++
++              if (rpc->function != NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD) {
++                      nvkm_error(&gsp->subdev,
++                                 "Not a continuation of a large RPC\n");
++                      r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
++                      return ERR_PTR(-EIO);
++              }
++      }
++
++      size = ALIGN(expected + GSP_MSG_HDR_SIZE, GSP_PAGE_SIZE);
++
++      len = ((gsp->msgq.cnt - rptr) * GSP_PAGE_SIZE) - sizeof(*mqe);
++      len = min_t(u32, expected, len);
++
++      if (info->continuation)
++              memcpy(buf, mqe->data + sizeof(struct nvfw_gsp_rpc),
++                     len - sizeof(struct nvfw_gsp_rpc));
++      else
++              memcpy(buf, mqe->data, len);
++
++      expected -= len;
++
++      if (expected) {
++              mqe = (void *)((u8 *)gsp->shm.msgq.ptr + 0x1000 + 0 * 0x1000);
++              memcpy(buf + len, mqe, expected);
++      }
++
++      rptr = (rptr + DIV_ROUND_UP(size, GSP_PAGE_SIZE)) % gsp->msgq.cnt;
++
++      mb();
++      (*gsp->msgq.rptr) = rptr;
++      return buf;
++}
++
++static void *
++r535_gsp_msgq_recv(struct nvkm_gsp *gsp, u32 gsp_rpc_len, int *retries)
++{
++      struct r535_gsp_msg *mqe;
++      const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*mqe);
++      struct nvfw_gsp_rpc *rpc;
++      struct r535_gsp_msg_info info = {0};
++      u32 expected = gsp_rpc_len;
++      void *buf;
++
++      mqe = r535_gsp_msgq_get_entry(gsp);
++      rpc = (struct nvfw_gsp_rpc *)mqe->data;
++
++      if (WARN_ON(rpc->length > max_rpc_size))
++              return NULL;
++
++      buf = kvmalloc(max_t(u32, rpc->length, expected), GFP_KERNEL);
++      if (!buf)
++              return ERR_PTR(-ENOMEM);
++
++      info.gsp_rpc_buf = buf;
++      info.retries = retries;
++      info.gsp_rpc_len = rpc->length;
++
++      buf = r535_gsp_msgq_recv_one_elem(gsp, &info);
++      if (IS_ERR(buf)) {
++              kvfree(info.gsp_rpc_buf);
++              info.gsp_rpc_buf = NULL;
++              return buf;
++      }
++
++      if (expected <= max_rpc_size)
++              return buf;
++
++      info.gsp_rpc_buf += info.gsp_rpc_len;
++      expected -= info.gsp_rpc_len;
++
++      while (expected) {
++              u32 size;
++
++              rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), info.retries);
++              if (IS_ERR_OR_NULL(rpc)) {
++                      kfree(buf);
++                      return rpc;
++              }
++
++              info.gsp_rpc_len = rpc->length;
++              info.continuation = true;
++
++              rpc = r535_gsp_msgq_recv_one_elem(gsp, &info);
++              if (IS_ERR_OR_NULL(rpc)) {
++                      kfree(buf);
++                      return rpc;
++              }
++
++              size = info.gsp_rpc_len - sizeof(*rpc);
++              expected -= size;
++              info.gsp_rpc_buf += size;
++      }
++
++      rpc = buf;
++      rpc->length = gsp_rpc_len;
++      return buf;
++}
++
++static int
++r535_gsp_cmdq_push(struct nvkm_gsp *gsp, void *rpc)
++{
++      struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg);
++      struct r535_gsp_msg *cqe;
++      u32 gsp_rpc_len = msg->checksum;
++      u64 *ptr = (void *)msg;
++      u64 *end;
++      u64 csum = 0;
++      int free, time = 1000000;
++      u32 wptr, size, step, len;
++      u32 off = 0;
++
++      len = ALIGN(GSP_MSG_HDR_SIZE + gsp_rpc_len, GSP_PAGE_SIZE);
++
++      end = (u64 *)((char *)ptr + len);
++      msg->pad = 0;
++      msg->checksum = 0;
++      msg->sequence = gsp->cmdq.seq++;
++      msg->elem_count = DIV_ROUND_UP(len, 0x1000);
++
++      while (ptr < end)
++              csum ^= *ptr++;
++
++      msg->checksum = upper_32_bits(csum) ^ lower_32_bits(csum);
++
++      wptr = *gsp->cmdq.wptr;
++      do {
++              do {
++                      free = *gsp->cmdq.rptr + gsp->cmdq.cnt - wptr - 1;
++                      if (free >= gsp->cmdq.cnt)
++                              free -= gsp->cmdq.cnt;
++                      if (free >= 1)
++                              break;
++
++                      usleep_range(1, 2);
++              } while(--time);
++
++              if (WARN_ON(!time)) {
++                      kvfree(msg);
++                      return -ETIMEDOUT;
++              }
++
++              cqe = (void *)((u8 *)gsp->shm.cmdq.ptr + 0x1000 + wptr * 0x1000);
++              step = min_t(u32, free, (gsp->cmdq.cnt - wptr));
++              size = min_t(u32, len, step * GSP_PAGE_SIZE);
++
++              memcpy(cqe, (u8 *)msg + off, size);
++
++              wptr += DIV_ROUND_UP(size, 0x1000);
++              if (wptr == gsp->cmdq.cnt)
++                      wptr = 0;
++
++              off  += size;
++              len -= size;
++      } while (len);
++
++      nvkm_trace(&gsp->subdev, "cmdq: wptr %d\n", wptr);
++      wmb();
++      (*gsp->cmdq.wptr) = wptr;
++      mb();
++
++      nvkm_falcon_wr32(&gsp->falcon, 0xc00, 0x00000000);
++
++      kvfree(msg);
++      return 0;
++}
++
++static void *
++r535_gsp_cmdq_get(struct nvkm_gsp *gsp, u32 gsp_rpc_len)
++{
++      struct r535_gsp_msg *msg;
++      u32 size = GSP_MSG_HDR_SIZE + gsp_rpc_len;
++
++      size = ALIGN(size, GSP_MSG_MIN_SIZE);
++      msg = kvzalloc(size, GFP_KERNEL);
++      if (!msg)
++              return ERR_PTR(-ENOMEM);
++
++      msg->checksum = gsp_rpc_len;
++      return msg->data;
++}
++
++static void
++r535_gsp_msg_done(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg)
++{
++      kvfree(msg);
++}
++
++static void
++r535_gsp_msg_dump(struct nvkm_gsp *gsp, struct nvfw_gsp_rpc *msg, int lvl)
++{
++      if (gsp->subdev.debug >= lvl) {
++              nvkm_printk__(&gsp->subdev, lvl, info,
++                            "msg fn:%d len:0x%x/0x%zx res:0x%x resp:0x%x\n",
++                            msg->function, msg->length, msg->length - sizeof(*msg),
++                            msg->rpc_result, msg->rpc_result_private);
++              print_hex_dump(KERN_INFO, "msg: ", DUMP_PREFIX_OFFSET, 16, 1,
++                             msg->data, msg->length - sizeof(*msg), true);
++      }
++}
++
++struct nvfw_gsp_rpc *
++r535_gsp_msg_recv(struct nvkm_gsp *gsp, int fn, u32 gsp_rpc_len)
++{
++      struct nvkm_subdev *subdev = &gsp->subdev;
++      struct nvfw_gsp_rpc *rpc;
++      int retries = 4000000, i;
++
++retry:
++      rpc = r535_gsp_msgq_peek(gsp, sizeof(*rpc), &retries);
++      if (IS_ERR_OR_NULL(rpc))
++              return rpc;
++
++      rpc = r535_gsp_msgq_recv(gsp, gsp_rpc_len, &retries);
++      if (IS_ERR_OR_NULL(rpc))
++              return rpc;
++
++      if (rpc->rpc_result) {
++              r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
++              r535_gsp_msg_done(gsp, rpc);
++              return ERR_PTR(-EINVAL);
++      }
++
++      r535_gsp_msg_dump(gsp, rpc, NV_DBG_TRACE);
++
++      if (fn && rpc->function == fn) {
++              if (gsp_rpc_len) {
++                      if (rpc->length < gsp_rpc_len) {
++                              nvkm_error(subdev, "rpc len %d < %d\n",
++                                         rpc->length, gsp_rpc_len);
++                              r535_gsp_msg_dump(gsp, rpc, NV_DBG_ERROR);
++                              r535_gsp_msg_done(gsp, rpc);
++                              return ERR_PTR(-EIO);
++                      }
++
++                      return rpc;
++              }
++
++              r535_gsp_msg_done(gsp, rpc);
++              return NULL;
++      }
++
++      for (i = 0; i < gsp->msgq.ntfy_nr; i++) {
++              struct nvkm_gsp_msgq_ntfy *ntfy = &gsp->msgq.ntfy[i];
++
++              if (ntfy->fn == rpc->function) {
++                      if (ntfy->func)
++                              ntfy->func(ntfy->priv, ntfy->fn, rpc->data,
++                                         rpc->length - sizeof(*rpc));
++                      break;
++              }
++      }
++
++      if (i == gsp->msgq.ntfy_nr)
++              r535_gsp_msg_dump(gsp, rpc, NV_DBG_WARN);
++
++      r535_gsp_msg_done(gsp, rpc);
++      if (fn)
++              goto retry;
++
++      if (*gsp->msgq.rptr != *gsp->msgq.wptr)
++              goto retry;
++
++      return NULL;
++}
++
++int
++r535_gsp_msg_ntfy_add(struct nvkm_gsp *gsp, u32 fn, nvkm_gsp_msg_ntfy_func func, void *priv)
++{
++      int ret = 0;
++
++      mutex_lock(&gsp->msgq.mutex);
++      if (WARN_ON(gsp->msgq.ntfy_nr >= ARRAY_SIZE(gsp->msgq.ntfy))) {
++              ret = -ENOSPC;
++      } else {
++              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].fn = fn;
++              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].func = func;
++              gsp->msgq.ntfy[gsp->msgq.ntfy_nr].priv = priv;
++              gsp->msgq.ntfy_nr++;
++      }
++      mutex_unlock(&gsp->msgq.mutex);
++      return ret;
++}
++
++int
++r535_gsp_rpc_poll(struct nvkm_gsp *gsp, u32 fn)
++{
++      void *repv;
++
++      mutex_lock(&gsp->cmdq.mutex);
++      repv = r535_gsp_msg_recv(gsp, fn, 0);
++      mutex_unlock(&gsp->cmdq.mutex);
++      if (IS_ERR(repv))
++              return PTR_ERR(repv);
++
++      return 0;
++}
++
++static void *
++r535_gsp_rpc_handle_reply(struct nvkm_gsp *gsp, u32 fn,
++                        enum nvkm_gsp_rpc_reply_policy policy,
++                        u32 gsp_rpc_len)
++{
++      struct nvfw_gsp_rpc *reply;
++      void *repv = NULL;
++
++      switch (policy) {
++      case NVKM_GSP_RPC_REPLY_NOWAIT:
++              break;
++      case NVKM_GSP_RPC_REPLY_RECV:
++              reply = r535_gsp_msg_recv(gsp, fn, gsp_rpc_len);
++              if (!IS_ERR_OR_NULL(reply))
++                      repv = reply->data;
++              else
++                      repv = reply;
++              break;
++      case NVKM_GSP_RPC_REPLY_POLL:
++              repv = r535_gsp_msg_recv(gsp, fn, 0);
++              break;
++      }
++
++      return repv;
++}
++
++static void *
++r535_gsp_rpc_send(struct nvkm_gsp *gsp, void *payload,
++                enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len)
++{
++      struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc);
++      u32 fn = rpc->function;
++      int ret;
++
++      if (gsp->subdev.debug >= NV_DBG_TRACE) {
++              nvkm_trace(&gsp->subdev, "rpc fn:%d len:0x%x/0x%zx\n", rpc->function,
++                         rpc->length, rpc->length - sizeof(*rpc));
++              print_hex_dump(KERN_INFO, "rpc: ", DUMP_PREFIX_OFFSET, 16, 1,
++                             rpc->data, rpc->length - sizeof(*rpc), true);
++      }
++
++      ret = r535_gsp_cmdq_push(gsp, rpc);
++      if (ret)
++              return ERR_PTR(ret);
++
++      return r535_gsp_rpc_handle_reply(gsp, fn, policy, gsp_rpc_len);
++}
++
++static void
++r535_gsp_rpc_done(struct nvkm_gsp *gsp, void *repv)
++{
++      struct nvfw_gsp_rpc *rpc = container_of(repv, typeof(*rpc), data);
++
++      r535_gsp_msg_done(gsp, rpc);
++}
++
++static void *
++r535_gsp_rpc_get(struct nvkm_gsp *gsp, u32 fn, u32 payload_size)
++{
++      struct nvfw_gsp_rpc *rpc;
++
++      rpc = r535_gsp_cmdq_get(gsp, ALIGN(sizeof(*rpc) + payload_size,
++                                         sizeof(u64)));
++      if (IS_ERR(rpc))
++              return ERR_CAST(rpc);
++
++      rpc->header_version = 0x03000000;
++      rpc->signature = ('C' << 24) | ('P' << 16) | ('R' << 8) | 'V';
++      rpc->function = fn;
++      rpc->rpc_result = 0xffffffff;
++      rpc->rpc_result_private = 0xffffffff;
++      rpc->length = sizeof(*rpc) + payload_size;
++      return rpc->data;
++}
++
++static void *
++r535_gsp_rpc_push(struct nvkm_gsp *gsp, void *payload,
++                enum nvkm_gsp_rpc_reply_policy policy, u32 gsp_rpc_len)
++{
++      struct nvfw_gsp_rpc *rpc = to_gsp_hdr(payload, rpc);
++      struct r535_gsp_msg *msg = to_gsp_hdr(rpc, msg);
++      const u32 max_rpc_size = GSP_MSG_MAX_SIZE - sizeof(*msg);
++      const u32 max_payload_size = max_rpc_size - sizeof(*rpc);
++      u32 payload_size = rpc->length - sizeof(*rpc);
++      void *repv;
++
++      mutex_lock(&gsp->cmdq.mutex);
++      if (payload_size > max_payload_size) {
++              const u32 fn = rpc->function;
++              u32 remain_payload_size = payload_size;
++
++              /* Adjust length, and send initial RPC. */
++              rpc->length = sizeof(*rpc) + max_payload_size;
++              msg->checksum = rpc->length;
++
++              repv = r535_gsp_rpc_send(gsp, payload, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
++              if (IS_ERR(repv))
++                      goto done;
++
++              payload += max_payload_size;
++              remain_payload_size -= max_payload_size;
++
++              /* Remaining chunks sent as CONTINUATION_RECORD RPCs. */
++              while (remain_payload_size) {
++                      u32 size = min(remain_payload_size,
++                                     max_payload_size);
++                      void *next;
++
++                      next = r535_gsp_rpc_get(gsp, NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD, size);
++                      if (IS_ERR(next)) {
++                              repv = next;
++                              goto done;
++                      }
++
++                      memcpy(next, payload, size);
++
++                      repv = r535_gsp_rpc_send(gsp, next, NVKM_GSP_RPC_REPLY_NOWAIT, 0);
++                      if (IS_ERR(repv))
++                              goto done;
++
++                      payload += size;
++                      remain_payload_size -= size;
++              }
++
++              /* Wait for reply. */
++              repv = r535_gsp_rpc_handle_reply(gsp, fn, policy, payload_size +
++                                               sizeof(*rpc));
++      } else {
++              repv = r535_gsp_rpc_send(gsp, payload, policy, gsp_rpc_len);
++      }
++
++done:
++      mutex_unlock(&gsp->cmdq.mutex);
++      return repv;
++}
++
++const struct nvkm_rm_api_rpc
++r535_rpc = {
++      .get = r535_gsp_rpc_get,
++      .push = r535_gsp_rpc_push,
++      .done = r535_gsp_rpc_done,
++};
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
+new file mode 100644
+index 0000000000000..7a0ece9791671
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rm.h
+@@ -0,0 +1,20 @@
++/* SPDX-License-Identifier: MIT
++ *
++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
++ */
++#include <subdev/gsp.h>
++#ifndef __NVKM_RM_H__
++#define __NVKM_RM_H__
++
++struct nvkm_rm_api {
++      const struct nvkm_rm_api_rpc {
++              void *(*get)(struct nvkm_gsp *, u32 fn, u32 argc);
++              void *(*push)(struct nvkm_gsp *gsp, void *argv,
++                            enum nvkm_gsp_rpc_reply_policy policy, u32 repc);
++              void (*done)(struct nvkm_gsp *gsp, void *repv);
++      } *rpc;
++};
++
++extern const struct nvkm_rm_api r535_rm;
++extern const struct nvkm_rm_api_rpc r535_rpc;
++#endif
+diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h
+new file mode 100644
+index 0000000000000..4431e33b33049
+--- /dev/null
++++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/rpc.h
+@@ -0,0 +1,18 @@
++/* SPDX-License-Identifier: MIT
++ *
++ * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
++ */
++#ifndef __NVKM_RM_RPC_H__
++#define __NVKM_RM_RPC_H__
++#include "rm.h"
++
++#define to_payload_hdr(p, header) \
++      container_of((void *)p, typeof(*header), params)
++
++int r535_gsp_rpc_poll(struct nvkm_gsp *, u32 fn);
++
++struct nvfw_gsp_rpc *r535_gsp_msg_recv(struct nvkm_gsp *, int fn, u32 gsp_rpc_len);
++int r535_gsp_msg_ntfy_add(struct nvkm_gsp *, u32 fn, nvkm_gsp_msg_ntfy_func, void *priv);
++
++int r535_rpc_status_to_errno(uint32_t rpc_status);
++#endif
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-ssd130x-fix-ssd132x_clear_screen-columns.patch b/queue-6.15/drm-ssd130x-fix-ssd132x_clear_screen-columns.patch
new file mode 100644 (file)
index 0000000..4ec131c
--- /dev/null
@@ -0,0 +1,38 @@
+From 45002d4eace58647fde0c7c78d9939b837a87b31 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Jun 2025 12:13:06 +0100
+Subject: drm/ssd130x: fix ssd132x_clear_screen() columns
+
+From: John Keeping <jkeeping@inmusicbrands.com>
+
+[ Upstream commit e479da4054875c4cc53a7fb956ebff03d2dac939 ]
+
+The number of columns relates to the width, not the height.  Use the
+correct variable.
+
+Signed-off-by: John Keeping <jkeeping@inmusicbrands.com>
+Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
+Fixes: fdd591e00a9c ("drm/ssd130x: Add support for the SSD132x OLED controller family")
+Link: https://lore.kernel.org/r/20250611111307.1814876-1-jkeeping@inmusicbrands.com
+Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/solomon/ssd130x.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c
+index dd2006d51c7a2..eec43d1a55951 100644
+--- a/drivers/gpu/drm/solomon/ssd130x.c
++++ b/drivers/gpu/drm/solomon/ssd130x.c
+@@ -974,7 +974,7 @@ static void ssd130x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
+ static void ssd132x_clear_screen(struct ssd130x_device *ssd130x, u8 *data_array)
+ {
+-      unsigned int columns = DIV_ROUND_UP(ssd130x->height, SSD132X_SEGMENT_WIDTH);
++      unsigned int columns = DIV_ROUND_UP(ssd130x->width, SSD132X_SEGMENT_WIDTH);
+       unsigned int height = ssd130x->height;
+       memset(data_array, 0, columns * height);
+-- 
+2.39.5
+
diff --git a/queue-6.15/drm-xe-bmg-update-wa_16023588340.patch b/queue-6.15/drm-xe-bmg-update-wa_16023588340.patch
new file mode 100644 (file)
index 0000000..2e11d68
--- /dev/null
@@ -0,0 +1,43 @@
+From 931688d922fdec64df5b9644a62530fe0b9cde1d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Jun 2025 00:09:01 -0700
+Subject: drm/xe/bmg: Update Wa_16023588340
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+
+[ Upstream commit 16c1241b08751a67cd7a0221ea9f82b0b02806f4 ]
+
+This allows for additional L2 caching modes.
+
+Fixes: 01570b446939 ("drm/xe/bmg: implement Wa_16023588340")
+Cc: Matthew Auld <matthew.auld@intel.com>
+Reviewed-by: Matthew Auld <matthew.auld@intel.com>
+Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
+Link: https://lore.kernel.org/r/20250612-wa-14022085890-v4-2-94ba5dcc1e30@intel.com
+Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
+(cherry picked from commit 6ab42fa03d4c88a0ddf5e56e62794853b198e7bf)
+Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/gpu/drm/xe/xe_gt.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c
+index 66198cf2662c5..4bad8894fa12c 100644
+--- a/drivers/gpu/drm/xe/xe_gt.c
++++ b/drivers/gpu/drm/xe/xe_gt.c
+@@ -116,7 +116,7 @@ static void xe_gt_enable_host_l2_vram(struct xe_gt *gt)
+               xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
+       }
+-      xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0x3);
++      xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0xF);
+       xe_force_wake_put(gt_to_fw(gt), fw_ref);
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/e1000e-set-fixed-clock-frequency-indication-for-nahu.patch b/queue-6.15/e1000e-set-fixed-clock-frequency-indication-for-nahu.patch
new file mode 100644 (file)
index 0000000..9b24ecf
--- /dev/null
@@ -0,0 +1,90 @@
+From 34c831c96435d9bbfa641e13bf8d703a813d9f23 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 25 May 2025 11:38:43 +0300
+Subject: e1000e: set fixed clock frequency indication for Nahum 11 and Nahum
+ 13
+
+From: Vitaly Lifshits <vitaly.lifshits@intel.com>
+
+[ Upstream commit 688a0d61b2d7427189c4eb036ce485d8fc957cbb ]
+
+On some systems with Nahum 11 and Nahum 13 the value of the XTAL clock in
+the software STRAP is incorrect. This causes the PTP timer to run at the
+wrong rate and can lead to synchronization issues.
+
+The STRAP value is configured by the system firmware, and a firmware
+update is not always possible. Since the XTAL clock on these systems
+always runs at 38.4MHz, the driver may ignore the STRAP and just set
+the correct value.
+
+Fixes: cc23f4f0b6b9 ("e1000e: Add support for Meteor Lake")
+Signed-off-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
+Tested-by: Mor Bar-Gabay <morx.bar.gabay@intel.com>
+Reviewed-by: Gil Fine <gil.fine@linux.intel.com>
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/e1000e/netdev.c | 14 +++++++++++---
+ drivers/net/ethernet/intel/e1000e/ptp.c    |  8 +++++---
+ 2 files changed, 16 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
+index 8ebcb6a7d608a..a0045aa9550b5 100644
+--- a/drivers/net/ethernet/intel/e1000e/netdev.c
++++ b/drivers/net/ethernet/intel/e1000e/netdev.c
+@@ -3534,9 +3534,6 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
+       case e1000_pch_cnp:
+       case e1000_pch_tgp:
+       case e1000_pch_adp:
+-      case e1000_pch_mtp:
+-      case e1000_pch_lnp:
+-      case e1000_pch_ptp:
+       case e1000_pch_nvp:
+               if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) {
+                       /* Stable 24MHz frequency */
+@@ -3552,6 +3549,17 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca)
+                       adapter->cc.shift = shift;
+               }
+               break;
++      case e1000_pch_mtp:
++      case e1000_pch_lnp:
++      case e1000_pch_ptp:
++              /* System firmware can misreport this value, so set it to a
++               * stable 38400KHz frequency.
++               */
++              incperiod = INCPERIOD_38400KHZ;
++              incvalue = INCVALUE_38400KHZ;
++              shift = INCVALUE_SHIFT_38400KHZ;
++              adapter->cc.shift = shift;
++              break;
+       case e1000_82574:
+       case e1000_82583:
+               /* Stable 25MHz frequency */
+diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
+index 89d57dd911dc8..ea3c3eb2ef202 100644
+--- a/drivers/net/ethernet/intel/e1000e/ptp.c
++++ b/drivers/net/ethernet/intel/e1000e/ptp.c
+@@ -295,15 +295,17 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)
+       case e1000_pch_cnp:
+       case e1000_pch_tgp:
+       case e1000_pch_adp:
+-      case e1000_pch_mtp:
+-      case e1000_pch_lnp:
+-      case e1000_pch_ptp:
+       case e1000_pch_nvp:
+               if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_24MHZ;
+               else
+                       adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
+               break;
++      case e1000_pch_mtp:
++      case e1000_pch_lnp:
++      case e1000_pch_ptp:
++              adapter->ptp_clock_info.max_adj = MAX_PPB_38400KHZ;
++              break;
+       case e1000_82574:
+       case e1000_82583:
+               adapter->ptp_clock_info.max_adj = MAX_PPB_25MHZ;
+-- 
+2.39.5
+
diff --git a/queue-6.15/eth-fbnic-avoid-double-free-when-failing-to-dma-map-.patch b/queue-6.15/eth-fbnic-avoid-double-free-when-failing-to-dma-map-.patch
new file mode 100644 (file)
index 0000000..20b45d5
--- /dev/null
@@ -0,0 +1,44 @@
+From 72a0eedd738edc33a939be57451e0a0ce8f8cbf3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 12:55:10 -0700
+Subject: eth: fbnic: avoid double free when failing to DMA-map FW msg
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 5bd1bafd4474ee26f504b41aba11f3e2a1175b88 ]
+
+The semantics are that caller of fbnic_mbx_map_msg() retains
+the ownership of the message on error. All existing callers
+dutifully free the page.
+
+Fixes: da3cde08209e ("eth: fbnic: Add FW communication mechanism")
+Reviewed-by: Alexander Duyck <alexanderduyck@fb.com>
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20250616195510.225819-1-kuba@kernel.org
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/meta/fbnic/fbnic_fw.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+index 3d9636a6c968e..0c3985613ea18 100644
+--- a/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
++++ b/drivers/net/ethernet/meta/fbnic/fbnic_fw.c
+@@ -127,11 +127,8 @@ static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx,
+               return -EBUSY;
+       addr = dma_map_single(fbd->dev, msg, PAGE_SIZE, direction);
+-      if (dma_mapping_error(fbd->dev, addr)) {
+-              free_page((unsigned long)msg);
+-
++      if (dma_mapping_error(fbd->dev, addr))
+               return -ENOSPC;
+-      }
+       mbx->buf_info[tail].msg = msg;
+       mbx->buf_info[tail].addr = addr;
+-- 
+2.39.5
+
diff --git a/queue-6.15/hwmon-ltc4282-avoid-repeated-register-write.patch b/queue-6.15/hwmon-ltc4282-avoid-repeated-register-write.patch
new file mode 100644 (file)
index 0000000..1ab948e
--- /dev/null
@@ -0,0 +1,45 @@
+From 3588d3db0bbfe9b98c078e2086ff7420583286eb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Jun 2025 17:26:12 +0100
+Subject: hwmon: (ltc4282) avoid repeated register write
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Nuno Sá <nuno.sa@analog.com>
+
+[ Upstream commit c25892b7a1744355e16281cd24a9b59ec15ec974 ]
+
+The fault enabled bits were being mistankenly enabled twice in case the FW
+property is present. Remove one of the writes.
+
+Fixes: cbc29538dbf7 ("hwmon: Add driver for LTC4282")
+Signed-off-by: Nuno Sá <nuno.sa@analog.com>
+Link: https://lore.kernel.org/r/20250611-fix-ltc4282-repetead-write-v1-1-fe46edd08cf1@analog.com
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/ltc4282.c | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
+index 7f38d26962396..f607fe8f79370 100644
+--- a/drivers/hwmon/ltc4282.c
++++ b/drivers/hwmon/ltc4282.c
+@@ -1511,13 +1511,6 @@ static int ltc4282_setup(struct ltc4282_state *st, struct device *dev)
+                       return ret;
+       }
+-      if (device_property_read_bool(dev, "adi,fault-log-enable")) {
+-              ret = regmap_set_bits(st->map, LTC4282_ADC_CTRL,
+-                                    LTC4282_FAULT_LOG_EN_MASK);
+-              if (ret)
+-                      return ret;
+-      }
+-
+       if (device_property_read_bool(dev, "adi,fault-log-enable")) {
+               ret = regmap_set_bits(st->map, LTC4282_ADC_CTRL, LTC4282_FAULT_LOG_EN_MASK);
+               if (ret)
+-- 
+2.39.5
+
diff --git a/queue-6.15/hwmon-occ-fix-unaligned-accesses.patch b/queue-6.15/hwmon-occ-fix-unaligned-accesses.patch
new file mode 100644 (file)
index 0000000..b52edff
--- /dev/null
@@ -0,0 +1,109 @@
+From efea170ca393004f01497b2eb829aa5a5704901f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Jun 2025 11:25:49 +0200
+Subject: hwmon: (occ) fix unaligned accesses
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 2c021b45c154958566aad0cae9f74ab26a2d5732 ]
+
+Passing a pointer to an unaligned integer as a function argument is
+undefined behavior:
+
+drivers/hwmon/occ/common.c:492:27: warning: taking address of packed member 'accumulator' of class or structure 'power_sensor_2' may result in an unaligned pointer value [-Waddress-of-packed-member]
+  492 |   val = occ_get_powr_avg(&power->accumulator,
+      |                           ^~~~~~~~~~~~~~~~~~
+drivers/hwmon/occ/common.c:493:13: warning: taking address of packed member 'update_tag' of class or structure 'power_sensor_2' may result in an unaligned pointer value [-Waddress-of-packed-member]
+  493 |            &power->update_tag);
+      |             ^~~~~~~~~~~~~~~~~
+
+Move the get_unaligned() calls out of the function and pass these
+through argument registers instead.
+
+Fixes: c10e753d43eb ("hwmon (occ): Add sensor types and versions")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://lore.kernel.org/r/20250610092553.2641094-1-arnd@kernel.org
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/occ/common.c | 28 +++++++++++++---------------
+ 1 file changed, 13 insertions(+), 15 deletions(-)
+
+diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
+index 9029ad53790b1..b3694a4209b97 100644
+--- a/drivers/hwmon/occ/common.c
++++ b/drivers/hwmon/occ/common.c
+@@ -459,12 +459,10 @@ static ssize_t occ_show_power_1(struct device *dev,
+       return sysfs_emit(buf, "%llu\n", val);
+ }
+-static u64 occ_get_powr_avg(u64 *accum, u32 *samples)
++static u64 occ_get_powr_avg(u64 accum, u32 samples)
+ {
+-      u64 divisor = get_unaligned_be32(samples);
+-
+-      return (divisor == 0) ? 0 :
+-              div64_u64(get_unaligned_be64(accum) * 1000000ULL, divisor);
++      return (samples == 0) ? 0 :
++              mul_u64_u32_div(accum, 1000000UL, samples);
+ }
+ static ssize_t occ_show_power_2(struct device *dev,
+@@ -489,8 +487,8 @@ static ssize_t occ_show_power_2(struct device *dev,
+                                 get_unaligned_be32(&power->sensor_id),
+                                 power->function_id, power->apss_channel);
+       case 1:
+-              val = occ_get_powr_avg(&power->accumulator,
+-                                     &power->update_tag);
++              val = occ_get_powr_avg(get_unaligned_be64(&power->accumulator),
++                                     get_unaligned_be32(&power->update_tag));
+               break;
+       case 2:
+               val = (u64)get_unaligned_be32(&power->update_tag) *
+@@ -527,8 +525,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
+               return sysfs_emit(buf, "%u_system\n",
+                                 get_unaligned_be32(&power->sensor_id));
+       case 1:
+-              val = occ_get_powr_avg(&power->system.accumulator,
+-                                     &power->system.update_tag);
++              val = occ_get_powr_avg(get_unaligned_be64(&power->system.accumulator),
++                                     get_unaligned_be32(&power->system.update_tag));
+               break;
+       case 2:
+               val = (u64)get_unaligned_be32(&power->system.update_tag) *
+@@ -541,8 +539,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
+               return sysfs_emit(buf, "%u_proc\n",
+                                 get_unaligned_be32(&power->sensor_id));
+       case 5:
+-              val = occ_get_powr_avg(&power->proc.accumulator,
+-                                     &power->proc.update_tag);
++              val = occ_get_powr_avg(get_unaligned_be64(&power->proc.accumulator),
++                                     get_unaligned_be32(&power->proc.update_tag));
+               break;
+       case 6:
+               val = (u64)get_unaligned_be32(&power->proc.update_tag) *
+@@ -555,8 +553,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
+               return sysfs_emit(buf, "%u_vdd\n",
+                                 get_unaligned_be32(&power->sensor_id));
+       case 9:
+-              val = occ_get_powr_avg(&power->vdd.accumulator,
+-                                     &power->vdd.update_tag);
++              val = occ_get_powr_avg(get_unaligned_be64(&power->vdd.accumulator),
++                                     get_unaligned_be32(&power->vdd.update_tag));
+               break;
+       case 10:
+               val = (u64)get_unaligned_be32(&power->vdd.update_tag) *
+@@ -569,8 +567,8 @@ static ssize_t occ_show_power_a0(struct device *dev,
+               return sysfs_emit(buf, "%u_vdn\n",
+                                 get_unaligned_be32(&power->sensor_id));
+       case 13:
+-              val = occ_get_powr_avg(&power->vdn.accumulator,
+-                                     &power->vdn.update_tag);
++              val = occ_get_powr_avg(get_unaligned_be64(&power->vdn.accumulator),
++                                     get_unaligned_be32(&power->vdn.update_tag));
+               break;
+       case 14:
+               val = (u64)get_unaligned_be32(&power->vdn.update_tag) *
+-- 
+2.39.5
+
diff --git a/queue-6.15/hwmon-occ-rework-attribute-registration-for-stack-us.patch b/queue-6.15/hwmon-occ-rework-attribute-registration-for-stack-us.patch
new file mode 100644 (file)
index 0000000..f8d012c
--- /dev/null
@@ -0,0 +1,365 @@
+From 9a52b2c5b4b68da3723211040405fbe91ecf2f85 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Jun 2025 11:23:06 +0200
+Subject: hwmon: (occ) Rework attribute registration for stack usage
+
+From: Arnd Bergmann <arnd@arndb.de>
+
+[ Upstream commit 744c2fe950e936c4d62430de899d6253424200ed ]
+
+clang produces an output with excessive stack usage when building the
+occ_setup_sensor_attrs() function, apparently the result of having
+a lot of struct literals and building with the -fno-strict-overflow
+option that leads clang to skip some optimization in case the 'attr'
+pointer overruns:
+
+drivers/hwmon/occ/common.c:775:12: error: stack frame size (1392) exceeds limit (1280) in 'occ_setup_sensor_attrs' [-Werror,-Wframe-larger-than]
+
+Replace the custom macros for initializing the attributes with a
+simpler function call that does not run into this corner case.
+
+Link: https://godbolt.org/z/Wf1Yx76a5
+Fixes: 54076cb3b5ff ("hwmon (occ): Add sensor attributes and register hwmon device")
+Signed-off-by: Arnd Bergmann <arnd@arndb.de>
+Link: https://lore.kernel.org/r/20250610092315.2640039-1-arnd@kernel.org
+Signed-off-by: Guenter Roeck <linux@roeck-us.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/hwmon/occ/common.c | 212 +++++++++++++++----------------------
+ 1 file changed, 85 insertions(+), 127 deletions(-)
+
+diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c
+index 9486db249c64f..9029ad53790b1 100644
+--- a/drivers/hwmon/occ/common.c
++++ b/drivers/hwmon/occ/common.c
+@@ -747,29 +747,30 @@ static ssize_t occ_show_extended(struct device *dev,
+ }
+ /*
+- * Some helper macros to make it easier to define an occ_attribute. Since these
+- * are dynamically allocated, we shouldn't use the existing kernel macros which
++ * A helper to make it easier to define an occ_attribute. Since these
++ * are dynamically allocated, we cannot use the existing kernel macros which
+  * stringify the name argument.
+  */
+-#define ATTR_OCC(_name, _mode, _show, _store) {                               \
+-      .attr   = {                                                     \
+-              .name = _name,                                          \
+-              .mode = VERIFY_OCTAL_PERMISSIONS(_mode),                \
+-      },                                                              \
+-      .show   = _show,                                                \
+-      .store  = _store,                                               \
+-}
+-
+-#define SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index) {   \
+-      .dev_attr       = ATTR_OCC(_name, _mode, _show, _store),        \
+-      .index          = _index,                                       \
+-      .nr             = _nr,                                          \
++static void occ_init_attribute(struct occ_attribute *attr, int mode,
++      ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf),
++      ssize_t (*store)(struct device *dev, struct device_attribute *attr,
++                                 const char *buf, size_t count),
++      int nr, int index, const char *fmt, ...)
++{
++      va_list args;
++
++      va_start(args, fmt);
++      vsnprintf(attr->name, sizeof(attr->name), fmt, args);
++      va_end(args);
++
++      attr->sensor.dev_attr.attr.name = attr->name;
++      attr->sensor.dev_attr.attr.mode = mode;
++      attr->sensor.dev_attr.show = show;
++      attr->sensor.dev_attr.store = store;
++      attr->sensor.index = index;
++      attr->sensor.nr = nr;
+ }
+-#define OCC_INIT_ATTR(_name, _mode, _show, _store, _nr, _index)               \
+-      ((struct sensor_device_attribute_2)                             \
+-              SENSOR_ATTR_OCC(_name, _mode, _show, _store, _nr, _index))
+-
+ /*
+  * Allocate and instatiate sensor_device_attribute_2s. It's most efficient to
+  * use our own instead of the built-in hwmon attribute types.
+@@ -855,14 +856,15 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+               sensors->extended.num_sensors = 0;
+       }
+-      occ->attrs = devm_kzalloc(dev, sizeof(*occ->attrs) * num_attrs,
++      occ->attrs = devm_kcalloc(dev, num_attrs, sizeof(*occ->attrs),
+                                 GFP_KERNEL);
+       if (!occ->attrs)
+               return -ENOMEM;
+       /* null-terminated list */
+-      occ->group.attrs = devm_kzalloc(dev, sizeof(*occ->group.attrs) *
+-                                      num_attrs + 1, GFP_KERNEL);
++      occ->group.attrs = devm_kcalloc(dev, num_attrs + 1,
++                                      sizeof(*occ->group.attrs),
++                                      GFP_KERNEL);
+       if (!occ->group.attrs)
+               return -ENOMEM;
+@@ -872,43 +874,33 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+               s = i + 1;
+               temp = ((struct temp_sensor_2 *)sensors->temp.data) + i;
+-              snprintf(attr->name, sizeof(attr->name), "temp%d_label", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
+-                                           0, i);
++              occ_init_attribute(attr, 0444, show_temp, NULL,
++                                 0, i, "temp%d_label", s);
+               attr++;
+               if (sensors->temp.version == 2 &&
+                   temp->fru_type == OCC_FRU_TYPE_VRM) {
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "temp%d_alarm", s);
++                      occ_init_attribute(attr, 0444, show_temp, NULL,
++                                         1, i, "temp%d_alarm", s);
+               } else {
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "temp%d_input", s);
++                      occ_init_attribute(attr, 0444, show_temp, NULL,
++                                         1, i, "temp%d_input", s);
+               }
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_temp, NULL,
+-                                           1, i);
+               attr++;
+               if (sensors->temp.version > 1) {
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "temp%d_fru_type", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_temp, NULL, 2, i);
++                      occ_init_attribute(attr, 0444, show_temp, NULL,
++                                         2, i, "temp%d_fru_type", s);
+                       attr++;
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "temp%d_fault", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_temp, NULL, 3, i);
++                      occ_init_attribute(attr, 0444, show_temp, NULL,
++                                         3, i, "temp%d_fault", s);
+                       attr++;
+                       if (sensors->temp.version == 0x10) {
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "temp%d_max", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_temp, NULL,
+-                                                           4, i);
++                              occ_init_attribute(attr, 0444, show_temp, NULL,
++                                                 4, i, "temp%d_max", s);
+                               attr++;
+                       }
+               }
+@@ -917,14 +909,12 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+       for (i = 0; i < sensors->freq.num_sensors; ++i) {
+               s = i + 1;
+-              snprintf(attr->name, sizeof(attr->name), "freq%d_label", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
+-                                           0, i);
++              occ_init_attribute(attr, 0444, show_freq, NULL,
++                                 0, i, "freq%d_label", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "freq%d_input", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_freq, NULL,
+-                                           1, i);
++              occ_init_attribute(attr, 0444, show_freq, NULL,
++                                 1, i, "freq%d_input", s);
+               attr++;
+       }
+@@ -940,32 +930,24 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+                       s = (i * 4) + 1;
+                       for (j = 0; j < 4; ++j) {
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "power%d_label", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_power, NULL,
+-                                                           nr++, i);
++                              occ_init_attribute(attr, 0444, show_power,
++                                                 NULL, nr++, i,
++                                                 "power%d_label", s);
+                               attr++;
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "power%d_average", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_power, NULL,
+-                                                           nr++, i);
++                              occ_init_attribute(attr, 0444, show_power,
++                                                 NULL, nr++, i,
++                                                 "power%d_average", s);
+                               attr++;
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "power%d_average_interval", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_power, NULL,
+-                                                           nr++, i);
++                              occ_init_attribute(attr, 0444, show_power,
++                                                 NULL, nr++, i,
++                                                 "power%d_average_interval", s);
+                               attr++;
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "power%d_input", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_power, NULL,
+-                                                           nr++, i);
++                              occ_init_attribute(attr, 0444, show_power,
++                                                 NULL, nr++, i,
++                                                 "power%d_input", s);
+                               attr++;
+                               s++;
+@@ -977,28 +959,20 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+               for (i = 0; i < sensors->power.num_sensors; ++i) {
+                       s = i + 1;
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "power%d_label", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_power, NULL, 0, i);
++                      occ_init_attribute(attr, 0444, show_power, NULL,
++                                         0, i, "power%d_label", s);
+                       attr++;
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "power%d_average", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_power, NULL, 1, i);
++                      occ_init_attribute(attr, 0444, show_power, NULL,
++                                         1, i, "power%d_average", s);
+                       attr++;
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "power%d_average_interval", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_power, NULL, 2, i);
++                      occ_init_attribute(attr, 0444, show_power, NULL,
++                                         2, i, "power%d_average_interval", s);
+                       attr++;
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "power%d_input", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_power, NULL, 3, i);
++                      occ_init_attribute(attr, 0444, show_power, NULL,
++                                         3, i, "power%d_input", s);
+                       attr++;
+               }
+@@ -1006,56 +980,43 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+       }
+       if (sensors->caps.num_sensors >= 1) {
+-              snprintf(attr->name, sizeof(attr->name), "power%d_label", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           0, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 0, 0, "power%d_label", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "power%d_cap", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           1, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 1, 0, "power%d_cap", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "power%d_input", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           2, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 2, 0, "power%d_input", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name),
+-                       "power%d_cap_not_redundant", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           3, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 3, 0, "power%d_cap_not_redundant", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "power%d_cap_max", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           4, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 4, 0, "power%d_cap_max", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "power%d_cap_min", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444, show_caps, NULL,
+-                                           5, 0);
++              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                 5, 0, "power%d_cap_min", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "power%d_cap_user",
+-                       s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0644, show_caps,
+-                                           occ_store_caps_user, 6, 0);
++              occ_init_attribute(attr, 0644, show_caps, occ_store_caps_user,
++                                 6, 0, "power%d_cap_user", s);
+               attr++;
+               if (sensors->caps.version > 1) {
+-                      snprintf(attr->name, sizeof(attr->name),
+-                               "power%d_cap_user_source", s);
+-                      attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                   show_caps, NULL, 7, 0);
++                      occ_init_attribute(attr, 0444, show_caps, NULL,
++                                         7, 0, "power%d_cap_user_source", s);
+                       attr++;
+                       if (sensors->caps.version > 2) {
+-                              snprintf(attr->name, sizeof(attr->name),
+-                                       "power%d_cap_min_soft", s);
+-                              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                                           show_caps, NULL,
+-                                                           8, 0);
++                              occ_init_attribute(attr, 0444, show_caps, NULL,
++                                                 8, 0,
++                                                 "power%d_cap_min_soft", s);
+                               attr++;
+                       }
+               }
+@@ -1064,19 +1025,16 @@ static int occ_setup_sensor_attrs(struct occ *occ)
+       for (i = 0; i < sensors->extended.num_sensors; ++i) {
+               s = i + 1;
+-              snprintf(attr->name, sizeof(attr->name), "extn%d_label", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                           occ_show_extended, NULL, 0, i);
++              occ_init_attribute(attr, 0444, occ_show_extended, NULL,
++                                 0, i, "extn%d_label", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "extn%d_flags", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                           occ_show_extended, NULL, 1, i);
++              occ_init_attribute(attr, 0444, occ_show_extended, NULL,
++                                 1, i, "extn%d_flags", s);
+               attr++;
+-              snprintf(attr->name, sizeof(attr->name), "extn%d_input", s);
+-              attr->sensor = OCC_INIT_ATTR(attr->name, 0444,
+-                                           occ_show_extended, NULL, 2, i);
++              occ_init_attribute(attr, 0444, occ_show_extended, NULL,
++                                 2, i, "extn%d_input", s);
+               attr++;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/ice-fix-eswitch-code-memory-leak-in-reset-scenario.patch b/queue-6.15/ice-fix-eswitch-code-memory-leak-in-reset-scenario.patch
new file mode 100644 (file)
index 0000000..226dc49
--- /dev/null
@@ -0,0 +1,78 @@
+From 3550daab06a25be7e50bfc6405e2399d60b97ca8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 16 May 2025 15:09:07 +0200
+Subject: ice: fix eswitch code memory leak in reset scenario
+
+From: Grzegorz Nitka <grzegorz.nitka@intel.com>
+
+[ Upstream commit 48c8b214974dc55283bd5f12e3a483b27c403bbc ]
+
+Add simple eswitch mode checker in attaching VF procedure and allocate
+required port representor memory structures only in switchdev mode.
+The reset flows triggers VF (if present) detach/attach procedure.
+It might involve VF port representor(s) re-creation if the device is
+configured is switchdev mode (not legacy one).
+The memory was blindly allocated in current implementation,
+regardless of the mode and not freed if in legacy mode.
+
+Kmemeleak trace:
+unreferenced object (percpu) 0x7e3bce5b888458 (size 40):
+  comm "bash", pid 1784, jiffies 4295743894
+  hex dump (first 32 bytes on cpu 45):
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
+  backtrace (crc 0):
+    pcpu_alloc_noprof+0x4c4/0x7c0
+    ice_repr_create+0x66/0x130 [ice]
+    ice_repr_create_vf+0x22/0x70 [ice]
+    ice_eswitch_attach_vf+0x1b/0xa0 [ice]
+    ice_reset_all_vfs+0x1dd/0x2f0 [ice]
+    ice_pci_err_resume+0x3b/0xb0 [ice]
+    pci_reset_function+0x8f/0x120
+    reset_store+0x56/0xa0
+    kernfs_fop_write_iter+0x120/0x1b0
+    vfs_write+0x31c/0x430
+    ksys_write+0x61/0xd0
+    do_syscall_64+0x5b/0x180
+    entry_SYSCALL_64_after_hwframe+0x76/0x7e
+
+Testing hints (ethX is PF netdev):
+- create at least one VF
+    echo 1 > /sys/class/net/ethX/device/sriov_numvfs
+- trigger the reset
+    echo 1 > /sys/class/net/ethX/device/reset
+
+Fixes: 415db8399d06 ("ice: make representor code generic")
+Signed-off-by: Grzegorz Nitka <grzegorz.nitka@intel.com>
+Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_eswitch.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_eswitch.c b/drivers/net/ethernet/intel/ice/ice_eswitch.c
+index ed21d7f55ac11..5b9a7ee278f17 100644
+--- a/drivers/net/ethernet/intel/ice/ice_eswitch.c
++++ b/drivers/net/ethernet/intel/ice/ice_eswitch.c
+@@ -502,10 +502,14 @@ ice_eswitch_attach(struct ice_pf *pf, struct ice_repr *repr, unsigned long *id)
+  */
+ int ice_eswitch_attach_vf(struct ice_pf *pf, struct ice_vf *vf)
+ {
+-      struct ice_repr *repr = ice_repr_create_vf(vf);
+       struct devlink *devlink = priv_to_devlink(pf);
++      struct ice_repr *repr;
+       int err;
++      if (!ice_is_eswitch_mode_switchdev(pf))
++              return 0;
++
++      repr = ice_repr_create_vf(vf);
+       if (IS_ERR(repr))
+               return PTR_ERR(repr);
+-- 
+2.39.5
+
diff --git a/queue-6.15/io_uring-fix-potential-page-leak-in-io_sqe_buffer_re.patch b/queue-6.15/io_uring-fix-potential-page-leak-in-io_sqe_buffer_re.patch
new file mode 100644 (file)
index 0000000..abfa319
--- /dev/null
@@ -0,0 +1,53 @@
+From f07dacedf7c03a2810988e2dabdcfcf77c6d5d98 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 09:56:44 -0700
+Subject: io_uring: fix potential page leak in io_sqe_buffer_register()
+
+From: Penglei Jiang <superman.xpt@gmail.com>
+
+[ Upstream commit e1c75831f682eef0f68b35723437146ed86070b1 ]
+
+If allocation of the 'imu' fails, then the existing pages aren't
+unpinned in the error path. This is mostly a theoretical issue,
+requiring fault injection to hit.
+
+Move unpin_user_pages() to unified error handling to fix the page leak
+issue.
+
+Fixes: d8c2237d0aa9 ("io_uring: add io_pin_pages() helper")
+Signed-off-by: Penglei Jiang <superman.xpt@gmail.com>
+Link: https://lore.kernel.org/r/20250617165644.79165-1-superman.xpt@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/rsrc.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
+index 91c5cb2e1f066..794d4ae6f0bc8 100644
+--- a/io_uring/rsrc.c
++++ b/io_uring/rsrc.c
+@@ -810,10 +810,8 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
+       imu->nr_bvecs = nr_pages;
+       ret = io_buffer_account_pin(ctx, pages, nr_pages, imu, last_hpage);
+-      if (ret) {
+-              unpin_user_pages(pages, nr_pages);
++      if (ret)
+               goto done;
+-      }
+       size = iov->iov_len;
+       /* store original address for later verification */
+@@ -843,6 +841,8 @@ static struct io_rsrc_node *io_sqe_buffer_register(struct io_ring_ctx *ctx,
+       if (ret) {
+               if (imu)
+                       io_free_imu(ctx, imu);
++              if (pages)
++                      unpin_user_pages(pages, nr_pages);
+               io_cache_free(&ctx->node_cache, node);
+               node = ERR_PTR(ret);
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/io_uring-sqpoll-don-t-put-task_struct-on-tctx-setup-.patch b/queue-6.15/io_uring-sqpoll-don-t-put-task_struct-on-tctx-setup-.patch
new file mode 100644 (file)
index 0000000..9ec91a1
--- /dev/null
@@ -0,0 +1,60 @@
+From 43c8e0214842d024692418b3b60e82d10cb2e132 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 06:43:18 -0600
+Subject: io_uring/sqpoll: don't put task_struct on tctx setup failure
+
+From: Jens Axboe <axboe@kernel.dk>
+
+[ Upstream commit f2320f1dd6f6f82cb2c7aff23a12bab537bdea89 ]
+
+A recent commit moved the error handling of sqpoll thread and tctx
+failures into the thread itself, as part of fixing an issue. However, it
+missed that tctx allocation may also fail, and that
+io_sq_offload_create() does its own error handling for the task_struct
+in that case.
+
+Remove the manual task putting in io_sq_offload_create(), as
+io_sq_thread() will notice that the tctx did not get setup and hence it
+should put itself and exit.
+
+Reported-by: syzbot+763e12bbf004fb1062e4@syzkaller.appspotmail.com
+Fixes: ac0b8b327a56 ("io_uring: fix use-after-free of sq->thread in __io_uring_show_fdinfo()")
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ io_uring/sqpoll.c | 5 +----
+ 1 file changed, 1 insertion(+), 4 deletions(-)
+
+diff --git a/io_uring/sqpoll.c b/io_uring/sqpoll.c
+index 268d2fbe6160c..d3a94cd0f5e65 100644
+--- a/io_uring/sqpoll.c
++++ b/io_uring/sqpoll.c
+@@ -419,7 +419,6 @@ void io_sqpoll_wait_sq(struct io_ring_ctx *ctx)
+ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
+                               struct io_uring_params *p)
+ {
+-      struct task_struct *task_to_put = NULL;
+       int ret;
+       /* Retain compatibility with failing for an invalid attach attempt */
+@@ -498,7 +497,7 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
+               rcu_assign_pointer(sqd->thread, tsk);
+               mutex_unlock(&sqd->lock);
+-              task_to_put = get_task_struct(tsk);
++              get_task_struct(tsk);
+               ret = io_uring_alloc_task_context(tsk, ctx);
+               wake_up_new_task(tsk);
+               if (ret)
+@@ -513,8 +512,6 @@ __cold int io_sq_offload_create(struct io_ring_ctx *ctx,
+       complete(&ctx->sq_data->exited);
+ err:
+       io_sq_thread_finish(ctx);
+-      if (task_to_put)
+-              put_task_struct(task_to_put);
+       return ret;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/ionic-prevent-driver-fw-getting-out-of-sync-on-devcm.patch b/queue-6.15/ionic-prevent-driver-fw-getting-out-of-sync-on-devcm.patch
new file mode 100644 (file)
index 0000000..a32787b
--- /dev/null
@@ -0,0 +1,53 @@
+From 126259b5b3c2a4124f28b4be9d56a57e4bf0f7a2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 9 Jun 2025 14:28:27 -0700
+Subject: ionic: Prevent driver/fw getting out of sync on devcmd(s)
+
+From: Brett Creeley <brett.creeley@amd.com>
+
+[ Upstream commit 5466491c9e3309ed5c7adbb8fad6e93fcc9a8fe9 ]
+
+Some stress/negative firmware testing around devcmd(s) returning
+EAGAIN found that the done bit could get out of sync in the
+firmware when it wasn't cleared in a retry case.
+
+While here, change the type of the local done variable to a bool
+to match the return type from ionic_dev_cmd_done().
+
+Fixes: ec8ee714736e ("ionic: stretch heartbeat detection")
+Signed-off-by: Brett Creeley <brett.creeley@amd.com>
+Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250609212827.53842-1-shannon.nelson@amd.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/pensando/ionic/ionic_main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
+index daf1e82cb76b3..0e60a6bef99a3 100644
+--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
++++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
+@@ -516,9 +516,9 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
+       unsigned long start_time;
+       unsigned long max_wait;
+       unsigned long duration;
+-      int done = 0;
+       bool fw_up;
+       int opcode;
++      bool done;
+       int err;
+       /* Wait for dev cmd to complete, retrying if we get EAGAIN,
+@@ -526,6 +526,7 @@ static int __ionic_dev_cmd_wait(struct ionic *ionic, unsigned long max_seconds,
+        */
+       max_wait = jiffies + (max_seconds * HZ);
+ try_again:
++      done = false;
+       opcode = idev->opcode;
+       start_time = jiffies;
+       for (fw_up = ionic_is_fw_running(idev);
+-- 
+2.39.5
+
diff --git a/queue-6.15/ksmbd-add-free_transport-ops-in-ksmbd-connection.patch b/queue-6.15/ksmbd-add-free_transport-ops-in-ksmbd-connection.patch
new file mode 100644 (file)
index 0000000..fb16672
--- /dev/null
@@ -0,0 +1,112 @@
+From 87ef9960d1a1d78faa8b1aa006a6f92e0c59f1b1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 10 Jun 2025 18:52:56 +0900
+Subject: ksmbd: add free_transport ops in ksmbd connection
+
+From: Namjae Jeon <linkinjeon@kernel.org>
+
+[ Upstream commit a89f5fae998bdc4d0505306f93844c9ae059d50c ]
+
+free_transport function for tcp connection can be called from smbdirect.
+It will cause kernel oops. This patch add free_transport ops in ksmbd
+connection, and add each free_transports for tcp and smbdirect.
+
+Fixes: 21a4e47578d4 ("ksmbd: fix use-after-free in __smb2_lease_break_noti()")
+Reviewed-by: Stefan Metzmacher <metze@samba.org>
+Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/smb/server/connection.c     |  2 +-
+ fs/smb/server/connection.h     |  1 +
+ fs/smb/server/transport_rdma.c | 10 ++++++++--
+ fs/smb/server/transport_tcp.c  |  3 ++-
+ 4 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
+index 83764c230e9d4..3f04a2977ba86 100644
+--- a/fs/smb/server/connection.c
++++ b/fs/smb/server/connection.c
+@@ -40,7 +40,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
+       kvfree(conn->request_buf);
+       kfree(conn->preauth_info);
+       if (atomic_dec_and_test(&conn->refcnt)) {
+-              ksmbd_free_transport(conn->transport);
++              conn->transport->ops->free_transport(conn->transport);
+               kfree(conn);
+       }
+ }
+diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h
+index 14620e147dda5..572102098c108 100644
+--- a/fs/smb/server/connection.h
++++ b/fs/smb/server/connection.h
+@@ -132,6 +132,7 @@ struct ksmbd_transport_ops {
+                         void *buf, unsigned int len,
+                         struct smb2_buffer_desc_v1 *desc,
+                         unsigned int desc_len);
++      void (*free_transport)(struct ksmbd_transport *kt);
+ };
+ struct ksmbd_transport {
+diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c
+index 4998df04ab95a..64a428a06ace0 100644
+--- a/fs/smb/server/transport_rdma.c
++++ b/fs/smb/server/transport_rdma.c
+@@ -159,7 +159,8 @@ struct smb_direct_transport {
+ };
+ #define KSMBD_TRANS(t) ((struct ksmbd_transport *)&((t)->transport))
+-
++#define SMBD_TRANS(t) ((struct smb_direct_transport *)container_of(t, \
++                              struct smb_direct_transport, transport))
+ enum {
+       SMB_DIRECT_MSG_NEGOTIATE_REQ = 0,
+       SMB_DIRECT_MSG_DATA_TRANSFER
+@@ -410,6 +411,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id)
+       return NULL;
+ }
++static void smb_direct_free_transport(struct ksmbd_transport *kt)
++{
++      kfree(SMBD_TRANS(kt));
++}
++
+ static void free_transport(struct smb_direct_transport *t)
+ {
+       struct smb_direct_recvmsg *recvmsg;
+@@ -455,7 +461,6 @@ static void free_transport(struct smb_direct_transport *t)
+       smb_direct_destroy_pools(t);
+       ksmbd_conn_free(KSMBD_TRANS(t)->conn);
+-      kfree(t);
+ }
+ static struct smb_direct_sendmsg
+@@ -2281,4 +2286,5 @@ static const struct ksmbd_transport_ops ksmbd_smb_direct_transport_ops = {
+       .read           = smb_direct_read,
+       .rdma_read      = smb_direct_rdma_read,
+       .rdma_write     = smb_direct_rdma_write,
++      .free_transport = smb_direct_free_transport,
+ };
+diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c
+index abedf510899a7..4e9f98db9ff40 100644
+--- a/fs/smb/server/transport_tcp.c
++++ b/fs/smb/server/transport_tcp.c
+@@ -93,7 +93,7 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk)
+       return t;
+ }
+-void ksmbd_free_transport(struct ksmbd_transport *kt)
++static void ksmbd_tcp_free_transport(struct ksmbd_transport *kt)
+ {
+       struct tcp_transport *t = TCP_TRANS(kt);
+@@ -656,4 +656,5 @@ static const struct ksmbd_transport_ops ksmbd_tcp_transport_ops = {
+       .read           = ksmbd_tcp_read,
+       .writev         = ksmbd_tcp_writev,
+       .disconnect     = ksmbd_tcp_disconnect,
++      .free_transport = ksmbd_tcp_free_transport,
+ };
+-- 
+2.39.5
+
diff --git a/queue-6.15/mlxbf_gige-return-eprobe_defer-if-phy-irq-is-not-ava.patch b/queue-6.15/mlxbf_gige-return-eprobe_defer-if-phy-irq-is-not-ava.patch
new file mode 100644 (file)
index 0000000..f55185c
--- /dev/null
@@ -0,0 +1,47 @@
+From dc6cb43aa49c2413444db4cfe6368f9c70773e55 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Jun 2025 13:59:02 +0000
+Subject: mlxbf_gige: return EPROBE_DEFER if PHY IRQ is not available
+
+From: David Thompson <davthompson@nvidia.com>
+
+[ Upstream commit e7ea5f5b1858ddb96b152584d5fe06e6fc623e89 ]
+
+The message "Error getting PHY irq. Use polling instead"
+is emitted when the mlxbf_gige driver is loaded by the
+kernel before the associated gpio-mlxbf driver, and thus
+the call to get the PHY IRQ fails since it is not yet
+available. The driver probe() must return -EPROBE_DEFER
+if acpi_dev_gpio_irq_get_by() returns the same.
+
+Fixes: 6c2a6ddca763 ("net: mellanox: mlxbf_gige: Replace non-standard interrupt handling")
+Signed-off-by: David Thompson <davthompson@nvidia.com>
+Reviewed-by: Asmaa Mnebhi <asmaa@nvidia.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250618135902.346-1-davthompson@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+index fb2e5b844c150..d76d7a945899c 100644
+--- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
++++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c
+@@ -447,8 +447,10 @@ static int mlxbf_gige_probe(struct platform_device *pdev)
+       priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX);
+       phy_irq = acpi_dev_gpio_irq_get_by(ACPI_COMPANION(&pdev->dev), "phy", 0);
+-      if (phy_irq < 0) {
+-              dev_err(&pdev->dev, "Error getting PHY irq. Use polling instead");
++      if (phy_irq == -EPROBE_DEFER) {
++              err = -EPROBE_DEFER;
++              goto out;
++      } else if (phy_irq < 0) {
+               phy_irq = PHY_POLL;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/mpls-use-rcu_dereference_rtnl-in-mpls_route_input_rc.patch b/queue-6.15/mpls-use-rcu_dereference_rtnl-in-mpls_route_input_rc.patch
new file mode 100644 (file)
index 0000000..cd19fe2
--- /dev/null
@@ -0,0 +1,95 @@
+From de9839c6817394889ae6293cb5169821af3e174d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 13:15:12 -0700
+Subject: mpls: Use rcu_dereference_rtnl() in mpls_route_input_rcu().
+
+From: Kuniyuki Iwashima <kuniyu@google.com>
+
+[ Upstream commit 6dbb0d97c5096072c78a6abffe393584e57ae945 ]
+
+As syzbot reported [0], mpls_route_input_rcu() can be called
+from mpls_getroute(), where is under RTNL.
+
+net->mpls.platform_label is only updated under RTNL.
+
+Let's use rcu_dereference_rtnl() in mpls_route_input_rcu() to
+silence the splat.
+
+[0]:
+WARNING: suspicious RCU usage
+6.15.0-rc7-syzkaller-00082-g5cdb2c77c4c3 #0 Not tainted
+ ----------------------------
+net/mpls/af_mpls.c:84 suspicious rcu_dereference_check() usage!
+
+other info that might help us debug this:
+
+rcu_scheduler_active = 2, debug_locks = 1
+1 lock held by syz.2.4451/17730:
+ #0: ffffffff9012a3e8 (rtnl_mutex){+.+.}-{4:4}, at: rtnl_lock net/core/rtnetlink.c:80 [inline]
+ #0: ffffffff9012a3e8 (rtnl_mutex){+.+.}-{4:4}, at: rtnetlink_rcv_msg+0x371/0xe90 net/core/rtnetlink.c:6961
+
+stack backtrace:
+CPU: 1 UID: 0 PID: 17730 Comm: syz.2.4451 Not tainted 6.15.0-rc7-syzkaller-00082-g5cdb2c77c4c3 #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
+Call Trace:
+ <TASK>
+ __dump_stack lib/dump_stack.c:94 [inline]
+ dump_stack_lvl+0x16c/0x1f0 lib/dump_stack.c:120
+ lockdep_rcu_suspicious+0x166/0x260 kernel/locking/lockdep.c:6865
+ mpls_route_input_rcu+0x1d4/0x200 net/mpls/af_mpls.c:84
+ mpls_getroute+0x621/0x1ea0 net/mpls/af_mpls.c:2381
+ rtnetlink_rcv_msg+0x3c9/0xe90 net/core/rtnetlink.c:6964
+ netlink_rcv_skb+0x16d/0x440 net/netlink/af_netlink.c:2534
+ netlink_unicast_kernel net/netlink/af_netlink.c:1313 [inline]
+ netlink_unicast+0x53a/0x7f0 net/netlink/af_netlink.c:1339
+ netlink_sendmsg+0x8d1/0xdd0 net/netlink/af_netlink.c:1883
+ sock_sendmsg_nosec net/socket.c:712 [inline]
+ __sock_sendmsg net/socket.c:727 [inline]
+ ____sys_sendmsg+0xa98/0xc70 net/socket.c:2566
+ ___sys_sendmsg+0x134/0x1d0 net/socket.c:2620
+ __sys_sendmmsg+0x200/0x420 net/socket.c:2709
+ __do_sys_sendmmsg net/socket.c:2736 [inline]
+ __se_sys_sendmmsg net/socket.c:2733 [inline]
+ __x64_sys_sendmmsg+0x9c/0x100 net/socket.c:2733
+ do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+ do_syscall_64+0xcd/0x230 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+RIP: 0033:0x7f0a2818e969
+Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
+RSP: 002b:00007f0a28f52038 EFLAGS: 00000246 ORIG_RAX: 0000000000000133
+RAX: ffffffffffffffda RBX: 00007f0a283b5fa0 RCX: 00007f0a2818e969
+RDX: 0000000000000003 RSI: 0000200000000080 RDI: 0000000000000003
+RBP: 00007f0a28210ab1 R08: 0000000000000000 R09: 0000000000000000
+R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
+R13: 0000000000000000 R14: 00007f0a283b5fa0 R15: 00007ffce5e9f268
+ </TASK>
+
+Fixes: 0189197f4416 ("mpls: Basic routing support")
+Reported-by: syzbot+8a583bdd1a5cc0b0e068@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/68507981.a70a0220.395abc.01ef.GAE@google.com/
+Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20250616201532.1036568-1-kuni1840@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/mpls/af_mpls.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
+index 1f63b32d76d67..aab2e79fcff04 100644
+--- a/net/mpls/af_mpls.c
++++ b/net/mpls/af_mpls.c
+@@ -81,8 +81,8 @@ static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
+       if (index < net->mpls.platform_labels) {
+               struct mpls_route __rcu **platform_label =
+-                      rcu_dereference(net->mpls.platform_label);
+-              rt = rcu_dereference(platform_label[index]);
++                      rcu_dereference_rtnl(net->mpls.platform_label);
++              rt = rcu_dereference_rtnl(platform_label[index]);
+       }
+       return rt;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-atm-add-lec_mutex.patch b/queue-6.15/net-atm-add-lec_mutex.patch
new file mode 100644 (file)
index 0000000..e0cc2eb
--- /dev/null
@@ -0,0 +1,161 @@
+From b50e6be4287300f9dad5e9b8acb0d7b15c0c91d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Jun 2025 14:08:43 +0000
+Subject: net: atm: add lec_mutex
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d13a3824bfd2b4774b671a75cf766a16637a0e67 ]
+
+syzbot found its way in net/atm/lec.c, and found an error path
+in lecd_attach() could leave a dangling pointer in dev_lec[].
+
+Add a mutex to protect dev_lecp[] uses from lecd_attach(),
+lec_vcc_attach() and lec_mcast_attach().
+
+Following patch will use this mutex for /proc/net/atm/lec.
+
+BUG: KASAN: slab-use-after-free in lecd_attach net/atm/lec.c:751 [inline]
+BUG: KASAN: slab-use-after-free in lane_ioctl+0x2224/0x23e0 net/atm/lec.c:1008
+Read of size 8 at addr ffff88807c7b8e68 by task syz.1.17/6142
+
+CPU: 1 UID: 0 PID: 6142 Comm: syz.1.17 Not tainted 6.16.0-rc1-syzkaller-00239-g08215f5486ec #0 PREEMPT(full)
+Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 05/07/2025
+Call Trace:
+ <TASK>
+  __dump_stack lib/dump_stack.c:94 [inline]
+  dump_stack_lvl+0x116/0x1f0 lib/dump_stack.c:120
+  print_address_description mm/kasan/report.c:408 [inline]
+  print_report+0xcd/0x680 mm/kasan/report.c:521
+  kasan_report+0xe0/0x110 mm/kasan/report.c:634
+  lecd_attach net/atm/lec.c:751 [inline]
+  lane_ioctl+0x2224/0x23e0 net/atm/lec.c:1008
+  do_vcc_ioctl+0x12c/0x930 net/atm/ioctl.c:159
+  sock_do_ioctl+0x118/0x280 net/socket.c:1190
+  sock_ioctl+0x227/0x6b0 net/socket.c:1311
+  vfs_ioctl fs/ioctl.c:51 [inline]
+  __do_sys_ioctl fs/ioctl.c:907 [inline]
+  __se_sys_ioctl fs/ioctl.c:893 [inline]
+  __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:893
+  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+  do_syscall_64+0xcd/0x4c0 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+ </TASK>
+
+Allocated by task 6132:
+  kasan_save_stack+0x33/0x60 mm/kasan/common.c:47
+  kasan_save_track+0x14/0x30 mm/kasan/common.c:68
+  poison_kmalloc_redzone mm/kasan/common.c:377 [inline]
+  __kasan_kmalloc+0xaa/0xb0 mm/kasan/common.c:394
+  kasan_kmalloc include/linux/kasan.h:260 [inline]
+  __do_kmalloc_node mm/slub.c:4328 [inline]
+  __kvmalloc_node_noprof+0x27b/0x620 mm/slub.c:5015
+  alloc_netdev_mqs+0xd2/0x1570 net/core/dev.c:11711
+  lecd_attach net/atm/lec.c:737 [inline]
+  lane_ioctl+0x17db/0x23e0 net/atm/lec.c:1008
+  do_vcc_ioctl+0x12c/0x930 net/atm/ioctl.c:159
+  sock_do_ioctl+0x118/0x280 net/socket.c:1190
+  sock_ioctl+0x227/0x6b0 net/socket.c:1311
+  vfs_ioctl fs/ioctl.c:51 [inline]
+  __do_sys_ioctl fs/ioctl.c:907 [inline]
+  __se_sys_ioctl fs/ioctl.c:893 [inline]
+  __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:893
+  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
+  do_syscall_64+0xcd/0x4c0 arch/x86/entry/syscall_64.c:94
+ entry_SYSCALL_64_after_hwframe+0x77/0x7f
+
+Freed by task 6132:
+  kasan_save_stack+0x33/0x60 mm/kasan/common.c:47
+  kasan_save_track+0x14/0x30 mm/kasan/common.c:68
+  kasan_save_free_info+0x3b/0x60 mm/kasan/generic.c:576
+  poison_slab_object mm/kasan/common.c:247 [inline]
+  __kasan_slab_free+0x51/0x70 mm/kasan/common.c:264
+  kasan_slab_free include/linux/kasan.h:233 [inline]
+  slab_free_hook mm/slub.c:2381 [inline]
+  slab_free mm/slub.c:4643 [inline]
+  kfree+0x2b4/0x4d0 mm/slub.c:4842
+  free_netdev+0x6c5/0x910 net/core/dev.c:11892
+  lecd_attach net/atm/lec.c:744 [inline]
+  lane_ioctl+0x1ce8/0x23e0 net/atm/lec.c:1008
+  do_vcc_ioctl+0x12c/0x930 net/atm/ioctl.c:159
+  sock_do_ioctl+0x118/0x280 net/socket.c:1190
+  sock_ioctl+0x227/0x6b0 net/socket.c:1311
+  vfs_ioctl fs/ioctl.c:51 [inline]
+  __do_sys_ioctl fs/ioctl.c:907 [inline]
+  __se_sys_ioctl fs/ioctl.c:893 [inline]
+  __x64_sys_ioctl+0x18e/0x210 fs/ioctl.c:893
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Reported-by: syzbot+8b64dec3affaed7b3af5@syzkaller.appspotmail.com
+Closes: https://lore.kernel.org/netdev/6852c6f6.050a0220.216029.0018.GAE@google.com/T/#u
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250618140844.1686882-2-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index ded2f0df2ee66..3010a2034d6af 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -124,6 +124,7 @@ static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ /* Device structures */
+ static struct net_device *dev_lec[MAX_LEC_ITF];
++static DEFINE_MUTEX(lec_mutex);
+ #if IS_ENABLED(CONFIG_BRIDGE)
+ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
+@@ -685,6 +686,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+       int bytes_left;
+       struct atmlec_ioc ioc_data;
++      lockdep_assert_held(&lec_mutex);
+       /* Lecd must be up in this case */
+       bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
+       if (bytes_left != 0)
+@@ -710,6 +712,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+ static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
+ {
++      lockdep_assert_held(&lec_mutex);
+       if (arg < 0 || arg >= MAX_LEC_ITF)
+               return -EINVAL;
+       arg = array_index_nospec(arg, MAX_LEC_ITF);
+@@ -725,6 +728,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+       int i;
+       struct lec_priv *priv;
++      lockdep_assert_held(&lec_mutex);
+       if (arg < 0)
+               arg = 0;
+       if (arg >= MAX_LEC_ITF)
+@@ -742,6 +746,7 @@ static int lecd_attach(struct atm_vcc *vcc, int arg)
+               snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
+               if (register_netdev(dev_lec[i])) {
+                       free_netdev(dev_lec[i]);
++                      dev_lec[i] = NULL;
+                       return -EINVAL;
+               }
+@@ -1003,6 +1008,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+               return -ENOIOCTLCMD;
+       }
++      mutex_lock(&lec_mutex);
+       switch (cmd) {
+       case ATMLEC_CTRL:
+               err = lecd_attach(vcc, (int)arg);
+@@ -1017,6 +1023,7 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+               break;
+       }
++      mutex_unlock(&lec_mutex);
+       return err;
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-atm-fix-proc-net-atm-lec-handling.patch b/queue-6.15/net-atm-fix-proc-net-atm-lec-handling.patch
new file mode 100644 (file)
index 0000000..039b8d6
--- /dev/null
@@ -0,0 +1,58 @@
+From 3ab61a8e40c2d51bacfdf2318553d1c623f7dc46 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Jun 2025 14:08:44 +0000
+Subject: net: atm: fix /proc/net/atm/lec handling
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit d03b79f459c7935cff830d98373474f440bd03ae ]
+
+/proc/net/atm/lec must ensure safety against dev_lec[] changes.
+
+It appears it had dev_put() calls without prior dev_hold(),
+leading to imbalance and UAF.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Acked-by: Francois Romieu <romieu@fr.zoreil.com> # Minor atm contributor
+Link: https://patch.msgid.link/20250618140844.1686882-3-edumazet@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/atm/lec.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/atm/lec.c b/net/atm/lec.c
+index 3010a2034d6af..07c01b6f2b2be 100644
+--- a/net/atm/lec.c
++++ b/net/atm/lec.c
+@@ -909,7 +909,6 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l)
+       v = (dev && netdev_priv(dev)) ?
+               lec_priv_walk(state, l, netdev_priv(dev)) : NULL;
+       if (!v && dev) {
+-              dev_put(dev);
+               /* Partial state reset for the next time we get called */
+               dev = NULL;
+       }
+@@ -933,6 +932,7 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
+ {
+       struct lec_state *state = seq->private;
++      mutex_lock(&lec_mutex);
+       state->itf = 0;
+       state->dev = NULL;
+       state->locked = NULL;
+@@ -950,8 +950,9 @@ static void lec_seq_stop(struct seq_file *seq, void *v)
+       if (state->dev) {
+               spin_unlock_irqrestore(&state->locked->lec_arp_lock,
+                                      state->flags);
+-              dev_put(state->dev);
++              state->dev = NULL;
+       }
++      mutex_unlock(&lec_mutex);
+ }
+ static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-ice-perform-accurate-arfs-flow-match.patch b/queue-6.15/net-ice-perform-accurate-arfs-flow-match.patch
new file mode 100644 (file)
index 0000000..db24b26
--- /dev/null
@@ -0,0 +1,158 @@
+From 7c006b6128eff2054305f9b65b880a190bfb7633 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 20 May 2025 22:36:56 +0530
+Subject: net: ice: Perform accurate aRFS flow match
+
+From: Krishna Kumar <krikku@gmail.com>
+
+[ Upstream commit 5d3bc9e5e725aa36cca9b794e340057feb6880b4 ]
+
+This patch fixes an issue seen in a large-scale deployment under heavy
+incoming pkts where the aRFS flow wrongly matches a flow and reprograms the
+NIC with wrong settings. That mis-steering causes RX-path latency spikes
+and noisy neighbor effects when many connections collide on the same
+hash (some of our production servers have 20-30K connections).
+
+set_rps_cpu() calls ndo_rx_flow_steer() with flow_id that is calculated by
+hashing the skb sized by the per rx-queue table size. This results in
+multiple connections (even across different rx-queues) getting the same
+hash value. The driver steer function modifies the wrong flow to use this
+rx-queue, e.g.: Flow#1 is first added:
+    Flow#1:  <ip1, port1, ip2, port2>, Hash 'h', q#10
+
+Later when a new flow needs to be added:
+           Flow#2:  <ip3, port3, ip4, port4>, Hash 'h', q#20
+
+The driver finds the hash 'h' from Flow#1 and updates it to use q#20. This
+results in both flows getting un-optimized - packets for Flow#1 goes to
+q#20, and then reprogrammed back to q#10 later and so on; and Flow #2
+programming is never done as Flow#1 is matched first for all misses. Many
+flows may wrongly share the same hash and reprogram rules of the original
+flow each with their own q#.
+
+Tested on two 144-core servers with 16K netperf sessions for 180s. Netperf
+clients are pinned to cores 0-71 sequentially (so that wrong packets on q#s
+72-143 can be measured). IRQs are set 1:1 for queues -> CPUs, enable XPS,
+enable aRFS (global value is 144 * rps_flow_cnt).
+
+Test notes about results from ice_rx_flow_steer():
+---------------------------------------------------
+1. "Skip:" counter increments here:
+    if (fltr_info->q_index == rxq_idx ||
+       arfs_entry->fltr_state != ICE_ARFS_ACTIVE)
+           goto out;
+2. "Add:" counter increments here:
+    ret = arfs_entry->fltr_info.fltr_id;
+    INIT_HLIST_NODE(&arfs_entry->list_entry);
+3. "Update:" counter increments here:
+    /* update the queue to forward to on an already existing flow */
+
+Runtime comparison: original code vs with the patch for different
+rps_flow_cnt values.
+
++-------------------------------+--------------+--------------+
+| rps_flow_cnt                  |      512     |    2048      |
++-------------------------------+--------------+--------------+
+| Ratio of Pkts on Good:Bad q's | 214 vs 822K  | 1.1M vs 980K |
+| Avoid wrong aRFS programming  | 0 vs 310K    | 0 vs 30K     |
+| CPU User                      | 216 vs 183   | 216 vs 206   |
+| CPU System                    | 1441 vs 1171 | 1447 vs 1320 |
+| CPU Softirq                   | 1245 vs 920  | 1238 vs 961  |
+| CPU Total                     | 29 vs 22.7   | 29 vs 24.9   |
+| aRFS Update                   | 533K vs 59   | 521K vs 32   |
+| aRFS Skip                     | 82M vs 77M   | 7.2M vs 4.5M |
++-------------------------------+--------------+--------------+
+
+A separate TCP_STREAM and TCP_RR with 1,4,8,16,64,128,256,512 connections
+showed no performance degradation.
+
+Some points on the patch/aRFS behavior:
+1. Enabling full tuple matching ensures flows are always correctly matched,
+   even with smaller hash sizes.
+2. 5-6% drop in CPU utilization as the packets arrive at the correct CPUs
+   and fewer calls to driver for programming on misses.
+3. Larger hash tables reduces mis-steering due to more unique flow hashes,
+   but still has clashes. However, with larger per-device rps_flow_cnt, old
+   flows take more time to expire and new aRFS flows cannot be added if h/w
+   limits are reached (rps_may_expire_flow() succeeds when 10*rps_flow_cnt
+   pkts have been processed by this cpu that are not part of the flow).
+
+Fixes: 28bf26724fdb0 ("ice: Implement aRFS")
+Signed-off-by: Krishna Kumar <krikku@gmail.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
+Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/intel/ice/ice_arfs.c | 48 +++++++++++++++++++++++
+ 1 file changed, 48 insertions(+)
+
+diff --git a/drivers/net/ethernet/intel/ice/ice_arfs.c b/drivers/net/ethernet/intel/ice/ice_arfs.c
+index 2bc5c7f598444..1f7834c035502 100644
+--- a/drivers/net/ethernet/intel/ice/ice_arfs.c
++++ b/drivers/net/ethernet/intel/ice/ice_arfs.c
+@@ -377,6 +377,50 @@ ice_arfs_is_perfect_flow_set(struct ice_hw *hw, __be16 l3_proto, u8 l4_proto)
+       return false;
+ }
++/**
++ * ice_arfs_cmp - Check if aRFS filter matches this flow.
++ * @fltr_info: filter info of the saved ARFS entry.
++ * @fk: flow dissector keys.
++ * @n_proto:  One of htons(ETH_P_IP) or htons(ETH_P_IPV6).
++ * @ip_proto: One of IPPROTO_TCP or IPPROTO_UDP.
++ *
++ * Since this function assumes limited values for n_proto and ip_proto, it
++ * is meant to be called only from ice_rx_flow_steer().
++ *
++ * Return:
++ * * true     - fltr_info refers to the same flow as fk.
++ * * false    - fltr_info and fk refer to different flows.
++ */
++static bool
++ice_arfs_cmp(const struct ice_fdir_fltr *fltr_info, const struct flow_keys *fk,
++           __be16 n_proto, u8 ip_proto)
++{
++      /* Determine if the filter is for IPv4 or IPv6 based on flow_type,
++       * which is one of ICE_FLTR_PTYPE_NONF_IPV{4,6}_{TCP,UDP}.
++       */
++      bool is_v4 = fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
++                   fltr_info->flow_type == ICE_FLTR_PTYPE_NONF_IPV4_UDP;
++
++      /* Following checks are arranged in the quickest and most discriminative
++       * fields first for early failure.
++       */
++      if (is_v4)
++              return n_proto == htons(ETH_P_IP) &&
++                      fltr_info->ip.v4.src_port == fk->ports.src &&
++                      fltr_info->ip.v4.dst_port == fk->ports.dst &&
++                      fltr_info->ip.v4.src_ip == fk->addrs.v4addrs.src &&
++                      fltr_info->ip.v4.dst_ip == fk->addrs.v4addrs.dst &&
++                      fltr_info->ip.v4.proto == ip_proto;
++
++      return fltr_info->ip.v6.src_port == fk->ports.src &&
++              fltr_info->ip.v6.dst_port == fk->ports.dst &&
++              fltr_info->ip.v6.proto == ip_proto &&
++              !memcmp(&fltr_info->ip.v6.src_ip, &fk->addrs.v6addrs.src,
++                      sizeof(struct in6_addr)) &&
++              !memcmp(&fltr_info->ip.v6.dst_ip, &fk->addrs.v6addrs.dst,
++                      sizeof(struct in6_addr));
++}
++
+ /**
+  * ice_rx_flow_steer - steer the Rx flow to where application is being run
+  * @netdev: ptr to the netdev being adjusted
+@@ -448,6 +492,10 @@ ice_rx_flow_steer(struct net_device *netdev, const struct sk_buff *skb,
+                       continue;
+               fltr_info = &arfs_entry->fltr_info;
++
++              if (!ice_arfs_cmp(fltr_info, &fk, n_proto, ip_proto))
++                      continue;
++
+               ret = fltr_info->fltr_id;
+               if (fltr_info->q_index == rxq_idx ||
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-lan743x-fix-potential-out-of-bounds-write-in-lan.patch b/queue-6.15/net-lan743x-fix-potential-out-of-bounds-write-in-lan.patch
new file mode 100644 (file)
index 0000000..637de0f
--- /dev/null
@@ -0,0 +1,61 @@
+From d53751e7520a779fe3aa66211c6fcb502322f99b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 11:37:43 +0000
+Subject: net: lan743x: fix potential out-of-bounds write in
+ lan743x_ptp_io_event_clock_get()
+
+From: Alexey Kodanev <aleksei.kodanev@bell-sw.com>
+
+[ Upstream commit e353b0854d3a1a31cb061df8d022fbfea53a0f24 ]
+
+Before calling lan743x_ptp_io_event_clock_get(), the 'channel' value
+is checked against the maximum value of PCI11X1X_PTP_IO_MAX_CHANNELS(8).
+This seems correct and aligns with the PTP interrupt status register
+(PTP_INT_STS) specifications.
+
+However, lan743x_ptp_io_event_clock_get() writes to ptp->extts[] with
+only LAN743X_PTP_N_EXTTS(4) elements, using channel as an index:
+
+    lan743x_ptp_io_event_clock_get(..., u8 channel,...)
+    {
+        ...
+        /* Update Local timestamp */
+        extts = &ptp->extts[channel];
+        extts->ts.tv_sec = sec;
+        ...
+    }
+
+To avoid an out-of-bounds write and utilize all the supported GPIO
+inputs, set LAN743X_PTP_N_EXTTS to 8.
+
+Detected using the static analysis tool - Svace.
+Fixes: 60942c397af6 ("net: lan743x: Add support for PTP-IO Event Input External Timestamp (extts)")
+Signed-off-by: Alexey Kodanev <aleksei.kodanev@bell-sw.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Acked-by: Rengarajan S <rengarajan.s@microchip.com>
+Link: https://patch.msgid.link/20250616113743.36284-1-aleksei.kodanev@bell-sw.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/microchip/lan743x_ptp.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/microchip/lan743x_ptp.h b/drivers/net/ethernet/microchip/lan743x_ptp.h
+index 0d29914cd4606..225e8232474d7 100644
+--- a/drivers/net/ethernet/microchip/lan743x_ptp.h
++++ b/drivers/net/ethernet/microchip/lan743x_ptp.h
+@@ -18,9 +18,9 @@
+  */
+ #define LAN743X_PTP_N_EVENT_CHAN      2
+ #define LAN743X_PTP_N_PEROUT          LAN743X_PTP_N_EVENT_CHAN
+-#define LAN743X_PTP_N_EXTTS           4
+-#define LAN743X_PTP_N_PPS             0
+ #define PCI11X1X_PTP_IO_MAX_CHANNELS  8
++#define LAN743X_PTP_N_EXTTS           PCI11X1X_PTP_IO_MAX_CHANNELS
++#define LAN743X_PTP_N_PPS             0
+ #define PTP_CMD_CTL_TIMEOUT_CNT               50
+ struct lan743x_adapter;
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-netmem-fix-skb_ensure_writable-with-unreadable-s.patch b/queue-6.15/net-netmem-fix-skb_ensure_writable-with-unreadable-s.patch
new file mode 100644 (file)
index 0000000..b8e4748
--- /dev/null
@@ -0,0 +1,47 @@
+From b577aae21caf058ba50400d5e505b304526196ba Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sun, 15 Jun 2025 20:07:33 +0000
+Subject: net: netmem: fix skb_ensure_writable with unreadable skbs
+
+From: Mina Almasry <almasrymina@google.com>
+
+[ Upstream commit 6f793a1d053775f8324b8dba1e7ed224f8b0166f ]
+
+skb_ensure_writable should succeed when it's trying to write to the
+header of the unreadable skbs, so it doesn't need an unconditional
+skb_frags_readable check. The preceding pskb_may_pull() call will
+succeed if write_len is within the head and fail if we're trying to
+write to the unreadable payload, so we don't need an additional check.
+
+Removing this check restores DSCP functionality with unreadable skbs as
+it's called from dscp_tg.
+
+Cc: willemb@google.com
+Cc: asml.silence@gmail.com
+Fixes: 65249feb6b3d ("net: add support for skbs with unreadable frags")
+Signed-off-by: Mina Almasry <almasrymina@google.com>
+Acked-by: Stanislav Fomichev <sdf@fomichev.me>
+Link: https://patch.msgid.link/20250615200733.520113-1-almasrymina@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skbuff.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 74a2d886a35b5..86cc58376392b 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -6220,9 +6220,6 @@ int skb_ensure_writable(struct sk_buff *skb, unsigned int write_len)
+       if (!pskb_may_pull(skb, write_len))
+               return -ENOMEM;
+-      if (!skb_frags_readable(skb))
+-              return -EFAULT;
+-
+       if (!skb_cloned(skb) || skb_clone_writable(skb, write_len))
+               return 0;
+-- 
+2.39.5
+
diff --git a/queue-6.15/net-ti-icssg-prueth-fix-packet-handling-for-xdp_tx.patch b/queue-6.15/net-ti-icssg-prueth-fix-packet-handling-for-xdp_tx.patch
new file mode 100644 (file)
index 0000000..8ecf0f7
--- /dev/null
@@ -0,0 +1,86 @@
+From 341a488d382a668580554b5d7346578f7485ca41 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 12:03:19 +0530
+Subject: net: ti: icssg-prueth: Fix packet handling for XDP_TX
+
+From: Meghana Malladi <m-malladi@ti.com>
+
+[ Upstream commit 60524f1d2bdf222db6dc3f680e0272441f697fe4 ]
+
+While transmitting XDP frames for XDP_TX, page_pool is
+used to get the DMA buffers (already mapped to the pages)
+and need to be freed/reycled once the transmission is complete.
+This need not be explicitly done by the driver as this is handled
+more gracefully by the xdp driver while returning the xdp frame.
+__xdp_return() frees the XDP memory based on its memory type,
+under which page_pool memory is also handled. This change fixes
+the transmit queue timeout while running XDP_TX.
+
+logs:
+[  309.069682] icssg-prueth icssg1-eth eth2: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 45860 ms
+[  313.933780] icssg-prueth icssg1-eth eth2: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 50724 ms
+[  319.053656] icssg-prueth icssg1-eth eth2: NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 55844 ms
+...
+
+Fixes: 62aa3246f462 ("net: ti: icssg-prueth: Add XDP support")
+Signed-off-by: Meghana Malladi <m-malladi@ti.com>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20250616063319.3347541-1-m-malladi@ti.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/ti/icssg/icssg_common.c | 19 ++-----------------
+ 1 file changed, 2 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
+index d88a0180294e0..7ae069e7af92b 100644
+--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
++++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
+@@ -98,20 +98,11 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
+ {
+       struct cppi5_host_desc_t *first_desc, *next_desc;
+       dma_addr_t buf_dma, next_desc_dma;
+-      struct prueth_swdata *swdata;
+-      struct page *page;
+       u32 buf_dma_len;
+       first_desc = desc;
+       next_desc = first_desc;
+-      swdata = cppi5_hdesc_get_swdata(desc);
+-      if (swdata->type == PRUETH_SWDATA_PAGE) {
+-              page = swdata->data.page;
+-              page_pool_recycle_direct(page->pp, swdata->data.page);
+-              goto free_desc;
+-      }
+-
+       cppi5_hdesc_get_obuf(first_desc, &buf_dma, &buf_dma_len);
+       k3_udma_glue_tx_cppi5_to_dma_addr(tx_chn->tx_chn, &buf_dma);
+@@ -135,7 +126,6 @@ void prueth_xmit_free(struct prueth_tx_chn *tx_chn,
+               k3_cppi_desc_pool_free(tx_chn->desc_pool, next_desc);
+       }
+-free_desc:
+       k3_cppi_desc_pool_free(tx_chn->desc_pool, first_desc);
+ }
+ EXPORT_SYMBOL_GPL(prueth_xmit_free);
+@@ -612,13 +602,8 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac,
+       k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
+       cppi5_hdesc_attach_buf(first_desc, buf_dma, xdpf->len, buf_dma, xdpf->len);
+       swdata = cppi5_hdesc_get_swdata(first_desc);
+-      if (page) {
+-              swdata->type = PRUETH_SWDATA_PAGE;
+-              swdata->data.page = page;
+-      } else {
+-              swdata->type = PRUETH_SWDATA_XDPF;
+-              swdata->data.xdpf = xdpf;
+-      }
++      swdata->type = PRUETH_SWDATA_XDPF;
++      swdata->data.xdpf = xdpf;
+       /* Report BQL before sending the packet */
+       netif_txq = netdev_get_tx_queue(ndev, tx_chn->id);
+-- 
+2.39.5
+
diff --git a/queue-6.15/octeontx2-pf-fix-backpresure-configuration.patch b/queue-6.15/octeontx2-pf-fix-backpresure-configuration.patch
new file mode 100644 (file)
index 0000000..fbe66f5
--- /dev/null
@@ -0,0 +1,61 @@
+From c499aa27ad5f30cf0f891245e2e21615255641e3 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 12:04:02 +0530
+Subject: Octeontx2-pf: Fix Backpresure configuration
+
+From: Hariprasad Kelam <hkelam@marvell.com>
+
+[ Upstream commit 9ac8d0c640a161486eaf71d1999ee990fad62947 ]
+
+NIX block can receive packets from multiple links such as
+MAC (RPM), LBK and CPT.
+
+       -----------------
+ RPM --|     NIX       |
+       -----------------
+             |
+             |
+            LBK
+
+Each link supports multiple channels for example RPM link supports
+16 channels. In case of link oversubsribe, NIX will assert backpressure
+on receive channels.
+
+The previous patch considered a single channel per link, resulting in
+backpressure not being enabled on the remaining channels
+
+Fixes: a7ef63dbd588 ("octeontx2-af: Disable backpressure between CPT and NIX")
+Signed-off-by: Hariprasad Kelam <hkelam@marvell.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Link: https://patch.msgid.link/20250617063403.3582210-1-hkelam@marvell.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+index 84cd029a85aab..1b3004ba4493e 100644
+--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
++++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c
+@@ -1822,7 +1822,7 @@ int otx2_nix_config_bp(struct otx2_nic *pfvf, bool enable)
+               req->chan_cnt = IEEE_8021QAZ_MAX_TCS;
+               req->bpid_per_chan = 1;
+       } else {
+-              req->chan_cnt = 1;
++              req->chan_cnt = pfvf->hw.rx_chan_cnt;
+               req->bpid_per_chan = 0;
+       }
+@@ -1847,7 +1847,7 @@ int otx2_nix_cpt_config_bp(struct otx2_nic *pfvf, bool enable)
+               req->chan_cnt = IEEE_8021QAZ_MAX_TCS;
+               req->bpid_per_chan = 1;
+       } else {
+-              req->chan_cnt = 1;
++              req->chan_cnt = pfvf->hw.rx_chan_cnt;
+               req->bpid_per_chan = 0;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/pldmfw-select-crc32-when-pldmfw-is-selected.patch b/queue-6.15/pldmfw-select-crc32-when-pldmfw-is-selected.patch
new file mode 100644 (file)
index 0000000..37cf46b
--- /dev/null
@@ -0,0 +1,51 @@
+From a92daa0cc39fd3366c8ce92773e8ebf3ba0ade71 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 17:46:20 +0100
+Subject: pldmfw: Select CRC32 when PLDMFW is selected
+
+From: Simon Horman <horms@kernel.org>
+
+[ Upstream commit 1224b218a4b9203656ecc932152f4c81a97b4fcc ]
+
+pldmfw calls crc32 code and depends on it being enabled, else
+there is a link error as follows. So PLDMFW should select CRC32.
+
+  lib/pldmfw/pldmfw.o: In function `pldmfw_flash_image':
+  pldmfw.c:(.text+0x70f): undefined reference to `crc32_le_base'
+
+This problem was introduced by commit b8265621f488 ("Add pldmfw library
+for PLDM firmware update").
+
+It manifests as of commit d69ea414c9b4 ("ice: implement device flash
+update via devlink").
+
+And is more likely to occur as of commit 9ad19171b6d6 ("lib/crc: remove
+unnecessary prompt for CONFIG_CRC32 and drop 'default y'").
+
+Found by chance while exercising builds based on tinyconfig.
+
+Fixes: b8265621f488 ("Add pldmfw library for PLDM firmware update")
+Signed-off-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
+Link: https://patch.msgid.link/20250613-pldmfw-crc32-v1-1-f3fad109eee6@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ lib/Kconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lib/Kconfig b/lib/Kconfig
+index 6c1b8f1842678..37db228f70a99 100644
+--- a/lib/Kconfig
++++ b/lib/Kconfig
+@@ -716,6 +716,7 @@ config GENERIC_LIB_DEVMEM_IS_ALLOWED
+ config PLDMFW
+       bool
++      select CRC32
+       default n
+ config ASN1_ENCODER
+-- 
+2.39.5
+
diff --git a/queue-6.15/ptp-allow-reading-of-currently-dialed-frequency-to-s.patch b/queue-6.15/ptp-allow-reading-of-currently-dialed-frequency-to-s.patch
new file mode 100644 (file)
index 0000000..f943bcd
--- /dev/null
@@ -0,0 +1,51 @@
+From bb9ffe2fd6eafa579802865873c2aa7d1ca2f4a0 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 20:47:49 +0300
+Subject: ptp: allow reading of currently dialed frequency to succeed on
+ free-running clocks
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit aa112cbc5f0ac6f3b44d829005bf34005d9fe9bb ]
+
+There is a bug in ptp_clock_adjtime() which makes it refuse the
+operation even if we just want to read the current clock dialed
+frequency, not modify anything (tx->modes == 0). That should be possible
+even if the clock is free-running. For context, the kernel UAPI is the
+same for getting and setting the frequency of a POSIX clock.
+
+For example, ptp4l errors out at clock_create() -> clockadj_get_freq()
+-> clock_adjtime() time, when it should logically only have failed on
+actual adjustments to the clock, aka if the clock was configured as
+slave. But in master mode it should work.
+
+This was discovered when examining the issue described in the previous
+commit, where ptp_clock_freerun() returned true despite n_vclocks being
+zero.
+
+Fixes: 73f37068d540 ("ptp: support ptp physical/virtual clocks conversion")
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Link: https://patch.msgid.link/20250613174749.406826-3-vladimir.oltean@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ptp/ptp_clock.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
+index 35a5994bf64f6..36f57d7b4a667 100644
+--- a/drivers/ptp/ptp_clock.c
++++ b/drivers/ptp/ptp_clock.c
+@@ -121,7 +121,8 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct __kernel_timex *tx)
+       struct ptp_clock_info *ops;
+       int err = -EOPNOTSUPP;
+-      if (ptp_clock_freerun(ptp)) {
++      if (tx->modes & (ADJ_SETOFFSET | ADJ_FREQUENCY | ADJ_OFFSET) &&
++          ptp_clock_freerun(ptp)) {
+               pr_err("ptp: physical clock is free running\n");
+               return -EBUSY;
+       }
+-- 
+2.39.5
+
diff --git a/queue-6.15/ptp-fix-breakage-after-ptp_vclock_in_use-rework.patch b/queue-6.15/ptp-fix-breakage-after-ptp_vclock_in_use-rework.patch
new file mode 100644 (file)
index 0000000..9adbab1
--- /dev/null
@@ -0,0 +1,164 @@
+From 17a709af8fb3ec172c0b91d3c3a976aabc83fb33 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 20:47:48 +0300
+Subject: ptp: fix breakage after ptp_vclock_in_use() rework
+
+From: Vladimir Oltean <vladimir.oltean@nxp.com>
+
+[ Upstream commit 5ab73b010cad294851e558f1d4714a85c6f206c7 ]
+
+What is broken
+--------------
+
+ptp4l, and any other application which calls clock_adjtime() on a
+physical clock, is greeted with error -EBUSY after commit 87f7ce260a3c
+("ptp: remove ptp->n_vclocks check logic in ptp_vclock_in_use()").
+
+Explanation for the breakage
+----------------------------
+
+The blamed commit was based on the false assumption that
+ptp_vclock_in_use() callers already test for n_vclocks prior to calling
+this function.
+
+This is notably incorrect for the code path below, in which there is, in
+fact, no n_vclocks test:
+
+ptp_clock_adjtime()
+-> ptp_clock_freerun()
+   -> ptp_vclock_in_use()
+
+The result is that any clock adjustment on any physical clock is now
+impossible. This is _despite_ there not being any vclock over this
+physical clock.
+
+$ ptp4l -i eno0 -2 -P -m
+ptp4l[58.425]: selected /dev/ptp0 as PTP clock
+[   58.429749] ptp: physical clock is free running
+ptp4l[58.431]: Failed to open /dev/ptp0: Device or resource busy
+failed to create a clock
+$ cat /sys/class/ptp/ptp0/n_vclocks
+0
+
+The patch makes the ptp_vclock_in_use() function say "if it's not a
+virtual clock, then this physical clock does have virtual clocks on
+top".
+
+Then ptp_clock_freerun() uses this information to say "this physical
+clock has virtual clocks on top, so it must stay free-running".
+
+Then ptp_clock_adjtime() uses this information to say "well, if this
+physical clock has to be free-running, I can't do it, return -EBUSY".
+
+Simply put, ptp_vclock_in_use() cannot be simplified so as to remove the
+test whether vclocks are in use.
+
+What did the blamed commit intend to fix
+----------------------------------------
+
+The blamed commit presents a lockdep warning stating "possible recursive
+locking detected", with the n_vclocks_store() and ptp_clock_unregister()
+functions involved.
+
+The recursive locking seems this:
+n_vclocks_store()
+-> mutex_lock_interruptible(&ptp->n_vclocks_mux) // 1
+-> device_for_each_child_reverse(..., unregister_vclock)
+   -> unregister_vclock()
+      -> ptp_vclock_unregister()
+         -> ptp_clock_unregister()
+            -> ptp_vclock_in_use()
+               -> mutex_lock_interruptible(&ptp->n_vclocks_mux) // 2
+
+The issue can be triggered by creating and then deleting vclocks:
+$ echo 2 > /sys/class/ptp/ptp0/n_vclocks
+$ echo 0 > /sys/class/ptp/ptp0/n_vclocks
+
+But note that in the original stack trace, the address of the first lock
+is different from the address of the second lock. This is because at
+step 1 marked above, &ptp->n_vclocks_mux is the lock of the parent
+(physical) PTP clock, and at step 2, the lock is of the child (virtual)
+PTP clock. They are different locks of different devices.
+
+In this situation there is no real deadlock, the lockdep warning is
+caused by the fact that the mutexes have the same lock class on both the
+parent and the child. Functionally it is fine.
+
+Proposed alternative solution
+-----------------------------
+
+We must reintroduce the body of ptp_vclock_in_use() mostly as it was
+structured prior to the blamed commit, but avoid the lockdep warning.
+
+Based on the fact that vclocks cannot be nested on top of one another
+(ptp_is_attribute_visible() hides n_vclocks for virtual clocks), we
+already know that ptp->n_vclocks is zero for a virtual clock. And
+ptp->is_virtual_clock is a runtime invariant, established at
+ptp_clock_register() time and never changed. There is no need to
+serialize on any mutex in order to read ptp->is_virtual_clock, and we
+take advantage of that by moving it outside the lock.
+
+Thus, virtual clocks do not need to acquire &ptp->n_vclocks_mux at
+all, and step 2 in the code walkthrough above can simply go away.
+We can simply return false to the question "ptp_vclock_in_use(a virtual
+clock)".
+
+Other notes
+-----------
+
+Releasing &ptp->n_vclocks_mux before ptp_vclock_in_use() returns
+execution seems racy, because the returned value can become stale as
+soon as the function returns and before the return value is used (i.e.
+n_vclocks_store() can run any time). The locking requirement should
+somehow be transferred to the caller, to ensure a longer life time for
+the returned value, but this seems out of scope for this severe bug fix.
+
+Because we are also fixing up the logic from the original commit, there
+is another Fixes: tag for that.
+
+Fixes: 87f7ce260a3c ("ptp: remove ptp->n_vclocks check logic in ptp_vclock_in_use()")
+Fixes: 73f37068d540 ("ptp: support ptp physical/virtual clocks conversion")
+Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
+Link: https://patch.msgid.link/20250613174749.406826-2-vladimir.oltean@nxp.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/ptp/ptp_private.h | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
+index 528d86a33f37d..a6aad743c282f 100644
+--- a/drivers/ptp/ptp_private.h
++++ b/drivers/ptp/ptp_private.h
+@@ -98,7 +98,27 @@ static inline int queue_cnt(const struct timestamp_event_queue *q)
+ /* Check if ptp virtual clock is in use */
+ static inline bool ptp_vclock_in_use(struct ptp_clock *ptp)
+ {
+-      return !ptp->is_virtual_clock;
++      bool in_use = false;
++
++      /* Virtual clocks can't be stacked on top of virtual clocks.
++       * Avoid acquiring the n_vclocks_mux on virtual clocks, to allow this
++       * function to be called from code paths where the n_vclocks_mux of the
++       * parent physical clock is already held. Functionally that's not an
++       * issue, but lockdep would complain, because they have the same lock
++       * class.
++       */
++      if (ptp->is_virtual_clock)
++              return false;
++
++      if (mutex_lock_interruptible(&ptp->n_vclocks_mux))
++              return true;
++
++      if (ptp->n_vclocks)
++              in_use = true;
++
++      mutex_unlock(&ptp->n_vclocks_mux);
++
++      return in_use;
+ }
+ /* Check if ptp clock shall be free running */
+-- 
+2.39.5
+
diff --git a/queue-6.15/rust-devres-do-not-dereference-to-the-internal-revoc.patch b/queue-6.15/rust-devres-do-not-dereference-to-the-internal-revoc.patch
new file mode 100644 (file)
index 0000000..ca65a13
--- /dev/null
@@ -0,0 +1,92 @@
+From facf7db52fc5f02c2656c481b8e0438de2d21a34 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 11 Jun 2025 19:48:25 +0200
+Subject: rust: devres: do not dereference to the internal Revocable
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit 20c96ed278e362ae4e324ed7d8c69fb48c508d3c ]
+
+We can't expose direct access to the internal Revocable, since this
+allows users to directly revoke the internal Revocable without Devres
+having the chance to synchronize with the devres callback -- we have to
+guarantee that the internal Revocable has been fully revoked before
+the device is fully unbound.
+
+Hence, remove the corresponding Deref implementation and, instead,
+provide indirect accessors for the internal Revocable.
+
+Note that we can still support Devres::revoke() by implementing the
+required synchronization (which would be almost identical to the
+synchronization in Devres::drop()).
+
+Fixes: 76c01ded724b ("rust: add devres abstraction")
+Reviewed-by: Benno Lossin <lossin@kernel.org>
+Link: https://lore.kernel.org/r/20250611174827.380555-1-dakr@kernel.org
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ rust/kernel/devres.rs | 27 ++++++++++++++++-----------
+ 1 file changed, 16 insertions(+), 11 deletions(-)
+
+diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
+index acb8e1d13ddd9..5f1a7be2ed512 100644
+--- a/rust/kernel/devres.rs
++++ b/rust/kernel/devres.rs
+@@ -12,13 +12,11 @@
+     error::{Error, Result},
+     ffi::c_void,
+     prelude::*,
+-    revocable::Revocable,
+-    sync::{Arc, Completion},
++    revocable::{Revocable, RevocableGuard},
++    sync::{rcu, Arc, Completion},
+     types::ARef,
+ };
+-use core::ops::Deref;
+-
+ #[pin_data]
+ struct DevresInner<T> {
+     dev: ARef<Device>,
+@@ -232,15 +230,22 @@ pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
+         // SAFETY: `dev` being the same device as the device this `Devres` has been created for
+         // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as
+         // long as `dev` lives; `dev` lives at least as long as `self`.
+-        Ok(unsafe { self.deref().access() })
++        Ok(unsafe { self.0.data.access() })
+     }
+-}
+-impl<T> Deref for Devres<T> {
+-    type Target = Revocable<T>;
++    /// [`Devres`] accessor for [`Revocable::try_access`].
++    pub fn try_access(&self) -> Option<RevocableGuard<'_, T>> {
++        self.0.data.try_access()
++    }
++
++    /// [`Devres`] accessor for [`Revocable::try_access_with`].
++    pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> {
++        self.0.data.try_access_with(f)
++    }
+-    fn deref(&self) -> &Self::Target {
+-        &self.0.data
++    /// [`Devres`] accessor for [`Revocable::try_access_with_guard`].
++    pub fn try_access_with_guard<'a>(&'a self, guard: &'a rcu::Guard) -> Option<&'a T> {
++        self.0.data.try_access_with_guard(guard)
+     }
+ }
+@@ -248,7 +253,7 @@ impl<T> Drop for Devres<T> {
+     fn drop(&mut self) {
+         // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
+         // anymore, hence it is safe not to wait for the grace period to finish.
+-        if unsafe { self.revoke_nosync() } {
++        if unsafe { self.0.data.revoke_nosync() } {
+             // We revoked `self.0.data` before the devres action did, hence try to remove it.
+             if !DevresInner::remove_action(&self.0) {
+                 // We could not remove the devres action, which means that it now runs concurrently,
+-- 
+2.39.5
+
diff --git a/queue-6.15/rust-devres-fix-race-in-devres-drop.patch b/queue-6.15/rust-devres-fix-race-in-devres-drop.patch
new file mode 100644 (file)
index 0000000..dfc4b7b
--- /dev/null
@@ -0,0 +1,210 @@
+From 2ae36e7b63e3826ac02a631f6b209b7fbe13cda5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 12 Jun 2025 14:17:15 +0200
+Subject: rust: devres: fix race in Devres::drop()
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit f744201c6159fc7323c40936fd079525f7063598 ]
+
+In Devres::drop() we first remove the devres action and then drop the
+wrapped device resource.
+
+The design goal is to give the owner of a Devres object control over when
+the device resource is dropped, but limit the overall scope to the
+corresponding device being bound to a driver.
+
+However, there's a race that was introduced with commit 8ff656643d30
+("rust: devres: remove action in `Devres::drop`"), but also has been
+(partially) present from the initial version on.
+
+In Devres::drop(), the devres action is removed successfully and
+subsequently the destructor of the wrapped device resource runs.
+However, there is no guarantee that the destructor of the wrapped device
+resource completes before the driver core is done unbinding the
+corresponding device.
+
+If in Devres::drop(), the devres action can't be removed, it means that
+the devres callback has been executed already, or is still running
+concurrently. In case of the latter, either Devres::drop() wins revoking
+the Revocable or the devres callback wins revoking the Revocable. If
+Devres::drop() wins, we (again) have no guarantee that the destructor of
+the wrapped device resource completes before the driver core is done
+unbinding the corresponding device.
+
+CPU0                                   CPU1
+------------------------------------------------------------------------
+Devres::drop() {                       Devres::devres_callback() {
+   self.data.revoke() {                           this.data.revoke() {
+      is_available.swap() == true
+                                             is_available.swap == false
+                                          }
+                                       }
+
+                                       // [...]
+                                       // device fully unbound
+      drop_in_place() {
+         // release device resource
+      }
+   }
+}
+
+Depending on the specific device resource, this can potentially lead to
+user-after-free bugs.
+
+In order to fix this, implement the following logic.
+
+In the devres callback, we're always good when we get to revoke the
+device resource ourselves, i.e. Revocable::revoke() returns true.
+
+If Revocable::revoke() returns false, it means that Devres::drop(),
+concurrently, already drops the device resource and we have to wait for
+Devres::drop() to signal that it finished dropping the device resource.
+
+Note that if we hit the case where we need to wait for the completion of
+Devres::drop() in the devres callback, it means that we're actually
+racing with a concurrent Devres::drop() call, which already started
+revoking the device resource for us. This is rather unlikely and means
+that the concurrent Devres::drop() already started doing our work and we
+just need to wait for it to complete it for us. Hence, there should not
+be any additional overhead from that.
+
+(Actually, for now it's even better if Devres::drop() does the work for
+us, since it can bypass the synchronize_rcu() call implied by
+Revocable::revoke(), but this goes away anyways once I get to implement
+the split devres callback approach, which allows us to first flip the
+atomics of all registered Devres objects of a certain device, execute a
+single synchronize_rcu() and then drop all revocable objects.)
+
+In Devres::drop() we try to revoke the device resource. If that is *not*
+successful, it means that the devres callback already did and we're good.
+
+Otherwise, we try to remove the devres action, which, if successful,
+means that we're good, since the device resource has just been revoked
+by us *before* we removed the devres action successfully.
+
+If the devres action could not be removed, it means that the devres
+callback must be running concurrently, hence we signal that the device
+resource has been revoked by us, using the completion.
+
+This makes it safe to drop a Devres object from any task and at any point
+of time, which is one of the design goals.
+
+Fixes: 76c01ded724b ("rust: add devres abstraction")
+Reported-by: Alice Ryhl <aliceryhl@google.com>
+Closes: https://lore.kernel.org/lkml/aD64YNuqbPPZHAa5@google.com/
+Reviewed-by: Benno Lossin <lossin@kernel.org>
+Link: https://lore.kernel.org/r/20250612121817.1621-4-dakr@kernel.org
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ rust/kernel/devres.rs | 37 +++++++++++++++++++++++++++++--------
+ 1 file changed, 29 insertions(+), 8 deletions(-)
+
+diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
+index ddb1ce4a78d94..f3a4e3383b8d2 100644
+--- a/rust/kernel/devres.rs
++++ b/rust/kernel/devres.rs
+@@ -13,7 +13,7 @@
+     ffi::c_void,
+     prelude::*,
+     revocable::Revocable,
+-    sync::Arc,
++    sync::{Arc, Completion},
+     types::ARef,
+ };
+@@ -25,13 +25,17 @@ struct DevresInner<T> {
+     callback: unsafe extern "C" fn(*mut c_void),
+     #[pin]
+     data: Revocable<T>,
++    #[pin]
++    revoke: Completion,
+ }
+ /// This abstraction is meant to be used by subsystems to containerize [`Device`] bound resources to
+ /// manage their lifetime.
+ ///
+ /// [`Device`] bound resources should be freed when either the resource goes out of scope or the
+-/// [`Device`] is unbound respectively, depending on what happens first.
++/// [`Device`] is unbound respectively, depending on what happens first. In any case, it is always
++/// guaranteed that revoking the device resource is completed before the corresponding [`Device`]
++/// is unbound.
+ ///
+ /// To achieve that [`Devres`] registers a devres callback on creation, which is called once the
+ /// [`Device`] is unbound, revoking access to the encapsulated resource (see also [`Revocable`]).
+@@ -105,6 +109,7 @@ fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {
+                 dev: dev.into(),
+                 callback: Self::devres_callback,
+                 data <- Revocable::new(data),
++                revoke <- Completion::new(),
+             }),
+             flags,
+         )?;
+@@ -133,26 +138,28 @@ fn as_ptr(&self) -> *const Self {
+         self as _
+     }
+-    fn remove_action(this: &Arc<Self>) {
++    fn remove_action(this: &Arc<Self>) -> bool {
+         // SAFETY:
+         // - `self.inner.dev` is a valid `Device`,
+         // - the `action` and `data` pointers are the exact same ones as given to devm_add_action()
+         //   previously,
+         // - `self` is always valid, even if the action has been released already.
+-        let ret = unsafe {
++        let success = unsafe {
+             bindings::devm_remove_action_nowarn(
+                 this.dev.as_raw(),
+                 Some(this.callback),
+                 this.as_ptr() as _,
+             )
+-        };
++        } == 0;
+-        if ret == 0 {
++        if success {
+             // SAFETY: We leaked an `Arc` reference to devm_add_action() in `DevresInner::new`; if
+             // devm_remove_action_nowarn() was successful we can (and have to) claim back ownership
+             // of this reference.
+             let _ = unsafe { Arc::from_raw(this.as_ptr()) };
+         }
++
++        success
+     }
+     #[allow(clippy::missing_safety_doc)]
+@@ -164,7 +171,12 @@ fn remove_action(this: &Arc<Self>) {
+         //         `DevresInner::new`.
+         let inner = unsafe { Arc::from_raw(ptr) };
+-        inner.data.revoke();
++        if !inner.data.revoke() {
++            // If `revoke()` returns false, it means that `Devres::drop` already started revoking
++            // `inner.data` for us. Hence we have to wait until `Devres::drop()` signals that it
++            // completed revoking `inner.data`.
++            inner.revoke.wait_for_completion();
++        }
+     }
+ }
+@@ -196,6 +208,15 @@ fn deref(&self) -> &Self::Target {
+ impl<T> Drop for Devres<T> {
+     fn drop(&mut self) {
+-        DevresInner::remove_action(&self.0);
++        // SAFETY: When `drop` runs, it is guaranteed that nobody is accessing the revocable data
++        // anymore, hence it is safe not to wait for the grace period to finish.
++        if unsafe { self.revoke_nosync() } {
++            // We revoked `self.0.data` before the devres action did, hence try to remove it.
++            if !DevresInner::remove_action(&self.0) {
++                // We could not remove the devres action, which means that it now runs concurrently,
++                // hence signal that `self.0.data` has been revoked successfully.
++                self.0.revoke.complete_all();
++            }
++        }
+     }
+ }
+-- 
+2.39.5
+
diff --git a/queue-6.15/rust-devres-implement-devres-access.patch b/queue-6.15/rust-devres-implement-devres-access.patch
new file mode 100644 (file)
index 0000000..3dd47d4
--- /dev/null
@@ -0,0 +1,93 @@
+From e9ec190d9683bcc4b1fe276c640b18cebd1bba45 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 28 Apr 2025 16:00:28 +0200
+Subject: rust: devres: implement Devres::access()
+
+From: Danilo Krummrich <dakr@kernel.org>
+
+[ Upstream commit f301cb978c068faa8fcd630be2cb317a2d0ec063 ]
+
+Implement a direct accessor for the data stored within the Devres for
+cases where we can prove that we own a reference to a Device<Bound>
+(i.e. a bound device) of the same device that was used to create the
+corresponding Devres container.
+
+Usually, when accessing the data stored within a Devres container, it is
+not clear whether the data has been revoked already due to the device
+being unbound and, hence, we have to try whether the access is possible
+and subsequently keep holding the RCU read lock for the duration of the
+access.
+
+However, when we can prove that we hold a reference to Device<Bound>
+matching the device the Devres container has been created with, we can
+guarantee that the device is not unbound for the duration of the
+lifetime of the Device<Bound> reference and, hence, it is not possible
+for the data within the Devres container to be revoked.
+
+Therefore, in this case, we can bypass the atomic check and the RCU read
+lock, which is a great optimization and simplification for drivers.
+
+Reviewed-by: Christian Schrefl <chrisi.schrefl@gmail.com>
+Reviewed-by: Alexandre Courbot <acourbot@nvidia.com>
+Acked-by: Boqun Feng <boqun.feng@gmail.com>
+Reviewed-by: Joel Fernandes <joelagnelf@nvidia.com>
+Link: https://lore.kernel.org/r/20250428140137.468709-3-dakr@kernel.org
+Signed-off-by: Danilo Krummrich <dakr@kernel.org>
+Stable-dep-of: 20c96ed278e3 ("rust: devres: do not dereference to the internal Revocable")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ rust/kernel/devres.rs | 38 ++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/rust/kernel/devres.rs b/rust/kernel/devres.rs
+index f3a4e3383b8d2..acb8e1d13ddd9 100644
+--- a/rust/kernel/devres.rs
++++ b/rust/kernel/devres.rs
+@@ -196,6 +196,44 @@ pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result {
+         Ok(())
+     }
++
++    /// Obtain `&'a T`, bypassing the [`Revocable`].
++    ///
++    /// This method allows to directly obtain a `&'a T`, bypassing the [`Revocable`], by presenting
++    /// a `&'a Device<Bound>` of the same [`Device`] this [`Devres`] instance has been created with.
++    ///
++    /// # Errors
++    ///
++    /// An error is returned if `dev` does not match the same [`Device`] this [`Devres`] instance
++    /// has been created with.
++    ///
++    /// # Example
++    ///
++    /// ```no_run
++    /// # use kernel::{device::Core, devres::Devres, pci};
++    ///
++    /// fn from_core(dev: &pci::Device<Core>, devres: Devres<pci::Bar<0x4>>) -> Result {
++    ///     let bar = devres.access(dev.as_ref())?;
++    ///
++    ///     let _ = bar.read32(0x0);
++    ///
++    ///     // might_sleep()
++    ///
++    ///     bar.write32(0x42, 0x0);
++    ///
++    ///     Ok(())
++    /// }
++    /// ```
++    pub fn access<'a>(&'a self, dev: &'a Device<Bound>) -> Result<&'a T> {
++        if self.0.dev.as_raw() != dev.as_raw() {
++            return Err(EINVAL);
++        }
++
++        // SAFETY: `dev` being the same device as the device this `Devres` has been created for
++        // proves that `self.0.data` hasn't been revoked and is guaranteed to not be revoked as
++        // long as `dev` lives; `dev` lives at least as long as `self`.
++        Ok(unsafe { self.deref().access() })
++    }
+ }
+ impl<T> Deref for Devres<T> {
+-- 
+2.39.5
+
index db3430319de27f6cdb00310c5f047fdb72470ca0..0079830452fa6b76114ea01a2158356ee6487ac7 100644 (file)
@@ -502,3 +502,54 @@ sunrpc-handle-svc_garbage-during-svc-auth-processing-as-auth-error.patch
 io_uring-net-always-use-current-transfer-count-for-buffer-put.patch
 drm-xe-svm-fix-regression-disallowing-64k-svm-migration.patch
 drm-v3d-avoid-null-pointer-dereference-in-v3d_job_update_stats.patch
+drm-msm-dp-disable-wide-bus-support-for-sdm845.patch
+drm-msm-disp-correct-porch-timing-for-sdm845.patch
+drm-msm-dsi-dsi_phy_10nm-fix-missing-initial-vco-rat.patch
+drm-msm-fix-cp_reset_context_state-bitfield-names.patch
+drm-msm-a7xx-call-cp_reset_context_state.patch
+drm-ssd130x-fix-ssd132x_clear_screen-columns.patch
+ionic-prevent-driver-fw-getting-out-of-sync-on-devcm.patch
+drm-nouveau-gsp-split-rpc-handling-out-on-its-own.patch
+drm-nouveau-fix-a-use-after-free-in-r535_gsp_rpc_pus.patch
+drm-nouveau-bl-increase-buffer-size-to-avoid-truncat.patch
+rust-devres-fix-race-in-devres-drop.patch
+rust-devres-implement-devres-access.patch
+rust-devres-do-not-dereference-to-the-internal-revoc.patch
+drm-i915-pmu-fix-build-error-with-gcov-and-autofdo-e.patch
+hwmon-occ-rework-attribute-registration-for-stack-us.patch
+hwmon-occ-fix-unaligned-accesses.patch
+hwmon-ltc4282-avoid-repeated-register-write.patch
+pldmfw-select-crc32-when-pldmfw-is-selected.patch
+aoe-clean-device-rq_list-in-aoedev_downdev.patch
+io_uring-sqpoll-don-t-put-task_struct-on-tctx-setup-.patch
+net-ice-perform-accurate-arfs-flow-match.patch
+ice-fix-eswitch-code-memory-leak-in-reset-scenario.patch
+e1000e-set-fixed-clock-frequency-indication-for-nahu.patch
+workqueue-initialize-wq_isolated_cpumask-in-workqueu.patch
+ksmbd-add-free_transport-ops-in-ksmbd-connection.patch
+net-ti-icssg-prueth-fix-packet-handling-for-xdp_tx.patch
+net-netmem-fix-skb_ensure_writable-with-unreadable-s.patch
+bnxt_en-fix-double-invocation-of-bnxt_ulp_stop-bnxt_.patch
+bnxt_en-add-a-helper-function-to-configure-mru-and-r.patch
+bnxt_en-update-mru-and-rss-table-of-rss-contexts-on-.patch
+ptp-fix-breakage-after-ptp_vclock_in_use-rework.patch
+ptp-allow-reading-of-currently-dialed-frequency-to-s.patch
+wifi-carl9170-do-not-ping-device-which-has-failed-to.patch
+mpls-use-rcu_dereference_rtnl-in-mpls_route_input_rc.patch
+atm-atmtcp-free-invalid-length-skb-in-atmtcp_c_send.patch
+tcp-fix-tcp_packet_delayed-for-tcp_is_non_sack_preve.patch
+io_uring-fix-potential-page-leak-in-io_sqe_buffer_re.patch
+drm-amdkfd-move-sdma-queue-reset-capability-check-to.patch
+octeontx2-pf-fix-backpresure-configuration.patch
+tipc-fix-null-ptr-deref-when-acquiring-remote-ip-of-.patch
+tcp-fix-passive-tfo-socket-having-invalid-napi-id.patch
+eth-fbnic-avoid-double-free-when-failing-to-dma-map-.patch
+net-lan743x-fix-potential-out-of-bounds-write-in-lan.patch
+ublk-santizize-the-arguments-from-userspace-when-add.patch
+drm-xe-bmg-update-wa_16023588340.patch
+calipso-fix-null-ptr-deref-in-calipso_req_-set-del-a.patch
+mlxbf_gige-return-eprobe_defer-if-phy-irq-is-not-ava.patch
+net-atm-add-lec_mutex.patch
+net-atm-fix-proc-net-atm-lec-handling.patch
+tools-ynl-parse-extack-for-sub-messages.patch
+tools-ynl-fix-mixing-ops-and-notifications-on-one-so.patch
diff --git a/queue-6.15/tcp-fix-passive-tfo-socket-having-invalid-napi-id.patch b/queue-6.15/tcp-fix-passive-tfo-socket-having-invalid-napi-id.patch
new file mode 100644 (file)
index 0000000..d05cb6c
--- /dev/null
@@ -0,0 +1,51 @@
+From 4bbe0d9afa794e6752740b23d3ff79cdb7f58a43 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 14:21:02 -0700
+Subject: tcp: fix passive TFO socket having invalid NAPI ID
+
+From: David Wei <dw@davidwei.uk>
+
+[ Upstream commit dbe0ca8da1f62b6252e7be6337209f4d86d4a914 ]
+
+There is a bug with passive TFO sockets returning an invalid NAPI ID 0
+from SO_INCOMING_NAPI_ID. Normally this is not an issue, but zero copy
+receive relies on a correct NAPI ID to process sockets on the right
+queue.
+
+Fix by adding a sk_mark_napi_id_set().
+
+Fixes: e5907459ce7e ("tcp: Record Rx hash and NAPI ID in tcp_child_process")
+Signed-off-by: David Wei <dw@davidwei.uk>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250617212102.175711-5-dw@davidwei.uk
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_fastopen.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
+index 1a6b1bc542451..dd8b60f5c5553 100644
+--- a/net/ipv4/tcp_fastopen.c
++++ b/net/ipv4/tcp_fastopen.c
+@@ -3,6 +3,7 @@
+ #include <linux/tcp.h>
+ #include <linux/rcupdate.h>
+ #include <net/tcp.h>
++#include <net/busy_poll.h>
+ void tcp_fastopen_init_key_once(struct net *net)
+ {
+@@ -279,6 +280,8 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,
+       refcount_set(&req->rsk_refcnt, 2);
++      sk_mark_napi_id_set(child, skb);
++
+       /* Now finish processing the fastopen child socket. */
+       tcp_init_transfer(child, BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB, skb);
+-- 
+2.39.5
+
diff --git a/queue-6.15/tcp-fix-tcp_packet_delayed-for-tcp_is_non_sack_preve.patch b/queue-6.15/tcp-fix-tcp_packet_delayed-for-tcp_is_non_sack_preve.patch
new file mode 100644 (file)
index 0000000..e351edc
--- /dev/null
@@ -0,0 +1,108 @@
+From 08a17f2a53b94df2425dff4dde8e0a58fcef4fcb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 13 Jun 2025 15:30:56 -0400
+Subject: tcp: fix tcp_packet_delayed() for tcp_is_non_sack_preventing_reopen()
+ behavior
+
+From: Neal Cardwell <ncardwell@google.com>
+
+[ Upstream commit d0fa59897e049e84432600e86df82aab3dce7aa5 ]
+
+After the following commit from 2024:
+
+commit e37ab7373696 ("tcp: fix to allow timestamp undo if no retransmits were sent")
+
+...there was buggy behavior where TCP connections without SACK support
+could easily see erroneous undo events at the end of fast recovery or
+RTO recovery episodes. The erroneous undo events could cause those
+connections to suffer repeated loss recovery episodes and high
+retransmit rates.
+
+The problem was an interaction between the non-SACK behavior on these
+connections and the undo logic. The problem is that, for non-SACK
+connections at the end of a loss recovery episode, if snd_una ==
+high_seq, then tcp_is_non_sack_preventing_reopen() holds steady in
+CA_Recovery or CA_Loss, but clears tp->retrans_stamp to 0. Then upon
+the next ACK the "tcp: fix to allow timestamp undo if no retransmits
+were sent" logic saw the tp->retrans_stamp at 0 and erroneously
+concluded that no data was retransmitted, and erroneously performed an
+undo of the cwnd reduction, restoring cwnd immediately to the value it
+had before loss recovery.  This caused an immediate burst of traffic
+and build-up of queues and likely another immediate loss recovery
+episode.
+
+This commit fixes tcp_packet_delayed() to ignore zero retrans_stamp
+values for non-SACK connections when snd_una is at or above high_seq,
+because tcp_is_non_sack_preventing_reopen() clears retrans_stamp in
+this case, so it's not a valid signal that we can undo.
+
+Note that the commit named in the Fixes footer restored long-present
+behavior from roughly 2005-2019, so apparently this bug was present
+for a while during that era, and this was simply not caught.
+
+Fixes: e37ab7373696 ("tcp: fix to allow timestamp undo if no retransmits were sent")
+Reported-by: Eric Wheeler <netdev@lists.ewheeler.net>
+Closes: https://lore.kernel.org/netdev/64ea9333-e7f9-0df-b0f2-8d566143acab@ewheeler.net/
+Signed-off-by: Neal Cardwell <ncardwell@google.com>
+Co-developed-by: Yuchung Cheng <ycheng@google.com>
+Signed-off-by: Yuchung Cheng <ycheng@google.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_input.c | 37 +++++++++++++++++++++++++------------
+ 1 file changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
+index 49adcbd73074d..bce2a111cc9e0 100644
+--- a/net/ipv4/tcp_input.c
++++ b/net/ipv4/tcp_input.c
+@@ -2480,20 +2480,33 @@ static inline bool tcp_packet_delayed(const struct tcp_sock *tp)
+ {
+       const struct sock *sk = (const struct sock *)tp;
+-      if (tp->retrans_stamp &&
+-          tcp_tsopt_ecr_before(tp, tp->retrans_stamp))
+-              return true;  /* got echoed TS before first retransmission */
+-
+-      /* Check if nothing was retransmitted (retrans_stamp==0), which may
+-       * happen in fast recovery due to TSQ. But we ignore zero retrans_stamp
+-       * in TCP_SYN_SENT, since when we set FLAG_SYN_ACKED we also clear
+-       * retrans_stamp even if we had retransmitted the SYN.
++      /* Received an echoed timestamp before the first retransmission? */
++      if (tp->retrans_stamp)
++              return tcp_tsopt_ecr_before(tp, tp->retrans_stamp);
++
++      /* We set tp->retrans_stamp upon the first retransmission of a loss
++       * recovery episode, so normally if tp->retrans_stamp is 0 then no
++       * retransmission has happened yet (likely due to TSQ, which can cause
++       * fast retransmits to be delayed). So if snd_una advanced while
++       * (tp->retrans_stamp is 0 then apparently a packet was merely delayed,
++       * not lost. But there are exceptions where we retransmit but then
++       * clear tp->retrans_stamp, so we check for those exceptions.
+        */
+-      if (!tp->retrans_stamp &&          /* no record of a retransmit/SYN? */
+-          sk->sk_state != TCP_SYN_SENT)  /* not the FLAG_SYN_ACKED case? */
+-              return true;  /* nothing was retransmitted */
+-      return false;
++      /* (1) For non-SACK connections, tcp_is_non_sack_preventing_reopen()
++       * clears tp->retrans_stamp when snd_una == high_seq.
++       */
++      if (!tcp_is_sack(tp) && !before(tp->snd_una, tp->high_seq))
++              return false;
++
++      /* (2) In TCP_SYN_SENT tcp_clean_rtx_queue() clears tp->retrans_stamp
++       * when setting FLAG_SYN_ACKED is set, even if the SYN was
++       * retransmitted.
++       */
++      if (sk->sk_state == TCP_SYN_SENT)
++              return false;
++
++      return true;    /* tp->retrans_stamp is zero; no retransmit yet */
+ }
+ /* Undo procedures. */
+-- 
+2.39.5
+
diff --git a/queue-6.15/tipc-fix-null-ptr-deref-when-acquiring-remote-ip-of-.patch b/queue-6.15/tipc-fix-null-ptr-deref-when-acquiring-remote-ip-of-.patch
new file mode 100644 (file)
index 0000000..9829b37
--- /dev/null
@@ -0,0 +1,65 @@
+From bec1583bb238b4d75443ca585f46fad8dd6f88d8 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 05:56:24 +0000
+Subject: tipc: fix null-ptr-deref when acquiring remote ip of ethernet bearer
+
+From: Haixia Qu <hxqu@hillstonenet.com>
+
+[ Upstream commit f82727adcf2992822e12198792af450a76ebd5ef ]
+
+The reproduction steps:
+1. create a tun interface
+2. enable l2 bearer
+3. TIPC_NL_UDP_GET_REMOTEIP with media name set to tun
+
+tipc: Started in network mode
+tipc: Node identity 8af312d38a21, cluster identity 4711
+tipc: Enabled bearer <eth:syz_tun>, priority 1
+Oops: general protection fault
+KASAN: null-ptr-deref in range
+CPU: 1 UID: 1000 PID: 559 Comm: poc Not tainted 6.16.0-rc1+ #117 PREEMPT
+Hardware name: QEMU Ubuntu 24.04 PC
+RIP: 0010:tipc_udp_nl_dump_remoteip+0x4a4/0x8f0
+
+the ub was in fact a struct dev.
+
+when bid != 0 && skip_cnt != 0, bearer_list[bid] may be NULL or
+other media when other thread changes it.
+
+fix this by checking media_id.
+
+Fixes: 832629ca5c313 ("tipc: add UDP remoteip dump to netlink API")
+Signed-off-by: Haixia Qu <hxqu@hillstonenet.com>
+Reviewed-by: Tung Nguyen <tung.quang.nguyen@est.tech>
+Link: https://patch.msgid.link/20250617055624.2680-1-hxqu@hillstonenet.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/tipc/udp_media.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
+index 108a4cc2e0010..258d6aa4f21ae 100644
+--- a/net/tipc/udp_media.c
++++ b/net/tipc/udp_media.c
+@@ -489,7 +489,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
+               rtnl_lock();
+               b = tipc_bearer_find(net, bname);
+-              if (!b) {
++              if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
+                       rtnl_unlock();
+                       return -EINVAL;
+               }
+@@ -500,7 +500,7 @@ int tipc_udp_nl_dump_remoteip(struct sk_buff *skb, struct netlink_callback *cb)
+               rtnl_lock();
+               b = rtnl_dereference(tn->bearer_list[bid]);
+-              if (!b) {
++              if (!b || b->bcast_addr.media_id != TIPC_MEDIA_TYPE_UDP) {
+                       rtnl_unlock();
+                       return -EINVAL;
+               }
+-- 
+2.39.5
+
diff --git a/queue-6.15/tools-ynl-fix-mixing-ops-and-notifications-on-one-so.patch b/queue-6.15/tools-ynl-fix-mixing-ops-and-notifications-on-one-so.patch
new file mode 100644 (file)
index 0000000..2ee86fe
--- /dev/null
@@ -0,0 +1,112 @@
+From 62a057f1d0252a762e2175862c1061e032bb64bf Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Jun 2025 10:17:46 -0700
+Subject: tools: ynl: fix mixing ops and notifications on one socket
+
+From: Jakub Kicinski <kuba@kernel.org>
+
+[ Upstream commit 9738280aae592b579a25b5b1b6584c894827d3c7 ]
+
+The multi message support loosened the connection between the request
+and response handling, as we can now submit multiple requests before
+we start processing responses. Passing the attr set to NlMsgs decoding
+no longer makes sense (if it ever did), attr set may differ message
+by messsage. Isolate the part of decoding responsible for attr-set
+specific interpretation and call it once we identified the correct op.
+
+Without this fix performing SET operation on an ethtool socket, while
+being subscribed to notifications causes:
+
+ # File "tools/net/ynl/pyynl/lib/ynl.py", line 1096, in _op
+ # Exception|     return self._ops(ops)[0]
+ # Exception|            ~~~~~~~~~^^^^^
+ # File "tools/net/ynl/pyynl/lib/ynl.py", line 1040, in _ops
+ # Exception|     nms = NlMsgs(reply, attr_space=op.attr_set)
+ # Exception|                                    ^^^^^^^^^^^
+
+The value of op we use on line 1040 is stale, it comes form the previous
+loop. If a notification comes before a response we will update op to None
+and the next iteration thru the loop will break with the trace above.
+
+Fixes: 6fda63c45fe8 ("tools/net/ynl: fix cli.py --subscribe feature")
+Fixes: ba8be00f68f5 ("tools/net/ynl: Add multi message support to ynl")
+Reviewed-by: Donald Hunter <donald.hunter@gmail.com>
+Link: https://patch.msgid.link/20250618171746.1201403-1-kuba@kernel.org
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/net/ynl/pyynl/lib/ynl.py | 28 +++++++++++++++++-----------
+ 1 file changed, 17 insertions(+), 11 deletions(-)
+
+diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py
+index 55b59f6c79b89..61deb59230671 100644
+--- a/tools/net/ynl/pyynl/lib/ynl.py
++++ b/tools/net/ynl/pyynl/lib/ynl.py
+@@ -231,14 +231,7 @@ class NlMsg:
+                     self.extack['unknown'].append(extack)
+             if attr_space:
+-                # We don't have the ability to parse nests yet, so only do global
+-                if 'miss-type' in self.extack and 'miss-nest' not in self.extack:
+-                    miss_type = self.extack['miss-type']
+-                    if miss_type in attr_space.attrs_by_val:
+-                        spec = attr_space.attrs_by_val[miss_type]
+-                        self.extack['miss-type'] = spec['name']
+-                        if 'doc' in spec:
+-                            self.extack['miss-type-doc'] = spec['doc']
++                self.annotate_extack(attr_space)
+     def _decode_policy(self, raw):
+         policy = {}
+@@ -264,6 +257,18 @@ class NlMsg:
+                 policy['mask'] = attr.as_scalar('u64')
+         return policy
++    def annotate_extack(self, attr_space):
++        """ Make extack more human friendly with attribute information """
++
++        # We don't have the ability to parse nests yet, so only do global
++        if 'miss-type' in self.extack and 'miss-nest' not in self.extack:
++            miss_type = self.extack['miss-type']
++            if miss_type in attr_space.attrs_by_val:
++                spec = attr_space.attrs_by_val[miss_type]
++                self.extack['miss-type'] = spec['name']
++                if 'doc' in spec:
++                    self.extack['miss-type-doc'] = spec['doc']
++
+     def cmd(self):
+         return self.nl_type
+@@ -277,12 +282,12 @@ class NlMsg:
+ class NlMsgs:
+-    def __init__(self, data, attr_space=None):
++    def __init__(self, data):
+         self.msgs = []
+         offset = 0
+         while offset < len(data):
+-            msg = NlMsg(data, offset, attr_space=attr_space)
++            msg = NlMsg(data, offset)
+             offset += msg.nl_len
+             self.msgs.append(msg)
+@@ -1034,12 +1039,13 @@ class YnlFamily(SpecFamily):
+         op_rsp = []
+         while not done:
+             reply = self.sock.recv(self._recv_size)
+-            nms = NlMsgs(reply, attr_space=op.attr_set)
++            nms = NlMsgs(reply)
+             self._recv_dbg_print(reply, nms)
+             for nl_msg in nms:
+                 if nl_msg.nl_seq in reqs_by_seq:
+                     (op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
+                     if nl_msg.extack:
++                        nl_msg.annotate_extack(op.attr_set)
+                         self._decode_extack(req_msg, op, nl_msg.extack, vals)
+                 else:
+                     op = None
+-- 
+2.39.5
+
diff --git a/queue-6.15/tools-ynl-parse-extack-for-sub-messages.patch b/queue-6.15/tools-ynl-parse-extack-for-sub-messages.patch
new file mode 100644 (file)
index 0000000..03d6d82
--- /dev/null
@@ -0,0 +1,135 @@
+From 5b2753e38305df1d88412a0eb14e873aed2a4e7d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 23 May 2025 11:30:31 +0100
+Subject: tools: ynl: parse extack for sub-messages
+
+From: Donald Hunter <donald.hunter@gmail.com>
+
+[ Upstream commit 09d7ff0694ea133c50ad905fd6e548c13f8af458 ]
+
+Extend the Python YNL extack decoding to handle sub-messages in the same
+way that YNL C does. This involves retaining the input values so that
+they are available during extack decoding.
+
+./tools/net/ynl/pyynl/cli.py --family rt-link --do newlink --create \
+    --json '{
+        "linkinfo": {"kind": "netkit", "data": {"policy": 10} }
+    }'
+Netlink error: Invalid argument
+nl_len = 92 (76) nl_flags = 0x300 nl_type = 2
+       error: -22
+       extack: {'msg': 'Provided default xmit policy not supported', 'bad-attr': '.linkinfo.data(netkit).policy'}
+
+Signed-off-by: Donald Hunter <donald.hunter@gmail.com>
+Link: https://patch.msgid.link/20250523103031.80236-1-donald.hunter@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Stable-dep-of: 9738280aae59 ("tools: ynl: fix mixing ops and notifications on one socket")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ tools/net/ynl/pyynl/lib/ynl.py | 39 ++++++++++++++++++++++------------
+ 1 file changed, 25 insertions(+), 14 deletions(-)
+
+diff --git a/tools/net/ynl/pyynl/lib/ynl.py b/tools/net/ynl/pyynl/lib/ynl.py
+index dcc2c6b298d60..55b59f6c79b89 100644
+--- a/tools/net/ynl/pyynl/lib/ynl.py
++++ b/tools/net/ynl/pyynl/lib/ynl.py
+@@ -594,7 +594,7 @@ class YnlFamily(SpecFamily):
+             scalar_selector = self._get_scalar(attr, value["selector"])
+             attr_payload = struct.pack("II", scalar_value, scalar_selector)
+         elif attr['type'] == 'sub-message':
+-            msg_format = self._resolve_selector(attr, search_attrs)
++            msg_format, _ = self._resolve_selector(attr, search_attrs)
+             attr_payload = b''
+             if msg_format.fixed_header:
+                 attr_payload += self._encode_struct(msg_format.fixed_header, value)
+@@ -712,10 +712,10 @@ class YnlFamily(SpecFamily):
+             raise Exception(f"No message format for '{value}' in sub-message spec '{sub_msg}'")
+         spec = sub_msg_spec.formats[value]
+-        return spec
++        return spec, value
+     def _decode_sub_msg(self, attr, attr_spec, search_attrs):
+-        msg_format = self._resolve_selector(attr_spec, search_attrs)
++        msg_format, _ = self._resolve_selector(attr_spec, search_attrs)
+         decoded = {}
+         offset = 0
+         if msg_format.fixed_header:
+@@ -787,7 +787,7 @@ class YnlFamily(SpecFamily):
+         return rsp
+-    def _decode_extack_path(self, attrs, attr_set, offset, target):
++    def _decode_extack_path(self, attrs, attr_set, offset, target, search_attrs):
+         for attr in attrs:
+             try:
+                 attr_spec = attr_set.attrs_by_val[attr.type]
+@@ -801,26 +801,37 @@ class YnlFamily(SpecFamily):
+             if offset + attr.full_len <= target:
+                 offset += attr.full_len
+                 continue
+-            if attr_spec['type'] != 'nest':
++
++            pathname = attr_spec.name
++            if attr_spec['type'] == 'nest':
++                sub_attrs = self.attr_sets[attr_spec['nested-attributes']]
++                search_attrs = SpaceAttrs(sub_attrs, search_attrs.lookup(attr_spec['name']))
++            elif attr_spec['type'] == 'sub-message':
++                msg_format, value = self._resolve_selector(attr_spec, search_attrs)
++                if msg_format is None:
++                    raise Exception(f"Can't resolve sub-message of {attr_spec['name']} for extack")
++                sub_attrs = self.attr_sets[msg_format.attr_set]
++                pathname += f"({value})"
++            else:
+                 raise Exception(f"Can't dive into {attr.type} ({attr_spec['name']}) for extack")
+             offset += 4
+-            subpath = self._decode_extack_path(NlAttrs(attr.raw),
+-                                               self.attr_sets[attr_spec['nested-attributes']],
+-                                               offset, target)
++            subpath = self._decode_extack_path(NlAttrs(attr.raw), sub_attrs,
++                                               offset, target, search_attrs)
+             if subpath is None:
+                 return None
+-            return '.' + attr_spec.name + subpath
++            return '.' + pathname + subpath
+         return None
+-    def _decode_extack(self, request, op, extack):
++    def _decode_extack(self, request, op, extack, vals):
+         if 'bad-attr-offs' not in extack:
+             return
+         msg = self.nlproto.decode(self, NlMsg(request, 0, op.attr_set), op)
+         offset = self.nlproto.msghdr_size() + self._struct_size(op.fixed_header)
++        search_attrs = SpaceAttrs(op.attr_set, vals)
+         path = self._decode_extack_path(msg.raw_attrs, op.attr_set, offset,
+-                                        extack['bad-attr-offs'])
++                                        extack['bad-attr-offs'], search_attrs)
+         if path:
+             del extack['bad-attr-offs']
+             extack['bad-attr'] = path
+@@ -1012,7 +1023,7 @@ class YnlFamily(SpecFamily):
+         for (method, vals, flags) in ops:
+             op = self.ops[method]
+             msg = self._encode_message(op, vals, flags, req_seq)
+-            reqs_by_seq[req_seq] = (op, msg, flags)
++            reqs_by_seq[req_seq] = (op, vals, msg, flags)
+             payload += msg
+             req_seq += 1
+@@ -1027,9 +1038,9 @@ class YnlFamily(SpecFamily):
+             self._recv_dbg_print(reply, nms)
+             for nl_msg in nms:
+                 if nl_msg.nl_seq in reqs_by_seq:
+-                    (op, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
++                    (op, vals, req_msg, req_flags) = reqs_by_seq[nl_msg.nl_seq]
+                     if nl_msg.extack:
+-                        self._decode_extack(req_msg, op, nl_msg.extack)
++                        self._decode_extack(req_msg, op, nl_msg.extack, vals)
+                 else:
+                     op = None
+                     req_flags = []
+-- 
+2.39.5
+
diff --git a/queue-6.15/ublk-santizize-the-arguments-from-userspace-when-add.patch b/queue-6.15/ublk-santizize-the-arguments-from-userspace-when-add.patch
new file mode 100644 (file)
index 0000000..b94296a
--- /dev/null
@@ -0,0 +1,40 @@
+From bfe32a3742eb6212bf1cf4e8ce158e773461bc6d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 19 Jun 2025 12:10:31 +1000
+Subject: ublk: santizize the arguments from userspace when adding a device
+
+From: Ronnie Sahlberg <rsahlberg@whamcloud.com>
+
+[ Upstream commit 8c8472855884355caf3d8e0c50adf825f83454b2 ]
+
+Sanity check the values for queue depth and number of queues
+we get from userspace when adding a device.
+
+Signed-off-by: Ronnie Sahlberg <rsahlberg@whamcloud.com>
+Reviewed-by: Ming Lei <ming.lei@redhat.com>
+Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver")
+Fixes: 62fe99cef94a ("ublk: add read()/write() support for ublk char device")
+Link: https://lore.kernel.org/r/20250619021031.181340-1-ronniesahlberg@gmail.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/block/ublk_drv.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
+index dc104c025cd56..8a482853a75ed 100644
+--- a/drivers/block/ublk_drv.c
++++ b/drivers/block/ublk_drv.c
+@@ -2710,6 +2710,9 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header)
+       if (copy_from_user(&info, argp, sizeof(info)))
+               return -EFAULT;
++      if (info.queue_depth > UBLK_MAX_QUEUE_DEPTH || info.nr_hw_queues > UBLK_MAX_NR_QUEUES)
++              return -EINVAL;
++
+       if (capable(CAP_SYS_ADMIN))
+               info.flags &= ~UBLK_F_UNPRIVILEGED_DEV;
+       else if (!(info.flags & UBLK_F_UNPRIVILEGED_DEV))
+-- 
+2.39.5
+
diff --git a/queue-6.15/wifi-carl9170-do-not-ping-device-which-has-failed-to.patch b/queue-6.15/wifi-carl9170-do-not-ping-device-which-has-failed-to.patch
new file mode 100644 (file)
index 0000000..e2360d5
--- /dev/null
@@ -0,0 +1,63 @@
+From adb7532278ee7f1351c585d34b3eca851194fd74 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 16 Jun 2025 21:12:05 +0300
+Subject: wifi: carl9170: do not ping device which has failed to load firmware
+
+From: Dmitry Antipov <dmantipov@yandex.ru>
+
+[ Upstream commit 15d25307692312cec4b57052da73387f91a2e870 ]
+
+Syzkaller reports [1, 2] crashes caused by an attempts to ping
+the device which has failed to load firmware. Since such a device
+doesn't pass 'ieee80211_register_hw()', an internal workqueue
+managed by 'ieee80211_queue_work()' is not yet created and an
+attempt to queue work on it causes null-ptr-deref.
+
+[1] https://syzkaller.appspot.com/bug?extid=9a4aec827829942045ff
+[2] https://syzkaller.appspot.com/bug?extid=0d8afba53e8fb2633217
+
+Fixes: e4a668c59080 ("carl9170: fix spurious restart due to high latency")
+Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>
+Acked-by: Christian Lamparter <chunkeey@gmail.com>
+Link: https://patch.msgid.link/20250616181205.38883-1-dmantipov@yandex.ru
+Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/wireless/ath/carl9170/usb.c | 19 +++++++++++++------
+ 1 file changed, 13 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/carl9170/usb.c b/drivers/net/wireless/ath/carl9170/usb.c
+index a3e03580cd9ff..564ca6a619856 100644
+--- a/drivers/net/wireless/ath/carl9170/usb.c
++++ b/drivers/net/wireless/ath/carl9170/usb.c
+@@ -438,14 +438,21 @@ static void carl9170_usb_rx_complete(struct urb *urb)
+               if (atomic_read(&ar->rx_anch_urbs) == 0) {
+                       /*
+-                       * The system is too slow to cope with
+-                       * the enormous workload. We have simply
+-                       * run out of active rx urbs and this
+-                       * unfortunately leads to an unpredictable
+-                       * device.
++                       * At this point, either the system is too slow to
++                       * cope with the enormous workload (so we have simply
++                       * run out of active rx urbs and this unfortunately
++                       * leads to an unpredictable device), or the device
++                       * is not fully functional after an unsuccessful
++                       * firmware loading attempts (so it doesn't pass
++                       * ieee80211_register_hw() and there is no internal
++                       * workqueue at all).
+                        */
+-                      ieee80211_queue_work(ar->hw, &ar->ping_work);
++                      if (ar->registered)
++                              ieee80211_queue_work(ar->hw, &ar->ping_work);
++                      else
++                              pr_warn_once("device %s is not registered\n",
++                                           dev_name(&ar->udev->dev));
+               }
+       } else {
+               /*
+-- 
+2.39.5
+
diff --git a/queue-6.15/workqueue-initialize-wq_isolated_cpumask-in-workqueu.patch b/queue-6.15/workqueue-initialize-wq_isolated_cpumask-in-workqueu.patch
new file mode 100644 (file)
index 0000000..48d5b24
--- /dev/null
@@ -0,0 +1,45 @@
+From 5891a4761b7d8690ebf633bfe263d77cacdd45e7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 17 Jun 2025 12:42:16 +0800
+Subject: workqueue: Initialize wq_isolated_cpumask in workqueue_init_early()
+
+From: Chuyi Zhou <zhouchuyi@bytedance.com>
+
+[ Upstream commit 261dce3d64021e7ec828a17b4975ce9182e54ceb ]
+
+Now when isolcpus is enabled via the cmdline, wq_isolated_cpumask does
+not include these isolated CPUs, even wq_unbound_cpumask has already
+excluded them. It is only when we successfully configure an isolate cpuset
+partition that wq_isolated_cpumask gets overwritten by
+workqueue_unbound_exclude_cpumask(), including both the cmdline-specified
+isolated CPUs and the isolated CPUs within the cpuset partitions.
+
+Fix this issue by initializing wq_isolated_cpumask properly in
+workqueue_init_early().
+
+Fixes: fe28f631fa94 ("workqueue: Add workqueue_unbound_exclude_cpumask() to exclude CPUs from wq_unbound_cpumask")
+Signed-off-by: Chuyi Zhou <zhouchuyi@bytedance.com>
+Reviewed-by: Waiman Long <longman@redhat.com>
+Signed-off-by: Tejun Heo <tj@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ kernel/workqueue.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/kernel/workqueue.c b/kernel/workqueue.c
+index 1ea62b8c76b32..c8083dd300167 100644
+--- a/kernel/workqueue.c
++++ b/kernel/workqueue.c
+@@ -7756,7 +7756,8 @@ void __init workqueue_init_early(void)
+               restrict_unbound_cpumask("workqueue.unbound_cpus", &wq_cmdline_cpumask);
+       cpumask_copy(wq_requested_unbound_cpumask, wq_unbound_cpumask);
+-
++      cpumask_andnot(wq_isolated_cpumask, cpu_possible_mask,
++                                              housekeeping_cpumask(HK_TYPE_DOMAIN));
+       pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
+       unbound_wq_update_pwq_attrs_buf = alloc_workqueue_attrs();
+-- 
+2.39.5
+