diff options
52 files changed, 6066 insertions, 0 deletions
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 index 0000000000..71f94a70ce --- /dev/null +++ b/queue-6.15/aoe-clean-device-rq_list-in-aoedev_downdev.patch @@ -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 index 0000000000..226b261d37 --- /dev/null +++ b/queue-6.15/atm-atmtcp-free-invalid-length-skb-in-atmtcp_c_send.patch @@ -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 index 0000000000..f31c45cabb --- /dev/null +++ b/queue-6.15/bnxt_en-add-a-helper-function-to-configure-mru-and-r.patch @@ -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 index 0000000000..350894fa89 --- /dev/null +++ b/queue-6.15/bnxt_en-fix-double-invocation-of-bnxt_ulp_stop-bnxt_.patch @@ -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 index 0000000000..1e028fea8b --- /dev/null +++ b/queue-6.15/bnxt_en-update-mru-and-rss-table-of-rss-contexts-on-.patch @@ -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 index 0000000000..81aa83eea7 --- /dev/null +++ b/queue-6.15/calipso-fix-null-ptr-deref-in-calipso_req_-set-del-a.patch @@ -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 index 0000000000..e96c547d6a --- /dev/null +++ b/queue-6.15/drm-amdkfd-move-sdma-queue-reset-capability-check-to.patch @@ -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 index 0000000000..17c42b9a72 --- /dev/null +++ b/queue-6.15/drm-i915-pmu-fix-build-error-with-gcov-and-autofdo-e.patch @@ -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 index 0000000000..56886355d3 --- /dev/null +++ b/queue-6.15/drm-msm-a7xx-call-cp_reset_context_state.patch @@ -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 index 0000000000..5e640dc7c1 --- /dev/null +++ b/queue-6.15/drm-msm-disp-correct-porch-timing-for-sdm845.patch @@ -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 index 0000000000..226fdb15bd --- /dev/null +++ b/queue-6.15/drm-msm-dp-disable-wide-bus-support-for-sdm845.patch @@ -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 index 0000000000..05027471bb --- /dev/null +++ b/queue-6.15/drm-msm-dsi-dsi_phy_10nm-fix-missing-initial-vco-rat.patch @@ -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 index 0000000000..612a93cd1b --- /dev/null +++ b/queue-6.15/drm-msm-fix-cp_reset_context_state-bitfield-names.patch @@ -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 index 0000000000..62c1ac7396 --- /dev/null +++ b/queue-6.15/drm-nouveau-bl-increase-buffer-size-to-avoid-truncat.patch @@ -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 index 0000000000..9b427b2488 --- /dev/null +++ b/queue-6.15/drm-nouveau-fix-a-use-after-free-in-r535_gsp_rpc_pus.patch @@ -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 index 0000000000..b50ae9977c --- /dev/null +++ b/queue-6.15/drm-nouveau-gsp-split-rpc-handling-out-on-its-own.patch @@ -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 index 0000000000..4ec131c8dd --- /dev/null +++ b/queue-6.15/drm-ssd130x-fix-ssd132x_clear_screen-columns.patch @@ -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 index 0000000000..2e11d68302 --- /dev/null +++ b/queue-6.15/drm-xe-bmg-update-wa_16023588340.patch @@ -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 index 0000000000..9b24ecf654 --- /dev/null +++ b/queue-6.15/e1000e-set-fixed-clock-frequency-indication-for-nahu.patch @@ -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 index 0000000000..20b45d5808 --- /dev/null +++ b/queue-6.15/eth-fbnic-avoid-double-free-when-failing-to-dma-map-.patch @@ -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 index 0000000000..1ab948e2ba --- /dev/null +++ b/queue-6.15/hwmon-ltc4282-avoid-repeated-register-write.patch @@ -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 index 0000000000..b52edffbb7 --- /dev/null +++ b/queue-6.15/hwmon-occ-fix-unaligned-accesses.patch @@ -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 index 0000000000..f8d012c3b4 --- /dev/null +++ b/queue-6.15/hwmon-occ-rework-attribute-registration-for-stack-us.patch @@ -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 index 0000000000..226dc494e9 --- /dev/null +++ b/queue-6.15/ice-fix-eswitch-code-memory-leak-in-reset-scenario.patch @@ -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 index 0000000000..abfa319060 --- /dev/null +++ b/queue-6.15/io_uring-fix-potential-page-leak-in-io_sqe_buffer_re.patch @@ -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 index 0000000000..9ec91a1275 --- /dev/null +++ b/queue-6.15/io_uring-sqpoll-don-t-put-task_struct-on-tctx-setup-.patch @@ -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 index 0000000000..a32787b208 --- /dev/null +++ b/queue-6.15/ionic-prevent-driver-fw-getting-out-of-sync-on-devcm.patch @@ -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 index 0000000000..fb16672c87 --- /dev/null +++ b/queue-6.15/ksmbd-add-free_transport-ops-in-ksmbd-connection.patch @@ -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 index 0000000000..f55185c2d9 --- /dev/null +++ b/queue-6.15/mlxbf_gige-return-eprobe_defer-if-phy-irq-is-not-ava.patch @@ -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 index 0000000000..cd19fe2b4f --- /dev/null +++ b/queue-6.15/mpls-use-rcu_dereference_rtnl-in-mpls_route_input_rc.patch @@ -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 index 0000000000..e0cc2eb77f --- /dev/null +++ b/queue-6.15/net-atm-add-lec_mutex.patch @@ -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 index 0000000000..039b8d618e --- /dev/null +++ b/queue-6.15/net-atm-fix-proc-net-atm-lec-handling.patch @@ -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 index 0000000000..db24b26928 --- /dev/null +++ b/queue-6.15/net-ice-perform-accurate-arfs-flow-match.patch @@ -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 index 0000000000..637de0fb1d --- /dev/null +++ b/queue-6.15/net-lan743x-fix-potential-out-of-bounds-write-in-lan.patch @@ -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 index 0000000000..b8e474886d --- /dev/null +++ b/queue-6.15/net-netmem-fix-skb_ensure_writable-with-unreadable-s.patch @@ -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 index 0000000000..8ecf0f705f --- /dev/null +++ b/queue-6.15/net-ti-icssg-prueth-fix-packet-handling-for-xdp_tx.patch @@ -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 index 0000000000..fbe66f58c8 --- /dev/null +++ b/queue-6.15/octeontx2-pf-fix-backpresure-configuration.patch @@ -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 index 0000000000..37cf46b39b --- /dev/null +++ b/queue-6.15/pldmfw-select-crc32-when-pldmfw-is-selected.patch @@ -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 index 0000000000..f943bcd2fb --- /dev/null +++ b/queue-6.15/ptp-allow-reading-of-currently-dialed-frequency-to-s.patch @@ -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 index 0000000000..9adbab1102 --- /dev/null +++ b/queue-6.15/ptp-fix-breakage-after-ptp_vclock_in_use-rework.patch @@ -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 index 0000000000..ca65a13b8a --- /dev/null +++ b/queue-6.15/rust-devres-do-not-dereference-to-the-internal-revoc.patch @@ -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 index 0000000000..dfc4b7bd54 --- /dev/null +++ b/queue-6.15/rust-devres-fix-race-in-devres-drop.patch @@ -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 index 0000000000..3dd47d42b3 --- /dev/null +++ b/queue-6.15/rust-devres-implement-devres-access.patch @@ -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 + diff --git a/queue-6.15/series b/queue-6.15/series index db3430319d..0079830452 100644 --- a/queue-6.15/series +++ b/queue-6.15/series @@ -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 index 0000000000..d05cb6c539 --- /dev/null +++ b/queue-6.15/tcp-fix-passive-tfo-socket-having-invalid-napi-id.patch @@ -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 index 0000000000..e351edcb80 --- /dev/null +++ b/queue-6.15/tcp-fix-tcp_packet_delayed-for-tcp_is_non_sack_preve.patch @@ -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 index 0000000000..9829b37dd4 --- /dev/null +++ b/queue-6.15/tipc-fix-null-ptr-deref-when-acquiring-remote-ip-of-.patch @@ -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 index 0000000000..2ee86fe8b8 --- /dev/null +++ b/queue-6.15/tools-ynl-fix-mixing-ops-and-notifications-on-one-so.patch @@ -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 index 0000000000..03d6d82d54 --- /dev/null +++ b/queue-6.15/tools-ynl-parse-extack-for-sub-messages.patch @@ -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 index 0000000000..b94296a6fe --- /dev/null +++ b/queue-6.15/ublk-santizize-the-arguments-from-userspace-when-add.patch @@ -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 index 0000000000..e2360d5cb0 --- /dev/null +++ b/queue-6.15/wifi-carl9170-do-not-ping-device-which-has-failed-to.patch @@ -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 index 0000000000..48d5b24f8b --- /dev/null +++ b/queue-6.15/workqueue-initialize-wq_isolated_cpumask-in-workqueu.patch @@ -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 + |